diff --git a/.dockerignore b/.dockerignore index 67f31588..a5d8f723 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,2 @@ -.git/ bin/ dist/ diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index 760189da..f5e0db45 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -7,10 +7,10 @@ jobs: if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/generate-artifacts') runs-on: ubuntu-latest steps: - - name: Set up Go 1.17 + - name: Set up Go 1.18 uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18.3 id: go - name: Checkout code into the Go module directory @@ -42,6 +42,12 @@ jobs: name: docker-compose-linux-amd64 path: ${{ github.workspace }}/bin/docker-compose-linux-amd64 + - name: Upload linux-ppc64le binary + uses: actions/upload-artifact@v2 + with: + name: docker-compose-linux-ppc64le + path: ${{ github.workspace }}/bin/docker-compose-linux-ppc64le + - name: Upload windows-amd64 binary uses: actions/upload-artifact@v2 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8570822..d0b8af50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,12 @@ on: branches: - v2 pull_request: + workflow_dispatch: + inputs: + debug_enabled: + description: 'To run with tmate enter "debug_enabled"' + required: false + default: "false" jobs: lint: @@ -13,16 +19,16 @@ jobs: env: GO111MODULE: "on" steps: - - name: Set up Go 1.17 + - name: Set up Go 1.18 uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18.3 id: go - name: Checkout code into the Go module directory uses: actions/checkout@v2 - - name: Validate go-mod is up-to-date and license headers + - name: Validate go-mod, license headers and docs are up-to-date run: make validate - name: Run golangci-lint @@ -40,10 +46,10 @@ jobs: env: GO111MODULE: "on" steps: - - name: Set up Go 1.17 + - name: Set up Go 1.18 uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18.3 id: go - name: Checkout code into the Go module directory @@ -65,10 +71,10 @@ jobs: env: GO111MODULE: "on" steps: - - name: Set up Go 1.17 + - name: Set up Go 1.18 uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18.3 id: go - name: Setup docker CLI @@ -90,7 +96,7 @@ jobs: - name: Build for local E2E env: BUILD_TAGS: e2e - run: make -f builder.Makefile compose-plugin + run: make GIT_TAG=e2e-PR-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }} -f builder.Makefile compose-plugin - name: E2E Test in plugin mode run: make e2e-compose @@ -101,10 +107,10 @@ jobs: env: GO111MODULE: "on" steps: - - name: Set up Go 1.17 + - name: Set up Go 1.18 uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18.3 id: go - name: Setup docker CLI @@ -123,7 +129,17 @@ jobs: - name: Build for local E2E env: BUILD_TAGS: e2e - run: make -f builder.Makefile compose-plugin + run: make GIT_TAG=e2e-PR-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }} -f builder.Makefile compose-plugin + + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + github-token: ${{ secrets.GITHUB_TOKEN }} + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} - name: E2E Test in standalone mode - run: make e2e-compose-standalone + run: | + rm -f /usr/local/bin/docker-compose + cp bin/docker-compose /usr/local/bin + make e2e-compose-standalone diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..0971034c --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,51 @@ +name: Docs + +on: + release: + types: [published] + +jobs: + open-pr: + runs-on: ubuntu-latest + steps: + - + name: Checkout docs repo + uses: actions/checkout@v3 + with: + token: ${{ secrets.GHPAT_DOCS_DISPATCH }} + repository: docker/docker.github.io + ref: master + - + name: Prepare + run: | + rm -rf ./_data/compose-cli/* + - + name: Build + uses: docker/build-push-action@v3 + with: + context: ${{ github.server_url }}/${{ github.repository }}.git#${{ github.event.release.name }} + target: docs-reference + outputs: ./_data/compose-cli + - + name: Update compose_version in _config.yml + run: | + sed -i "s|^compose_version\:.*|compose_version\: \"${{ github.event.release.name }}\"|g" _config.yml + cat _config.yml | yq .compose_version + - + name: Commit changes + run: | + git add -A . + - + name: Create PR on docs repo + uses: peter-evans/create-pull-request@923ad837f191474af6b1721408744feb989a4c27 # v4.0.4 + with: + token: ${{ secrets.GHPAT_DOCS_DISPATCH }} + commit-message: Update Compose reference API to ${{ github.event.release.name }} + signoff: true + branch: dispatch/compose-api-reference-${{ github.event.release.name }} + delete-branch: true + title: Update Compose reference API to ${{ github.event.release.name }} + body: | + Update the Compose reference API documentation to keep in sync with the latest release `${{ github.event.release.name }}` + labels: area/Compose + draft: false diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ee9413cc..74805b21 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -11,10 +11,10 @@ jobs: upload-release: runs-on: ubuntu-latest steps: - - name: Set up Go 1.17 + - name: Set up Go 1.18 uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18.3 id: go - name: Setup docker CLI @@ -36,7 +36,7 @@ jobs: run: make GIT_TAG=${{ github.event.inputs.tag }} -f builder.Makefile cross - name: Compute checksums - run: cd bin; for f in *; do shasum --algorithm 256 $f > $f.sha256; done + run: cd bin; for f in *; do shasum --binary --algorithm 256 $f | tee -a checksums.txt > $f.sha256; done - name: License run: cp packaging/* bin/ @@ -44,7 +44,8 @@ jobs: - uses: ncipollo/release-action@v1 with: artifacts: "bin/*" - prerelease: true + generateReleaseNotes: true + draft: true commit: "v2" token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ github.event.inputs.tag }} diff --git a/.golangci.yml b/.golangci.yml index 48ca9cf9..49e5801d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,12 +1,11 @@ +run: + concurrency: 2 linters: - run: - concurrency: 2 - skip-dirs: - - tests/composefiles enable-all: false disable-all: true enable: - deadcode + - depguard - errcheck - gocyclo - gofmt @@ -26,6 +25,13 @@ linters: - unused - varcheck linters-settings: + depguard: + list-type: blacklist + include-go-root: true + packages: + # The io/ioutil package has been deprecated. + # https://go.dev/doc/go1.16#ioutil + - io/ioutil gocyclo: min-complexity: 16 lll: diff --git a/BUILDING.md b/BUILDING.md index a1f22be7..a73fb53e 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -8,7 +8,7 @@ * [Docker Desktop](https://hub.docker.com/editions/community/docker-ce-desktop-mac) * make * Linux: - * [Docker 19.03 or later](https://docs.docker.com/engine/install/) + * [Docker 20.10 or later](https://docs.docker.com/engine/install/) * make ### Building the CLI diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 799a78a9..55be2a92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,7 +83,7 @@ don't get discouraged! Our contributor's guide explains Community Slack - The Docker Community has a dedicated Slack chat to discuss features and issues. You can sign-up with this link. + The Docker Community has a dedicated Slack chat to discuss features and issues. You can sign-up with this link. diff --git a/Dockerfile b/Dockerfile index 548caed5..f0d96385 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG GO_VERSION=1.17-alpine +ARG GO_VERSION=1.18.3-alpine ARG GOLANGCI_LINT_VERSION=v1.40.1-alpine ARG PROTOC_GEN_GO_VERSION=v1.4.3 @@ -88,7 +88,7 @@ RUN --mount=target=. \ make -f builder.Makefile test FROM base AS check-license-headers -RUN go get -u github.com/kunalkushwaha/ltag +RUN go install github.com/kunalkushwaha/ltag@latest RUN --mount=target=. \ make -f builder.Makefile check-license-headers @@ -105,3 +105,9 @@ COPY --from=make-go-mod-tidy /compose-cli/go.sum . FROM base AS check-go-mod COPY . . RUN make -f builder.Makefile check-go-mod + +# docs-reference is a target used as remote context to update docs on release +# with latest changes on docker.github.io. +# see open-pr job in .github/workflows/docs.yml for more details +FROM scratch AS docs-reference +COPY docs/reference/*.yaml . diff --git a/Makefile b/Makefile index 3a6098f9..0b36672c 100644 --- a/Makefile +++ b/Makefile @@ -43,12 +43,19 @@ compose-plugin: ## Compile the compose cli-plugin .PHONY: e2e-compose e2e-compose: ## Run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test + docker compose version go test $(TEST_FLAGS) -count=1 ./pkg/e2e .PHONY: e2e-compose-standalone e2e-compose-standalone: ## Run End to end local tests in standalone mode. Set E2E_TEST=TestName to run a single test - go test $(TEST_FLAGS) -count=1 --tags=standalone ./pkg/e2e + docker-compose version + go test $(TEST_FLAGS) -v -count=1 -parallel=1 --tags=standalone ./pkg/e2e +.PHONY: mocks +mocks: + mockgen -destination pkg/mocks/mock_docker_cli.go -package mocks github.com/docker/cli/cli/command Cli + mockgen -destination pkg/mocks/mock_docker_api.go -package mocks github.com/docker/docker/client APIClient + mockgen -destination pkg/mocks/mock_docker_compose_api.go -package mocks -source=./pkg/api/api.go Service .PHONY: e2e e2e: e2e-compose e2e-compose-standalone ## Run end to end local tests in both modes. Set E2E_TEST=TestName to run a single test @@ -78,6 +85,23 @@ lint: ## run linter(s) --build-arg GIT_TAG=$(GIT_TAG) \ --target lint +.PHONY: docs +docs: ## generate documentation + $(eval $@_TMP_OUT := $(shell mktemp -d -t dockercli-output.XXXXXXXXXX)) + docker build . \ + --output type=local,dest=$($@_TMP_OUT) \ + -f ./docs/docs.Dockerfile \ + --target update + rm -rf ./docs/internal + cp -R "$($@_TMP_OUT)"/out/* ./docs/ + rm -rf "$($@_TMP_OUT)"/* + +.PHONY: validate-docs +validate-docs: ## validate the doc does not change + @docker build . \ + -f ./docs/docs.Dockerfile \ + --target validate + .PHONY: check-dependencies check-dependencies: ## check dependency updates go list -u -m -f '{{if not .Indirect}}{{if .Update}}{{.}}{{end}}{{end}}' all @@ -94,7 +118,7 @@ go-mod-tidy: ## Run go mod tidy in a container and output resulting go.mod and g validate-go-mod: ## Validate go.mod and go.sum are up-to-date @docker build . --target check-go-mod -validate: validate-go-mod validate-headers ## Validate sources +validate: validate-go-mod validate-headers validate-docs ## Validate sources pre-commit: validate check-dependencies lint compose-plugin test e2e-compose diff --git a/builder.Makefile b/builder.Makefile index bd610a0c..0f525adb 100644 --- a/builder.Makefile +++ b/builder.Makefile @@ -47,6 +47,7 @@ compose-plugin: .PHONY: cross cross: GOOS=linux GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-x86_64 ./cmd + GOOS=linux GOARCH=ppc64le $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-ppc64le ./cmd GOOS=linux GOARCH=arm64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-aarch64 ./cmd GOOS=linux GOARM=6 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-armv6 ./cmd GOOS=linux GOARM=7 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-armv7 ./cmd @@ -70,7 +71,3 @@ check-license-headers: .PHONY: check-go-mod check-go-mod: ./scripts/validate/check-go-mod - -.PHONY: yamldocs -yamldocs: - go run docs/yaml/main/generate.go \ No newline at end of file diff --git a/cmd/compatibility/convert.go b/cmd/compatibility/convert.go index 27a57063..9bef94bf 100644 --- a/cmd/compatibility/convert.go +++ b/cmd/compatibility/convert.go @@ -50,7 +50,7 @@ func Convert(args []string) []string { l := len(args) for i := 0; i < l; i++ { arg := args[i] - if arg[0] != '-' { + if len(arg) > 0 && arg[0] != '-' { // not a top-level flag anymore, keep the rest of the command unmodified if arg == compose.PluginName { i++ @@ -58,17 +58,18 @@ func Convert(args []string) []string { command = append(command, args[i:]...) break } - if arg == "--verbose" { + + switch arg { + case "--verbose": arg = "--debug" - } - if arg == "-h" { + case "-h": // docker cli has deprecated -h to avoid ambiguity with -H, while docker-compose still support it arg = "--help" - } - if arg == "--version" || arg == "-v" { + case "--version", "-v": // redirect --version pseudo-command to actual command arg = "version" } + if contains(getBoolFlags(), arg) { rootFlags = append(rootFlags, arg) continue diff --git a/cmd/compatibility/convert_test.go b/cmd/compatibility/convert_test.go index 68fc66de..ae242362 100644 --- a/cmd/compatibility/convert_test.go +++ b/cmd/compatibility/convert_test.go @@ -43,11 +43,21 @@ func Test_convert(t *testing.T) { args: []string{"--host", "tcp://1.2.3.4", "up"}, want: []string{"--host", "tcp://1.2.3.4", "compose", "up"}, }, + { + name: "compose --verbose", + args: []string{"--verbose"}, + want: []string{"--debug", "compose"}, + }, { name: "compose --version", args: []string{"--version"}, want: []string{"compose", "version"}, }, + { + name: "compose -v", + args: []string{"-v"}, + want: []string{"compose", "version"}, + }, { name: "help", args: []string{"-h"}, @@ -68,6 +78,11 @@ func Test_convert(t *testing.T) { args: []string{"--log-level", "INFO", "up"}, want: []string{"--log-level", "INFO", "compose", "up"}, }, + { + name: "empty string argument", + args: []string{"--project-directory", "", "ps"}, + want: []string{"compose", "--project-directory", "", "ps"}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/cmd/compose/build.go b/cmd/compose/build.go index 4a4fe993..298d3b67 100644 --- a/cmd/compose/build.go +++ b/cmd/compose/build.go @@ -23,6 +23,7 @@ import ( "strings" "github.com/compose-spec/compose-go/cli" + "github.com/compose-spec/compose-go/loader" "github.com/compose-spec/compose-go/types" buildx "github.com/docker/buildx/util/progress" "github.com/docker/compose/v2/pkg/utils" @@ -40,6 +41,28 @@ type buildOptions struct { args []string noCache bool memory string + ssh string +} + +func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions, error) { + var SSHKeys []types.SSHKey + var err error + if opts.ssh != "" { + SSHKeys, err = loader.ParseShortSSHSyntax(opts.ssh) + if err != nil { + return api.BuildOptions{}, err + } + } + + return api.BuildOptions{ + Pull: opts.pull, + Progress: opts.progress, + Args: types.NewMappingWithEquals(opts.args), + NoCache: opts.noCache, + Quiet: opts.quiet, + Services: services, + SSHs: SSHKeys, + }, nil } var printerModes = []string{ @@ -73,7 +96,10 @@ func buildCommand(p *projectOptions, backend api.Service) *cobra.Command { } return nil }), - RunE: Adapt(func(ctx context.Context, args []string) error { + RunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error { + if cmd.Flags().Changed("ssh") && opts.ssh == "" { + opts.ssh = "default" + } return runBuild(ctx, backend, opts, args) }), ValidArgsFunction: serviceCompletion(p), @@ -82,6 +108,7 @@ func buildCommand(p *projectOptions, backend api.Service) *cobra.Command { cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.") cmd.Flags().StringVar(&opts.progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", "))) cmd.Flags().StringArrayVar(&opts.args, "build-arg", []string{}, "Set build-time variables for services.") + cmd.Flags().StringVar(&opts.ssh, "ssh", "", "Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent)") cmd.Flags().Bool("parallel", true, "Build images in parallel. DEPRECATED") cmd.Flags().MarkHidden("parallel") //nolint:errcheck cmd.Flags().Bool("compress", true, "Compress the build context using gzip. DEPRECATED") @@ -103,12 +130,9 @@ func runBuild(ctx context.Context, backend api.Service, opts buildOptions, servi return err } - return backend.Build(ctx, project, api.BuildOptions{ - Pull: opts.pull, - Progress: opts.progress, - Args: types.NewMappingWithEquals(opts.args), - NoCache: opts.noCache, - Quiet: opts.quiet, - Services: services, - }) + apiBuildOptions, err := opts.toAPIBuildOptions(services) + if err != nil { + return err + } + return backend.Build(ctx, project, apiBuildOptions) } diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 89002f06..84f24d8b 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -27,17 +27,21 @@ import ( "github.com/compose-spec/compose-go/cli" "github.com/compose-spec/compose-go/types" + composegoutils "github.com/compose-spec/compose-go/utils" dockercli "github.com/docker/cli/cli" "github.com/docker/cli/cli-plugins/manager" - "github.com/docker/compose/v2/cmd/formatter" + "github.com/docker/cli/cli/command" "github.com/morikuni/aec" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" + "github.com/docker/compose/v2/cmd/formatter" "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/compose" + "github.com/docker/compose/v2/pkg/progress" + "github.com/docker/compose/v2/pkg/utils" ) // Command defines a compose CLI command as a func with args @@ -86,9 +90,6 @@ func Adapt(fn Command) func(cmd *cobra.Command, args []string) error { }) } -// Warning is a global warning to be displayed to user on command failure -var Warning string - type projectOptions struct { ProjectName string Profiles []string @@ -129,8 +130,8 @@ func (o *projectOptions) addProjectFlags(f *pflag.FlagSet) { f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name") f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files") f.StringVar(&o.EnvFile, "env-file", "", "Specify an alternate environment file.") - f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the Compose file)") - f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the Compose file)") + f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the, first specified, Compose file)") + f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the, first specified, Compose file)") f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode") _ = f.MarkHidden("workdir") } @@ -140,6 +141,11 @@ func (o *projectOptions) toProjectName() (string, error) { return o.ProjectName, nil } + envProjectName := os.Getenv("COMPOSE_PROJECT_NAME") + if envProjectName != "" { + return envProjectName, nil + } + project, err := o.toProject(nil) if err != nil { return "", err @@ -158,13 +164,16 @@ func (o *projectOptions) toProject(services []string, po ...cli.ProjectOptionsFn return nil, compose.WrapComposeError(err) } - if o.Compatibility || project.Environment["COMPOSE_COMPATIBILITY"] == "true" { + if o.Compatibility || utils.StringToBool(project.Environment["COMPOSE_COMPATIBILITY"]) { compose.Separator = "_" } ef := o.EnvFile if ef != "" && !filepath.IsAbs(ef) { - ef = filepath.Join(project.WorkingDir, o.EnvFile) + ef, err = filepath.Abs(ef) + if err != nil { + return nil, err + } } for i, s := range project.Services { s.CustomLabels = map[string]string{ @@ -205,9 +214,9 @@ func (o *projectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.Proj return cli.NewProjectOptions(o.ConfigPaths, append(po, cli.WithWorkingDirectory(o.ProjectDir), + cli.WithOsEnv, cli.WithEnvFile(o.EnvFile), cli.WithDotEnv, - cli.WithOsEnv, cli.WithConfigFileEnv, cli.WithDefaultConfigPath, cli.WithName(o.ProjectName))...) @@ -222,7 +231,7 @@ func RunningAsStandalone() bool { } // RootCommand returns the compose command with its child commands -func RootCommand(backend api.Service) *cobra.Command { +func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { opts := projectOptions{} var ( ansi string @@ -249,6 +258,10 @@ func RootCommand(backend api.Service) *cobra.Command { } }, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + err := setEnvWithDotEnv(&opts) + if err != nil { + return err + } parent := cmd.Root() if parent != nil { parentPrerun := parent.PersistentPreRunE @@ -264,12 +277,18 @@ func RootCommand(backend api.Service) *cobra.Command { return errors.New(`cannot specify DEPRECATED "--no-ansi" and "--ansi". Please use only "--ansi"`) } ansi = "never" - fmt.Fprint(os.Stderr, aec.Apply("option '--no-ansi' is DEPRECATED ! Please use '--ansi' instead.\n", aec.RedF)) + fmt.Fprint(os.Stderr, "option '--no-ansi' is DEPRECATED ! Please use '--ansi' instead.\n") } if verbose { logrus.SetLevel(logrus.TraceLevel) } formatter.SetANSIMode(ansi) + switch ansi { + case "never": + progress.Mode = progress.ModePlain + case "tty": + progress.Mode = progress.ModeTTY + } if opts.WorkDir != "" { if opts.ProjectDir != "" { return errors.New(`cannot specify DEPRECATED "--workdir" and "--project-directory". Please use only "--project-directory" instead`) @@ -292,9 +311,9 @@ func RootCommand(backend api.Service) *cobra.Command { logsCommand(&opts, backend), convertCommand(&opts, backend), killCommand(&opts, backend), - runCommand(&opts, backend), + runCommand(&opts, dockerCli, backend), removeCommand(&opts, backend), - execCommand(&opts, backend), + execCommand(&opts, dockerCli, backend), pauseCommand(&opts, backend), unpauseCommand(&opts, backend), topCommand(&opts, backend), @@ -319,3 +338,27 @@ func RootCommand(backend api.Service) *cobra.Command { command.Flags().MarkHidden("verbose") //nolint:errcheck return command } + +func setEnvWithDotEnv(prjOpts *projectOptions) error { + options, err := prjOpts.toProjectOptions() + if err != nil { + return compose.WrapComposeError(err) + } + workingDir, err := options.GetWorkingDir() + if err != nil { + return err + } + + envFromFile, err := cli.GetEnvFromFile(composegoutils.GetAsEqualsMap(os.Environ()), workingDir, options.EnvFile) + if err != nil { + return err + } + for k, v := range envFromFile { + if _, ok := os.LookupEnv(k); !ok { + if err = os.Setenv(k, v); err != nil { + return err + } + } + } + return nil +} diff --git a/cmd/compose/cp.go b/cmd/compose/cp.go index e38b9de4..80492075 100644 --- a/cmd/compose/cp.go +++ b/cmd/compose/cp.go @@ -55,7 +55,7 @@ func copyCommand(p *projectOptions, backend api.Service) *cobra.Command { } return nil }), - RunE: Adapt(func(ctx context.Context, args []string) error { + RunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error { opts.source = args[0] opts.destination = args[1] return runCopy(ctx, backend, opts) @@ -64,8 +64,10 @@ func copyCommand(p *projectOptions, backend api.Service) *cobra.Command { } flags := copyCmd.Flags() - flags.IntVar(&opts.index, "index", 1, "Index of the container if there are multiple instances of a service [default: 1].") + flags.IntVar(&opts.index, "index", 0, "Index of the container if there are multiple instances of a service .") flags.BoolVar(&opts.all, "all", false, "Copy to all the containers of the service.") + flags.MarkHidden("all") //nolint:errcheck + flags.MarkDeprecated("all", "By default all the containers of the service will get the source file/directory to be copied.") //nolint:errcheck flags.BoolVarP(&opts.followLink, "follow-link", "L", false, "Always follow symbol link in SRC_PATH") flags.BoolVarP(&opts.copyUIDGID, "archive", "a", false, "Archive mode (copy all uid/gid information)") diff --git a/cmd/compose/down.go b/cmd/compose/down.go index 4c0369de..e94aec1f 100644 --- a/cmd/compose/down.go +++ b/cmd/compose/down.go @@ -20,10 +20,10 @@ import ( "context" "fmt" "os" - "strings" "time" "github.com/compose-spec/compose-go/types" + "github.com/docker/compose/v2/pkg/utils" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -59,10 +59,11 @@ func downCommand(p *projectOptions, backend api.Service) *cobra.Command { RunE: Adapt(func(ctx context.Context, args []string) error { return runDown(ctx, backend, opts) }), + Args: cobra.NoArgs, ValidArgsFunction: noCompletion(), } flags := downCmd.Flags() - removeOrphans := strings.ToLower(os.Getenv("COMPOSE_REMOVE_ORPHANS ")) == "true" + removeOrphans := utils.StringToBool(os.Getenv("COMPOSE_REMOVE_ORPHANS")) flags.BoolVar(&opts.removeOrphans, "remove-orphans", removeOrphans, "Remove containers for services not defined in the Compose file.") flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds") flags.BoolVarP(&opts.volumes, "volumes", "v", false, " Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers.") diff --git a/cmd/compose/exec.go b/cmd/compose/exec.go index 708c7e73..00faae6c 100644 --- a/cmd/compose/exec.go +++ b/cmd/compose/exec.go @@ -18,12 +18,10 @@ package compose import ( "context" - "fmt" - "os" "github.com/compose-spec/compose-go/types" - "github.com/containerd/console" "github.com/docker/cli/cli" + "github.com/docker/cli/cli/command" "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/compose" "github.com/spf13/cobra" @@ -37,14 +35,15 @@ type execOpts struct { environment []string workingDir string - noTty bool - user string - detach bool - index int - privileged bool + noTty bool + user string + detach bool + index int + privileged bool + interactive bool } -func execCommand(p *projectOptions, backend api.Service) *cobra.Command { +func execCommand(p *projectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command { opts := execOpts{ composeOptions: &composeOptions{ projectOptions: p, @@ -70,9 +69,14 @@ func execCommand(p *projectOptions, backend api.Service) *cobra.Command { runCmd.Flags().IntVar(&opts.index, "index", 1, "index of the container if there are multiple instances of a service [default: 1].") runCmd.Flags().BoolVarP(&opts.privileged, "privileged", "", false, "Give extended privileges to the process.") runCmd.Flags().StringVarP(&opts.user, "user", "u", "", "Run the command as this user.") - runCmd.Flags().BoolVarP(&opts.noTty, "no-TTY", "T", false, "Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY.") + runCmd.Flags().BoolVarP(&opts.noTty, "no-TTY", "T", !dockerCli.Out().IsTerminal(), "Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY.") runCmd.Flags().StringVarP(&opts.workingDir, "workdir", "w", "", "Path to workdir directory for this command.") + runCmd.Flags().BoolVarP(&opts.interactive, "interactive", "i", true, "Keep STDIN open even if not attached.") + runCmd.Flags().MarkHidden("interactive") //nolint:errcheck + runCmd.Flags().BoolP("tty", "t", true, "Allocate a pseudo-TTY.") + runCmd.Flags().MarkHidden("tty") //nolint:errcheck + runCmd.Flags().SetInterspersed(false) return runCmd } @@ -100,27 +104,9 @@ func runExec(ctx context.Context, backend api.Service, opts execOpts) error { Index: opts.index, Detach: opts.detach, WorkingDir: opts.workingDir, - - Stdin: os.Stdin, - Stdout: os.Stdout, - Stderr: os.Stderr, + Interactive: opts.interactive, } - if execOpts.Tty { - con := console.Current() - if err := con.SetRaw(); err != nil { - return err - } - defer func() { - if err := con.Reset(); err != nil { - fmt.Println("Unable to close the console") - } - }() - - execOpts.Stdin = con - execOpts.Stdout = con - execOpts.Stderr = con - } exitCode, err := backend.Exec(ctx, projectName, execOpts) if exitCode != 0 { errMsg := "" diff --git a/cmd/compose/kill.go b/cmd/compose/kill.go index a39fda67..eb17f1f1 100644 --- a/cmd/compose/kill.go +++ b/cmd/compose/kill.go @@ -19,25 +19,44 @@ package compose import ( "context" - "github.com/compose-spec/compose-go/types" "github.com/spf13/cobra" "github.com/docker/compose/v2/pkg/api" ) +type killOptions struct { + *projectOptions + signal string +} + func killCommand(p *projectOptions, backend api.Service) *cobra.Command { - var opts api.KillOptions + opts := killOptions{ + projectOptions: p, + } cmd := &cobra.Command{ Use: "kill [options] [SERVICE...]", Short: "Force stop service containers.", - RunE: p.WithProject(func(ctx context.Context, project *types.Project) error { - return backend.Kill(ctx, project, opts) + RunE: Adapt(func(ctx context.Context, args []string) error { + return runKill(ctx, backend, opts, args) }), ValidArgsFunction: serviceCompletion(p), } flags := cmd.Flags() - flags.StringVarP(&opts.Signal, "signal", "s", "SIGKILL", "SIGNAL to send to the container.") + flags.StringVarP(&opts.signal, "signal", "s", "SIGKILL", "SIGNAL to send to the container.") return cmd } + +func runKill(ctx context.Context, backend api.Service, opts killOptions, services []string) error { + projectName, err := opts.toProjectName() + if err != nil { + return err + } + + return backend.Kill(ctx, projectName, api.KillOptions{ + Services: services, + Signal: opts.signal, + }) + +} diff --git a/cmd/compose/ps.go b/cmd/compose/ps.go index 634a1154..0c294998 100644 --- a/cmd/compose/ps.go +++ b/cmd/compose/ps.go @@ -27,6 +27,7 @@ import ( "github.com/docker/compose/v2/cmd/formatter" "github.com/docker/compose/v2/pkg/utils" + "github.com/docker/docker/api/types" formatter2 "github.com/docker/cli/cli/command/formatter" "github.com/pkg/errors" @@ -81,12 +82,11 @@ func psCommand(p *projectOptions, backend api.Service) *cobra.Command { } flags := psCmd.Flags() flags.StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json]") - flags.StringVar(&opts.Filter, "filter", "", "Filter services by a property. Deprecated, use --status instead") + flags.StringVar(&opts.Filter, "filter", "", "Filter services by a property (supported filters: status).") flags.StringArrayVar(&opts.Status, "status", []string{}, "Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited]") flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs") flags.BoolVar(&opts.Services, "services", false, "Display services") flags.BoolVarP(&opts.All, "all", "a", false, "Show all stopped containers (including those created by the run command)") - flags.Lookup("filter").Hidden = true return psCmd } @@ -140,14 +140,14 @@ SERVICES: } return formatter.Print(containers, opts.Format, os.Stdout, - writter(containers), + writer(containers), "NAME", "COMMAND", "SERVICE", "STATUS", "PORTS") } -func writter(containers []api.ContainerSummary) func(w io.Writer) { +func writer(containers []api.ContainerSummary) func(w io.Writer) { return func(w io.Writer) { for _, container := range containers { - ports := DisplayablePorts(container) + ports := displayablePorts(container) status := container.State if status == "running" && container.Health != "" { status = fmt.Sprintf("%s (%s)", container.State, container.Health) @@ -179,72 +179,20 @@ func hasStatus(c api.ContainerSummary, statuses []string) bool { return false } -type portRange struct { - pStart int - pEnd int - tStart int - tEnd int - IP string - protocol string -} - -func (pr portRange) String() string { - var ( - pub string - tgt string - ) - - if pr.pEnd > pr.pStart { - pub = fmt.Sprintf("%s:%d-%d->", pr.IP, pr.pStart, pr.pEnd) - } else if pr.pStart > 0 { - pub = fmt.Sprintf("%s:%d->", pr.IP, pr.pStart) - } - if pr.tEnd > pr.tStart { - tgt = fmt.Sprintf("%d-%d", pr.tStart, pr.tEnd) - } else { - tgt = fmt.Sprintf("%d", pr.tStart) - } - return fmt.Sprintf("%s%s/%s", pub, tgt, pr.protocol) -} - -// DisplayablePorts is copy pasted from https://github.com/docker/cli/pull/581/files -func DisplayablePorts(c api.ContainerSummary) string { +func displayablePorts(c api.ContainerSummary) string { if c.Publishers == nil { return "" } - sort.Sort(c.Publishers) - - pr := portRange{} - ports := []string{} - for _, p := range c.Publishers { - prIsRange := pr.tEnd != pr.tStart - tOverlaps := p.TargetPort <= pr.tEnd - - // Start a new port-range if: - // - the protocol is different from the current port-range - // - published or target port are not consecutive to the current port-range - // - the current port-range is a _range_, and the target port overlaps with the current range's target-ports - if p.Protocol != pr.protocol || p.URL != pr.IP || p.PublishedPort-pr.pEnd > 1 || p.TargetPort-pr.tEnd > 1 || prIsRange && tOverlaps { - // start a new port-range, and print the previous port-range (if any) - if pr.pStart > 0 { - ports = append(ports, pr.String()) - } - pr = portRange{ - pStart: p.PublishedPort, - pEnd: p.PublishedPort, - tStart: p.TargetPort, - tEnd: p.TargetPort, - protocol: p.Protocol, - IP: p.URL, - } - continue + ports := make([]types.Port, len(c.Publishers)) + for i, pub := range c.Publishers { + ports[i] = types.Port{ + IP: pub.URL, + PrivatePort: uint16(pub.TargetPort), + PublicPort: uint16(pub.PublishedPort), + Type: pub.Protocol, } - pr.pEnd = p.PublishedPort - pr.tEnd = p.TargetPort } - if pr.tStart > 0 { - ports = append(ports, pr.String()) - } - return strings.Join(ports, ", ") + + return formatter2.DisplayablePorts(ports) } diff --git a/cmd/compose/ps_test.go b/cmd/compose/ps_test.go new file mode 100644 index 00000000..2a6d6bb6 --- /dev/null +++ b/cmd/compose/ps_test.go @@ -0,0 +1,84 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package compose + +import ( + "context" + "os" + "path/filepath" + "testing" + + "github.com/docker/compose/v2/pkg/api" + "github.com/docker/compose/v2/pkg/mocks" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +func TestPsPretty(t *testing.T) { + ctx := context.Background() + origStdout := os.Stdout + t.Cleanup(func() { + os.Stdout = origStdout + }) + dir := t.TempDir() + f, err := os.Create(filepath.Join(dir, "output.txt")) + if err != nil { + t.Fatal("could not create output file") + } + defer func() { _ = f.Close() }() + + os.Stdout = f + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + backend := mocks.NewMockService(ctrl) + backend.EXPECT(). + Ps(gomock.Eq(ctx), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, projectName string, options api.PsOptions) ([]api.ContainerSummary, error) { + return []api.ContainerSummary{ + { + ID: "abc123", + Name: "ABC", + Publishers: api.PortPublishers{ + { + TargetPort: 8080, + PublishedPort: 8080, + Protocol: "tcp", + }, + { + TargetPort: 8443, + PublishedPort: 8443, + Protocol: "tcp", + }, + }, + }, + }, nil + }).AnyTimes() + + opts := psOptions{projectOptions: &projectOptions{ProjectName: "test"}} + err = runPs(ctx, backend, nil, opts) + assert.NoError(t, err) + + _, err = f.Seek(0, 0) + assert.NoError(t, err) + + output := make([]byte, 256) + _, err = f.Read(output) + assert.NoError(t, err) + + assert.Contains(t, string(output), "8080/tcp, 8443/tcp") +} diff --git a/cmd/compose/remove.go b/cmd/compose/remove.go index b4b61d58..8f0bbd21 100644 --- a/cmd/compose/remove.go +++ b/cmd/compose/remove.go @@ -59,13 +59,13 @@ Any data which is not in a volume will be lost.`, } func runRemove(ctx context.Context, backend api.Service, opts removeOptions, services []string) error { - project, err := opts.toProject(services) + project, err := opts.toProjectName() if err != nil { return err } if opts.stop { - err := backend.Stop(ctx, project.Name, api.StopOptions{ + err := backend.Stop(ctx, project, api.StopOptions{ Services: services, }) if err != nil { diff --git a/cmd/compose/run.go b/cmd/compose/run.go index 57502620..39f47609 100644 --- a/cmd/compose/run.go +++ b/cmd/compose/run.go @@ -19,12 +19,12 @@ package compose import ( "context" "fmt" - "os" "strings" cgo "github.com/compose-spec/compose-go/cli" "github.com/compose-spec/compose-go/loader" "github.com/compose-spec/compose-go/types" + "github.com/docker/cli/cli/command" "github.com/mattn/go-shellwords" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -42,6 +42,7 @@ type runOptions struct { Detach bool Remove bool noTty bool + interactive bool user string workdir string entrypoint string @@ -53,6 +54,7 @@ type runOptions struct { servicePorts bool name string noDeps bool + ignoreOrphans bool quietPull bool } @@ -61,6 +63,9 @@ func (opts runOptions) apply(project *types.Project) error { if err != nil { return err } + + target.Tty = !opts.noTty + target.StdinOpen = opts.interactive if !opts.servicePorts { target.Ports = []types.ServicePortConfig{} } @@ -102,7 +107,7 @@ func (opts runOptions) apply(project *types.Project) error { return nil } -func runCommand(p *projectOptions, backend api.Service) *cobra.Command { +func runCommand(p *projectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command { opts := runOptions{ composeOptions: &composeOptions{ projectOptions: p, @@ -134,6 +139,8 @@ func runCommand(p *projectOptions, backend api.Service) *cobra.Command { if err != nil { return err } + ignore := project.Environment["COMPOSE_IGNORE_ORPHANS"] + opts.ignoreOrphans = strings.ToLower(ignore) == "true" return runRun(ctx, backend, project, opts) }), ValidArgsFunction: serviceCompletion(p), @@ -143,7 +150,7 @@ func runCommand(p *projectOptions, backend api.Service) *cobra.Command { flags.StringArrayVarP(&opts.environment, "env", "e", []string{}, "Set environment variables") flags.StringArrayVarP(&opts.labels, "label", "l", []string{}, "Add or override a label") flags.BoolVar(&opts.Remove, "rm", false, "Automatically remove the container when it exits") - flags.BoolVarP(&opts.noTty, "no-TTY", "T", false, "Disable pseudo-noTty allocation. By default docker compose run allocates a TTY") + flags.BoolVarP(&opts.noTty, "no-TTY", "T", !dockerCli.Out().IsTerminal(), "Disable pseudo-TTY allocation (default: auto-detected).") flags.StringVar(&opts.name, "name", "", " Assign a name to the container") flags.StringVarP(&opts.user, "user", "u", "", "Run as specified username or uid") flags.StringVarP(&opts.workdir, "workdir", "w", "", "Working directory inside the container") @@ -155,6 +162,10 @@ func runCommand(p *projectOptions, backend api.Service) *cobra.Command { flags.BoolVar(&opts.servicePorts, "service-ports", false, "Run command with the service's ports enabled and mapped to the host.") flags.BoolVar(&opts.quietPull, "quiet-pull", false, "Pull without printing progress information.") + cmd.Flags().BoolVarP(&opts.interactive, "interactive", "i", true, "Keep STDIN open even if not attached.") + cmd.Flags().BoolP("tty", "t", true, "Allocate a pseudo-TTY.") + cmd.Flags().MarkHidden("tty") //nolint:errcheck + flags.SetNormalizeFunc(normalizeRunFlags) flags.SetInterspersed(false) return cmd @@ -177,7 +188,7 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op } err = progress.Run(ctx, func(ctx context.Context) error { - return startDependencies(ctx, backend, *project, opts.Service) + return startDependencies(ctx, backend, *project, opts.Service, opts.ignoreOrphans) }) if err != nil { return err @@ -199,10 +210,8 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op Command: opts.Command, Detach: opts.Detach, AutoRemove: opts.Remove, - Stdin: os.Stdin, - Stdout: os.Stdout, - Stderr: os.Stderr, Tty: !opts.noTty, + Interactive: opts.interactive, WorkingDir: opts.workdir, User: opts.user, Environment: opts.environment, @@ -213,6 +222,14 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op Index: 0, QuietPull: opts.quietPull, } + + for i, service := range project.Services { + if service.Name == opts.Service { + service.StdinOpen = opts.interactive + project.Services[i] = service + } + } + exitCode, err := backend.RunOneOffContainer(ctx, project, runOpts) if exitCode != 0 { errMsg := "" @@ -224,7 +241,7 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op return err } -func startDependencies(ctx context.Context, backend api.Service, project types.Project, requestedServiceName string) error { +func startDependencies(ctx context.Context, backend api.Service, project types.Project, requestedServiceName string, ignoreOrphans bool) error { dependencies := types.Services{} var requestedService types.ServiceConfig for _, service := range project.Services { @@ -237,8 +254,17 @@ func startDependencies(ctx context.Context, backend api.Service, project types.P project.Services = dependencies project.DisabledServices = append(project.DisabledServices, requestedService) - if err := backend.Create(ctx, &project, api.CreateOptions{}); err != nil { + err := backend.Create(ctx, &project, api.CreateOptions{ + IgnoreOrphans: ignoreOrphans, + }) + if err != nil { return err } - return backend.Start(ctx, project.Name, api.StartOptions{}) + + if len(dependencies) > 0 { + return backend.Start(ctx, project.Name, api.StartOptions{ + Project: &project, + }) + } + return nil } diff --git a/cmd/compose/up.go b/cmd/compose/up.go index f889d3b8..7a89e1dd 100644 --- a/cmd/compose/up.go +++ b/cmd/compose/up.go @@ -103,8 +103,7 @@ func upCommand(p *projectOptions, backend api.Service) *cobra.Command { return validateFlags(&up, &create) }), RunE: p.WithServices(func(ctx context.Context, project *types.Project, services []string) error { - ignore := project.Environment["COMPOSE_IGNORE_ORPHANS"] - create.ignoreOrphans = strings.ToLower(ignore) == "true" + create.ignoreOrphans = utils.StringToBool(project.Environment["COMPOSE_IGNORE_ORPHANS"]) if create.ignoreOrphans && create.removeOrphans { return fmt.Errorf("COMPOSE_IGNORE_ORPHANS and --remove-orphans cannot be combined") } @@ -186,6 +185,9 @@ func runUp(ctx context.Context, backend api.Service, createOptions createOptions if upOptions.attachDependencies { attachTo = project.ServiceNames() } + if len(attachTo) == 0 { + attachTo = project.ServiceNames() + } create := api.CreateOptions{ Services: services, @@ -205,6 +207,7 @@ func runUp(ctx context.Context, backend api.Service, createOptions createOptions return backend.Up(ctx, project, api.UpOptions{ Create: create, Start: api.StartOptions{ + Project: project, Attach: consumer, AttachTo: attachTo, ExitCodeFrom: upOptions.exitCodeFrom, diff --git a/cmd/compose/version.go b/cmd/compose/version.go index 15e35676..30e0e753 100644 --- a/cmd/compose/version.go +++ b/cmd/compose/version.go @@ -57,7 +57,7 @@ func runVersion(opts versionOptions) { return } if opts.format == formatter.JSON { - fmt.Printf(`{"version":%q}\n`, internal.Version) + fmt.Printf("{\"version\":%q}\n", internal.Version) return } fmt.Println("Docker Compose version", internal.Version) diff --git a/cmd/formatter/logs.go b/cmd/formatter/logs.go index 5543ca86..2cc9c84e 100644 --- a/cmd/formatter/logs.go +++ b/cmd/formatter/logs.go @@ -79,7 +79,7 @@ func (l *logConsumer) Log(container, service, message string) { } p := l.getPresenter(container) for _, line := range strings.Split(message, "\n") { - fmt.Fprintf(l.writer, "%s %s\n", p.prefix, line) // nolint:errcheck + fmt.Fprintf(l.writer, "%s%s\n", p.prefix, line) // nolint:errcheck } } @@ -118,5 +118,5 @@ type presenter struct { } func (p *presenter) setPrefix(width int) { - p.prefix = p.colors(fmt.Sprintf("%-"+strconv.Itoa(width)+"s |", p.name)) + p.prefix = p.colors(fmt.Sprintf("%-"+strconv.Itoa(width)+"s | ", p.name)) } diff --git a/cmd/main.go b/cmd/main.go index 957910a3..2325d975 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -32,21 +32,16 @@ import ( "github.com/docker/compose/v2/pkg/compose" ) -func init() { - commands.Warning = "The new 'docker compose' command is currently experimental. " + - "To provide feedback or request new features please open issues at https://github.com/docker/compose" -} - func pluginMain() { plugin.Run(func(dockerCli command.Cli) *cobra.Command { lazyInit := api.NewServiceProxy() - cmd := commands.RootCommand(lazyInit) + cmd := commands.RootCommand(dockerCli, lazyInit) originalPreRun := cmd.PersistentPreRunE cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { if err := plugin.PersistentPreRunE(cmd, args); err != nil { return err } - lazyInit.WithService(compose.NewComposeService(dockerCli.Client(), dockerCli.ConfigFile())) + lazyInit.WithService(compose.NewComposeService(dockerCli)) if originalPreRun != nil { return originalPreRun(cmd, args) } @@ -68,7 +63,7 @@ func pluginMain() { } func main() { - if commands.RunningAsStandalone() { + if plugin.RunningStandalone() { os.Args = append([]string{"docker"}, compatibility.Convert(os.Args[1:])...) } pluginMain() diff --git a/docs/docs.Dockerfile b/docs/docs.Dockerfile new file mode 100644 index 00000000..61657b7e --- /dev/null +++ b/docs/docs.Dockerfile @@ -0,0 +1,57 @@ +# syntax=docker/dockerfile:1.3-labs + + +# Copyright 2020 Docker Compose CLI authors + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG GO_VERSION=1.18.3 +ARG FORMATS=md,yaml + +FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION}-alpine AS docsgen +WORKDIR /src +RUN --mount=target=. \ + --mount=target=/root/.cache,type=cache \ + go build -o /out/docsgen ./docs/yaml/main/generate.go + +FROM --platform=${BUILDPLATFORM} alpine AS gen +RUN apk add --no-cache rsync git +WORKDIR /src +COPY --from=docsgen /out/docsgen /usr/bin +ARG FORMATS +RUN --mount=target=/context \ + --mount=target=.,type=tmpfs <&2 'ERROR: Docs result differs. Please update with "make docs"' + git status --porcelain -- docs/reference + exit 1 +fi +EOT diff --git a/docs/reference/compose.md b/docs/reference/compose.md index a3bba298..46d3a1a7 100644 --- a/docs/reference/compose.md +++ b/docs/reference/compose.md @@ -1,4 +1,54 @@ +# docker compose + +Docker Compose + +### Subcommands + +| Name | Description | +| --- | --- | +| [`build`](compose_build.md) | Build or rebuild services | +| [`convert`](compose_convert.md) | Converts the compose file to platform's canonical format | +| [`cp`](compose_cp.md) | Copy files/folders between a service container and the local filesystem | +| [`create`](compose_create.md) | Creates containers for a service. | +| [`down`](compose_down.md) | Stop and remove containers, networks | +| [`events`](compose_events.md) | Receive real time events from containers. | +| [`exec`](compose_exec.md) | Execute a command in a running container. | +| [`images`](compose_images.md) | List images used by the created containers | +| [`kill`](compose_kill.md) | Force stop service containers. | +| [`logs`](compose_logs.md) | View output from containers | +| [`ls`](compose_ls.md) | List running compose projects | +| [`pause`](compose_pause.md) | Pause services | +| [`port`](compose_port.md) | Print the public port for a port binding. | +| [`ps`](compose_ps.md) | List containers | +| [`pull`](compose_pull.md) | Pull service images | +| [`push`](compose_push.md) | Push service images | +| [`restart`](compose_restart.md) | Restart containers | +| [`rm`](compose_rm.md) | Removes stopped service containers | +| [`run`](compose_run.md) | Run a one-off command on a service. | +| [`start`](compose_start.md) | Start services | +| [`stop`](compose_stop.md) | Stop services | +| [`top`](compose_top.md) | Display the running processes | +| [`unpause`](compose_unpause.md) | Unpause services | +| [`up`](compose_up.md) | Create and start containers | +| [`version`](compose_version.md) | Show the Docker Compose version information | + + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--ansi` | `string` | `auto` | Control when to print ANSI control characters ("never"\|"always"\|"auto") | +| `--compatibility` | | | Run compose in backward compatibility mode | +| `--env-file` | `string` | | Specify an alternate environment file. | +| `-f`, `--file` | `stringArray` | | Compose configuration files | +| `--profile` | `stringArray` | | Specify a profile to enable | +| `--project-directory` | `string` | | Specify an alternate working directory +(default: the path of the, first specified, Compose file) | +| `-p`, `--project-name` | `string` | | Project name | + + + ## Description @@ -9,8 +59,8 @@ multiple services in Docker containers. Use the `-f` flag to specify the location of a Compose configuration file. #### Specifying multiple Compose files -You can supply multiple `-f` configuration files. When you supply multiple files, Compose combines them into a single -configuration. Compose builds the configuration in the order you supply the files. Subsequent files override and add +You can supply multiple `-f` configuration files. When you supply multiple files, Compose combines them into a single +configuration. Compose builds the configuration in the order you supply the files. Subsequent files override and add to their predecessors. For example, consider this command line: @@ -30,7 +80,7 @@ services: volumes: - "/data" ``` -If the `docker-compose.admin.yml` also specifies this same service, any matching fields override the previous file. +If the `docker-compose.admin.yml` also specifies this same service, any matching fields override the previous file. New values, add to the `webapp` service configuration. ```yaml @@ -41,22 +91,22 @@ services: - DEBUG=1 ``` -When you use multiple Compose files, all paths in the files are relative to the first configuration file specified +When you use multiple Compose files, all paths in the files are relative to the first configuration file specified with `-f`. You can use the `--project-directory` option to override this base path. -Use a `-f` with `-` (dash) as the filename to read the configuration from stdin. When stdin is used all paths in the +Use a `-f` with `-` (dash) as the filename to read the configuration from stdin. When stdin is used all paths in the configuration are relative to the current working directory. -The `-f` flag is optional. If you don’t provide this flag on the command line, Compose traverses the working directory +The `-f` flag is optional. If you don’t provide this flag on the command line, Compose traverses the working directory and its parent directories looking for a `compose.yaml` or `docker-compose.yaml` file. #### Specifying a path to a single Compose file -You can use the `-f` flag to specify a path to a Compose file that is not located in the current directory, either +You can use the `-f` flag to specify a path to a Compose file that is not located in the current directory, either from the command line or by setting up a `COMPOSE_FILE` environment variable in your shell or in an environment file. -For an example of using the `-f` option at the command line, suppose you are running the Compose Rails sample, and -have a `compose.yaml` file in a directory called `sandbox/rails`. You can use a command like `docker compose pull` to -get the postgres image for the db service from anywhere by using the `-f` flag as follows: +For an example of using the `-f` option at the command line, suppose you are running the Compose Rails sample, and +have a `compose.yaml` file in a directory called `sandbox/rails`. You can use a command like `docker compose pull` to +get the postgres image for the db service from anywhere by using the `-f` flag as follows: ```console $ docker compose -f ~/sandbox/rails/compose.yaml pull db @@ -64,17 +114,17 @@ $ docker compose -f ~/sandbox/rails/compose.yaml pull db ### Use `-p` to specify a project name -Each configuration has a project name. If you supply a `-p` flag, you can specify a project name. If you don’t -specify the flag, Compose uses the current directory name. +Each configuration has a project name. If you supply a `-p` flag, you can specify a project name. If you don’t +specify the flag, Compose uses the current directory name. Project name can also be set by `COMPOSE_PROJECT_NAME` environment variable. -Most compose subcommand can be ran without a compose file, just passing +Most compose subcommand can be ran without a compose file, just passing project name to retrieve the relevant resources. ```console $ docker compose -p my_project ps -a NAME SERVICE STATUS PORTS -my_project_demo_1 demo running +my_project_demo_1 demo running $ docker compose -p my_project logs demo_1 | PING localhost (127.0.0.1): 56 data bytes @@ -84,8 +134,8 @@ demo_1 | 64 bytes from 127.0.0.1: seq=0 ttl=64 time=0.095 ms ### Use profiles to enable optional services Use `--profile` to specify one or more active profiles -Calling `docker compose --profile frontend up` will start the services with the profile `frontend` and services -without any specified profiles. +Calling `docker compose --profile frontend up` will start the services with the profile `frontend` and services +without any specified profiles. You can also enable multiple profiles, e.g. with `docker compose --profile frontend --profile debug up` the profiles `frontend` and `debug` will be enabled. Profiles can also be set by `COMPOSE_PROFILES` environment variable. @@ -99,3 +149,6 @@ Setting the `COMPOSE_FILE` environment variable is equivalent to passing the `-f and so does `COMPOSE_PROFILES` environment variable for to the `--profiles` flag. If flags are explicitly set on command line, associated environment variable is ignored + +Setting the `COMPOSE_IGNORE_ORPHANS` environment variable to `true` will stop docker compose from detecting orphaned +containers for the project. diff --git a/docs/reference/compose_build.md b/docs/reference/compose_build.md index df3d78f8..292df454 100644 --- a/docs/reference/compose_build.md +++ b/docs/reference/compose_build.md @@ -1,12 +1,30 @@ +# docker compose build + + +Build or rebuild services + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--build-arg` | `stringArray` | | Set build-time variables for services. | +| `--no-cache` | | | Do not use cache when building the image | +| `--progress` | `string` | `auto` | Set type of progress output (auto, tty, plain, quiet) | +| `--pull` | | | Always attempt to pull a newer version of the image. | +| `-q`, `--quiet` | | | Don't print anything to STDOUT | +| `--ssh` | `string` | | Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent) | + + + ## Description -Services are built once and then tagged, by default as `project_service`. +Services are built once and then tagged, by default as `project_service`. If the Compose file specifies an -[image](https://github.com/compose-spec/compose-spec/blob/master/spec.md#image) name, +[image](https://github.com/compose-spec/compose-spec/blob/master/spec.md#image) name, the image is tagged with that name, substituting any variables beforehand. See [variable interpolation](https://github.com/compose-spec/compose-spec/blob/master/spec.md#interpolation). -If you change a service's `Dockerfile` or the contents of its build directory, +If you change a service's `Dockerfile` or the contents of its build directory, run `docker compose build` to rebuild it. diff --git a/docs/reference/compose_convert.md b/docs/reference/compose_convert.md index 344060f0..91ff89ea 100644 --- a/docs/reference/compose_convert.md +++ b/docs/reference/compose_convert.md @@ -1,9 +1,35 @@ +# docker compose convert + +Converts the compose file to platform's canonical format + +### Aliases + +`convert`, `config` + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--format` | `string` | `yaml` | Format the output. Values: [yaml \| json] | +| `--hash` | `string` | | Print the service config hash, one per line. | +| `--images` | | | Print the image names, one per line. | +| `--no-interpolate` | | | Don't interpolate environment variables. | +| `--no-normalize` | | | Don't normalize compose model. | +| `-o`, `--output` | `string` | | Save to file (default to stdout) | +| `--profiles` | | | Print the profile names, one per line. | +| `-q`, `--quiet` | | | Only validate the configuration, don't print anything. | +| `--resolve-image-digests` | | | Pin image tags to digests. | +| `--services` | | | Print the service names, one per line. | +| `--volumes` | | | Print the volume names, one per line. | + + + ## Description `docker compose convert` render the actual data model to be applied on target platform. When used with Docker engine, -it merges the Compose files set by `-f` flags, resolves variables in Compose file, and expands short-notation into -fully defined Compose model. +it merges the Compose files set by `-f` flags, resolves variables in Compose file, and expands short-notation into +fully defined Compose model. To allow smooth migration from docker-compose, this subcommand declares alias `docker compose config` diff --git a/docs/reference/compose_cp.md b/docs/reference/compose_cp.md index e69de29b..dd9a02e6 100644 --- a/docs/reference/compose_cp.md +++ b/docs/reference/compose_cp.md @@ -0,0 +1,16 @@ +# docker compose cp + + +Copy files/folders between a service container and the local filesystem + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-a`, `--archive` | | | Archive mode (copy all uid/gid information) | +| `-L`, `--follow-link` | | | Always follow symbol link in SRC_PATH | +| `--index` | `int` | `0` | Index of the container if there are multiple instances of a service . | + + + + diff --git a/docs/reference/compose_create.md b/docs/reference/compose_create.md index e69de29b..00123ba7 100644 --- a/docs/reference/compose_create.md +++ b/docs/reference/compose_create.md @@ -0,0 +1,17 @@ +# docker compose create + + +Creates containers for a service. + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--build` | | | Build images before starting containers. | +| `--force-recreate` | | | Recreate containers even if their configuration and image haven't changed. | +| `--no-build` | | | Don't build an image, even if it's missing. | +| `--no-recreate` | | | If containers already exist, don't recreate them. Incompatible with --force-recreate. | + + + + diff --git a/docs/reference/compose_down.md b/docs/reference/compose_down.md index 1cc21d81..8864aa6e 100644 --- a/docs/reference/compose_down.md +++ b/docs/reference/compose_down.md @@ -1,4 +1,19 @@ +# docker compose down + +Stop and remove containers, networks + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--remove-orphans` | | | Remove containers for services not defined in the Compose file. | +| `--rmi` | `string` | | Remove images used by services. "local" remove only images that don't have a custom tag ("local"\|"all") | +| `-t`, `--timeout` | `int` | `10` | Specify a shutdown timeout in seconds | +| `-v`, `--volumes` | | | Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers. | + + + ## Description diff --git a/docs/reference/compose_events.md b/docs/reference/compose_events.md index 4225974a..496d204e 100644 --- a/docs/reference/compose_events.md +++ b/docs/reference/compose_events.md @@ -1,3 +1,16 @@ +# docker compose events + + +Receive real time events from containers. + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--json` | | | Output events as a stream of json objects | + + + ## Description diff --git a/docs/reference/compose_exec.md b/docs/reference/compose_exec.md index 1a392f62..9dd818b9 100644 --- a/docs/reference/compose_exec.md +++ b/docs/reference/compose_exec.md @@ -1,7 +1,26 @@ +# docker compose exec + + +Execute a command in a running container. + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-d`, `--detach` | | | Detached mode: Run command in the background. | +| `-e`, `--env` | `stringArray` | | Set environment variables | +| `--index` | `int` | `1` | index of the container if there are multiple instances of a service [default: 1]. | +| `-T`, `--no-TTY` | | | Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY. | +| `--privileged` | | | Give extended privileges to the process. | +| `-u`, `--user` | `string` | | Run the command as this user. | +| `-w`, `--workdir` | `string` | | Path to workdir directory for this command. | + + + ## Description -This is the equivalent of `docker exec` targeting a Compose service. +This is the equivalent of `docker exec` targeting a Compose service. -With this subcommand you can run arbitrary commands in your services. Commands are by default allocating a TTY, so +With this subcommand you can run arbitrary commands in your services. Commands are by default allocating a TTY, so you can use a command such as `docker compose exec web sh` to get an interactive prompt. diff --git a/docs/reference/compose_images.md b/docs/reference/compose_images.md index e69de29b..cfb0ad2c 100644 --- a/docs/reference/compose_images.md +++ b/docs/reference/compose_images.md @@ -0,0 +1,14 @@ +# docker compose images + + +List images used by the created containers + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-q`, `--quiet` | | | Only display IDs | + + + + diff --git a/docs/reference/compose_kill.md b/docs/reference/compose_kill.md index cb8fb249..d0512faa 100644 --- a/docs/reference/compose_kill.md +++ b/docs/reference/compose_kill.md @@ -1,3 +1,16 @@ +# docker compose kill + + +Force stop service containers. + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-s`, `--signal` | `string` | `SIGKILL` | SIGNAL to send to the container. | + + + ## Description diff --git a/docs/reference/compose_logs.md b/docs/reference/compose_logs.md index f325e0a7..4f9690a7 100644 --- a/docs/reference/compose_logs.md +++ b/docs/reference/compose_logs.md @@ -1,3 +1,22 @@ +# docker compose logs + + +View output from containers + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-f`, `--follow` | | | Follow log output. | +| `--no-color` | | | Produce monochrome output. | +| `--no-log-prefix` | | | Don't print prefix in logs. | +| `--since` | `string` | | Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) | +| `--tail` | `string` | `all` | Number of lines to show from the end of the logs for each container. | +| `-t`, `--timestamps` | | | Show timestamps. | +| `--until` | `string` | | Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) | + + + ## Description diff --git a/docs/reference/compose_ls.md b/docs/reference/compose_ls.md index 19ff6de7..b172c7f3 100644 --- a/docs/reference/compose_ls.md +++ b/docs/reference/compose_ls.md @@ -1,3 +1,19 @@ +# docker compose ls + + +List running compose projects + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-a`, `--all` | | | Show all stopped Compose projects | +| `--filter` | `filter` | | Filter output based on conditions provided. | +| `--format` | `string` | `pretty` | Format the output. Values: [pretty \| json]. | +| `-q`, `--quiet` | | | Only display IDs. | + + + ## Description diff --git a/docs/reference/compose_pause.md b/docs/reference/compose_pause.md index acbf1ff2..dd34191b 100644 --- a/docs/reference/compose_pause.md +++ b/docs/reference/compose_pause.md @@ -1,3 +1,10 @@ +# docker compose pause + + +Pause services + + + ## Description diff --git a/docs/reference/compose_port.md b/docs/reference/compose_port.md index b78d0837..8ab893f0 100644 --- a/docs/reference/compose_port.md +++ b/docs/reference/compose_port.md @@ -1,3 +1,17 @@ +# docker compose port + + +Print the public port for a port binding. + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--index` | `int` | `1` | index of the container if service has multiple replicas | +| `--protocol` | `string` | `tcp` | tcp or udp | + + + ## Description diff --git a/docs/reference/compose_ps.md b/docs/reference/compose_ps.md index ac7faaea..edac9310 100644 --- a/docs/reference/compose_ps.md +++ b/docs/reference/compose_ps.md @@ -1,11 +1,117 @@ +# docker compose ps + + +List containers + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-a`, `--all` | | | Show all stopped containers (including those created by the run command) | +| [`--filter`](#filter) | `string` | | Filter services by a property (supported filters: status). | +| [`--format`](#format) | `string` | `pretty` | Format the output. Values: [pretty \| json] | +| `-q`, `--quiet` | | | Only display IDs | +| `--services` | | | Display services | +| [`--status`](#status) | `stringArray` | | Filter services by status. Values: [paused \| restarting \| removing \| running \| dead \| created \| exited] | + + + ## Description Lists containers for a Compose project, with current status and exposed ports. +By default, both running and stopped containers are shown: ```console $ docker compose ps -NAME SERVICE STATUS PORTS -example_foo_1 foo running (healthy) 0.0.0.0:8000->80/tcp -example_bar_1 bar exited (1) +NAME COMMAND SERVICE STATUS PORTS +example-bar-1 "/docker-entrypoint.…" bar exited (0) +example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp ``` + +## Examples + +### Format the output (--format) + +By default, the `docker compose ps` command uses a table ("pretty") format to +show the containers. The `--format` flag allows you to specify alternative +presentations for the output. Currently supported options are `pretty` (default), +and `json`, which outputs information about the containers as a JSON array: + +```console +$ docker compose ps --format json +[{"ID":"1553b0236cf4d2715845f053a4ee97042c4f9a2ef655731ee34f1f7940eaa41a","Name":"example-bar-1","Command":"/docker-entrypoint.sh nginx -g 'daemon off;'","Project":"example","Service":"bar","State":"exited","Health":"","ExitCode":0,"Publishers":null},{"ID":"f02a4efaabb67416e1ff127d51c4b5578634a0ad5743bd65225ff7d1909a3fa0","Name":"example-foo-1","Command":"/docker-entrypoint.sh nginx -g 'daemon off;'","Project":"example","Service":"foo","State":"running","Health":"","ExitCode":0,"Publishers":[{"URL":"0.0.0.0","TargetPort":80,"PublishedPort":8080,"Protocol":"tcp"}]}] +``` + +The JSON output allows you to use the information in other tools for further +processing, for example, using the [`jq` utility](https://stedolan.github.io/jq/){:target="_blank" rel="noopener" class="_"} +to pretty-print the JSON: + +```console +$ docker compose ps --format json | jq . +[ + { + "ID": "1553b0236cf4d2715845f053a4ee97042c4f9a2ef655731ee34f1f7940eaa41a", + "Name": "example-bar-1", + "Command": "/docker-entrypoint.sh nginx -g 'daemon off;'", + "Project": "example", + "Service": "bar", + "State": "exited", + "Health": "", + "ExitCode": 0, + "Publishers": null + }, + { + "ID": "f02a4efaabb67416e1ff127d51c4b5578634a0ad5743bd65225ff7d1909a3fa0", + "Name": "example-foo-1", + "Command": "/docker-entrypoint.sh nginx -g 'daemon off;'", + "Project": "example", + "Service": "foo", + "State": "running", + "Health": "", + "ExitCode": 0, + "Publishers": [ + { + "URL": "0.0.0.0", + "TargetPort": 80, + "PublishedPort": 8080, + "Protocol": "tcp" + } + ] + } +] +``` + +### Filter containers by status (--status) + +Use the `--status` flag to filter the list of containers by status. For example, +to show only containers that are running, or only containers that have exited: + +```console +$ docker compose ps --status=running +NAME COMMAND SERVICE STATUS PORTS +example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp + +$ docker compose ps --status=exited +NAME COMMAND SERVICE STATUS PORTS +example-bar-1 "/docker-entrypoint.…" bar exited (0) +``` + +### Filter containers by status (--filter) + +The [`--status` flag](#status) is a convenience shorthand for the `--filter status=` +flag. The example below is the equivalent to the example from the previous section, +this time using the `--filter` flag: + +```console +$ docker compose ps --filter status=running +NAME COMMAND SERVICE STATUS PORTS +example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp + +$ docker compose ps --filter status=running +NAME COMMAND SERVICE STATUS PORTS +example-bar-1 "/docker-entrypoint.…" bar exited (0) +``` + +The `docker compose ps` command currently only supports the `--filter status=` +option, but additional filter options may be added in future. diff --git a/docs/reference/compose_pull.md b/docs/reference/compose_pull.md index 0f6b6845..c081c228 100644 --- a/docs/reference/compose_pull.md +++ b/docs/reference/compose_pull.md @@ -1,11 +1,26 @@ +# docker compose pull + + +Pull service images + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--ignore-pull-failures` | | | Pull what it can and ignores images with pull failures | +| `--include-deps` | | | Also pull services declared as dependencies | +| `-q`, `--quiet` | | | Pull without printing progress information | + + + ## Description -Pulls an image associated with a service defined in a `compose.yaml` file, but does not start containers based on +Pulls an image associated with a service defined in a `compose.yaml` file, but does not start containers based on those images. -## Examples +## Examples suppose you have this `compose.yaml`: @@ -24,8 +39,8 @@ services: - db ``` -If you run `docker compose pull ServiceName` in the same directory as the `compose.yaml` file that defines the service, -Docker pulls the associated image. For example, to call the postgres image configured as the db service in our example, +If you run `docker compose pull ServiceName` in the same directory as the `compose.yaml` file that defines the service, +Docker pulls the associated image. For example, to call the postgres image configured as the db service in our example, you would run `docker compose pull db`. ```console @@ -46,4 +61,4 @@ $ docker compose pull db ⠹ f63c47038e66 Waiting 9.3s ⠹ 77a0c198cde5 Waiting 9.3s ⠹ c8752d5b785c Waiting 9.3s -``̀ \ No newline at end of file +``̀` diff --git a/docs/reference/compose_push.md b/docs/reference/compose_push.md index 9015d961..a1569cc8 100644 --- a/docs/reference/compose_push.md +++ b/docs/reference/compose_push.md @@ -1,3 +1,16 @@ +# docker compose push + + +Push service images + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--ignore-push-failures` | | | Push what it can and ignores images with push failures | + + + ## Description diff --git a/docs/reference/compose_restart.md b/docs/reference/compose_restart.md index 0e38b565..12326662 100644 --- a/docs/reference/compose_restart.md +++ b/docs/reference/compose_restart.md @@ -1,8 +1,24 @@ +# docker compose restart + + +Restart containers + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-t`, `--timeout` | `int` | `10` | Specify a shutdown timeout in seconds | + + + + +## Description + Restarts all stopped and running services. -If you make changes to your `compose.yml` configuration, these changes are not reflected -after running this command. For example, changes to environment variables (which are added -after a container is built, but before the container's command is executed) are not updated +If you make changes to your `compose.yml` configuration, these changes are not reflected +after running this command. For example, changes to environment variables (which are added +after a container is built, but before the container's command is executed) are not updated after restarting. If you are looking to configure a service's restart policy, please refer to diff --git a/docs/reference/compose_rm.md b/docs/reference/compose_rm.md index da458488..017c7f12 100644 --- a/docs/reference/compose_rm.md +++ b/docs/reference/compose_rm.md @@ -1,3 +1,23 @@ +# docker compose rm + + +Removes stopped service containers + +By default, anonymous volumes attached to containers will not be removed. You +can override this with -v. To list all volumes, use "docker volume ls". + +Any data which is not in a volume will be lost. + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-f`, `--force` | | | Don't ask to confirm removal | +| `-s`, `--stop` | | | Stop the containers, if required, before removing | +| `-v`, `--volumes` | | | Remove any anonymous volumes attached to containers | + + + ## Description diff --git a/docs/reference/compose_run.md b/docs/reference/compose_run.md index c2d4eab1..3d616963 100644 --- a/docs/reference/compose_run.md +++ b/docs/reference/compose_run.md @@ -1,7 +1,35 @@ +# docker compose run + + +Run a one-off command on a service. + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-d`, `--detach` | | | Run container in background and print container ID | +| `--entrypoint` | `string` | | Override the entrypoint of the image | +| `-e`, `--env` | `stringArray` | | Set environment variables | +| `-i`, `--interactive` | | | Keep STDIN open even if not attached. | +| `-l`, `--label` | `stringArray` | | Add or override a label | +| `--name` | `string` | | Assign a name to the container | +| `-T`, `--no-TTY` | | | Disable pseudo-TTY allocation (default: auto-detected). | +| `--no-deps` | | | Don't start linked services. | +| `-p`, `--publish` | `stringArray` | | Publish a container's port(s) to the host. | +| `--quiet-pull` | | | Pull without printing progress information. | +| `--rm` | | | Automatically remove the container when it exits | +| `--service-ports` | | | Run command with the service's ports enabled and mapped to the host. | +| `--use-aliases` | | | Use the service's network useAliases in the network(s) the container connects to. | +| `-u`, `--user` | `string` | | Run as specified username or uid | +| `-v`, `--volume` | `stringArray` | | Bind mount a volume. | +| `-w`, `--workdir` | `string` | | Working directory inside the container | + + + ## Description -Runs a one-time command against a service. +Runs a one-time command against a service. the following command starts the `web` service and runs `bash` as its command: @@ -12,12 +40,12 @@ $ docker compose run web bash Commands you use with run start in new containers with configuration defined by that of the service, including volumes, links, and other details. However, there are two important differences: -First, the command passed by `run` overrides the command defined in the service configuration. For example, if the -`web` service configuration is started with `bash`, then `docker compose run web python app.py` overrides it with +First, the command passed by `run` overrides the command defined in the service configuration. For example, if the +`web` service configuration is started with `bash`, then `docker compose run web python app.py` overrides it with `python app.py`. -The second difference is that the `docker compose run` command does not create any of the ports specified in the -service configuration. This prevents port collisions with already-open ports. If you do want the service’s ports +The second difference is that the `docker compose run` command does not create any of the ports specified in the +service configuration. This prevents port collisions with already-open ports. If you do want the service’s ports to be created and mapped to the host, specify the `--service-ports` ```console @@ -30,8 +58,8 @@ Alternatively, manual port mapping can be specified with the `--publish` or `-p` $ docker compose run --publish 8080:80 -p 2022:22 -p 127.0.0.1:2021:21 web python manage.py shell ``` -If you start a service configured with links, the run command first checks to see if the linked service is running -and starts the service if it is stopped. Once all the linked services are running, the run executes the command you +If you start a service configured with links, the run command first checks to see if the linked service is running +and starts the service if it is stopped. Once all the linked services are running, the run executes the command you passed it. For example, you could run: ```console @@ -52,5 +80,5 @@ If you want to remove the container after running while overriding the container $ docker compose run --rm web python manage.py db upgrade ``` -This runs a database upgrade script, and removes the container when finished running, even if a restart policy is +This runs a database upgrade script, and removes the container when finished running, even if a restart policy is specified in the service configuration. diff --git a/docs/reference/compose_start.md b/docs/reference/compose_start.md index 569dfe58..8f8cb5b4 100644 --- a/docs/reference/compose_start.md +++ b/docs/reference/compose_start.md @@ -1,3 +1,10 @@ +# docker compose start + + +Start services + + + ## Description diff --git a/docs/reference/compose_stop.md b/docs/reference/compose_stop.md index 5d5c5db9..9d8ead82 100644 --- a/docs/reference/compose_stop.md +++ b/docs/reference/compose_stop.md @@ -1,3 +1,16 @@ +# docker compose stop + + +Stop services + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-t`, `--timeout` | `int` | `10` | Specify a shutdown timeout in seconds | + + + ## Description diff --git a/docs/reference/compose_top.md b/docs/reference/compose_top.md index 5ccb40bb..eee5a3ca 100644 --- a/docs/reference/compose_top.md +++ b/docs/reference/compose_top.md @@ -1,3 +1,10 @@ +# docker compose top + + +Display the running processes + + + ## Description @@ -9,5 +16,5 @@ Displays the running processes. $ docker compose top example_foo_1 UID PID PPID C STIME TTY TIME CMD -root 142353 142331 2 15:33 ? 00:00:00 ping localhost -c 5 +root 142353 142331 2 15:33 ? 00:00:00 ping localhost -c 5 ``` diff --git a/docs/reference/compose_unpause.md b/docs/reference/compose_unpause.md index b071841a..e819c0c4 100644 --- a/docs/reference/compose_unpause.md +++ b/docs/reference/compose_unpause.md @@ -1,3 +1,10 @@ +# docker compose unpause + + +Unpause services + + + ## Description diff --git a/docs/reference/compose_up.md b/docs/reference/compose_up.md index f1652735..1a110f3f 100644 --- a/docs/reference/compose_up.md +++ b/docs/reference/compose_up.md @@ -1,3 +1,35 @@ +# docker compose up + + +Create and start containers + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `--abort-on-container-exit` | | | Stops all containers if any container was stopped. Incompatible with -d | +| `--always-recreate-deps` | | | Recreate dependent containers. Incompatible with --no-recreate. | +| `--attach` | `stringArray` | | Attach to service output. | +| `--attach-dependencies` | | | Attach to dependent containers. | +| `--build` | | | Build images before starting containers. | +| `-d`, `--detach` | | | Detached mode: Run containers in the background | +| `--exit-code-from` | `string` | | Return the exit code of the selected service container. Implies --abort-on-container-exit | +| `--force-recreate` | | | Recreate containers even if their configuration and image haven't changed. | +| `--no-build` | | | Don't build an image, even if it's missing. | +| `--no-color` | | | Produce monochrome output. | +| `--no-deps` | | | Don't start linked services. | +| `--no-log-prefix` | | | Don't print prefix in logs. | +| `--no-recreate` | | | If containers already exist, don't recreate them. Incompatible with --force-recreate. | +| `--no-start` | | | Don't start the services after creating them. | +| `--quiet-pull` | | | Pull without printing progress information. | +| `--remove-orphans` | | | Remove containers for services not defined in the Compose file. | +| `-V`, `--renew-anon-volumes` | | | Recreate anonymous volumes instead of retrieving data from the previous containers. | +| `--scale` | `stringArray` | | Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present. | +| `-t`, `--timeout` | `int` | `10` | Use this timeout in seconds for container shutdown when attached or when containers are already running. | +| `--wait` | | | Wait for services to be running\|healthy. Implies detached mode. | + + + ## Description @@ -5,12 +37,12 @@ Builds, (re)creates, starts, and attaches to containers for a service. Unless they are already running, this command also starts any linked services. -The `docker compose up` command aggregates the output of each container (like `docker compose logs --follow` does). -When the command exits, all containers are stopped. Running `docker compose up --detach` starts the containers in the +The `docker compose up` command aggregates the output of each container (like `docker compose logs --follow` does). +When the command exits, all containers are stopped. Running `docker compose up --detach` starts the containers in the background and leaves them running. -If there are existing containers for a service, and the service’s configuration or image was changed after the -container’s creation, `docker compose up` picks up the changes by stopping and recreating the containers +If there are existing containers for a service, and the service’s configuration or image was changed after the +container’s creation, `docker compose up` picks up the changes by stopping and recreating the containers (preserving mounted volumes). To prevent Compose from picking up changes, use the `--no-recreate` flag. If you want to force Compose to stop and recreate all containers, use the `--force-recreate` flag. diff --git a/docs/reference/compose_version.md b/docs/reference/compose_version.md index e69de29b..94b2d36d 100644 --- a/docs/reference/compose_version.md +++ b/docs/reference/compose_version.md @@ -0,0 +1,14 @@ +# docker compose version + + +Show the Docker Compose version information + +### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `-f`, `--format` | `string` | | Format the output. Values: [pretty \| json]. (Default: pretty) | +| `--short` | | | Shows only Compose's version number. | + + + diff --git a/docs/reference/docker_compose.yaml b/docs/reference/docker_compose.yaml index 5f60611b..1af2baab 100644 --- a/docs/reference/docker_compose.yaml +++ b/docs/reference/docker_compose.yaml @@ -98,6 +98,9 @@ long: |- and so does `COMPOSE_PROFILES` environment variable for to the `--profiles` flag. If flags are explicitly set on command line, associated environment variable is ignored + + Setting the `COMPOSE_IGNORE_ORPHANS` environment variable to `true` will stop docker compose from detecting orphaned + containers for the project. usage: docker compose pname: docker plink: docker.yaml @@ -126,6 +129,7 @@ cname: - docker compose top - docker compose unpause - docker compose up +- docker compose version clink: - docker_compose_build.yaml - docker_compose_convert.yaml @@ -151,6 +155,7 @@ clink: - docker_compose_top.yaml - docker_compose_unpause.yaml - docker_compose_up.yaml +- docker_compose_version.yaml options: - option: ansi value_type: string @@ -158,6 +163,17 @@ options: description: | Control when to print ANSI control characters ("never"|"always"|"auto") deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: compatibility + value_type: bool + default_value: "false" + description: Run compose in backward compatibility mode + deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -166,6 +182,7 @@ options: value_type: string description: Specify an alternate environment file. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -176,6 +193,7 @@ options: default_value: '[]' description: Compose configuration files deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -185,6 +203,7 @@ options: default_value: "false" description: Do not print ANSI control characters (DEPRECATED) deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -194,6 +213,7 @@ options: default_value: '[]' description: Specify a profile to enable deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -202,8 +222,9 @@ options: value_type: string description: |- Specify an alternate working directory - (default: the path of the Compose file) + (default: the path of the, first specified, Compose file) deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -213,6 +234,7 @@ options: value_type: string description: Project name deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -222,6 +244,18 @@ options: default_value: "false" description: Show more output deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: version + shorthand: v + value_type: bool + default_value: "false" + description: Show the Docker Compose version information + deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -231,8 +265,9 @@ options: description: |- DEPRECATED! USE --project-directory INSTEAD. Specify an alternate working directory - (default: the path of the Compose file) + (default: the path of the, first specified, Compose file) deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_build.yaml b/docs/reference/docker_compose_build.yaml index bc55d0bd..05c62bd3 100644 --- a/docs/reference/docker_compose_build.yaml +++ b/docs/reference/docker_compose_build.yaml @@ -19,6 +19,7 @@ options: default_value: '[]' description: Set build-time variables for services. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -28,6 +29,7 @@ options: default_value: "true" description: Compress the build context using gzip. DEPRECATED deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -37,6 +39,7 @@ options: default_value: "true" description: Always remove intermediate containers. DEPRECATED deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -47,6 +50,7 @@ options: description: | Set memory limit for the build container. Not supported on buildkit yet. deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -56,6 +60,7 @@ options: default_value: "false" description: Do not use cache when building the image deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -66,6 +71,7 @@ options: description: | Do not remove intermediate containers after a successful build. DEPRECATED deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -75,6 +81,7 @@ options: default_value: "true" description: Build images in parallel. DEPRECATED deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -82,8 +89,9 @@ options: - option: progress value_type: string default_value: auto - description: Set type of progress output ("auto", "plain", "noTty") + description: Set type of progress output (auto, tty, plain, quiet) deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -93,6 +101,7 @@ options: default_value: "false" description: Always attempt to pull a newer version of the image. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -103,6 +112,17 @@ options: default_value: "false" description: Don't print anything to STDOUT deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: ssh + value_type: string + description: | + Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent) + deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_convert.yaml b/docs/reference/docker_compose_convert.yaml index 796f3b98..2c23e2e0 100644 --- a/docs/reference/docker_compose_convert.yaml +++ b/docs/reference/docker_compose_convert.yaml @@ -16,6 +16,7 @@ options: default_value: yaml description: 'Format the output. Values: [yaml | json]' deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -24,6 +25,17 @@ options: value_type: string description: Print the service config hash, one per line. deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: images + value_type: bool + default_value: "false" + description: Print the image names, one per line. + deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -33,6 +45,27 @@ options: default_value: "false" description: Don't interpolate environment variables. deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: no-normalize + value_type: bool + default_value: "false" + description: Don't normalize compose model. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: output + shorthand: o + value_type: string + description: Save to file (default to stdout) + deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -42,6 +75,7 @@ options: default_value: "false" description: Print the profile names, one per line. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -52,6 +86,7 @@ options: default_value: "false" description: Only validate the configuration, don't print anything. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -61,6 +96,7 @@ options: default_value: "false" description: Pin image tags to digests. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -70,6 +106,7 @@ options: default_value: "false" description: Print the service names, one per line. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -79,6 +116,7 @@ options: default_value: "false" description: Print the volume names, one per line. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_cp.yaml b/docs/reference/docker_compose_cp.yaml index 3382d65b..9f338242 100644 --- a/docs/reference/docker_compose_cp.yaml +++ b/docs/reference/docker_compose_cp.yaml @@ -10,7 +10,8 @@ options: value_type: bool default_value: "false" description: Copy to all the containers of the service. - deprecated: false + deprecated: true + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -21,6 +22,7 @@ options: default_value: "false" description: Archive mode (copy all uid/gid information) deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -31,16 +33,18 @@ options: default_value: "false" description: Always follow symbol link in SRC_PATH deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false swarm: false - option: index value_type: int - default_value: "1" + default_value: "0" description: | - Index of the container if there are multiple instances of a service [default: 1]. + Index of the container if there are multiple instances of a service . deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_create.yaml b/docs/reference/docker_compose_create.yaml index 1372b445..f71ea7b7 100644 --- a/docs/reference/docker_compose_create.yaml +++ b/docs/reference/docker_compose_create.yaml @@ -10,6 +10,7 @@ options: default_value: "false" description: Build images before starting containers. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -20,6 +21,7 @@ options: description: | Recreate containers even if their configuration and image haven't changed. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -29,6 +31,7 @@ options: default_value: "false" description: Don't build an image, even if it's missing. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -39,6 +42,7 @@ options: description: | If containers already exist, don't recreate them. Incompatible with --force-recreate. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_down.yaml b/docs/reference/docker_compose_down.yaml index c5046a1e..95ed4c1f 100644 --- a/docs/reference/docker_compose_down.yaml +++ b/docs/reference/docker_compose_down.yaml @@ -23,6 +23,7 @@ options: default_value: "false" description: Remove containers for services not defined in the Compose file. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -32,6 +33,7 @@ options: description: | Remove images used by services. "local" remove only images that don't have a custom tag ("local"|"all") deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -42,6 +44,7 @@ options: default_value: "10" description: Specify a shutdown timeout in seconds deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -53,6 +56,7 @@ options: description: | Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_events.yaml b/docs/reference/docker_compose_events.yaml index abe27ff1..1f0f8250 100644 --- a/docs/reference/docker_compose_events.yaml +++ b/docs/reference/docker_compose_events.yaml @@ -29,6 +29,7 @@ options: default_value: "false" description: Output events as a stream of json objects deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_exec.yaml b/docs/reference/docker_compose_exec.yaml index f63ad7c7..5f70743f 100644 --- a/docs/reference/docker_compose_exec.yaml +++ b/docs/reference/docker_compose_exec.yaml @@ -15,6 +15,7 @@ options: default_value: "false" description: 'Detached mode: Run command in the background.' deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -25,6 +26,7 @@ options: default_value: '[]' description: Set environment variables deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -35,6 +37,18 @@ options: description: | index of the container if there are multiple instances of a service [default: 1]. deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: interactive + shorthand: i + value_type: bool + default_value: "true" + description: Keep STDIN open even if not attached. + deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -42,10 +56,11 @@ options: - option: no-TTY shorthand: T value_type: bool - default_value: "false" + default_value: "true" description: | Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -55,6 +70,18 @@ options: default_value: "false" description: Give extended privileges to the process. deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: tty + shorthand: t + value_type: bool + default_value: "true" + description: Allocate a pseudo-TTY. + deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -64,6 +91,7 @@ options: value_type: string description: Run the command as this user. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -73,6 +101,7 @@ options: value_type: string description: Path to workdir directory for this command. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_images.yaml b/docs/reference/docker_compose_images.yaml index de815e8e..8e263aef 100644 --- a/docs/reference/docker_compose_images.yaml +++ b/docs/reference/docker_compose_images.yaml @@ -11,6 +11,7 @@ options: default_value: "false" description: Only display IDs deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_kill.yaml b/docs/reference/docker_compose_kill.yaml index 2640d71b..f9334782 100644 --- a/docs/reference/docker_compose_kill.yaml +++ b/docs/reference/docker_compose_kill.yaml @@ -16,6 +16,7 @@ options: default_value: SIGKILL description: SIGNAL to send to the container. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_logs.yaml b/docs/reference/docker_compose_logs.yaml index c7fddc9f..2846bacc 100644 --- a/docs/reference/docker_compose_logs.yaml +++ b/docs/reference/docker_compose_logs.yaml @@ -11,6 +11,7 @@ options: default_value: "false" description: Follow log output. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -20,6 +21,7 @@ options: default_value: "false" description: Produce monochrome output. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -29,6 +31,7 @@ options: default_value: "false" description: Don't print prefix in logs. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -38,6 +41,7 @@ options: description: | Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -48,6 +52,7 @@ options: description: | Number of lines to show from the end of the logs for each container. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -58,6 +63,7 @@ options: default_value: "false" description: Show timestamps. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -67,6 +73,7 @@ options: description: | Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_ls.yaml b/docs/reference/docker_compose_ls.yaml index 305084f9..97ce1364 100644 --- a/docs/reference/docker_compose_ls.yaml +++ b/docs/reference/docker_compose_ls.yaml @@ -11,6 +11,7 @@ options: default_value: "false" description: Show all stopped Compose projects deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -19,6 +20,7 @@ options: value_type: filter description: Filter output based on conditions provided. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -28,6 +30,7 @@ options: default_value: pretty description: 'Format the output. Values: [pretty | json].' deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -38,6 +41,7 @@ options: default_value: "false" description: Only display IDs. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_pause.yaml b/docs/reference/docker_compose_pause.yaml index 71922298..95342fda 100644 --- a/docs/reference/docker_compose_pause.yaml +++ b/docs/reference/docker_compose_pause.yaml @@ -1,5 +1,5 @@ command: docker compose pause -short: pause services +short: Pause services long: | Pauses running containers of a service. They can be unpaused with `docker compose unpause`. usage: docker compose pause [SERVICE...] diff --git a/docs/reference/docker_compose_port.yaml b/docs/reference/docker_compose_port.yaml index 04b9f4a0..739d3d7e 100644 --- a/docs/reference/docker_compose_port.yaml +++ b/docs/reference/docker_compose_port.yaml @@ -10,6 +10,7 @@ options: default_value: "1" description: index of the container if service has multiple replicas deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -19,6 +20,7 @@ options: default_value: tcp description: tcp or udp deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_ps.yaml b/docs/reference/docker_compose_ps.yaml index b43c3911..896f3069 100644 --- a/docs/reference/docker_compose_ps.yaml +++ b/docs/reference/docker_compose_ps.yaml @@ -2,12 +2,13 @@ command: docker compose ps short: List containers long: |- Lists containers for a Compose project, with current status and exposed ports. + By default, both running and stopped containers are shown: ```console $ docker compose ps - NAME SERVICE STATUS PORTS - example_foo_1 foo running (healthy) 0.0.0.0:8000->80/tcp - example_bar_1 bar exited (1) + NAME COMMAND SERVICE STATUS PORTS + example-bar-1 "/docker-entrypoint.…" bar exited (0) + example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp ``` usage: docker compose ps [SERVICE...] pname: docker compose @@ -20,14 +21,17 @@ options: description: | Show all stopped containers (including those created by the run command) deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false swarm: false - option: filter value_type: string - description: Filter services by a property + description: 'Filter services by a property (supported filters: status).' + details_url: '#filter' deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -36,7 +40,9 @@ options: value_type: string default_value: pretty description: 'Format the output. Values: [pretty | json]' + details_url: '#format' deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -47,6 +53,7 @@ options: default_value: "false" description: Only display IDs deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -56,18 +63,108 @@ options: default_value: "false" description: Display services deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false swarm: false - option: status - value_type: string - description: Filter services by status + value_type: stringArray + default_value: '[]' + description: | + Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited] + details_url: '#status' deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false swarm: false +examples: |- + ### Format the output (--format) {#format} + + By default, the `docker compose ps` command uses a table ("pretty") format to + show the containers. The `--format` flag allows you to specify alternative + presentations for the output. Currently supported options are `pretty` (default), + and `json`, which outputs information about the containers as a JSON array: + + ```console + $ docker compose ps --format json + [{"ID":"1553b0236cf4d2715845f053a4ee97042c4f9a2ef655731ee34f1f7940eaa41a","Name":"example-bar-1","Command":"/docker-entrypoint.sh nginx -g 'daemon off;'","Project":"example","Service":"bar","State":"exited","Health":"","ExitCode":0,"Publishers":null},{"ID":"f02a4efaabb67416e1ff127d51c4b5578634a0ad5743bd65225ff7d1909a3fa0","Name":"example-foo-1","Command":"/docker-entrypoint.sh nginx -g 'daemon off;'","Project":"example","Service":"foo","State":"running","Health":"","ExitCode":0,"Publishers":[{"URL":"0.0.0.0","TargetPort":80,"PublishedPort":8080,"Protocol":"tcp"}]}] + ``` + + The JSON output allows you to use the information in other tools for further + processing, for example, using the [`jq` utility](https://stedolan.github.io/jq/){:target="_blank" rel="noopener" class="_"} + to pretty-print the JSON: + + ```console + $ docker compose ps --format json | jq . + [ + { + "ID": "1553b0236cf4d2715845f053a4ee97042c4f9a2ef655731ee34f1f7940eaa41a", + "Name": "example-bar-1", + "Command": "/docker-entrypoint.sh nginx -g 'daemon off;'", + "Project": "example", + "Service": "bar", + "State": "exited", + "Health": "", + "ExitCode": 0, + "Publishers": null + }, + { + "ID": "f02a4efaabb67416e1ff127d51c4b5578634a0ad5743bd65225ff7d1909a3fa0", + "Name": "example-foo-1", + "Command": "/docker-entrypoint.sh nginx -g 'daemon off;'", + "Project": "example", + "Service": "foo", + "State": "running", + "Health": "", + "ExitCode": 0, + "Publishers": [ + { + "URL": "0.0.0.0", + "TargetPort": 80, + "PublishedPort": 8080, + "Protocol": "tcp" + } + ] + } + ] + ``` + + ### Filter containers by status (--status) {#status} + + Use the `--status` flag to filter the list of containers by status. For example, + to show only containers that are running, or only containers that have exited: + + ```console + $ docker compose ps --status=running + NAME COMMAND SERVICE STATUS PORTS + example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp + + $ docker compose ps --status=exited + NAME COMMAND SERVICE STATUS PORTS + example-bar-1 "/docker-entrypoint.…" bar exited (0) + ``` + + ### Filter containers by status (--filter) {#filter} + + The [`--status` flag](#status) is a convenience shorthand for the `--filter status=` + flag. The example below is the equivalent to the example from the previous section, + this time using the `--filter` flag: + + ```console + $ docker compose ps --filter status=running + NAME COMMAND SERVICE STATUS PORTS + example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp + + $ docker compose ps --filter status=running + NAME COMMAND SERVICE STATUS PORTS + example-bar-1 "/docker-entrypoint.…" bar exited (0) + ``` + + The `docker compose ps` command currently only supports the `--filter status=` + option, but additional filter options may be added in future. deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_pull.yaml b/docs/reference/docker_compose_pull.yaml index 52d75785..c7da031e 100644 --- a/docs/reference/docker_compose_pull.yaml +++ b/docs/reference/docker_compose_pull.yaml @@ -12,6 +12,7 @@ options: default_value: "false" description: Pull what it can and ignores images with pull failures deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -21,6 +22,7 @@ options: default_value: "false" description: Also pull services declared as dependencies deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -30,6 +32,7 @@ options: default_value: "true" description: DEPRECATED disable parallel pulling. deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -39,6 +42,7 @@ options: default_value: "true" description: DEPRECATED pull multiple images in parallel. deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -49,10 +53,52 @@ options: default_value: "false" description: Pull without printing progress information deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false swarm: false +examples: |- + suppose you have this `compose.yaml`: + + ```yaml + services: + db: + image: postgres + web: + build: . + command: bundle exec rails s -p 3000 -b '0.0.0.0' + volumes: + - .:/myapp + ports: + - "3000:3000" + depends_on: + - db + ``` + + If you run `docker compose pull ServiceName` in the same directory as the `compose.yaml` file that defines the service, + Docker pulls the associated image. For example, to call the postgres image configured as the db service in our example, + you would run `docker compose pull db`. + + ```console + $ docker compose pull db + [+] Running 1/15 + ⠸ db Pulling 12.4s + ⠿ 45b42c59be33 Already exists 0.0s + ⠹ 40adec129f1a Downloading 3.374MB/4.178MB 9.3s + ⠹ b4c431d00c78 Download complete 9.3s + ⠹ 2696974e2815 Download complete 9.3s + ⠹ 564b77596399 Downloading 5.622MB/7.965MB 9.3s + ⠹ 5044045cf6f2 Downloading 216.7kB/391.1kB 9.3s + ⠹ d736e67e6ac3 Waiting 9.3s + ⠹ 390c1c9a5ae4 Waiting 9.3s + ⠹ c0e62f172284 Waiting 9.3s + ⠹ ebcdc659c5bf Waiting 9.3s + ⠹ 29be22cb3acc Waiting 9.3s + ⠹ f63c47038e66 Waiting 9.3s + ⠹ 77a0c198cde5 Waiting 9.3s + ⠹ c8752d5b785c Waiting 9.3s + ``̀` deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_push.yaml b/docs/reference/docker_compose_push.yaml index e81694ad..f006ad61 100644 --- a/docs/reference/docker_compose_push.yaml +++ b/docs/reference/docker_compose_push.yaml @@ -28,6 +28,7 @@ options: default_value: "false" description: Push what it can and ignores images with push failures deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_restart.yaml b/docs/reference/docker_compose_restart.yaml index 689907fa..9f646cc0 100644 --- a/docs/reference/docker_compose_restart.yaml +++ b/docs/reference/docker_compose_restart.yaml @@ -1,6 +1,16 @@ command: docker compose restart short: Restart containers -long: Restart containers +long: |- + Restarts all stopped and running services. + + If you make changes to your `compose.yml` configuration, these changes are not reflected + after running this command. For example, changes to environment variables (which are added + after a container is built, but before the container's command is executed) are not updated + after restarting. + + If you are looking to configure a service's restart policy, please refer to + [restart](https://github.com/compose-spec/compose-spec/blob/master/spec.md#restart) + or [restart_policy](https://github.com/compose-spec/compose-spec/blob/master/deploy.md#restart_policy). usage: docker compose restart pname: docker compose plink: docker_compose.yaml @@ -11,6 +21,7 @@ options: default_value: "10" description: Specify a shutdown timeout in seconds deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_rm.yaml b/docs/reference/docker_compose_rm.yaml index 62dd17a6..48108dcd 100644 --- a/docs/reference/docker_compose_rm.yaml +++ b/docs/reference/docker_compose_rm.yaml @@ -26,6 +26,7 @@ options: default_value: "false" description: Deprecated - no effect deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -36,6 +37,7 @@ options: default_value: "false" description: Don't ask to confirm removal deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -46,6 +48,7 @@ options: default_value: "false" description: Stop the containers, if required, before removing deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -56,6 +59,7 @@ options: default_value: "false" description: Remove any anonymous volumes attached to containers deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_run.yaml b/docs/reference/docker_compose_run.yaml index c88e58c7..1862a70a 100644 --- a/docs/reference/docker_compose_run.yaml +++ b/docs/reference/docker_compose_run.yaml @@ -65,6 +65,7 @@ options: default_value: "false" description: Run container in background and print container ID deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -73,6 +74,7 @@ options: value_type: string description: Override the entrypoint of the image deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -83,16 +85,29 @@ options: default_value: '[]' description: Set environment variables deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false swarm: false -- option: labels +- option: interactive + shorthand: i + value_type: bool + default_value: "true" + description: Keep STDIN open even if not attached. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: label shorthand: l value_type: stringArray default_value: '[]' description: Add or override a label deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -101,6 +116,7 @@ options: value_type: string description: Assign a name to the container deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -108,10 +124,10 @@ options: - option: no-TTY shorthand: T value_type: bool - default_value: "false" - description: | - Disable pseudo-noTty allocation. By default docker compose run allocates a TTY + default_value: "true" + description: 'Disable pseudo-TTY allocation (default: auto-detected).' deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -121,6 +137,7 @@ options: default_value: "false" description: Don't start linked services. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -131,6 +148,17 @@ options: default_value: '[]' description: Publish a container's port(s) to the host. deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: quiet-pull + value_type: bool + default_value: "false" + description: Pull without printing progress information. + deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -140,6 +168,7 @@ options: default_value: "false" description: Automatically remove the container when it exits deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -150,6 +179,18 @@ options: description: | Run command with the service's ports enabled and mapped to the host. deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: tty + shorthand: t + value_type: bool + default_value: "true" + description: Allocate a pseudo-TTY. + deprecated: false + hidden: true experimental: false experimentalcli: false kubernetes: false @@ -160,6 +201,7 @@ options: description: | Use the service's network useAliases in the network(s) the container connects to. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -169,6 +211,7 @@ options: value_type: string description: Run as specified username or uid deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -179,6 +222,7 @@ options: default_value: '[]' description: Bind mount a volume. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -188,6 +232,7 @@ options: value_type: string description: Working directory inside the container deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_stop.yaml b/docs/reference/docker_compose_stop.yaml index 04b316d7..e0c74f59 100644 --- a/docs/reference/docker_compose_stop.yaml +++ b/docs/reference/docker_compose_stop.yaml @@ -12,6 +12,7 @@ options: default_value: "10" description: Specify a shutdown timeout in seconds deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_unpause.yaml b/docs/reference/docker_compose_unpause.yaml index 44ec4c0d..0a2961ba 100644 --- a/docs/reference/docker_compose_unpause.yaml +++ b/docs/reference/docker_compose_unpause.yaml @@ -1,5 +1,5 @@ command: docker compose unpause -short: unpause services +short: Unpause services long: Unpauses paused containers of a service. usage: docker compose unpause [SERVICE...] pname: docker compose diff --git a/docs/reference/docker_compose_up.yaml b/docs/reference/docker_compose_up.yaml index f4f82a65..e76c20e8 100644 --- a/docs/reference/docker_compose_up.yaml +++ b/docs/reference/docker_compose_up.yaml @@ -27,6 +27,7 @@ options: description: | Stops all containers if any container was stopped. Incompatible with -d deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -36,6 +37,7 @@ options: default_value: "false" description: Recreate dependent containers. Incompatible with --no-recreate. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -45,6 +47,7 @@ options: default_value: '[]' description: Attach to service output. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -54,6 +57,7 @@ options: default_value: "false" description: Attach to dependent containers. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -63,6 +67,7 @@ options: default_value: "false" description: Build images before starting containers. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -73,16 +78,7 @@ options: default_value: "false" description: 'Detached mode: Run containers in the background' deprecated: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: environment - shorthand: e - value_type: stringArray - default_value: '[]' - description: Environment variables - deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -92,6 +88,7 @@ options: description: | Return the exit code of the selected service container. Implies --abort-on-container-exit deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -102,6 +99,7 @@ options: description: | Recreate containers even if their configuration and image haven't changed. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -111,6 +109,7 @@ options: default_value: "false" description: Don't build an image, even if it's missing. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -120,6 +119,7 @@ options: default_value: "false" description: Produce monochrome output. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -129,6 +129,7 @@ options: default_value: "false" description: Don't start linked services. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -138,6 +139,7 @@ options: default_value: "false" description: Don't print prefix in logs. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -148,6 +150,7 @@ options: description: | If containers already exist, don't recreate them. Incompatible with --force-recreate. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -157,6 +160,7 @@ options: default_value: "false" description: Don't start the services after creating them. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -166,6 +170,7 @@ options: default_value: "false" description: Pull without printing progress information. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -175,6 +180,7 @@ options: default_value: "false" description: Remove containers for services not defined in the Compose file. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -186,6 +192,7 @@ options: description: | Recreate anonymous volumes instead of retrieving data from the previous containers. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -196,6 +203,7 @@ options: description: | Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -207,6 +215,17 @@ options: description: | Use this timeout in seconds for container shutdown when attached or when containers are already running. deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +- option: wait + value_type: bool + default_value: "false" + description: Wait for services to be running|healthy. Implies detached mode. + deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/reference/docker_compose_version.yaml b/docs/reference/docker_compose_version.yaml index cdc2dd5d..cc7c5ca3 100644 --- a/docs/reference/docker_compose_version.yaml +++ b/docs/reference/docker_compose_version.yaml @@ -10,6 +10,7 @@ options: value_type: string description: 'Format the output. Values: [pretty | json]. (Default: pretty)' deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false @@ -19,6 +20,7 @@ options: default_value: "false" description: Shows only Compose's version number. deprecated: false + hidden: false experimental: false experimentalcli: false kubernetes: false diff --git a/docs/yaml/main/generate.go b/docs/yaml/main/generate.go index 5821b7da..90ac25cf 100644 --- a/docs/yaml/main/generate.go +++ b/docs/yaml/main/generate.go @@ -22,16 +22,23 @@ import ( "path/filepath" clidocstool "github.com/docker/cli-docs-tool" + "github.com/docker/cli/cli/command" "github.com/docker/compose/v2/cmd/compose" "github.com/spf13/cobra" ) -func generateCliYaml(opts *options) error { - cmd := &cobra.Command{Use: "docker"} - cmd.AddCommand(compose.RootCommand(nil)) +func generateDocs(opts *options) error { + dockerCLI, err := command.NewDockerCli() + if err != nil { + return err + } + cmd := &cobra.Command{ + Use: "docker", + DisableAutoGenTag: true, + } + cmd.AddCommand(compose.RootCommand(dockerCLI, nil)) disableFlagsInUseLine(cmd) - cmd.DisableAutoGenTag = true tool, err := clidocstool.New(clidocstool.Options{ Root: cmd, SourceDir: opts.source, @@ -41,7 +48,7 @@ func generateCliYaml(opts *options) error { if err != nil { return err } - return tool.GenYamlTree(cmd) + return tool.GenAllTree() } func disableFlagsInUseLine(cmd *cobra.Command) { @@ -69,12 +76,12 @@ type options struct { func main() { cwd, _ := os.Getwd() opts := &options{ - source: cwd, + source: filepath.Join(cwd, "docs", "reference"), target: filepath.Join(cwd, "docs", "reference"), } fmt.Printf("Project root: %s\n", opts.source) fmt.Printf("Generating yaml files into %s\n", opts.target) - if err := generateCliYaml(opts); err != nil { - fmt.Fprintf(os.Stderr, "Failed to generate yaml files: %s\n", err.Error()) + if err := generateDocs(opts); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "Failed to generate documentation: %s\n", err.Error()) } } diff --git a/go.mod b/go.mod index a635e6fc..5829b335 100644 --- a/go.mod +++ b/go.mod @@ -1,144 +1,153 @@ module github.com/docker/compose/v2 -go 1.17 +go 1.18 require ( - github.com/AlecAivazis/survey/v2 v2.3.2 + github.com/AlecAivazis/survey/v2 v2.3.5 github.com/buger/goterm v1.0.4 - github.com/cnabio/cnab-to-oci v0.3.1-beta1 - github.com/compose-spec/compose-go v1.1.0 + github.com/cnabio/cnab-to-oci v0.3.4 + github.com/compose-spec/compose-go v1.2.8 github.com/containerd/console v1.0.3 - github.com/containerd/containerd v1.6.0 + github.com/containerd/containerd v1.6.6 github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e - github.com/docker/buildx v0.7.1 - github.com/docker/cli v20.10.12+incompatible - github.com/docker/cli-docs-tool v0.2.1 - github.com/docker/docker v20.10.7+incompatible + github.com/docker/buildx v0.8.2 // when updating, also update the replace rules accordingly + github.com/docker/cli v20.10.17+incompatible + github.com/docker/cli-docs-tool v0.4.0 + github.com/docker/docker v20.10.17+incompatible github.com/docker/go-connections v0.4.0 github.com/docker/go-units v0.4.0 github.com/golang/mock v1.6.0 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/go-version v1.3.0 + github.com/hashicorp/go-version v1.6.0 github.com/mattn/go-isatty v0.0.14 github.com/mattn/go-shellwords v1.0.12 - github.com/moby/buildkit v0.9.1-0.20211019185819-8778943ac3da + github.com/moby/buildkit v0.10.1-0.20220403220257-10e6f94bf90d github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 github.com/morikuni/aec v1.0.0 github.com/opencontainers/go-digest v1.0.0 - github.com/opencontainers/image-spec v1.0.2 + github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 github.com/pkg/errors v0.9.1 github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b github.com/sirupsen/logrus v1.8.1 - github.com/spf13/cobra v1.3.0 + github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.8.0 + github.com/theupdateframework/notary v0.7.0 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c gotest.tools v2.2.0+incompatible - gotest.tools/v3 v3.1.0 + gotest.tools/v3 v3.3.0 ) require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Masterminds/semver v1.5.0 // indirect - github.com/Microsoft/go-winio v0.5.1 // indirect - github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect + github.com/Microsoft/go-winio v0.5.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cnabio/cnab-go v0.10.0-beta1 // indirect + github.com/cnabio/cnab-go v0.23.4 // indirect github.com/containerd/continuity v0.2.2 // indirect + github.com/containerd/ttrpc v1.1.0 // indirect github.com/containerd/typeurl v1.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/distribution v2.8.0+incompatible // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect - github.com/fvbommel/sortorder v1.0.1 // indirect + github.com/fvbommel/sortorder v1.0.2 // indirect github.com/go-logr/logr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gofrs/flock v0.8.0 // indirect - github.com/gogo/googleapis v1.4.0 // indirect + github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/go-cmp v0.5.6 // indirect + github.com/google/go-cmp v0.5.7 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/klauspost/compress v1.13.5 // indirect + github.com/klauspost/compress v1.15.1 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect - github.com/miekg/pkcs11 v1.0.3 // indirect - github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/miekg/pkcs11 v1.1.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/locker v1.0.1 // indirect - github.com/moby/sys/mount v0.2.0 // indirect - github.com/moby/sys/mountinfo v0.5.0 // indirect github.com/moby/sys/signal v0.6.0 // indirect github.com/moby/sys/symlink v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/opencontainers/runc v1.1.0 // indirect + github.com/opencontainers/runc v1.1.2 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.11.0 // indirect + github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.30.0 // indirect + github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - github.com/qri-io/jsonpointer v0.1.0 // indirect - github.com/qri-io/jsonschema v0.1.1 // indirect - github.com/sergi/go-diff v1.1.0 // indirect - github.com/theupdateframework/notary v0.6.1 // indirect - github.com/tonistiigi/fsutil v0.0.0-20210818161904-4442383b5028 // indirect + github.com/qri-io/jsonpointer v0.1.1 // indirect + github.com/qri-io/jsonschema v0.2.2-0.20210831022256-780655b2ba0e // indirect + github.com/tonistiigi/fsutil v0.0.0-20220315205639-9ed612626da3 // indirect github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - go.opentelemetry.io/contrib v0.21.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.21.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.21.0 // indirect - go.opentelemetry.io/otel v1.3.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0 // indirect - go.opentelemetry.io/otel/internal/metric v0.21.0 // indirect - go.opentelemetry.io/otel/metric v0.21.0 // indirect - go.opentelemetry.io/otel/sdk v1.3.0 // indirect - go.opentelemetry.io/otel/trace v1.3.0 // indirect - go.opentelemetry.io/proto/otlp v0.11.0 // indirect - golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect - golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 // indirect + go.opentelemetry.io/otel v1.4.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 // indirect + go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect + go.opentelemetry.io/otel/metric v0.27.0 // indirect + go.opentelemetry.io/otel/sdk v1.4.1 // indirect + go.opentelemetry.io/otel/trace v1.4.1 // indirect + go.opentelemetry.io/proto/otlp v0.12.0 // indirect + golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect + golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect - golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect + golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect - google.golang.org/grpc v1.43.0 // indirect + google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 // indirect + google.golang.org/grpc v1.45.0 // indirect google.golang.org/protobuf v1.27.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/apimachinery v0.22.5 // indirect - k8s.io/client-go v0.22.5 // indirect - k8s.io/klog/v2 v2.30.0 // indirect - k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apimachinery v0.24.1 // indirect; see replace for the actual version used + k8s.io/client-go v0.24.1 // indirect; see replace for the actual version used + k8s.io/klog/v2 v2.60.1 // indirect + k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect sigs.k8s.io/yaml v1.2.0 // indirect ) -// (for buildx) -replace ( - github.com/docker/cli => github.com/docker/cli v20.10.3-0.20210702143511-f782d1355eff+incompatible - github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220121014307-40bb9831756f+incompatible - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc => github.com/tonistiigi/opentelemetry-go-contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.0.0-20210714055410-d010b05b4939 - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace => github.com/tonistiigi/opentelemetry-go-contrib/instrumentation/net/http/httptrace/otelhttptrace v0.0.0-20210714055410-d010b05b4939 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => github.com/tonistiigi/opentelemetry-go-contrib/instrumentation/net/http/otelhttp v0.0.0-20210714055410-d010b05b4939 +require ( + github.com/cyberphone/json-canonicalization v0.0.0-20210303052042-6bc126869bf4 // indirect + github.com/zmap/zcrypto v0.0.0-20220605182715-4dfcec6e9a8c // indirect + github.com/zmap/zlint v1.1.0 // indirect +) + +replace ( + github.com/docker/cli => github.com/docker/cli v20.10.3-0.20220309205733-2b52f62e9627+incompatible + github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220309172631-83b51522df43+incompatible + + github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.2 // Can be removed on next bump of containerd to > 1.6.4 + + // For k8s dependencies, we use a replace directive, to prevent them being + // upgraded to the version specified in containerd, which is not relevant to the + // version needed. + // See https://github.com/docker/buildx/pull/948 for details. + // https://github.com/docker/buildx/blob/v0.8.1/go.mod#L62-L64 + k8s.io/api => k8s.io/api v0.22.4 + k8s.io/apimachinery => k8s.io/apimachinery v0.22.4 + k8s.io/client-go => k8s.io/client-go v0.22.4 ) diff --git a/go.sum b/go.sum index 7125f3f3..5db359a7 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,11 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= -bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= cloud.google.com/go v0.25.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.2/go.mod h1:H8IAquKe2L30IxoupDgqTaQvKSwF/c8prYHynGIWQbA= -cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= @@ -16,7 +14,6 @@ cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= @@ -28,17 +25,8 @@ cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKP cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= -cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -48,7 +36,6 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -69,8 +56,8 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/AkihiroSuda/containerd-fuse-overlayfs v1.0.0/go.mod h1:0mMDvQFeLbbn1Wy8P2j3hwFhqBq+FKn8OZPno8WLmp8= -github.com/AlecAivazis/survey/v2 v2.3.2 h1:TqTB+aDDCLYhf9/bD2TwSO8u8jDSmMUd2SUVO4gCnU8= -github.com/AlecAivazis/survey/v2 v2.3.2/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg= +github.com/AlecAivazis/survey/v2 v2.3.5 h1:A8cYupsAZkjaUmhtTYv3sSqc7LO5mp1XDfqe5E/9wRQ= +github.com/AlecAivazis/survey/v2 v2.3.5/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= @@ -90,22 +77,17 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg6 github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v10.15.5+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v12.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= -github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= github.com/Azure/go-autorest/autorest v0.10.2/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= -github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= @@ -115,24 +97,19 @@ github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSY github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Djarvur/go-err113 v0.0.0-20200410182137-af658d038157/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/Djarvur/go-err113 v0.1.0/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= -github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -149,9 +126,9 @@ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugX github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -160,26 +137,25 @@ github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3H github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= -github.com/Microsoft/hcsshim v0.8.18/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= -github.com/Microsoft/hcsshim v0.9.2 h1:wB06W5aYFfUB3IvootYAY2WnOmIdgPGfqSI6tufQNnY= github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim v0.9.3 h1:k371PzBuRrz2b+ebGuI2nVgVhgsVX60jMfSw80NECxo= github.com/Microsoft/hcsshim/test v0.0.0-20200826032352-301c83a30e7c/go.mod h1:30A5igQ91GEmhYJF8TaRP79pMBOYynRsyOByfVV0dU4= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= @@ -187,9 +163,7 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= -github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -210,12 +184,12 @@ github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/Y github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= @@ -230,13 +204,14 @@ github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= @@ -259,9 +234,9 @@ github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQt github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v1.4.1/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v1.5.0 h1:tP8hiPv1pGGW3LA6LKy5lW6WG+y9J2xWUdPd3WC452k= -github.com/bugsnag/bugsnag-go v1.5.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA= @@ -270,24 +245,16 @@ github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGr github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= -github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -296,21 +263,15 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= +github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiKw= -github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo= -github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= -github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= -github.com/cnabio/cnab-go v0.10.0-beta1 h1:5LEEODVQkyCHfeT6pggPz5zq/PinA/CzlNrChFkfGkg= -github.com/cnabio/cnab-go v0.10.0-beta1/go.mod h1:5c4uOP6ZppR4nUGtCMAElscRiYEUi44vNQwtSAvISXk= -github.com/cnabio/cnab-to-oci v0.3.1-beta1 h1:qAuLRt+2J7U7wIB5YG+COtS630NQCf4G1h1p0Yk6llo= -github.com/cnabio/cnab-to-oci v0.3.1-beta1/go.mod h1:8BomA5Vye+3V/Kd2NSFblCBmp1rJV5NfXBYKbIGT5Rw= +github.com/cnabio/cnab-go v0.23.4 h1:jplQcSnvFyQlD6swiqL3BmqRnhbnS+lc/EKdBLH9E80= +github.com/cnabio/cnab-go v0.23.4/go.mod h1:9EmgHR51LFqQStzaC+xHPJlkD4OPsF6Ev5Y8e/YHEns= +github.com/cnabio/cnab-to-oci v0.3.4 h1:u1AUUplhKojCMgee17QkjU27yM1tfH9fOTFvxkrEqVw= +github.com/cnabio/cnab-to-oci v0.3.4/go.mod h1:7f86Z39HUg67wg8dZvxvFpW2pGDjK3RwbJAMJGxTXHQ= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -318,18 +279,15 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/compose-spec/compose-go v1.0.5/go.mod h1:LQ/JAjSIyh8bTu4RV6nkyf0Ow/Yf3qpvzrdEigxduiw= -github.com/compose-spec/compose-go v1.1.0 h1:n/0O7Fl90doi5AG9bfF0SOSLXtveXxLkGXblSrxVC5Q= -github.com/compose-spec/compose-go v1.1.0/go.mod h1:pAy7Mikpeft4pxkFU565/DRHEbDfR84G6AQuiL+Hdg8= -github.com/compose-spec/godotenv v1.1.0/go.mod h1:zF/3BOa18Z24tts5qnO/E9YURQanJTBUf7nlcCTNsyc= +github.com/compose-spec/compose-go v1.2.1/go.mod h1:pAy7Mikpeft4pxkFU565/DRHEbDfR84G6AQuiL+Hdg8= +github.com/compose-spec/compose-go v1.2.8 h1:ImPy82xn+rJKL5xmgEyesZEfqJmrzJ1WuZSHEhxMEFI= +github.com/compose-spec/compose-go v1.2.8/go.mod h1:813WrDd7NtOl9ZVqswlJ5iCQy3lxI3KYxKkY8EeHQ7w= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= @@ -349,12 +307,10 @@ github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJ github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= -github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -371,12 +327,11 @@ github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= -github.com/containerd/containerd v1.5.5/go.mod h1:oSTh0QpT1w6jYcGmbiSbxv9OSQYaa88mPyWIuU79zyo= github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= -github.com/containerd/containerd v1.6.0 h1:CLa12ZcV0d2ZTRKq1ssioeJpTnPJBMyndpEKA+UtzJg= -github.com/containerd/containerd v1.6.0/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE= -github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE= +github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0= +github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= @@ -388,7 +343,6 @@ github.com/containerd/continuity v0.2.2 h1:QSqfxcn8c+12slxwu00AtzXrsami0MJb/MQs9 github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk= github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/fifo v0.0.0-20190816180239-bda0ff6ed73c/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= @@ -413,10 +367,9 @@ github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFY github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= github.com/containerd/stargz-snapshotter v0.0.0-20201027054423-3a04e4c2c116/go.mod h1:o59b3PCKVAf9jjiKtCc/9hLAd+5p/rfhBfm6aBcTEr4= -github.com/containerd/stargz-snapshotter v0.8.1-0.20210910092506-a3ecdc9366fb/go.mod h1:VWbnkZwoaOVh9W1n+dQ9xxXNgTA14SrDNVhq269Odp8= +github.com/containerd/stargz-snapshotter v0.11.2/go.mod h1:HfhsbZ98KIoqA2GLmibTpRwMF/lq3utZ0ElV9ARqU7M= github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= -github.com/containerd/stargz-snapshotter/estargz v0.8.0/go.mod h1:mwIwuwb+D8FX2t45Trwi0hmWmZm5VW7zPP/rekwhWQU= -github.com/containerd/stargz-snapshotter/estargz v0.8.1-0.20210910092506-a3ecdc9366fb/go.mod h1:ndCBLrMyXFyfgBEPHgdR0Ywe8O/kuTShyUsKOzIVeyw= +github.com/containerd/stargz-snapshotter/estargz v0.11.2/go.mod h1:rjbdAXaytDSIrAy2WAy2kUrJ4ehzDS0eUQLlIb5UCY0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= @@ -468,24 +421,25 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyberphone/json-canonicalization v0.0.0-20210303052042-6bc126869bf4 h1:7AjYfmq7AmviXsuZjV5DcE7PuhJ4dWMi8gLllpLVDQY= +github.com/cyberphone/json-canonicalization v0.0.0-20210303052042-6bc126869bf4/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= -github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= +github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -496,26 +450,24 @@ github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/ github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e h1:n81KvOMrLZa+VWHwST7dun9f0G98X3zREHS1ztYzZKU= github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e/go.mod h1:xpWTC2KnJMiDLkoawhsPQcXjvwATEBcbq0xevG2YR9M= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/buildx v0.7.1 h1:l2DlW8YDbB3pH2bUFY5Q9pPQdhd42wqlnO5hoyWrjYM= -github.com/docker/buildx v0.7.1/go.mod h1:PzxALHhYWPNhw/8JajPOJBkvx1w2tgOnppL4ESg0wOY= -github.com/docker/cli v20.10.3-0.20210702143511-f782d1355eff+incompatible h1:CaaxCD/l9Dxogu6lxf7AQautlv3sHULrasPadayp0fM= -github.com/docker/cli v20.10.3-0.20210702143511-f782d1355eff+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli-docs-tool v0.2.1 h1:ffZhhdws6kE+dCKHLMlYROZz8z01RtWbz+g4xz0eBIU= -github.com/docker/cli-docs-tool v0.2.1/go.mod h1:rgW5KKdNpLMBIuH4WQ/1RNh38nH+/Ay5jgL4P0ZMPpY= -github.com/docker/compose-on-kubernetes v0.4.19-0.20190128150448-356b2919c496/go.mod h1:iT2pYfi580XlpaV4KmK0T6+4/9+XoKmk/fhoDod1emE= +github.com/docker/buildx v0.8.2 h1:dsd3F0hhmUydFX/KFrvbK81JvlTA4T3Iy0lwDJt4PsU= +github.com/docker/buildx v0.8.2/go.mod h1:5sMOfNwOmO2jy/MxBL4ySk2LoLIG1tQFu2EU8wbKa34= +github.com/docker/cli v20.10.3-0.20220309205733-2b52f62e9627+incompatible h1:RWXvuBczWuSIMjI69AnkNklNNVX2gmS0X+15AttGDVk= +github.com/docker/cli v20.10.3-0.20220309205733-2b52f62e9627+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli-docs-tool v0.4.0 h1:MdfKoErGEbFqIxQ8an9BsZ+YzKUGd58RBVkV+Q82GPo= +github.com/docker/cli-docs-tool v0.4.0/go.mod h1:rgW5KKdNpLMBIuH4WQ/1RNh38nH+/Ay5jgL4P0ZMPpY= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.0+incompatible h1:l9EaZDICImO1ngI+uTifW+ZYvvz7fKISBAKpg+MbWbY= github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v20.10.3-0.20220121014307-40bb9831756f+incompatible h1:IDzw9qR4h7PF3aEriDajLKrkvc3owPWHasPKUEliWUE= -github.com/docker/docker v20.10.3-0.20220121014307-40bb9831756f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v20.10.3-0.20220309172631-83b51522df43+incompatible h1:bL4hLpxukr5Ls3bzYrn3LCYIwML+XXCktZHaGBIN3og= +github.com/docker/docker v20.10.3-0.20220309172631-83b51522df43+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= -github.com/docker/go v1.5.1-1/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -524,7 +476,6 @@ github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6Uezg github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= -github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -535,14 +486,13 @@ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNE github.com/docker/libtrust v0.0.0-20150526203908-9cbd2a1374f4/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= @@ -556,16 +506,13 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -576,19 +523,17 @@ github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= -github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= +github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= +github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-critic/go-critic v0.4.1/go.mod h1:7/14rZGnZbY6E38VEGk2kVhoq6itzc1E68facVDK23g= github.com/go-critic/go-critic v0.4.3/go.mod h1:j4O3D4RoIwRqlZw5jJpx0BNfXWWbpcJoKu5cYSe4YmQ= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -654,7 +599,6 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= -github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -662,14 +606,14 @@ github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQq github.com/gofrs/flock v0.7.3/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= -github.com/gogo/googleapis v1.3.0/go.mod h1:d+q1s/xVJxZGKWwC/6UfPIF33J+G1Tq4GYv9Y+Tg/EU= github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= -github.com/gogo/googleapis v1.4.0 h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= +github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -678,6 +622,8 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -718,7 +664,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= @@ -743,6 +688,7 @@ github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Z github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/crfs v0.0.0-20191108021818-71d77da419c9/go.mod h1:etGhoOqfwPkooV6aqoX3eBGQOJblqdoc9XvWOeuxpPw= @@ -757,10 +703,10 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-containerregistry v0.0.0-20191010200024-a3d713f9b7f8/go.mod h1:KyKXa9ciM8+lgMXwOVsXi7UxGrsf9mM61Mzs+xKUrKE= -github.com/google/go-containerregistry v0.0.0-20191015185424-71da34e4d9b3/go.mod h1:ZXFeSndFcK4vB1NR4voH1Zm38K7ViUNiYtfIBDxrwf0= github.com/google/go-containerregistry v0.1.2/go.mod h1:GPivBPgdAyd2SU+vf6EpsgOtWDuPqjW0hJZt4rNdTZ4= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= @@ -778,7 +724,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -790,9 +735,6 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -801,17 +743,15 @@ github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= @@ -827,6 +767,7 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -837,7 +778,6 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -858,66 +798,49 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok= github.com/hanwen/go-fuse/v2 v2.0.3/go.mod h1:0EQM6aH2ctVpvZ6a+onrQ/vaykxh2GH7hy3e13vzTUY= -github.com/hanwen/go-fuse/v2 v2.1.0/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc= +github.com/hanwen/go-fuse/v2 v2.1.1-0.20220112183258-f57e95bda82d/go.mod h1:B1nGE/6RBFyBRC1RRnf23UpwCdyJ31eukw34oAKukAc= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cty-funcs v0.0.0-20200930094925-2721b1e36840/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= -github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl/v2 v2.8.2/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/uuid v0.0.0-20160311170451-ebb0a03e909c/go.mod h1:fHzc09UnyJyqyW+bFuq864eh+wC7dj65aXmXLRe5to0= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -925,8 +848,9 @@ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= @@ -937,23 +861,20 @@ github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbB github.com/jaguilar/vt100 v0.0.0-20150826170717-2703a27b14ea/go.mod h1:QMdK4dGB3YhEW2BmA1wgGpPYI3HZy/5gD705PXKUVSg= github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= +github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/gorm v1.9.11 h1:gaHGvE+UnWGlbWG4Y3FUwY1EcZ5n6S9WtqBA/uySMLE= -github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= +github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k= github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= -github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= -github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= @@ -967,7 +888,6 @@ github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBv github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -975,9 +895,9 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= @@ -986,14 +906,13 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= -github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.5 h1:9O69jUPDcsT9fEm74W92rZL9FQY7rCdaXVneq+yyzl4= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1007,22 +926,19 @@ github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= +github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= @@ -1040,7 +956,6 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= @@ -1050,7 +965,6 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= @@ -1061,9 +975,8 @@ github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vq github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1073,13 +986,12 @@ github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88J github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= +github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= @@ -1087,32 +999,34 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/moby/buildkit v0.8.1/go.mod h1:/kyU1hKy/aYCuP39GZA9MaKioovHku57N6cqlKZIaiQ= -github.com/moby/buildkit v0.9.1-0.20211019185819-8778943ac3da h1:DJ6zT0cdxXgUf17GmYAWqCGv47cJXx7nZ1CTHojZ3A4= -github.com/moby/buildkit v0.9.1-0.20211019185819-8778943ac3da/go.mod h1:be+M6HNNl/Et0cUrFWRwEnXC1OChl1wPxXO5uEg4w6A= +github.com/moby/buildkit v0.10.1-0.20220403220257-10e6f94bf90d h1:6pLVBJO3V/lMegbVD5kh2QrpZwqS4ZrxEm/MyifCPaY= +github.com/moby/buildkit v0.10.1-0.20220403220257-10e6f94bf90d/go.mod h1:WvwAZv8aRScHkqc/+X46cRC2CKMKpqcaX+pRvUTtPes= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mount v0.1.0/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74= github.com/moby/sys/mount v0.1.1/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74= -github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM= -github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM= +github.com/moby/sys/mount v0.3.0 h1:bXZYMmq7DBQPwHRxH/MG+u9+XF90ZOwoXpHTOznMGp0= +github.com/moby/sys/mount v0.3.0/go.mod h1:U2Z3ur2rXPFrFmy4q6WMwWrBOAQGYtYTRVM8BIvzbwk= github.com/moby/sys/mountinfo v0.1.0/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/sys/signal v0.5.0/go.mod h1:JwObcMnOrUy2VTP5swPKWwywH0Mbgk8Y5qua9iwtIRM= +github.com/moby/sys/mountinfo v0.6.0 h1:gUDhXQx58YNrpHlK4nSL+7y2pxFZkUcXqzFDKWdC0Oo= +github.com/moby/sys/mountinfo v0.6.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/sys/signal v0.6.0 h1:aDpY94H8VlhTGa9sNYUFCFsMZIUh5wm0B6XkIoJj/iY= github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= @@ -1136,7 +1050,6 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= -github.com/mrunalp/fileutils v0.0.0-20200520151820-abd8a0e76976/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -1147,7 +1060,6 @@ github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5w github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -1185,21 +1097,11 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2-0.20210819154149-5ad6f50d6283/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc10/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc92/go.mod h1:X1zlU4p7wOlX4+WRCz+hvlRv8phdL7UqbYD+vQwNMmE= -github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= -github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= -github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= -github.com/opencontainers/runc v1.1.0 h1:O9+X96OcDjkmmZyfaG996kV7yq8HsoU2h1XRRQcefG8= -github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= +github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v1.1.2 h1:2VSZwLx5k/BfsBxMMipG/LYUnmqOD/BPkIVgQUcTlLw= +github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -1212,16 +1114,16 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= -github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.1 h1:09LIPVRP3uuZGQvgR+SgMSNBd1Eb3vlRbGqQpoHsF8w= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= @@ -1232,7 +1134,6 @@ github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pivotal/image-relocation v0.0.0-20191111101224-e94aff6df06c/go.mod h1:/JNbQwGylYm3AQh8q+MBF8e/h0W1Jy20JGTvozuXYTE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1244,19 +1145,19 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -1271,12 +1172,11 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.30.0 h1:JEkYlQnpzrzQFxi6gnukFPdQ+ac82oRhzMcIduJu/Ug= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1293,10 +1193,10 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/qri-io/jsonpointer v0.1.0 h1:OcTtTmorodUCRc2CZhj/ZwOET8zVj6uo0ArEmzoThZI= -github.com/qri-io/jsonpointer v0.1.0/go.mod h1:DnJPaYgiKu56EuDp8TU5wFLdZIcAnb/uH9v37ZaMV64= -github.com/qri-io/jsonschema v0.1.1 h1:t//Doa/gvMqJ0bDhG7PGIKfaWGGxRVaffp+bcvBGGEk= -github.com/qri-io/jsonschema v0.1.1/go.mod h1:QpzJ6gBQ0GYgGmh7mDQ1YsvvhSgE4rYj0k8t5MBOmUY= +github.com/qri-io/jsonpointer v0.1.1 h1:prVZBZLL6TW5vsSB9fFHFAMBLI4b0ri5vribQlTJiBA= +github.com/qri-io/jsonpointer v0.1.1/go.mod h1:DnJPaYgiKu56EuDp8TU5wFLdZIcAnb/uH9v37ZaMV64= +github.com/qri-io/jsonschema v0.2.2-0.20210831022256-780655b2ba0e h1:gqHzseevuZPr3oOLES1nrPO3exQfeTKUiPcJub5axVs= +github.com/qri-io/jsonschema v0.2.2-0.20210831022256-780655b2ba0e/go.mod h1:g7DPkiOsK1xv6T/Ao5scXRkd+yTFygcANPBaaqW+VrI= github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -1318,7 +1218,6 @@ github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUcc github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= -github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b h1:jUK33OXuZP/l6babJtnLo1qsGvq6G9so9KMflGAm4YA= github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b/go.mod h1:8458kAagoME2+LN5//WxE71ysZ3B7r22fdgb7qVmXSY= github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= @@ -1326,14 +1225,12 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/securego/gosec v0.0.0-20200103095621-79fbf3af8d83/go.mod h1:vvbZ2Ae7AzSq3/kywjUDxSNq2SJ27RxCz2un0H3ePqE= github.com/securego/gosec v0.0.0-20200401082031-e946c8c39989/go.mod h1:i9l/TNj+yDFh9SZXUTvspXTjbFXgZGP/UvhU1S65A4A= github.com/securego/gosec/v2 v2.3.0/go.mod h1:UzeVyUXbxukhLeHKV3VVqo7HdoQR9MrRfFmZYotn8ME= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc= github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= @@ -1363,54 +1260,58 @@ github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVj github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= -github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= -github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk= -github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -1422,8 +1323,9 @@ github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0 github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= github.com/tetafro/godot v0.3.7/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= github.com/tetafro/godot v0.4.2/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= -github.com/theupdateframework/notary v0.6.1 h1:7wshjstgS9x9F5LuB1L5mBI2xNMObWqjz+cjWoom6l0= github.com/theupdateframework/notary v0.6.1/go.mod h1:MOfgIfmox8s7/7fduvB2xyPPMJCrjRLRizA8OFwpnKY= +github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c= +github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw= github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= @@ -1436,20 +1338,15 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1 github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= github.com/tonistiigi/fsutil v0.0.0-20201103201449-0834f99b7b85/go.mod h1:a7cilN64dG941IOXfhJhlH0qB92hxJ9A1ewrdUmJ6xo= -github.com/tonistiigi/fsutil v0.0.0-20210818161904-4442383b5028 h1:uEkkUFMCPtzz1HVOa42u15OHems1ugiRt172tSRTWSk= -github.com/tonistiigi/fsutil v0.0.0-20210818161904-4442383b5028/go.mod h1:E6osHKls9ix67jofYQ61RQKwlJhqJOZM2hintp+49iI= -github.com/tonistiigi/go-actions-cache v0.0.0-20211002214948-4d48f2ff622a/go.mod h1:YiIBjH5gP7mao3t0dBrNNBGuKYdeJmcAJjYLXr43k6A= -github.com/tonistiigi/opentelemetry-go-contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.0.0-20210714055410-d010b05b4939 h1:s6wDMZYNyWt8KvkjhrMpOthFPgI3JB8ipJS+eCV/psg= -github.com/tonistiigi/opentelemetry-go-contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.0.0-20210714055410-d010b05b4939/go.mod h1:Vm5u/mtkj1OMhtao0v+BGo2LUoLCgHYXvRmj0jWITlE= -github.com/tonistiigi/opentelemetry-go-contrib/instrumentation/net/http/httptrace/otelhttptrace v0.0.0-20210714055410-d010b05b4939 h1:ZZ1KHKvs97BcRoblbm6RhrDzs/OejFv7miYSIcZI7Ds= -github.com/tonistiigi/opentelemetry-go-contrib/instrumentation/net/http/httptrace/otelhttptrace v0.0.0-20210714055410-d010b05b4939/go.mod h1:a9cocRplhIBkUAJmak+BPDx+LVL7cTmqUPB0uBcTA4k= -github.com/tonistiigi/opentelemetry-go-contrib/instrumentation/net/http/otelhttp v0.0.0-20210714055410-d010b05b4939 h1:iYUjYA5PwiJjvlY1PkCjFZIoDFOlL4g/AqSrcd5lJtE= -github.com/tonistiigi/opentelemetry-go-contrib/instrumentation/net/http/otelhttp v0.0.0-20210714055410-d010b05b4939/go.mod h1:JQAtechjxLEL81EjmbRwxBq/XEzGaHcsPuDHAx54hg4= +github.com/tonistiigi/fsutil v0.0.0-20220115021204-b19f7f9cb274/go.mod h1:oPAfvw32vlUJSjyDcQ3Bu0nb2ON2B+G0dtVN/SZNJiA= +github.com/tonistiigi/fsutil v0.0.0-20220315205639-9ed612626da3 h1:T1pEe+WB3SCPVAfVquvfPfagKZU2Z8c1OP3SuGB+id0= +github.com/tonistiigi/fsutil v0.0.0-20220315205639-9ed612626da3/go.mod h1:oPAfvw32vlUJSjyDcQ3Bu0nb2ON2B+G0dtVN/SZNJiA= +github.com/tonistiigi/go-actions-cache v0.0.0-20211202175116-9642704158ff/go.mod h1:qqvyZqkfwkoJuPU/bw61bItaoO0SJ8YSW0vSVRRvsRg= +github.com/tonistiigi/go-archvariant v1.0.0/go.mod h1:TxFmO5VS6vMq2kvs3ht04iPXtu2rUT/erOnGFYfk5Ho= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk= github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f h1:DLpt6B5oaaS8jyXHa9VA4rrZloBVPVXeCtrOsrFauxc= github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= @@ -1467,7 +1364,6 @@ github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= @@ -1485,8 +1381,8 @@ github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+ github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= -github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/weppos/publicsuffix-go v0.15.1-0.20220329081811-9a40b608a236 h1:vMJBP3PQViZsF6cOINtvyMC8ptpLsyJ4EwyFnzuWNxc= +github.com/weppos/publicsuffix-go v0.15.1-0.20220329081811-9a40b608a236/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= @@ -1501,7 +1397,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1513,14 +1408,14 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPS github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ= -github.com/zclconf/go-cty v1.7.1/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o= -github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= -github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e h1:mvOa4+/DXStR4ZXOks/UsjeFdn5O5JpLUtzqk9U8xXw= -github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8= -github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb h1:vxqkjztXSaPVDc8FQCdHTaejm2x747f6yPbnu1h2xkg= -github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY= +github.com/zmap/zcrypto v0.0.0-20191112190257-7f2fe6faf8cf/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8= +github.com/zmap/zcrypto v0.0.0-20220605182715-4dfcec6e9a8c h1:ufDm/IlBYZYLuiqvQuhpTKwrcAS2OlXEzWbDvTVGbSQ= +github.com/zmap/zcrypto v0.0.0-20220605182715-4dfcec6e9a8c/go.mod h1:egdRkzUylATvPkWMpebZbXhv0FMEMJGX/ur0D3Csk2s= +github.com/zmap/zlint v1.1.0 h1:Vyh2GmprXw5TLmKmkTa2BgFvvYAFBValBFesqkKsszM= +github.com/zmap/zlint v1.1.0/go.mod h1:3MvSF/QhEftzpxKhh3jkBIOvugsSDYMCofl+UaIv0ww= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -1528,11 +1423,8 @@ go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= @@ -1542,7 +1434,6 @@ go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1551,50 +1442,57 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib v0.21.0 h1:RMJ6GlUVzLYp/zmItxTTdAmr1gnpO/HHMFmvjAhvJQM= -go.opentelemetry.io/contrib v0.21.0/go.mod h1:EH4yDYeNoaTqn/8yCWQmfNB78VHfGX2Jt2bvnvzBlGM= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0 h1:n9b7AAdbQtQ0k9dm0Dm2/KUcUqtG8i2O15KzNaDze8c= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0/go.mod h1:LsankqVDx4W+RhZNA5uWarULII/MBhF5qwCYxTuyXjs= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0 h1:Wjp9vsVSIEyvdiaECfqxY9xBqQ7JaSCGtvHgR4doXZk= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0/go.mod h1:vHItvsnJtp7ES++nFLLFBzUWny7fJQSvTlxFcqQGUr4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 h1:SLme4Porm+UwX0DdHMxlwRt7FzPSE0sys81bet2o0pU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0/go.mod h1:tLYsuf2v8fZreBVwp9gVMhefZlLFZaUiNVSq8QxXRII= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel v1.0.0-RC1/go.mod h1:x9tRa9HK4hSSq7jf2TKbqFbtt58/TGk0f9XiEYISI1I= -go.opentelemetry.io/otel v1.3.0 h1:APxLf0eiBwLl+SOXiJJCVYzA1OOJNyAoV8C5RNRyy7Y= go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= -go.opentelemetry.io/otel/exporters/jaeger v1.0.0-RC1/go.mod h1:FXJnjGCoTQL6nQ8OpFJ0JI1DrdOvMoVx49ic0Hg4+D4= -go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= +go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk= +go.opentelemetry.io/otel v1.4.1 h1:QbINgGDDcoQUoMJa2mMaWno49lja9sHwp6aoa2n3a4g= +go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4= +go.opentelemetry.io/otel/exporters/jaeger v1.4.1/go.mod h1:ZW7vkOu9nC1CxsD8bHNHCia5JUbwP39vxgd1q4Z5rCI= go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.0-RC1/go.mod h1:FliQjImlo7emZVjixV8nbDMAa4iAkcWTE9zzSEOiEPw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0 h1:giGm8w67Ja7amYNfYMdme7xSp2pIxThWopw8+QP51Yk= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.0-RC1/go.mod h1:cDwRc2Jrh5Gku1peGK8p9rRuX/Uq2OtVmLicjlw2WYU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 h1:WPpPsAAs8I2rA47v5u0558meKmmwm1Dj99ZbqCV8sZ8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1/go.mod h1:o5RW5o2pKpJLD5dNTCmjF1DorYwMeFJmb/rKr5sLaa8= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.0.0-RC1/go.mod h1:OYKzEoxgXFvehW7X12WYT4/a2BlASJK9l7RtG4A91fg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1/go.mod h1:c6E4V3/U+miqjs/8l950wggHGL1qzlp0Ypj9xoGrPqo= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= -go.opentelemetry.io/otel/internal/metric v0.21.0 h1:gZlIBo5O51hZOOZz8vEcuRx/l5dnADadKfpT70AELoo= -go.opentelemetry.io/otel/internal/metric v0.21.0/go.mod h1:iOfAaY2YycsXfYD4kaRSbLx2LKmfpKObWBEv9QK5zFo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.4.1/go.mod h1:VwYo0Hak6Efuy0TXsZs8o1hnV3dHDPNtDbycG0hI8+M= +go.opentelemetry.io/otel/internal/metric v0.27.0 h1:9dAVGAfFiiEq5NVB9FUJ5et+btbDQAUIJehJ+ikyryk= +go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/onvKapPGv7y/rpyOTI+LFNzw= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/metric v0.21.0 h1:ZtcJlHqVE4l8Su0WOLOd9fEPheJuYEiQ0wr9wv2p25I= -go.opentelemetry.io/otel/metric v0.21.0/go.mod h1:JWCt1bjivC4iCrz/aCrM1GSw+ZcvY44KCbaeeRhzHnc= +go.opentelemetry.io/otel/metric v0.27.0 h1:HhJPsGhJoKRSegPQILFbODU56NS/L1UE4fS1sC5kIwQ= +go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/oteltest v1.0.0-RC1 h1:G685iP3XiskCwk/z0eIabL55XUl2gk0cljhGk9sB0Yk= -go.opentelemetry.io/otel/oteltest v1.0.0-RC1/go.mod h1:+eoIG0gdEOaPNftuy1YScLr1Gb4mL/9lpDkZ0JjMRq4= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk v1.0.0-RC1/go.mod h1:kj6yPn7Pgt5ByRuwesbaWcRLA+V7BSDg3Hf8xRvsvf8= -go.opentelemetry.io/otel/sdk v1.3.0 h1:3278edCoH89MEJ0Ky8WQXVmDQv3FX4ZJ3Pp+9fJreAI= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= +go.opentelemetry.io/otel/sdk v1.4.1 h1:J7EaW71E0v87qflB4cDolaqq3AcujGrtyIPGQoZOB0Y= +go.opentelemetry.io/otel/sdk v1.4.1/go.mod h1:NBwHDgDIBYjwK2WNu1OPgsIc2IJzmBXNnvIJxJc8BpE= go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/otel/trace v1.0.0-RC1/go.mod h1:86UHmyHWFEtWjfWPSbu0+d0Pf9Q6e1U+3ViBOc+NXAg= -go.opentelemetry.io/otel/trace v1.3.0 h1:doy8Hzb1RJ+I3yFhtDmwNc7tIyw1tNMOIsyPzp1NOGY= go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= +go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE= +go.opentelemetry.io/otel/trace v1.4.1 h1:O+16qcdTrT7zxv2J6GejTPFinSwA++cYerC5iSiF8EQ= +go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= -go.opentelemetry.io/proto/otlp v0.11.0 h1:cLDgIBTf4lLOlztkhzAEdQsJ4Lj+i5Wc9k6Nn0K1VyU= go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= +go.opentelemetry.io/proto/otlp v0.12.0 h1:CMJ/3Wp7iOWES+CYLfnBv+DVmPbB+kmy9PJ92XvlR6c= +go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -1614,27 +1512,28 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200422194213-44a606286825/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1674,7 +1573,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1703,7 +1601,6 @@ golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1735,16 +1632,15 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1763,10 +1659,7 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= @@ -1816,14 +1709,11 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190830141801-acfa387b8d69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1875,7 +1765,6 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210313202042-bd2e13477e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1888,34 +1777,28 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1932,10 +1815,10 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1968,12 +1851,10 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191014205221-18e3458ac98b/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2024,8 +1905,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2041,7 +1920,6 @@ google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+ google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU= google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= @@ -2068,17 +1946,6 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2095,7 +1962,6 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -2143,31 +2009,13 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 h1:ErU+UA6wxadoU8nWrsy5MZUVBs75K17zUCsUCIfrXCE= +google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -2175,7 +2023,6 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= @@ -2195,16 +2042,13 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -2221,6 +2065,8 @@ google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+Rur google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII= +gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2229,26 +2075,23 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/dancannon/gorethink.v3 v3.0.5 h1:/g7PWP7zUS6vSNmHSDbjCHQh1Rqn8Jy6zSMQxAsBSMQ= gopkg.in/dancannon/gorethink.v3 v3.0.5/go.mod h1:GXsi1e3N2OcKhcP6nsYABTiUejbWMFO4GY5a4pEaeEc= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg= gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU= gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= -gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1 h1:d4KQkxAaAiRY2h5Zqis161Pv91A37uZyJOx73duwUwM= +gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1/go.mod h1:WbjuEoo1oadwzQ4apSDU+JTvmllEHtsNHS6y7vFc7iw= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -2267,14 +2110,17 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk= gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ= +gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo= +gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2286,42 +2132,17 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/api v0.0.0-20191016110408-35e52d86657a/go.mod h1:/L5qH+AD540e7Cetbui1tuJeXdmNhO8jM6VkXeDdDhQ= -k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA= -k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= -k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= -k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= -k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= -k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY= -k8s.io/api v0.22.5 h1:xk7C+rMjF/EGELiD560jdmwzrB788mfcHiNbMQLIVI8= -k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= -k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/apimachinery v0.0.0-20190806215851-162a2dabc72f/go.mod h1:+ntn62igV2hyNj7/0brOvXSMONE2KxcePkSxK7/9FFQ= -k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= -k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= -k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= -k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= -k8s.io/apimachinery v0.22.5 h1:cIPwldOYm1Slq9VLBRPtEYpyhjIm1C6aAMAoENuvN9s= -k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= +k8s.io/api v0.22.4 h1:UvyHW0ezB2oIgHAxlYoo6UJQObYXU7awuNarwoHEOjw= +k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk= +k8s.io/apimachinery v0.22.4 h1:9uwcvPpukBw/Ri0EUmWz+49cnFtaoiyEhQTK+xOe7Ck= +k8s.io/apimachinery v0.22.4/go.mod h1:yU6oA6Gnax9RrxGzVvPFFJ+mpnW6PBSqp0sx0I0HHW0= k8s.io/apiserver v0.17.4/go.mod h1:5ZDQ6Xr5MNBxyi3iUZXS84QOhZl+W7Oq2us/29c0j9I= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= -k8s.io/client-go v0.0.0-20180910083459-2cefa64ff137/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/client-go v0.0.0-20191016111102-bec269661e48/go.mod h1:hrwktSwYGI4JK+TJA3dMaFyyvHVi/aLarVHpbs8bgCU= -k8s.io/client-go v0.17.4/go.mod h1:ouF6o5pz3is8qU0/qYL2RnoxOPqgfuidYLowytyLJmc= -k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU= -k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= -k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= -k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= -k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk= -k8s.io/client-go v0.22.5 h1:I8Zn/UqIdi2r02aZmhaJ1hqMxcpfJ3t5VqvHtctHYFo= -k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= +k8s.io/client-go v0.22.4 h1:aAQ1Wk+I3bjCNk35YWUqbaueqrIonkfDPJSPDDe8Kfg= +k8s.io/client-go v0.22.4/go.mod h1:Yzw4e5e7h1LNHA4uqnMVrpEpUs1hJOiuBsJKIlRCHDA= k8s.io/cloud-provider v0.17.4/go.mod h1:XEjKDzfD+b9MTLXQFlDGkk6Ho8SGMpaU8Uugx/KNK9U= k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= @@ -2334,8 +2155,8 @@ k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= -k8s.io/cri-api v0.22.1/go.mod h1:mj5DGUtElRyErU5AZ8EM0ahxbElYsaLAMTPhLPQ40Eg= k8s.io/cri-api v0.23.1/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= +k8s.io/cri-api v0.24.0-alpha.3/go.mod h1:c/NLI5Zdyup5+oEYqFO2IE32ptofNiZpS1nL2y51gAg= k8s.io/csi-translation-lib v0.17.4/go.mod h1:CsxmjwxEI0tTNMzffIAcgR9lX4wOh6AKHdxQrT7L0oo= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= @@ -2344,35 +2165,28 @@ k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuBkhu+yxOc1Js= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= @@ -2390,16 +2204,15 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyz sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= sourcegraph.com/sqs/pbtypes v1.0.0/go.mod h1:3AciMUv4qUuRHRHhOG4TZOB+72GdPVz5k+c648qsFS4= -vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/pkg/api/api.go b/pkg/api/api.go index 2c9e2680..08f6433d 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -19,7 +19,6 @@ package api import ( "context" "fmt" - "io" "strings" "time" @@ -33,9 +32,9 @@ type Service interface { // Push executes the equivalent ot a `compose push` Push(ctx context.Context, project *types.Project, options PushOptions) error // Pull executes the equivalent of a `compose pull` - Pull(ctx context.Context, project *types.Project, opts PullOptions) error + Pull(ctx context.Context, project *types.Project, options PullOptions) error // Create executes the equivalent to a `compose create` - Create(ctx context.Context, project *types.Project, opts CreateOptions) error + Create(ctx context.Context, project *types.Project, options CreateOptions) error // Start executes the equivalent to a `compose start` Start(ctx context.Context, projectName string, options StartOptions) error // Restart restarts containers @@ -55,25 +54,25 @@ type Service interface { // Convert translate compose model into backend's native format Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) // Kill executes the equivalent to a `compose kill` - Kill(ctx context.Context, project *types.Project, options KillOptions) error + Kill(ctx context.Context, projectName string, options KillOptions) error // RunOneOffContainer creates a service oneoff container and starts its dependencies RunOneOffContainer(ctx context.Context, project *types.Project, opts RunOptions) (int, error) // Remove executes the equivalent to a `compose rm` - Remove(ctx context.Context, project *types.Project, options RemoveOptions) error + Remove(ctx context.Context, projectName string, options RemoveOptions) error // Exec executes a command in a running service container - Exec(ctx context.Context, project string, opts RunOptions) (int, error) + Exec(ctx context.Context, projectName string, options RunOptions) (int, error) // Copy copies a file/folder between a service container and the local filesystem - Copy(ctx context.Context, project string, options CopyOptions) error + Copy(ctx context.Context, projectName string, options CopyOptions) error // Pause executes the equivalent to a `compose pause` - Pause(ctx context.Context, project string, options PauseOptions) error + Pause(ctx context.Context, projectName string, options PauseOptions) error // UnPause executes the equivalent to a `compose unpause` - UnPause(ctx context.Context, project string, options PauseOptions) error + UnPause(ctx context.Context, projectName string, options PauseOptions) error // Top executes the equivalent to a `compose top` Top(ctx context.Context, projectName string, services []string) ([]ContainerProcSummary, error) // Events executes the equivalent to a `compose events` - Events(ctx context.Context, project string, options EventsOptions) error + Events(ctx context.Context, projectName string, options EventsOptions) error // Port executes the equivalent to a `compose port` - Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) + Port(ctx context.Context, projectName string, service string, port int, options PortOptions) (string, int, error) // Images executes the equivalent of a `compose images` Images(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error) } @@ -92,6 +91,8 @@ type BuildOptions struct { Quiet bool // Services passed in the command line to be built Services []string + // Ssh authentications passed in the command line + SSHs []types.SSHKey } // CreateOptions group options of the Create API @@ -116,6 +117,8 @@ type CreateOptions struct { // StartOptions group options of the Start API type StartOptions struct { + // Project is the compose project used to define this app. Might be nil if user ran `start` just with project name + Project *types.Project // Attach to container and forward logs if not nil Attach LogConsumer // AttachTo set the services to attach to @@ -216,10 +219,8 @@ type RunOptions struct { Entrypoint []string Detach bool AutoRemove bool - Stdin io.ReadCloser - Stdout io.WriteCloser - Stderr io.WriteCloser Tty bool + Interactive bool WorkingDir string User string Environment []string diff --git a/pkg/api/proxy.go b/pkg/api/proxy.go index 9a06b9cb..5dcfa0e7 100644 --- a/pkg/api/proxy.go +++ b/pkg/api/proxy.go @@ -37,9 +37,9 @@ type ServiceProxy struct { PsFn func(ctx context.Context, projectName string, options PsOptions) ([]ContainerSummary, error) ListFn func(ctx context.Context, options ListOptions) ([]Stack, error) ConvertFn func(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) - KillFn func(ctx context.Context, project *types.Project, options KillOptions) error + KillFn func(ctx context.Context, project string, options KillOptions) error RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error) - RemoveFn func(ctx context.Context, project *types.Project, options RemoveOptions) error + RemoveFn func(ctx context.Context, project string, options RemoveOptions) error ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error) CopyFn func(ctx context.Context, project string, options CopyOptions) error PauseFn func(ctx context.Context, project string, options PauseOptions) error @@ -219,14 +219,11 @@ func (s *ServiceProxy) Convert(ctx context.Context, project *types.Project, opti } // Kill implements Service interface -func (s *ServiceProxy) Kill(ctx context.Context, project *types.Project, options KillOptions) error { +func (s *ServiceProxy) Kill(ctx context.Context, projectName string, options KillOptions) error { if s.KillFn == nil { return ErrNotImplemented } - for _, i := range s.interceptors { - i(ctx, project) - } - return s.KillFn(ctx, project, options) + return s.KillFn(ctx, projectName, options) } // RunOneOffContainer implements Service interface @@ -241,46 +238,43 @@ func (s *ServiceProxy) RunOneOffContainer(ctx context.Context, project *types.Pr } // Remove implements Service interface -func (s *ServiceProxy) Remove(ctx context.Context, project *types.Project, options RemoveOptions) error { +func (s *ServiceProxy) Remove(ctx context.Context, projectName string, options RemoveOptions) error { if s.RemoveFn == nil { return ErrNotImplemented } - for _, i := range s.interceptors { - i(ctx, project) - } - return s.RemoveFn(ctx, project, options) + return s.RemoveFn(ctx, projectName, options) } // Exec implements Service interface -func (s *ServiceProxy) Exec(ctx context.Context, project string, options RunOptions) (int, error) { +func (s *ServiceProxy) Exec(ctx context.Context, projectName string, options RunOptions) (int, error) { if s.ExecFn == nil { return 0, ErrNotImplemented } - return s.ExecFn(ctx, project, options) + return s.ExecFn(ctx, projectName, options) } // Copy implements Service interface -func (s *ServiceProxy) Copy(ctx context.Context, project string, options CopyOptions) error { +func (s *ServiceProxy) Copy(ctx context.Context, projectName string, options CopyOptions) error { if s.CopyFn == nil { return ErrNotImplemented } - return s.CopyFn(ctx, project, options) + return s.CopyFn(ctx, projectName, options) } // Pause implements Service interface -func (s *ServiceProxy) Pause(ctx context.Context, project string, options PauseOptions) error { +func (s *ServiceProxy) Pause(ctx context.Context, projectName string, options PauseOptions) error { if s.PauseFn == nil { return ErrNotImplemented } - return s.PauseFn(ctx, project, options) + return s.PauseFn(ctx, projectName, options) } // UnPause implements Service interface -func (s *ServiceProxy) UnPause(ctx context.Context, project string, options PauseOptions) error { +func (s *ServiceProxy) UnPause(ctx context.Context, projectName string, options PauseOptions) error { if s.UnPauseFn == nil { return ErrNotImplemented } - return s.UnPauseFn(ctx, project, options) + return s.UnPauseFn(ctx, projectName, options) } // Top implements Service interface @@ -292,19 +286,19 @@ func (s *ServiceProxy) Top(ctx context.Context, project string, services []strin } // Events implements Service interface -func (s *ServiceProxy) Events(ctx context.Context, project string, options EventsOptions) error { +func (s *ServiceProxy) Events(ctx context.Context, projectName string, options EventsOptions) error { if s.EventsFn == nil { return ErrNotImplemented } - return s.EventsFn(ctx, project, options) + return s.EventsFn(ctx, projectName, options) } // Port implements Service interface -func (s *ServiceProxy) Port(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error) { +func (s *ServiceProxy) Port(ctx context.Context, projectName string, service string, port int, options PortOptions) (string, int, error) { if s.PortFn == nil { return "", 0, ErrNotImplemented } - return s.PortFn(ctx, project, service, port, options) + return s.PortFn(ctx, projectName, service, port, options) } // Images implements Service interface diff --git a/pkg/compose/attach.go b/pkg/compose/attach.go index dc8466d4..42b815f3 100644 --- a/pkg/compose/attach.go +++ b/pkg/compose/attach.go @@ -48,7 +48,7 @@ func (s *composeService) attach(ctx context.Context, project *types.Project, lis fmt.Printf("Attaching to %s\n", strings.Join(names, ", ")) for _, container := range containers { - err := s.attachContainer(ctx, container, listener, project) + err := s.attachContainer(ctx, container, listener) if err != nil { return nil, err } @@ -56,13 +56,9 @@ func (s *composeService) attach(ctx context.Context, project *types.Project, lis return containers, err } -func (s *composeService) attachContainer(ctx context.Context, container moby.Container, listener api.ContainerEventListener, project *types.Project) error { +func (s *composeService) attachContainer(ctx context.Context, container moby.Container, listener api.ContainerEventListener) error { serviceName := container.Labels[api.ServiceLabel] containerName := getContainerNameWithoutProject(container) - service, err := project.GetService(serviceName) - if err != nil { - return err - } listener(api.ContainerEvent{ Type: api.ContainerEventAttach, @@ -78,7 +74,13 @@ func (s *composeService) attachContainer(ctx context.Context, container moby.Con Line: line, }) }) - _, _, err = s.attachContainerStreams(ctx, container.ID, service.Tty, nil, w, w) + + inspect, err := s.dockerCli.Client().ContainerInspect(ctx, container.ID) + if err != nil { + return err + } + + _, _, err = s.attachContainerStreams(ctx, container.ID, inspect.Config.Tty, nil, w, w) return err } @@ -137,7 +139,7 @@ func (s *composeService) attachContainerStreams(ctx context.Context, container s func (s *composeService) getContainerStreams(ctx context.Context, container string) (io.WriteCloser, io.ReadCloser, error) { var stdout io.ReadCloser var stdin io.WriteCloser - cnx, err := s.apiClient.ContainerAttach(ctx, container, moby.ContainerAttachOptions{ + cnx, err := s.apiClient().ContainerAttach(ctx, container, moby.ContainerAttachOptions{ Stream: true, Stdin: true, Stdout: true, @@ -151,7 +153,7 @@ func (s *composeService) getContainerStreams(ctx context.Context, container stri } // Fallback to logs API - logs, err := s.apiClient.ContainerLogs(ctx, container, moby.ContainerLogsOptions{ + logs, err := s.apiClient().ContainerLogs(ctx, container, moby.ContainerLogsOptions{ ShowStdout: true, ShowStderr: true, Follow: true, diff --git a/pkg/compose/build.go b/pkg/compose/build.go index c9bb56e0..689a6cd8 100644 --- a/pkg/compose/build.go +++ b/pkg/compose/build.go @@ -19,7 +19,6 @@ package compose import ( "context" "fmt" - "os" "path/filepath" "github.com/compose-spec/compose-go/types" @@ -28,11 +27,12 @@ import ( _ "github.com/docker/buildx/driver/docker" // required to get default driver registered "github.com/docker/buildx/util/buildflags" xprogress "github.com/docker/buildx/util/progress" - "github.com/docker/cli/cli/command" "github.com/docker/docker/pkg/urlutil" bclient "github.com/moby/buildkit/client" "github.com/moby/buildkit/session" "github.com/moby/buildkit/session/auth/authprovider" + "github.com/moby/buildkit/session/secrets/secretsprovider" + "github.com/moby/buildkit/session/sshforward/sshprovider" specs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/docker/compose/v2/pkg/api" @@ -64,7 +64,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti if service.Build != nil { imageName := getImageName(service, project.Name) imagesToBuild = append(imagesToBuild, imageName) - buildOptions, err := s.toBuildOptions(project, service, imageName) + buildOptions, err := s.toBuildOptions(project, service, imageName, options.SSHs) if err != nil { return err } @@ -82,7 +82,6 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti Attrs: map[string]string{"ref": image}, }) } - opts[imageName] = buildOptions } } @@ -161,7 +160,7 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri if localImagePresent && service.PullPolicy != types.PullPolicyBuild { continue } - opt, err := s.toBuildOptions(project, service, imageName) + opt, err := s.toBuildOptions(project, service, imageName, []types.SSHKey{}) if err != nil { return nil, err } @@ -189,37 +188,29 @@ func (s *composeService) getLocalImagesDigests(ctx context.Context, project *typ for name, info := range imgs { images[name] = info.ID } - return images, nil -} -func (s *composeService) serverInfo(ctx context.Context) (command.ServerInfo, error) { - ping, err := s.apiClient.Ping(ctx) - if err != nil { - return command.ServerInfo{}, err + for _, s := range project.Services { + imgName := getImageName(s, project.Name) + digest, ok := images[imgName] + if ok { + s.CustomLabels[api.ImageDigestLabel] = digest + } } - serverInfo := command.ServerInfo{ - HasExperimental: ping.Experimental, - OSType: ping.OSType, - BuildkitVersion: ping.BuilderVersion, - } - return serverInfo, err + + return images, nil } func (s *composeService) doBuild(ctx context.Context, project *types.Project, opts map[string]build.Options, mode string) (map[string]string, error) { if len(opts) == 0 { return nil, nil } - serverInfo, err := s.serverInfo(ctx) - if err != nil { - return nil, err - } - if buildkitEnabled, err := command.BuildKitEnabled(serverInfo); err != nil || !buildkitEnabled { - return s.doBuildClassic(ctx, opts) + if buildkitEnabled, err := s.dockerCli.BuildKitEnabled(); err != nil || !buildkitEnabled { + return s.doBuildClassic(ctx, project, opts) } return s.doBuildBuildkit(ctx, project, opts, mode) } -func (s *composeService) toBuildOptions(project *types.Project, service types.ServiceConfig, imageTag string) (build.Options, error) { +func (s *composeService) toBuildOptions(project *types.Project, service types.ServiceConfig, imageTag string, sshKeys []types.SSHKey) (build.Options, error) { var tags []string tags = append(tags, imageTag) @@ -244,11 +235,59 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se plats = append(plats, p) } + cacheFrom, err := buildflags.ParseCacheEntry(service.Build.CacheFrom) + if err != nil { + return build.Options{}, err + } + cacheTo, err := buildflags.ParseCacheEntry(service.Build.CacheTo) + if err != nil { + return build.Options{}, err + } + + sessionConfig := []session.Attachable{ + authprovider.NewDockerAuthProvider(s.stderr()), + } + if len(sshKeys) > 0 || len(service.Build.SSH) > 0 { + sshAgentProvider, err := sshAgentProvider(append(service.Build.SSH, sshKeys...)) + if err != nil { + return build.Options{}, err + } + sessionConfig = append(sessionConfig, sshAgentProvider) + } + + if len(service.Build.Secrets) > 0 { + var sources []secretsprovider.Source + for _, secret := range service.Build.Secrets { + config := project.Secrets[secret.Source] + if config.File == "" { + return build.Options{}, fmt.Errorf("build.secrets only supports file-based secrets: %q", secret.Source) + } + sources = append(sources, secretsprovider.Source{ + ID: secret.Source, + FilePath: config.File, + }) + } + store, err := secretsprovider.NewStore(sources) + if err != nil { + return build.Options{}, err + } + p := secretsprovider.NewSecretProvider(store) + sessionConfig = append(sessionConfig, p) + } + + if len(service.Build.Tags) > 0 { + tags = append(tags, service.Build.Tags...) + } + return build.Options{ Inputs: build.Inputs{ ContextPath: service.Build.Context, DockerfilePath: dockerFilePath(service.Build.Context, service.Build.Dockerfile), }, + CacheFrom: cacheFrom, + CacheTo: cacheTo, + NoCache: service.Build.NoCache, + Pull: service.Build.Pull, BuildArgs: buildArgs, Tags: tags, Target: service.Build.Target, @@ -256,10 +295,8 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se Platforms: plats, Labels: service.Build.Labels, NetworkMode: service.Build.Network, - ExtraHosts: service.Build.ExtraHosts, - Session: []session.Attachable{ - authprovider.NewDockerAuthProvider(os.Stderr), - }, + ExtraHosts: service.Build.ExtraHosts.AsList(), + Session: sessionConfig, }, nil } @@ -293,3 +330,14 @@ func dockerFilePath(context string, dockerfile string) string { } return filepath.Join(context, dockerfile) } + +func sshAgentProvider(sshKeys types.SSHConfig) (session.Attachable, error) { + sshConfig := make([]sshprovider.AgentConfig, 0, len(sshKeys)) + for _, sshKey := range sshKeys { + sshConfig = append(sshConfig, sshprovider.AgentConfig{ + ID: sshKey.ID, + Paths: []string{sshKey.Path}, + }) + } + return sshprovider.NewSSHAgentProvider(sshConfig) +} diff --git a/pkg/compose/build_buildkit.go b/pkg/compose/build_buildkit.go index c2188edf..d4120ced 100644 --- a/pkg/compose/build_buildkit.go +++ b/pkg/compose/build_buildkit.go @@ -29,7 +29,7 @@ import ( func (s *composeService) doBuildBuildkit(ctx context.Context, project *types.Project, opts map[string]build.Options, mode string) (map[string]string, error) { const drivername = "default" - d, err := driver.GetDriver(ctx, drivername, nil, s.apiClient, s.configFile, nil, nil, nil, nil, nil, project.WorkingDir) + d, err := driver.GetDriver(ctx, drivername, nil, s.apiClient(), s.configFile(), nil, nil, nil, nil, nil, project.WorkingDir) if err != nil { return nil, err } @@ -45,10 +45,10 @@ func (s *composeService) doBuildBuildkit(ctx context.Context, project *types.Pro // build and will lock progressCtx, cancel := context.WithCancel(context.Background()) defer cancel() - w := xprogress.NewPrinter(progressCtx, os.Stdout, mode) + w := xprogress.NewPrinter(progressCtx, s.stdout(), os.Stdout, mode) // We rely on buildx "docker" builder integrated in docker engine, so don't need a DockerAPI here - response, err := build.Build(ctx, driverInfo, opts, nil, filepath.Dir(s.configFile.Filename), w) + response, err := build.Build(ctx, driverInfo, opts, nil, filepath.Dir(s.configFile().Filename), w) errW := w.Wait() if err == nil { err = errW diff --git a/pkg/compose/build_classic.go b/pkg/compose/build_classic.go index 3354b4b2..3c6487be 100644 --- a/pkg/compose/build_classic.go +++ b/pkg/compose/build_classic.go @@ -21,12 +21,12 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "os" "path/filepath" "runtime" "strings" + "github.com/compose-spec/compose-go/types" buildx "github.com/docker/buildx/build" "github.com/docker/cli/cli/command/image/build" dockertypes "github.com/docker/docker/api/types" @@ -41,15 +41,24 @@ import ( "github.com/pkg/errors" ) -func (s *composeService) doBuildClassic(ctx context.Context, opts map[string]buildx.Options) (map[string]string, error) { +func (s *composeService) doBuildClassic(ctx context.Context, project *types.Project, opts map[string]buildx.Options) (map[string]string, error) { var nameDigests = make(map[string]string) var errs error - for name, o := range opts { + err := project.WithServices(nil, func(service types.ServiceConfig) error { + imageName := getImageName(service, project.Name) + o, ok := opts[imageName] + if !ok { + return nil + } digest, err := s.doBuildClassicSimpleImage(ctx, o) if err != nil { errs = multierror.Append(errs, err).ErrorOrNil() } - nameDigests[name] = digest + nameDigests[imageName] = digest + return nil + }) + if err != nil { + return nil, err } return nameDigests, errs @@ -69,8 +78,8 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options dockerfileName := options.Inputs.DockerfilePath specifiedContext := options.Inputs.ContextPath - progBuff := os.Stdout - buildBuff := os.Stdout + progBuff := s.stdout() + buildBuff := s.stdout() if options.ImageIDFile != "" { // Avoid leaving a stale file if we eventually fail if err := os.Remove(options.ImageIDFile); err != nil && !os.IsNotExist(err) { @@ -143,19 +152,10 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options return "", err } - // if up to this point nothing has set the context then we must have another - // way for sending it(streaming) and set the context to the Dockerfile - if dockerfileCtx != nil && buildCtx == nil { - buildCtx = dockerfileCtx - } - progressOutput := streamformatter.NewProgressOutput(progBuff) - var body io.Reader - if buildCtx != nil { - body = progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon") - } + body := progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon") - configFile := s.configFile + configFile := s.configFile() creds, err := configFile.GetAllCredentials() if err != nil { return "", err @@ -171,7 +171,7 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options ctx, cancel := context.WithCancel(ctx) defer cancel() - response, err := s.apiClient.ImageBuild(ctx, body, buildOptions) + response, err := s.apiClient().ImageBuild(ctx, body, buildOptions) if err != nil { return "", err } @@ -181,13 +181,13 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options aux := func(msg jsonmessage.JSONMessage) { var result dockertypes.BuildResult if err := json.Unmarshal(*msg.Aux, &result); err != nil { - fmt.Fprintf(os.Stderr, "Failed to parse aux message: %s", err) + fmt.Fprintf(s.stderr(), "Failed to parse aux message: %s", err) } else { imageID = result.ID } } - err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, progBuff.Fd(), true, aux) + err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, progBuff.FD(), true, aux) if err != nil { if jerr, ok := err.(*jsonmessage.JSONError); ok { // If no error code is set, default to 1 @@ -203,7 +203,7 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options // daemon isn't running Windows. if response.OSType != "windows" && runtime.GOOS == "windows" { // if response.OSType != "windows" && runtime.GOOS == "windows" && !options.quiet { - fmt.Fprintln(os.Stdout, "SECURITY WARNING: You are building a Docker "+ + fmt.Fprintln(s.stdout(), "SECURITY WARNING: You are building a Docker "+ "image from Windows against a non-Windows Docker host. All files and "+ "directories added to build context will have '-rwxr-xr-x' permissions. "+ "It is recommended to double check and reset permissions for sensitive "+ @@ -214,7 +214,7 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options if imageID == "" { return "", errors.Errorf("Server did not provide an image ID. Cannot write %s", options.ImageIDFile) } - if err := ioutil.WriteFile(options.ImageIDFile, []byte(imageID), 0666); err != nil { + if err := os.WriteFile(options.ImageIDFile, []byte(imageID), 0666); err != nil { return "", err } } diff --git a/pkg/compose/compose.go b/pkg/compose/compose.go index 7c3c96a2..5f7446e0 100644 --- a/pkg/compose/compose.go +++ b/pkg/compose/compose.go @@ -21,15 +21,18 @@ import ( "context" "encoding/json" "fmt" + "io" "strings" - "github.com/docker/compose/v2/pkg/api" - "github.com/pkg/errors" - "github.com/compose-spec/compose-go/types" + "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/config/configfile" + "github.com/docker/cli/cli/streams" + "github.com/docker/compose/v2/pkg/api" moby "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" + "github.com/pkg/errors" "github.com/sanathkr/go-yaml" ) @@ -37,19 +40,41 @@ import ( var Separator = "-" // NewComposeService create a local implementation of the compose.Service API -func NewComposeService(apiClient client.APIClient, configFile *configfile.ConfigFile) api.Service { +func NewComposeService(dockerCli command.Cli) api.Service { return &composeService{ - apiClient: apiClient, - configFile: configFile, + dockerCli: dockerCli, } } type composeService struct { - apiClient client.APIClient - configFile *configfile.ConfigFile + dockerCli command.Cli +} + +func (s *composeService) apiClient() client.APIClient { + return s.dockerCli.Client() +} + +func (s *composeService) configFile() *configfile.ConfigFile { + return s.dockerCli.ConfigFile() +} + +func (s *composeService) stdout() *streams.Out { + return s.dockerCli.Out() +} + +func (s *composeService) stdin() *streams.In { + return s.dockerCli.In() +} + +func (s *composeService) stderr() io.Writer { + return s.dockerCli.Err() } func getCanonicalContainerName(c moby.Container) string { + if len(c.Names) == 0 { + // corner case, sometime happens on removal. return short ID as a safeguard value + return c.ID[:12] + } // Names return container canonical name /foo + link aliases /linked_by/foo for _, name := range c.Names { if strings.LastIndex(name, "/") == 0 { @@ -100,7 +125,7 @@ func (s *composeService) projectFromName(containers Containers, projectName stri Name: projectName, } if len(containers) == 0 { - return project, errors.New("no such project: " + projectName) + return project, errors.Wrap(api.ErrNotFound, fmt.Sprintf("no container found for project %q", projectName)) } set := map[string]*types.ServiceConfig{} for _, c := range containers { @@ -140,7 +165,7 @@ SERVICES: continue SERVICES } } - return project, errors.New("no such service: " + qs) + return project, errors.Wrapf(api.ErrNotFound, "no such service: %q", qs) } err := project.ForServices(services) if err != nil { @@ -149,3 +174,59 @@ SERVICES: return project, nil } + +// actualState list resources labelled by projectName to rebuild compose project model +func (s *composeService) actualState(ctx context.Context, projectName string, services []string) (Containers, *types.Project, error) { + var containers Containers + // don't filter containers by options.Services so projectFromName can rebuild project with all existing resources + containers, err := s.getContainers(ctx, projectName, oneOffInclude, true) + if err != nil { + return nil, nil, err + } + + project, err := s.projectFromName(containers, projectName, services...) + if err != nil && !api.IsNotFoundError(err) { + return nil, nil, err + } + + if len(services) > 0 { + containers = containers.filter(isService(services...)) + } + return containers, project, nil +} + +func (s *composeService) actualVolumes(ctx context.Context, projectName string) (types.Volumes, error) { + volumes, err := s.apiClient().VolumeList(ctx, filters.NewArgs(projectFilter(projectName))) + if err != nil { + return nil, err + } + + actual := types.Volumes{} + for _, vol := range volumes.Volumes { + actual[vol.Labels[api.VolumeLabel]] = types.VolumeConfig{ + Name: vol.Name, + Driver: vol.Driver, + Labels: vol.Labels, + } + } + return actual, nil +} + +func (s *composeService) actualNetworks(ctx context.Context, projectName string) (types.Networks, error) { + networks, err := s.apiClient().NetworkList(ctx, moby.NetworkListOptions{ + Filters: filters.NewArgs(projectFilter(projectName)), + }) + if err != nil { + return nil, err + } + + actual := types.Networks{} + for _, net := range networks { + actual[net.Labels[api.NetworkLabel]] = types.NetworkConfig{ + Name: net.Name, + Driver: net.Driver, + Labels: net.Labels, + } + } + return actual, nil +} diff --git a/pkg/compose/containers.go b/pkg/compose/containers.go index 25e1fabb..31ea5c8a 100644 --- a/pkg/compose/containers.go +++ b/pkg/compose/containers.go @@ -18,14 +18,13 @@ package compose import ( "context" + "fmt" "sort" - "strconv" - - moby "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/utils" + moby "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" ) // Containers is a set of moby Container @@ -41,18 +40,8 @@ const ( func (s *composeService) getContainers(ctx context.Context, project string, oneOff oneOff, stopped bool, selectedServices ...string) (Containers, error) { var containers Containers - f := []filters.KeyValuePair{projectFilter(project)} - if len(selectedServices) == 1 { - f = append(f, serviceFilter(selectedServices[0])) - } - switch oneOff { - case oneOffOnly: - f = append(f, oneOffFilter(true)) - case oneOffExclude: - f = append(f, oneOffFilter(false)) - case oneOffInclude: - } - containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + f := getDefaultFilters(project, oneOff, selectedServices...) + containers, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs(f...), All: stopped, }) @@ -65,6 +54,40 @@ func (s *composeService) getContainers(ctx context.Context, project string, oneO return containers, nil } +func getDefaultFilters(projectName string, oneOff oneOff, selectedServices ...string) []filters.KeyValuePair { + f := []filters.KeyValuePair{projectFilter(projectName)} + if len(selectedServices) == 1 { + f = append(f, serviceFilter(selectedServices[0])) + } + switch oneOff { + case oneOffOnly: + f = append(f, oneOffFilter(true)) + case oneOffExclude: + f = append(f, oneOffFilter(false)) + case oneOffInclude: + } + return f +} + +func (s *composeService) getSpecifiedContainer(ctx context.Context, projectName string, oneOff oneOff, stopped bool, serviceName string, containerIndex int) (moby.Container, error) { + defaultFilters := getDefaultFilters(projectName, oneOff, serviceName) + defaultFilters = append(defaultFilters, containerNumberFilter(containerIndex)) + containers, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{ + Filters: filters.NewArgs( + defaultFilters..., + ), + All: stopped, + }) + if err != nil { + return moby.Container{}, err + } + if len(containers) < 1 { + return moby.Container{}, fmt.Errorf("service %q is not running container #%d", serviceName, containerIndex) + } + container := containers[0] + return container, nil +} + // containerPredicate define a predicate we want container to satisfy for filtering operations type containerPredicate func(c moby.Container) bool @@ -87,14 +110,6 @@ func isNotOneOff(c moby.Container) bool { return !ok || v == "False" } -func indexed(index int) containerPredicate { - return func(c moby.Container) bool { - number := c.Labels[api.ContainerNumberLabel] - idx, err := strconv.Atoi(number) - return err == nil && index == idx - } -} - // filter return Containers with elements to match predicate func (containers Containers) filter(predicate containerPredicate) Containers { var filtered Containers diff --git a/pkg/compose/convergence.go b/pkg/compose/convergence.go index 2e6304f7..1db3bc3d 100644 --- a/pkg/compose/convergence.go +++ b/pkg/compose/convergence.go @@ -180,26 +180,20 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project, // Scale Down container := container eg.Go(func() error { - err := c.service.apiClient.ContainerStop(ctx, container.ID, timeout) + err := c.service.apiClient().ContainerStop(ctx, container.ID, timeout) if err != nil { return err } - return c.service.apiClient.ContainerRemove(ctx, container.ID, moby.ContainerRemoveOptions{}) + return c.service.apiClient().ContainerRemove(ctx, container.ID, moby.ContainerRemoveOptions{}) }) continue } - if recreate == api.RecreateNever { - continue - } - // Re-create diverged containers - configHash, err := ServiceHash(service) + mustRecreate, err := mustRecreate(service, container, recreate) if err != nil { return err } - name := getContainerProgressName(container) - diverged := container.Labels[api.ConfigHashLabel] != configHash - if diverged || recreate == api.RecreateForce || service.Extensions[extLifecycle] == forceRecreate { + if mustRecreate { i, container := i, container eg.Go(func() error { recreated, err := c.service.recreateContainer(ctx, project, service, container, inherit, timeout) @@ -211,6 +205,7 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project, // Enforce non-diverged containers are running w := progress.ContextWriter(ctx) + name := getContainerProgressName(container) switch container.State { case ContainerRunning: w.Event(progress.RunningEvent(name)) @@ -249,6 +244,22 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project, return err } +func mustRecreate(expected types.ServiceConfig, actual moby.Container, policy string) (bool, error) { + if policy == api.RecreateNever { + return false, nil + } + if policy == api.RecreateForce || expected.Extensions[extLifecycle] == forceRecreate { + return true, nil + } + configHash, err := ServiceHash(expected) + if err != nil { + return false, err + } + configChanged := actual.Labels[api.ConfigHashLabel] != configHash + imageUpdated := actual.Labels[api.ImageDigestLabel] != expected.CustomLabels[api.ImageDigestLabel] + return configChanged || imageUpdated, nil +} + func getContainerName(projectName string, service types.ServiceConfig, number int) string { name := strings.Join([]string{projectName, service.Name, strconv.Itoa(number)}, Separator) if service.ContainerName != "" { @@ -395,13 +406,13 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P var created moby.Container w := progress.ContextWriter(ctx) w.Event(progress.NewEvent(getContainerProgressName(replaced), progress.Working, "Recreate")) - err := s.apiClient.ContainerStop(ctx, replaced.ID, timeout) + err := s.apiClient().ContainerStop(ctx, replaced.ID, timeout) if err != nil { return created, err } name := getCanonicalContainerName(replaced) tmpName := fmt.Sprintf("%s_%s", replaced.ID[:12], name) - err = s.apiClient.ContainerRename(ctx, replaced.ID, tmpName) + err = s.apiClient().ContainerRename(ctx, replaced.ID, tmpName) if err != nil { return created, err } @@ -419,7 +430,7 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P if err != nil { return created, err } - err = s.apiClient.ContainerRemove(ctx, replaced.ID, moby.ContainerRemoveOptions{}) + err = s.apiClient().ContainerRemove(ctx, replaced.ID, moby.ContainerRemoveOptions{}) if err != nil { return created, err } @@ -444,7 +455,7 @@ func setDependentLifecycle(project *types.Project, service string, strategy stri func (s *composeService) startContainer(ctx context.Context, container moby.Container) error { w := progress.ContextWriter(ctx) w.Event(progress.NewEvent(getContainerProgressName(container), progress.Working, "Restart")) - err := s.apiClient.ContainerStart(ctx, container.ID, moby.ContainerStartOptions{}) + err := s.apiClient().ContainerStart(ctx, container.ID, moby.ContainerStartOptions{}) if err != nil { return err } @@ -468,11 +479,11 @@ func (s *composeService) createMobyContainer(ctx context.Context, project *types } plat = &p } - response, err := s.apiClient.ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, plat, name) + response, err := s.apiClient().ContainerCreate(ctx, containerConfig, hostConfig, networkingConfig, plat, name) if err != nil { return created, err } - inspectedContainer, err := s.apiClient.ContainerInspect(ctx, response.ID) + inspectedContainer, err := s.apiClient().ContainerInspect(ctx, response.ID) if err != nil { return created, err } @@ -502,7 +513,7 @@ func (s *composeService) createMobyContainer(ctx context.Context, project *types if shortIDAliasExists(created.ID, val.Aliases...) { continue } - err = s.apiClient.NetworkDisconnect(ctx, netwrk.Name, created.ID, false) + err = s.apiClient().NetworkDisconnect(ctx, netwrk.Name, created.ID, false) if err != nil { return created, err } @@ -512,6 +523,8 @@ func (s *composeService) createMobyContainer(ctx context.Context, project *types return created, err } } + + err = s.injectSecrets(ctx, project, service, created.ID) return created, err } @@ -596,7 +609,7 @@ func (s *composeService) connectContainerToNetwork(ctx context.Context, id strin IPv6Address: ipv6Address, } } - err := s.apiClient.NetworkConnect(ctx, netwrk, id, &network.EndpointSettings{ + err := s.apiClient().NetworkConnect(ctx, netwrk, id, &network.EndpointSettings{ Aliases: aliases, IPAddress: ipv4Address, GlobalIPv6Address: ipv6Address, @@ -619,7 +632,7 @@ func (s *composeService) isServiceHealthy(ctx context.Context, project *types.Pr return false, nil } for _, c := range containers { - container, err := s.apiClient.ContainerInspect(ctx, c.ID) + container, err := s.apiClient().ContainerInspect(ctx, c.ID) if err != nil { return false, err } @@ -651,7 +664,7 @@ func (s *composeService) isServiceCompleted(ctx context.Context, project *types. return false, 0, err } for _, c := range containers { - container, err := s.apiClient.ContainerInspect(ctx, c.ID) + container, err := s.apiClient().ContainerInspect(ctx, c.ID) if err != nil { return false, 0, err } @@ -671,7 +684,7 @@ func (s *composeService) startService(ctx context.Context, project *types.Projec if err != nil { return err } - containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + containers, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs( projectFilter(project.Name), serviceFilter(service.Name), @@ -700,7 +713,7 @@ func (s *composeService) startService(ctx context.Context, project *types.Projec eg.Go(func() error { eventName := getContainerProgressName(container) w.Event(progress.StartingEvent(eventName)) - err := s.apiClient.ContainerStart(ctx, container.ID, moby.ContainerStartOptions{}) + err := s.apiClient().ContainerStart(ctx, container.ID, moby.ContainerStartOptions{}) if err == nil { w.Event(progress.StartedEvent(eventName)) } diff --git a/pkg/compose/convergence_test.go b/pkg/compose/convergence_test.go index 917af7af..bd41db30 100644 --- a/pkg/compose/convergence_test.go +++ b/pkg/compose/convergence_test.go @@ -74,8 +74,11 @@ func TestServiceLinks(t *testing.T) { t.Run("service links default", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() + apiClient := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = apiClient + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(apiClient).AnyTimes() s.Links = []string{"db"} @@ -95,7 +98,9 @@ func TestServiceLinks(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() apiClient := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = apiClient + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(apiClient).AnyTimes() s.Links = []string{"db:db"} @@ -115,7 +120,9 @@ func TestServiceLinks(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() apiClient := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = apiClient + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(apiClient).AnyTimes() s.Links = []string{"db:dbname"} @@ -135,7 +142,9 @@ func TestServiceLinks(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() apiClient := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = apiClient + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(apiClient).AnyTimes() s.Links = []string{"db:dbname"} s.ExternalLinks = []string{"db1:db2"} @@ -159,7 +168,9 @@ func TestServiceLinks(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() apiClient := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = apiClient + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(apiClient).AnyTimes() s.Links = []string{} s.ExternalLinks = []string{} @@ -189,8 +200,11 @@ func TestServiceLinks(t *testing.T) { func TestWaitDependencies(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - api := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = api + + apiClient := mocks.NewMockAPIClient(mockCtrl) + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(apiClient).AnyTimes() t.Run("should skip dependencies with scale 0", func(t *testing.T) { dbService := types.ServiceConfig{Name: "db", Scale: 0} diff --git a/pkg/compose/cp.go b/pkg/compose/cp.go index 435c9601..558de13e 100644 --- a/pkg/compose/cp.go +++ b/pkg/compose/cp.go @@ -42,59 +42,80 @@ const ( acrossServices = fromService | toService ) -func (s *composeService) Copy(ctx context.Context, project string, opts api.CopyOptions) error { - srcService, srcPath := splitCpArg(opts.Source) - destService, dstPath := splitCpArg(opts.Destination) +func (s *composeService) Copy(ctx context.Context, projectName string, options api.CopyOptions) error { + projectName = strings.ToLower(projectName) + srcService, srcPath := splitCpArg(options.Source) + destService, dstPath := splitCpArg(options.Destination) var direction copyDirection var serviceName string + var copyFunc func(ctx context.Context, containerID string, srcPath string, dstPath string, opts api.CopyOptions) error if srcService != "" { direction |= fromService serviceName = srcService + copyFunc = s.copyFromContainer // copying from multiple containers of a services doesn't make sense. - if opts.All { + if options.All { return errors.New("cannot use the --all flag when copying from a service") } } if destService != "" { direction |= toService serviceName = destService + copyFunc = s.copyToContainer + } + if direction == acrossServices { + return errors.New("copying between services is not supported") } - containers, err := s.getContainers(ctx, project, oneOffExclude, true, serviceName) + if direction == 0 { + return errors.New("unknown copy direction") + } + + containers, err := s.listContainersTargetedForCopy(ctx, projectName, options.Index, direction, serviceName) if err != nil { return err } - if len(containers) < 1 { - return fmt.Errorf("no container found for service %q", serviceName) - } - - if !opts.All { - containers = containers.filter(indexed(opts.Index)) - } - g := errgroup.Group{} for _, container := range containers { containerID := container.ID g.Go(func() error { - switch direction { - case fromService: - return s.copyFromContainer(ctx, containerID, srcPath, dstPath, opts) - case toService: - return s.copyToContainer(ctx, containerID, srcPath, dstPath, opts) - case acrossServices: - return errors.New("copying between services is not supported") - default: - return errors.New("unknown copy direction") - } + return copyFunc(ctx, containerID, srcPath, dstPath, options) }) } return g.Wait() } +func (s *composeService) listContainersTargetedForCopy(ctx context.Context, projectName string, index int, direction copyDirection, serviceName string) (Containers, error) { + var containers Containers + var err error + switch { + case index > 0: + container, err := s.getSpecifiedContainer(ctx, projectName, oneOffExclude, true, serviceName, index) + if err != nil { + return nil, err + } + return append(containers, container), nil + default: + containers, err = s.getContainers(ctx, projectName, oneOffExclude, true, serviceName) + if err != nil { + return nil, err + } + + if len(containers) < 1 { + return nil, fmt.Errorf("no container found for service %q", serviceName) + } + if direction == fromService { + return containers[:1], err + + } + return containers, err + } +} + func (s *composeService) copyToContainer(ctx context.Context, containerID string, srcPath string, dstPath string, opts api.CopyOptions) error { var err error if srcPath != "-" { @@ -107,7 +128,7 @@ func (s *composeService) copyToContainer(ctx context.Context, containerID string // Prepare destination copy info by stat-ing the container path. dstInfo := archive.CopyInfo{Path: dstPath} - dstStat, err := s.apiClient.ContainerStatPath(ctx, containerID, dstPath) + dstStat, err := s.apiClient().ContainerStatPath(ctx, containerID, dstPath) // If the destination is a symbolic link, we should evaluate it. if err == nil && dstStat.Mode&os.ModeSymlink != 0 { @@ -119,7 +140,7 @@ func (s *composeService) copyToContainer(ctx context.Context, containerID string } dstInfo.Path = linkTarget - dstStat, err = s.apiClient.ContainerStatPath(ctx, containerID, linkTarget) + dstStat, err = s.apiClient().ContainerStatPath(ctx, containerID, linkTarget) } // Validate the destination path @@ -143,7 +164,7 @@ func (s *composeService) copyToContainer(ctx context.Context, containerID string ) if srcPath == "-" { - content = os.Stdin + content = s.stdin() resolvedDstPath = dstInfo.Path if !dstInfo.IsDir { return errors.Errorf("destination \"%s:%s\" must be a directory", containerID, dstPath) @@ -187,7 +208,7 @@ func (s *composeService) copyToContainer(ctx context.Context, containerID string AllowOverwriteDirWithFile: false, CopyUIDGID: opts.CopyUIDGID, } - return s.apiClient.CopyToContainer(ctx, containerID, resolvedDstPath, content, options) + return s.apiClient().CopyToContainer(ctx, containerID, resolvedDstPath, content, options) } func (s *composeService) copyFromContainer(ctx context.Context, containerID, srcPath, dstPath string, opts api.CopyOptions) error { @@ -207,7 +228,7 @@ func (s *composeService) copyFromContainer(ctx context.Context, containerID, src // if client requests to follow symbol link, then must decide target file to be copied var rebaseName string if opts.FollowLink { - srcStat, err := s.apiClient.ContainerStatPath(ctx, containerID, srcPath) + srcStat, err := s.apiClient().ContainerStatPath(ctx, containerID, srcPath) // If the destination is a symbolic link, we should follow it. if err == nil && srcStat.Mode&os.ModeSymlink != 0 { @@ -223,14 +244,14 @@ func (s *composeService) copyFromContainer(ctx context.Context, containerID, src } } - content, stat, err := s.apiClient.CopyFromContainer(ctx, containerID, srcPath) + content, stat, err := s.apiClient().CopyFromContainer(ctx, containerID, srcPath) if err != nil { return err } defer content.Close() //nolint:errcheck if dstPath == "-" { - _, err = io.Copy(os.Stdout, content) + _, err = io.Copy(s.stdout(), content) return err } diff --git a/pkg/compose/create.go b/pkg/compose/create.go index 14fd57e5..34e728eb 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -21,7 +21,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "os" "path" "path/filepath" "strconv" @@ -31,6 +31,7 @@ import ( moby "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/blkiodev" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/strslice" @@ -173,13 +174,21 @@ func prepareServicesDependsOn(p *types.Project) error { dependencies = append(dependencies, spec[0]) } + for _, link := range service.Links { + dependencies = append(dependencies, strings.Split(link, ":")[0]) + } + if len(dependencies) == 0 { continue } if service.DependsOn == nil { service.DependsOn = make(types.DependsOnConfig) } - deps, err := p.GetServices(dependencies...) + + // Verify dependencies exist in the project, whether disabled or not + projAllServices := types.Project{} + projAllServices.Services = p.AllServices() + deps, err := projAllServices.GetServices(dependencies...) if err != nil { return err } @@ -255,7 +264,7 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, return nil, nil, nil, err } - proxyConfig := types.MappingWithEquals(s.configFile.ParseProxyConfig(s.apiClient.DaemonHost(), nil)) + proxyConfig := types.MappingWithEquals(s.configFile().ParseProxyConfig(s.apiClient().DaemonHost(), nil)) env := proxyConfig.OverrideBy(service.Environment) containerConfig := container.Config{ @@ -347,6 +356,11 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, volumesFrom = append(volumesFrom, v[len("container:"):]) } + links, err := s.getLinks(ctx, p.Name, service, number) + if err != nil { + return nil, nil, nil, err + } + securityOpts, err := parseSecurityOpts(p, service.SecurityOpt) if err != nil { return nil, nil, nil, err @@ -371,7 +385,7 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, DNS: service.DNS, DNSSearch: service.DNSSearch, DNSOptions: service.DNSOpts, - ExtraHosts: service.ExtraHosts, + ExtraHosts: service.ExtraHosts.AsList(), SecurityOpt: securityOpts, UsernsMode: container.UsernsMode(service.UserNSMode), Privileged: service.Privileged, @@ -381,6 +395,7 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, Runtime: service.Runtime, LogConfig: logConfig, GroupAdd: service.GroupAdd, + Links: links, } return &containerConfig, &hostConfig, networkConfig, nil @@ -399,7 +414,7 @@ func parseSecurityOpts(p *types.Project, securityOpts []string) ([]string, error } } if con[0] == "seccomp" && con[1] != "unconfined" { - f, err := ioutil.ReadFile(p.RelativePath(con[1])) + f, err := os.ReadFile(p.RelativePath(con[1])) if err != nil { return securityOpts, errors.Errorf("opening seccomp profile (%s) failed: %v", con[1], err) } @@ -500,6 +515,7 @@ func getDeployResources(s types.ServiceConfig) container.Resources { CPUShares: s.CPUShares, CPUPercent: int64(s.CPUS * 100), CpusetCpus: s.CPUSet, + DeviceCgroupRules: s.DeviceCgroupRules, } if s.PidsLimit != 0 { @@ -579,8 +595,12 @@ func setLimits(limits *types.Resource, resources *container.Resources) { resources.Memory = int64(limits.MemoryBytes) } if limits.NanoCPUs != "" { - i, _ := strconv.ParseInt(limits.NanoCPUs, 10, 64) - resources.NanoCPUs = i + if f, err := strconv.ParseFloat(limits.NanoCPUs, 64); err == nil { + resources.NanoCPUs = int64(f * 1e9) + } + } + if limits.PIds > 0 { + resources.PidsLimit = &limits.PIds } } @@ -693,7 +713,7 @@ func (s *composeService) buildContainerVolumes(ctx context.Context, p types.Proj var mounts = []mount.Mount{} image := getImageName(service, p.Name) - imgInspect, _, err := s.apiClient.ImageInspectWithRaw(ctx, image) + imgInspect, _, err := s.apiClient().ImageInspectWithRaw(ctx, image) if err != nil { return nil, nil, nil, err } @@ -708,12 +728,20 @@ func (s *composeService) buildContainerVolumes(ctx context.Context, p types.Proj MOUNTS: for _, m := range mountOptions { volumeMounts[m.Target] = struct{}{} - // `Bind` API is used when host path need to be created if missing, `Mount` is preferred otherwise if m.Type == mount.TypeBind || m.Type == mount.TypeNamedPipe { + // `Mount` is preferred but does not offer option to created host path if missing + // so `Bind` API is used here with raw volume string + // see https://github.com/moby/moby/issues/43483 for _, v := range service.Volumes { - if v.Target == m.Target && v.Bind != nil && v.Bind.CreateHostPath { - binds = append(binds, fmt.Sprintf("%s:%s:%s", m.Source, m.Target, getBindMode(v.Bind, m.ReadOnly))) - continue MOUNTS + if v.Target == m.Target { + switch { + case string(m.Type) != v.Type: + v.Source = m.Source + fallthrough + case v.Bind != nil && v.Bind.CreateHostPath: + binds = append(binds, v.String()) + continue MOUNTS + } } } } @@ -722,23 +750,6 @@ MOUNTS: return volumeMounts, binds, mounts, nil } -func getBindMode(bind *types.ServiceVolumeBind, readOnly bool) string { - mode := "rw" - - if readOnly { - mode = "ro" - } - - switch bind.SELinux { - case types.SELinuxShared: - mode += ",z" - case types.SELinuxPrivate: - mode += ",Z" - } - - return mode -} - func buildContainerMountOptions(p types.Project, s types.ServiceConfig, img moby.ImageInspect, inherit *moby.Container) ([]mount.Mount, error) { var mounts = map[string]mount.Mount{} if inherit != nil { @@ -878,6 +889,10 @@ func buildContainerSecretMounts(p types.Project, s types.ServiceConfig) ([]mount return nil, fmt.Errorf("unsupported external secret %s", definedSecret.Name) } + if definedSecret.Environment != "" { + continue + } + mount, err := buildMount(p, types.ServiceVolumeConfig{ Type: types.VolumeTypeBind, Source: definedSecret.File, @@ -921,10 +936,14 @@ func buildMount(project types.Project, volume types.ServiceVolumeConfig) (mount. } } - bind, vol, tmpfs := buildMountOptions(volume) + bind, vol, tmpfs := buildMountOptions(project, volume) volume.Target = path.Clean(volume.Target) + if bind != nil { + volume.Type = types.VolumeTypeBind + } + return mount.Mount{ Type: mount.Type(volume.Type), Source: source, @@ -937,7 +956,7 @@ func buildMount(project types.Project, volume types.ServiceVolumeConfig) (mount. }, nil } -func buildMountOptions(volume types.ServiceVolumeConfig) (*mount.BindOptions, *mount.VolumeOptions, *mount.TmpfsOptions) { +func buildMountOptions(project types.Project, volume types.ServiceVolumeConfig) (*mount.BindOptions, *mount.VolumeOptions, *mount.TmpfsOptions) { switch volume.Type { case "bind": if volume.Volume != nil { @@ -954,6 +973,11 @@ func buildMountOptions(volume types.ServiceVolumeConfig) (*mount.BindOptions, *m if volume.Tmpfs != nil { logrus.Warnf("mount of type `volume` should not define `tmpfs` option") } + if v, ok := project.Volumes[volume.Source]; ok && v.DriverOpts["o"] == types.VolumeTypeBind { + return buildBindOption(&types.ServiceVolumeBind{ + CreateHostPath: true, + }), nil, nil + } return nil, buildVolumeOptions(volume.Volume), nil case "tmpfs": if volume.Bind != nil { @@ -1007,92 +1031,88 @@ func getAliases(s types.ServiceConfig, c *types.ServiceNetworkConfig) []string { } func (s *composeService) ensureNetwork(ctx context.Context, n types.NetworkConfig) error { - _, err := s.apiClient.NetworkInspect(ctx, n.Name, moby.NetworkInspectOptions{}) + // NetworkInspect will match on ID prefix, so NetworkList with a name + // filter is used to look for an exact match to prevent e.g. a network + // named `db` from getting erroneously matched to a network with an ID + // like `db9086999caf` + networks, err := s.apiClient().NetworkList(ctx, moby.NetworkListOptions{ + Filters: filters.NewArgs(filters.Arg("name", n.Name)), + }) if err != nil { - if errdefs.IsNotFound(err) { - if n.External.External { - if n.Driver == "overlay" { - // Swarm nodes do not register overlay networks that were - // created on a different node unless they're in use. - // Here we assume `driver` is relevant for a network we don't manage - // which is a non-sense, but this is our legacy ¯\(ツ)/¯ - // networkAttach will later fail anyway if network actually doesn't exists - return nil - } - return fmt.Errorf("network %s declared as external, but could not be found", n.Name) - } - var ipam *network.IPAM - if n.Ipam.Config != nil { - var config []network.IPAMConfig - for _, pool := range n.Ipam.Config { - config = append(config, network.IPAMConfig{ - Subnet: pool.Subnet, - IPRange: pool.IPRange, - Gateway: pool.Gateway, - AuxAddress: pool.AuxiliaryAddresses, - }) - } - ipam = &network.IPAM{ - Driver: n.Ipam.Driver, - Config: config, - } - } - createOpts := moby.NetworkCreate{ - // TODO NameSpace Labels - Labels: n.Labels, - Driver: n.Driver, - Options: n.DriverOpts, - Internal: n.Internal, - Attachable: n.Attachable, - IPAM: ipam, - EnableIPv6: n.EnableIPv6, - } - - if n.Ipam.Driver != "" || len(n.Ipam.Config) > 0 { - createOpts.IPAM = &network.IPAM{} - } - - if n.Ipam.Driver != "" { - createOpts.IPAM.Driver = n.Ipam.Driver - } - - for _, ipamConfig := range n.Ipam.Config { - config := network.IPAMConfig{ - Subnet: ipamConfig.Subnet, - } - createOpts.IPAM.Config = append(createOpts.IPAM.Config, config) - } - networkEventName := fmt.Sprintf("Network %s", n.Name) - w := progress.ContextWriter(ctx) - w.Event(progress.CreatingEvent(networkEventName)) - if _, err := s.apiClient.NetworkCreate(ctx, n.Name, createOpts); err != nil { - w.Event(progress.ErrorEvent(networkEventName)) - return errors.Wrapf(err, "failed to create network %s", n.Name) - } - w.Event(progress.CreatedEvent(networkEventName)) - return nil - } return err } - return nil -} + if len(networks) == 0 { + if n.External.External { + if n.Driver == "overlay" { + // Swarm nodes do not register overlay networks that were + // created on a different node unless they're in use. + // Here we assume `driver` is relevant for a network we don't manage + // which is a non-sense, but this is our legacy ¯\(ツ)/¯ + // networkAttach will later fail anyway if network actually doesn't exists + return nil + } + return fmt.Errorf("network %s declared as external, but could not be found", n.Name) + } + var ipam *network.IPAM + if n.Ipam.Config != nil { + var config []network.IPAMConfig + for _, pool := range n.Ipam.Config { + config = append(config, network.IPAMConfig{ + Subnet: pool.Subnet, + IPRange: pool.IPRange, + Gateway: pool.Gateway, + AuxAddress: pool.AuxiliaryAddresses, + }) + } + ipam = &network.IPAM{ + Driver: n.Ipam.Driver, + Config: config, + } + } + createOpts := moby.NetworkCreate{ + CheckDuplicate: true, + // TODO NameSpace Labels + Labels: n.Labels, + Driver: n.Driver, + Options: n.DriverOpts, + Internal: n.Internal, + Attachable: n.Attachable, + IPAM: ipam, + EnableIPv6: n.EnableIPv6, + } -func (s *composeService) removeNetwork(ctx context.Context, networkID string, networkName string) error { - w := progress.ContextWriter(ctx) - eventName := fmt.Sprintf("Network %s", networkName) - w.Event(progress.RemovingEvent(eventName)) + if n.Ipam.Driver != "" || len(n.Ipam.Config) > 0 { + createOpts.IPAM = &network.IPAM{} + } - if err := s.apiClient.NetworkRemove(ctx, networkID); err != nil { - w.Event(progress.ErrorEvent(eventName)) - return errors.Wrapf(err, fmt.Sprintf("failed to remove network %s", networkID)) + if n.Ipam.Driver != "" { + createOpts.IPAM.Driver = n.Ipam.Driver + } + + for _, ipamConfig := range n.Ipam.Config { + config := network.IPAMConfig{ + Subnet: ipamConfig.Subnet, + IPRange: ipamConfig.IPRange, + Gateway: ipamConfig.Gateway, + AuxAddress: ipamConfig.AuxiliaryAddresses, + } + createOpts.IPAM.Config = append(createOpts.IPAM.Config, config) + } + networkEventName := fmt.Sprintf("Network %s", n.Name) + w := progress.ContextWriter(ctx) + w.Event(progress.CreatingEvent(networkEventName)) + if _, err := s.apiClient().NetworkCreate(ctx, n.Name, createOpts); err != nil { + w.Event(progress.ErrorEvent(networkEventName)) + return errors.Wrapf(err, "failed to create network %s", n.Name) + } + w.Event(progress.CreatedEvent(networkEventName)) + return nil } - - w.Event(progress.RemovedEvent(eventName)) return nil } func (s *composeService) ensureVolume(ctx context.Context, volume types.VolumeConfig, project string) error { - inspected, err := s.apiClient.VolumeInspect(ctx, volume.Name) + inspected, err := s.apiClient().VolumeInspect(ctx, volume.Name) if err != nil { if !errdefs.IsNotFound(err) { return err @@ -1123,7 +1143,7 @@ func (s *composeService) createVolume(ctx context.Context, volume types.VolumeCo eventName := fmt.Sprintf("Volume %q", volume.Name) w := progress.ContextWriter(ctx) w.Event(progress.CreatingEvent(eventName)) - _, err := s.apiClient.VolumeCreate(ctx, volume_api.VolumeCreateBody{ + _, err := s.apiClient().VolumeCreate(ctx, volume_api.VolumeCreateBody{ Labels: volume.Labels, Name: volume.Name, Driver: volume.Driver, diff --git a/pkg/compose/create_test.go b/pkg/compose/create_test.go index ea2ec88a..6c6a4f19 100644 --- a/pkg/compose/create_test.go +++ b/pkg/compose/create_test.go @@ -143,15 +143,6 @@ func TestBuildContainerMountOptions(t *testing.T) { assert.Equal(t, mounts[1].Target, "/var/myvolume2") } -func TestGetBindMode(t *testing.T) { - assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{}, false), "rw") - assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{}, true), "ro") - assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{SELinux: composetypes.SELinuxShared}, false), "rw,z") - assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{SELinux: composetypes.SELinuxPrivate}, false), "rw,Z") - assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{SELinux: composetypes.SELinuxShared}, true), "ro,z") - assert.Equal(t, getBindMode(&composetypes.ServiceVolumeBind{SELinux: composetypes.SELinuxPrivate}, true), "ro,Z") -} - func TestGetDefaultNetworkMode(t *testing.T) { t.Run("returns the network with the highest priority when service has multiple networks", func(t *testing.T) { service := composetypes.ServiceConfig{ diff --git a/pkg/compose/dependencies.go b/pkg/compose/dependencies.go index 2147862b..ed33ec2b 100644 --- a/pkg/compose/dependencies.go +++ b/pkg/compose/dependencies.go @@ -132,7 +132,7 @@ func getParents(v *Vertex) []*Vertex { return v.GetParents() } -// GetParents returns a slice with the parent vertexes of the a Vertex +// GetParents returns a slice with the parent vertices of the a Vertex func (v *Vertex) GetParents() []*Vertex { var res []*Vertex for _, p := range v.Parents { @@ -145,7 +145,7 @@ func getChildren(v *Vertex) []*Vertex { return v.GetChildren() } -// GetChildren returns a slice with the child vertexes of the a Vertex +// GetChildren returns a slice with the child vertices of the a Vertex func (v *Vertex) GetChildren() []*Vertex { var res []*Vertex for _, p := range v.Children { @@ -194,7 +194,7 @@ func (g *Graph) AddVertex(key string, service string, initialStatus ServiceStatu g.Vertices[key] = v } -// AddEdge adds a relationship of dependency between vertexes `source` and `destination` +// AddEdge adds a relationship of dependency between vertices `source` and `destination` func (g *Graph) AddEdge(source string, destination string) error { g.lock.Lock() defer g.lock.Unlock() diff --git a/pkg/compose/down.go b/pkg/compose/down.go index 60498ffa..b04ac108 100644 --- a/pkg/compose/down.go +++ b/pkg/compose/down.go @@ -26,6 +26,7 @@ import ( moby "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/errdefs" + "github.com/pkg/errors" "golang.org/x/sync/errgroup" "github.com/docker/compose/v2/pkg/api" @@ -41,7 +42,6 @@ func (s *composeService) Down(ctx context.Context, projectName string, options a } func (s *composeService) down(ctx context.Context, projectName string, options api.DownOptions) error { - builtFromResources := options.Project == nil w := progress.ContextWriter(ctx) resourceToRemove := false @@ -51,8 +51,9 @@ func (s *composeService) down(ctx context.Context, projectName string, options a return err } - if builtFromResources { - options.Project, err = s.getProjectWithVolumes(ctx, containers, projectName) + project := options.Project + if project == nil { + project, err = s.getProjectWithResources(ctx, containers, projectName) if err != nil { return err } @@ -62,7 +63,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options a resourceToRemove = true } - err = InReverseDependencyOrder(ctx, options.Project, func(c context.Context, service string) error { + err = InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error { serviceContainers := containers.filter(isService(service)) err := s.removeContainers(ctx, w, serviceContainers, options.Timeout, options.Volumes) return err @@ -71,7 +72,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options a return err } - orphans := containers.filter(isNotService(options.Project.ServiceNames()...)) + orphans := containers.filter(isNotService(project.ServiceNames()...)) if options.RemoveOrphans && len(orphans) > 0 { err := s.removeContainers(ctx, w, orphans, options.Timeout, false) if err != nil { @@ -79,21 +80,18 @@ func (s *composeService) down(ctx context.Context, projectName string, options a } } - ops, err := s.ensureNetworksDown(ctx, projectName) - if err != nil { - return err - } + ops := s.ensureNetworksDown(ctx, project, w) if options.Images != "" { - ops = append(ops, s.ensureImagesDown(ctx, projectName, options, w)...) + ops = append(ops, s.ensureImagesDown(ctx, project, options, w)...) } if options.Volumes { - ops = append(ops, s.ensureVolumesDown(ctx, options.Project, w)...) + ops = append(ops, s.ensureVolumesDown(ctx, project, w)...) } if !resourceToRemove && len(ops) == 0 { - w.Event(progress.NewEvent(projectName, progress.Done, "Warning: No resource found to remove")) + fmt.Fprintf(s.stderr(), "Warning: No resource found to remove for project %q.\n", projectName) } eg, _ := errgroup.WithContext(ctx) @@ -106,6 +104,9 @@ func (s *composeService) down(ctx context.Context, projectName string, options a func (s *composeService) ensureVolumesDown(ctx context.Context, project *types.Project, w progress.Writer) []downOp { var ops []downOp for _, vol := range project.Volumes { + if vol.External.External { + continue + } volumeName := vol.Name ops = append(ops, func() error { return s.removeVolume(ctx, volumeName, w) @@ -114,9 +115,9 @@ func (s *composeService) ensureVolumesDown(ctx context.Context, project *types.P return ops } -func (s *composeService) ensureImagesDown(ctx context.Context, projectName string, options api.DownOptions, w progress.Writer) []downOp { +func (s *composeService) ensureImagesDown(ctx context.Context, project *types.Project, options api.DownOptions, w progress.Writer) []downOp { var ops []downOp - for image := range s.getServiceImages(options, projectName) { + for image := range s.getServiceImages(options, project) { image := image ops = append(ops, func() error { return s.removeImage(ctx, image, w) @@ -125,31 +126,74 @@ func (s *composeService) ensureImagesDown(ctx context.Context, projectName strin return ops } -func (s *composeService) ensureNetworksDown(ctx context.Context, projectName string) ([]downOp, error) { +func (s *composeService) ensureNetworksDown(ctx context.Context, project *types.Project, w progress.Writer) []downOp { var ops []downOp - networks, err := s.apiClient.NetworkList(ctx, moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(projectName))}) - if err != nil { - return ops, err - } - for _, n := range networks { - networkID := n.ID + for _, n := range project.Networks { + if n.External.External { + continue + } + // loop capture variable for op closure networkName := n.Name ops = append(ops, func() error { - return s.removeNetwork(ctx, networkID, networkName) + return s.removeNetwork(ctx, networkName, w) }) } - return ops, nil + return ops } -func (s *composeService) getServiceImages(options api.DownOptions, projectName string) map[string]struct{} { +func (s *composeService) removeNetwork(ctx context.Context, name string, w progress.Writer) error { + // networks are guaranteed to have unique IDs but NOT names, so it's + // possible to get into a situation where a compose down will fail with + // an error along the lines of: + // failed to remove network test: Error response from daemon: network test is ambiguous (2 matches found based on name) + // as a workaround here, the delete is done by ID after doing a list using + // the name as a filter (99.9% of the time this will return a single result) + networks, err := s.apiClient().NetworkList(ctx, moby.NetworkListOptions{ + Filters: filters.NewArgs(filters.Arg("name", name)), + }) + if err != nil { + return errors.Wrapf(err, fmt.Sprintf("failed to inspect network %s", name)) + } + if len(networks) == 0 { + return nil + } + + eventName := fmt.Sprintf("Network %s", name) + w.Event(progress.RemovingEvent(eventName)) + + var removed int + for _, net := range networks { + if err := s.apiClient().NetworkRemove(ctx, net.ID); err != nil { + if errdefs.IsNotFound(err) { + continue + } + w.Event(progress.ErrorEvent(eventName)) + return errors.Wrapf(err, fmt.Sprintf("failed to remove network %s", name)) + } + removed++ + } + + if removed == 0 { + // in practice, it's extremely unlikely for this to ever occur, as it'd + // mean the network was present when we queried at the start of this + // method but was then deleted by something else in the interim + w.Event(progress.NewEvent(eventName, progress.Done, "Warning: No resource found to remove")) + return nil + } + + w.Event(progress.RemovedEvent(eventName)) + return nil +} + +func (s *composeService) getServiceImages(options api.DownOptions, project *types.Project) map[string]struct{} { images := map[string]struct{}{} - for _, service := range options.Project.Services { + for _, service := range project.Services { image := service.Image if options.Images == "local" && image != "" { continue } if image == "" { - image = getImageName(service, projectName) + image = getImageName(service, project.Name) } images[image] = struct{}{} } @@ -159,7 +203,7 @@ func (s *composeService) getServiceImages(options api.DownOptions, projectName s func (s *composeService) removeImage(ctx context.Context, image string, w progress.Writer) error { id := fmt.Sprintf("Image %s", image) w.Event(progress.NewEvent(id, progress.Working, "Removing")) - _, err := s.apiClient.ImageRemove(ctx, image, moby.ImageRemoveOptions{}) + _, err := s.apiClient().ImageRemove(ctx, image, moby.ImageRemoveOptions{}) if err == nil { w.Event(progress.NewEvent(id, progress.Done, "Removed")) return nil @@ -174,7 +218,7 @@ func (s *composeService) removeImage(ctx context.Context, image string, w progre func (s *composeService) removeVolume(ctx context.Context, id string, w progress.Writer) error { resource := fmt.Sprintf("Volume %s", id) w.Event(progress.NewEvent(resource, progress.Working, "Removing")) - err := s.apiClient.VolumeRemove(ctx, id, true) + err := s.apiClient().VolumeRemove(ctx, id, true) if err == nil { w.Event(progress.NewEvent(resource, progress.Done, "Removed")) return nil @@ -193,7 +237,7 @@ func (s *composeService) stopContainers(ctx context.Context, w progress.Writer, eg.Go(func() error { eventName := getContainerProgressName(container) w.Event(progress.StoppingEvent(eventName)) - err := s.apiClient.ContainerStop(ctx, container.ID, timeout) + err := s.apiClient().ContainerStop(ctx, container.ID, timeout) if err != nil { w.Event(progress.ErrorMessageEvent(eventName, "Error while Stopping")) return err @@ -218,7 +262,7 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer return err } w.Event(progress.RemovingEvent(eventName)) - err = s.apiClient.ContainerRemove(ctx, container.ID, moby.ContainerRemoveOptions{ + err = s.apiClient().ContainerRemove(ctx, container.ID, moby.ContainerRemoveOptions{ Force: true, RemoveVolumes: volumes, }) @@ -233,21 +277,23 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer return eg.Wait() } -func (s *composeService) getProjectWithVolumes(ctx context.Context, containers Containers, projectName string) (*types.Project, error) { +func (s *composeService) getProjectWithResources(ctx context.Context, containers Containers, projectName string) (*types.Project, error) { containers = containers.filter(isNotOneOff) - project, _ := s.projectFromName(containers, projectName) - volumes, err := s.apiClient.VolumeList(ctx, filters.NewArgs(projectFilter(projectName))) - if err != nil { + project, err := s.projectFromName(containers, projectName) + if err != nil && !api.IsNotFoundError(err) { return nil, err } - project.Volumes = types.Volumes{} - for _, vol := range volumes.Volumes { - project.Volumes[vol.Labels[api.VolumeLabel]] = types.VolumeConfig{ - Name: vol.Name, - Driver: vol.Driver, - Labels: vol.Labels, - } + volumes, err := s.actualVolumes(ctx, projectName) + if err != nil { + return nil, err } + project.Volumes = volumes + + networks, err := s.actualNetworks(ctx, projectName) + if err != nil { + return nil, err + } + project.Networks = networks return project, nil } diff --git a/pkg/compose/down_test.go b/pkg/compose/down_test.go index b862ce15..ea952793 100644 --- a/pkg/compose/down_test.go +++ b/pkg/compose/down_test.go @@ -21,21 +21,24 @@ import ( "strings" "testing" - compose "github.com/docker/compose/v2/pkg/api" - "github.com/docker/compose/v2/pkg/mocks" - moby "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/volume" "github.com/golang/mock/gomock" "gotest.tools/v3/assert" + + compose "github.com/docker/compose/v2/pkg/api" + "github.com/docker/compose/v2/pkg/mocks" ) func TestDown(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() + api := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = api + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(api).AnyTimes() api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return( []moby.Container{ @@ -47,6 +50,14 @@ func TestDown(t *testing.T) { api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))). Return(volume.VolumeListOKBody{}, nil) + // network names are not guaranteed to be unique, ensure Compose handles + // cleanup properly if duplicates are inadvertently created + api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}). + Return([]moby.NetworkResource{ + {ID: "abc123", Name: "myProject_default"}, + {ID: "def456", Name: "myProject_default"}, + }, nil) + api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil) api.EXPECT().ContainerStop(gomock.Any(), "456", nil).Return(nil) api.EXPECT().ContainerStop(gomock.Any(), "789", nil).Return(nil) @@ -55,10 +66,14 @@ func TestDown(t *testing.T) { api.EXPECT().ContainerRemove(gomock.Any(), "456", moby.ContainerRemoveOptions{Force: true}).Return(nil) api.EXPECT().ContainerRemove(gomock.Any(), "789", moby.ContainerRemoveOptions{Force: true}).Return(nil) - api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).Return([]moby.NetworkResource{{ID: "myProject_default"}}, - nil) - - api.EXPECT().NetworkRemove(gomock.Any(), "myProject_default").Return(nil) + api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{ + Filters: filters.NewArgs(filters.Arg("name", "myProject_default")), + }).Return([]moby.NetworkResource{ + {ID: "abc123", Name: "myProject_default"}, + {ID: "def456", Name: "myProject_default"}, + }, nil) + api.EXPECT().NetworkRemove(gomock.Any(), "abc123").Return(nil) + api.EXPECT().NetworkRemove(gomock.Any(), "def456").Return(nil) err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{}) assert.NilError(t, err) @@ -67,8 +82,11 @@ func TestDown(t *testing.T) { func TestDownRemoveOrphans(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() + api := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = api + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(api).AnyTimes() api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return( []moby.Container{ @@ -78,6 +96,8 @@ func TestDownRemoveOrphans(t *testing.T) { }, nil) api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))). Return(volume.VolumeListOKBody{}, nil) + api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}). + Return([]moby.NetworkResource{{Name: "myProject_default"}}, nil) api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil) api.EXPECT().ContainerStop(gomock.Any(), "789", nil).Return(nil) @@ -87,10 +107,10 @@ func TestDownRemoveOrphans(t *testing.T) { api.EXPECT().ContainerRemove(gomock.Any(), "789", moby.ContainerRemoveOptions{Force: true}).Return(nil) api.EXPECT().ContainerRemove(gomock.Any(), "321", moby.ContainerRemoveOptions{Force: true}).Return(nil) - api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).Return([]moby.NetworkResource{{ID: "myProject_default"}}, - nil) - - api.EXPECT().NetworkRemove(gomock.Any(), "myProject_default").Return(nil) + api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{ + Filters: filters.NewArgs(filters.Arg("name", "myProject_default")), + }).Return([]moby.NetworkResource{{ID: "abc123", Name: "myProject_default"}}, nil) + api.EXPECT().NetworkRemove(gomock.Any(), "abc123").Return(nil) err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{RemoveOrphans: true}) assert.NilError(t, err) @@ -99,8 +119,11 @@ func TestDownRemoveOrphans(t *testing.T) { func TestDownRemoveVolumes(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() + api := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = api + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(api).AnyTimes() api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return( []moby.Container{testContainer("service1", "123", false)}, nil) @@ -108,12 +131,12 @@ func TestDownRemoveVolumes(t *testing.T) { Return(volume.VolumeListOKBody{ Volumes: []*moby.Volume{{Name: "myProject_volume"}}, }, nil) + api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}). + Return(nil, nil) api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil) api.EXPECT().ContainerRemove(gomock.Any(), "123", moby.ContainerRemoveOptions{Force: true, RemoveVolumes: true}).Return(nil) - api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).Return(nil, nil) - api.EXPECT().VolumeRemove(gomock.Any(), "myProject_volume", true).Return(nil) err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{Volumes: true}) diff --git a/pkg/compose/events.go b/pkg/compose/events.go index 4fdd1a30..172e3eec 100644 --- a/pkg/compose/events.go +++ b/pkg/compose/events.go @@ -29,9 +29,10 @@ import ( "github.com/docker/compose/v2/pkg/utils" ) -func (s *composeService) Events(ctx context.Context, project string, options api.EventsOptions) error { - events, errors := s.apiClient.Events(ctx, moby.EventsOptions{ - Filters: filters.NewArgs(projectFilter(project)), +func (s *composeService) Events(ctx context.Context, projectName string, options api.EventsOptions) error { + projectName = strings.ToLower(projectName) + events, errors := s.apiClient().Events(ctx, moby.EventsOptions{ + Filters: filters.NewArgs(projectFilter(projectName)), }) for { select { diff --git a/pkg/compose/exec.go b/pkg/compose/exec.go index b0f06004..6477ca06 100644 --- a/pkg/compose/exec.go +++ b/pkg/compose/exec.go @@ -18,149 +18,44 @@ package compose import ( "context" - "fmt" - "io" - - "github.com/docker/cli/cli/streams" - moby "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/pkg/stdcopy" - "github.com/moby/term" + "strings" + "github.com/docker/cli/cli" + "github.com/docker/cli/cli/command/container" "github.com/docker/compose/v2/pkg/api" + moby "github.com/docker/docker/api/types" ) -func (s *composeService) Exec(ctx context.Context, project string, opts api.RunOptions) (int, error) { - container, err := s.getExecTarget(ctx, project, opts) +func (s *composeService) Exec(ctx context.Context, projectName string, options api.RunOptions) (int, error) { + projectName = strings.ToLower(projectName) + target, err := s.getExecTarget(ctx, projectName, options) if err != nil { return 0, err } - exec, err := s.apiClient.ContainerExecCreate(ctx, container.ID, moby.ExecConfig{ - Cmd: opts.Command, - Env: opts.Environment, - User: opts.User, - Privileged: opts.Privileged, - Tty: opts.Tty, - Detach: opts.Detach, - WorkingDir: opts.WorkingDir, - - AttachStdin: true, - AttachStdout: true, - AttachStderr: true, - }) - if err != nil { - return 0, err - } - - if opts.Detach { - return 0, s.apiClient.ContainerExecStart(ctx, exec.ID, moby.ExecStartCheck{ - Detach: true, - Tty: opts.Tty, - }) - } - - resp, err := s.apiClient.ContainerExecAttach(ctx, exec.ID, moby.ExecStartCheck{ - Tty: opts.Tty, - }) - if err != nil { - return 0, err - } - defer resp.Close() //nolint:errcheck - - if opts.Tty { - s.monitorTTySize(ctx, exec.ID, s.apiClient.ContainerExecResize) + exec := container.NewExecOptions() + exec.Interactive = options.Interactive + exec.TTY = options.Tty + exec.Detach = options.Detach + exec.User = options.User + exec.Privileged = options.Privileged + exec.Workdir = options.WorkingDir + exec.Container = target.ID + exec.Command = options.Command + for _, v := range options.Environment { + err := exec.Env.Set(v) if err != nil { return 0, err } } - err = s.interactiveExec(ctx, opts, resp) - if err != nil { - return 0, err - } - - return s.getExecExitStatus(ctx, exec.ID) -} - -// inspired by https://github.com/docker/cli/blob/master/cli/command/container/exec.go#L116 -func (s *composeService) interactiveExec(ctx context.Context, opts api.RunOptions, resp moby.HijackedResponse) error { - outputDone := make(chan error) - inputDone := make(chan error) - - stdout := ContainerStdout{HijackedResponse: resp} - stdin := ContainerStdin{HijackedResponse: resp} - r, err := s.getEscapeKeyProxy(opts.Stdin, opts.Tty) - if err != nil { - return err - } - - in := streams.NewIn(opts.Stdin) - if in.IsTerminal() && opts.Tty { - state, err := term.SetRawTerminal(in.FD()) - if err != nil { - return err - } - defer term.RestoreTerminal(in.FD(), state) //nolint:errcheck - } - - go func() { - if opts.Tty { - _, err := io.Copy(opts.Stdout, stdout) - outputDone <- err - } else { - _, err := stdcopy.StdCopy(opts.Stdout, opts.Stderr, stdout) - outputDone <- err - } - stdout.Close() //nolint:errcheck - }() - - go func() { - _, err := io.Copy(stdin, r) - inputDone <- err - stdin.Close() //nolint:errcheck - }() - - for { - select { - case err := <-outputDone: - return err - case err := <-inputDone: - if _, ok := err.(term.EscapeError); ok { - return nil - } - if err != nil { - return err - } - // Wait for output to complete streaming - case <-ctx.Done(): - return ctx.Err() - } + err = container.RunExec(s.dockerCli, exec) + if sterr, ok := err.(cli.StatusError); ok { + return sterr.StatusCode, nil } + return 0, err } func (s *composeService) getExecTarget(ctx context.Context, projectName string, opts api.RunOptions) (moby.Container, error) { - containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ - Filters: filters.NewArgs( - projectFilter(projectName), - serviceFilter(opts.Service), - containerNumberFilter(opts.Index), - ), - }) - if err != nil { - return moby.Container{}, err - } - if len(containers) < 1 { - return moby.Container{}, fmt.Errorf("service %q is not running container #%d", opts.Service, opts.Index) - } - container := containers[0] - return container, nil -} - -func (s *composeService) getExecExitStatus(ctx context.Context, execID string) (int, error) { - resp, err := s.apiClient.ContainerExecInspect(ctx, execID) - if err != nil { - return 0, err - } - return resp.ExitCode, nil + return s.getSpecifiedContainer(ctx, projectName, oneOffInclude, false, opts.Service, opts.Index) } diff --git a/pkg/compose/images.go b/pkg/compose/images.go index 180bfb86..7c25b20d 100644 --- a/pkg/compose/images.go +++ b/pkg/compose/images.go @@ -32,7 +32,8 @@ import ( ) func (s *composeService) Images(ctx context.Context, projectName string, options api.ImagesOptions) ([]api.ImageSummary, error) { - allContainers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + projectName = strings.ToLower(projectName) + allContainers, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{ All: true, Filters: filters.NewArgs(projectFilter(projectName)), }) @@ -83,7 +84,7 @@ func (s *composeService) getImages(ctx context.Context, images []string) (map[st for _, img := range images { img := img eg.Go(func() error { - inspect, _, err := s.apiClient.ImageInspectWithRaw(ctx, img) + inspect, _, err := s.apiClient().ImageInspectWithRaw(ctx, img) if err != nil { if errdefs.IsNotFound(err) { return nil @@ -93,7 +94,6 @@ func (s *composeService) getImages(ctx context.Context, images []string) (map[st tag := "" repository := "" if len(inspect.RepoTags) > 0 { - repotag := strings.Split(inspect.RepoTags[0], ":") repository = repotag[0] if len(repotag) > 1 { diff --git a/pkg/compose/kill.go b/pkg/compose/kill.go index 9bef116d..aa057bc8 100644 --- a/pkg/compose/kill.go +++ b/pkg/compose/kill.go @@ -18,8 +18,9 @@ package compose import ( "context" + "fmt" + "strings" - "github.com/compose-spec/compose-go/types" moby "github.com/docker/docker/api/types" "golang.org/x/sync/errgroup" @@ -27,34 +28,34 @@ import ( "github.com/docker/compose/v2/pkg/progress" ) -func (s *composeService) Kill(ctx context.Context, project *types.Project, options api.KillOptions) error { +func (s *composeService) Kill(ctx context.Context, projectName string, options api.KillOptions) error { return progress.Run(ctx, func(ctx context.Context) error { - return s.kill(ctx, project, options) + return s.kill(ctx, strings.ToLower(projectName), options) }) } -func (s *composeService) kill(ctx context.Context, project *types.Project, options api.KillOptions) error { +func (s *composeService) kill(ctx context.Context, projectName string, options api.KillOptions) error { w := progress.ContextWriter(ctx) services := options.Services - if len(services) == 0 { - services = project.ServiceNames() - } var containers Containers - containers, err := s.getContainers(ctx, project.Name, oneOffInclude, false, services...) + containers, err := s.getContainers(ctx, projectName, oneOffInclude, false, services...) if err != nil { return err } + if len(containers) == 0 { + fmt.Fprintf(s.stderr(), "no container to kill") + } + eg, ctx := errgroup.WithContext(ctx) containers. - filter(isService(project.ServiceNames()...)). forEach(func(container moby.Container) { eg.Go(func() error { eventName := getContainerProgressName(container) w.Event(progress.KillingEvent(eventName)) - err := s.apiClient.ContainerKill(ctx, container.ID, options.Signal) + err := s.apiClient().ContainerKill(ctx, container.ID, options.Signal) if err != nil { w.Event(progress.ErrorMessageEvent(eventName, "Error while Killing")) return err diff --git a/pkg/compose/kill_test.go b/pkg/compose/kill_test.go index 91cc7184..9680afe3 100644 --- a/pkg/compose/kill_test.go +++ b/pkg/compose/kill_test.go @@ -22,7 +22,6 @@ import ( "strings" "testing" - "github.com/compose-spec/compose-go/types" moby "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/golang/mock/gomock" @@ -39,21 +38,24 @@ var tested = composeService{} func TestKillAll(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - api := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = api - project := types.Project{Name: strings.ToLower(testProject), Services: []types.ServiceConfig{testService("service1"), testService("service2")}} + api := mocks.NewMockAPIClient(mockCtrl) + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(api).AnyTimes() + + name := strings.ToLower(testProject) ctx := context.Background() api.EXPECT().ContainerList(ctx, moby.ContainerListOptions{ - Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject))), + Filters: filters.NewArgs(projectFilter(name)), }).Return( []moby.Container{testContainer("service1", "123", false), testContainer("service1", "456", false), testContainer("service2", "789", false)}, nil) api.EXPECT().ContainerKill(anyCancellableContext(), "123", "").Return(nil) api.EXPECT().ContainerKill(anyCancellableContext(), "456", "").Return(nil) api.EXPECT().ContainerKill(anyCancellableContext(), "789", "").Return(nil) - err := tested.kill(ctx, &project, compose.KillOptions{}) + err := tested.kill(ctx, name, compose.KillOptions{}) assert.NilError(t, err) } @@ -61,26 +63,25 @@ func TestKillSignal(t *testing.T) { const serviceName = "service1" mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() - api := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = api - project := types.Project{Name: strings.ToLower(testProject), Services: []types.ServiceConfig{testService(serviceName)}} + api := mocks.NewMockAPIClient(mockCtrl) + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(api).AnyTimes() + + name := strings.ToLower(testProject) listOptions := moby.ContainerListOptions{ - Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)), serviceFilter(serviceName)), + Filters: filters.NewArgs(projectFilter(name), serviceFilter(serviceName)), } ctx := context.Background() api.EXPECT().ContainerList(ctx, listOptions).Return([]moby.Container{testContainer(serviceName, "123", false)}, nil) api.EXPECT().ContainerKill(anyCancellableContext(), "123", "SIGTERM").Return(nil) - err := tested.kill(ctx, &project, compose.KillOptions{Services: []string{serviceName}, Signal: "SIGTERM"}) + err := tested.kill(ctx, name, compose.KillOptions{Services: []string{serviceName}, Signal: "SIGTERM"}) assert.NilError(t, err) } -func testService(name string) types.ServiceConfig { - return types.ServiceConfig{Name: name} -} - func testContainer(service string, id string, oneOff bool) moby.Container { return moby.Container{ ID: id, diff --git a/pkg/compose/logs.go b/pkg/compose/logs.go index 15aef3ec..7f252074 100644 --- a/pkg/compose/logs.go +++ b/pkg/compose/logs.go @@ -19,6 +19,7 @@ package compose import ( "context" "io" + "strings" "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/utils" @@ -28,6 +29,7 @@ import ( ) func (s *composeService) Logs(ctx context.Context, projectName string, consumer api.LogConsumer, options api.LogOptions) error { + projectName = strings.ToLower(projectName) containers, err := s.getContainers(ctx, projectName, oneOffExclude, true, options.Services...) if err != nil { return err @@ -75,13 +77,13 @@ func (s *composeService) Logs(ctx context.Context, projectName string, consumer } func (s *composeService) logContainers(ctx context.Context, consumer api.LogConsumer, c types.Container, options api.LogOptions) error { - cnt, err := s.apiClient.ContainerInspect(ctx, c.ID) + cnt, err := s.apiClient().ContainerInspect(ctx, c.ID) if err != nil { return err } service := c.Labels[api.ServiceLabel] - r, err := s.apiClient.ContainerLogs(ctx, cnt.ID, types.ContainerLogsOptions{ + r, err := s.apiClient().ContainerLogs(ctx, cnt.ID, types.ContainerLogsOptions{ ShowStdout: true, ShowStderr: true, Follow: options.Follow, diff --git a/pkg/compose/ls.go b/pkg/compose/ls.go index 272edf34..942827ef 100644 --- a/pkg/compose/ls.go +++ b/pkg/compose/ls.go @@ -30,7 +30,7 @@ import ( ) func (s *composeService) List(ctx context.Context, opts api.ListOptions) ([]api.Stack, error) { - list, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ + list, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs(hasProjectLabelFilter()), All: opts.All, }) diff --git a/pkg/compose/pause.go b/pkg/compose/pause.go index ac94760e..3ea593ee 100644 --- a/pkg/compose/pause.go +++ b/pkg/compose/pause.go @@ -18,6 +18,7 @@ package compose import ( "context" + "strings" moby "github.com/docker/docker/api/types" "golang.org/x/sync/errgroup" @@ -26,9 +27,9 @@ import ( "github.com/docker/compose/v2/pkg/progress" ) -func (s *composeService) Pause(ctx context.Context, project string, options api.PauseOptions) error { +func (s *composeService) Pause(ctx context.Context, projectName string, options api.PauseOptions) error { return progress.Run(ctx, func(ctx context.Context) error { - return s.pause(ctx, project, options) + return s.pause(ctx, strings.ToLower(projectName), options) }) } @@ -42,7 +43,7 @@ func (s *composeService) pause(ctx context.Context, project string, options api. eg, ctx := errgroup.WithContext(ctx) containers.forEach(func(container moby.Container) { eg.Go(func() error { - err := s.apiClient.ContainerPause(ctx, container.ID) + err := s.apiClient().ContainerPause(ctx, container.ID) if err == nil { eventName := getContainerProgressName(container) w.Event(progress.NewEvent(eventName, progress.Done, "Paused")) @@ -54,14 +55,14 @@ func (s *composeService) pause(ctx context.Context, project string, options api. return eg.Wait() } -func (s *composeService) UnPause(ctx context.Context, project string, options api.PauseOptions) error { +func (s *composeService) UnPause(ctx context.Context, projectName string, options api.PauseOptions) error { return progress.Run(ctx, func(ctx context.Context) error { - return s.unPause(ctx, project, options) + return s.unPause(ctx, strings.ToLower(projectName), options) }) } -func (s *composeService) unPause(ctx context.Context, project string, options api.PauseOptions) error { - containers, err := s.getContainers(ctx, project, oneOffExclude, false, options.Services...) +func (s *composeService) unPause(ctx context.Context, projectName string, options api.PauseOptions) error { + containers, err := s.getContainers(ctx, projectName, oneOffExclude, false, options.Services...) if err != nil { return err } @@ -70,7 +71,7 @@ func (s *composeService) unPause(ctx context.Context, project string, options ap eg, ctx := errgroup.WithContext(ctx) containers.forEach(func(container moby.Container) { eg.Go(func() error { - err = s.apiClient.ContainerUnpause(ctx, container.ID) + err = s.apiClient().ContainerUnpause(ctx, container.ID) if err == nil { eventName := getContainerProgressName(container) w.Event(progress.NewEvent(eventName, progress.Done, "Unpaused")) diff --git a/pkg/compose/port.go b/pkg/compose/port.go index 2b4b3b69..c41781d0 100644 --- a/pkg/compose/port.go +++ b/pkg/compose/port.go @@ -19,6 +19,7 @@ package compose import ( "context" "fmt" + "strings" "github.com/docker/compose/v2/pkg/api" @@ -26,10 +27,11 @@ import ( "github.com/docker/docker/api/types/filters" ) -func (s *composeService) Port(ctx context.Context, project string, service string, port int, options api.PortOptions) (string, int, error) { - list, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ +func (s *composeService) Port(ctx context.Context, projectName string, service string, port int, options api.PortOptions) (string, int, error) { + projectName = strings.ToLower(projectName) + list, err := s.apiClient().ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs( - projectFilter(project), + projectFilter(projectName), serviceFilter(service), containerNumberFilter(options.Index), ), diff --git a/pkg/compose/ps.go b/pkg/compose/ps.go index e1a76cbb..de4b25f2 100644 --- a/pkg/compose/ps.go +++ b/pkg/compose/ps.go @@ -19,6 +19,7 @@ package compose import ( "context" "sort" + "strings" "golang.org/x/sync/errgroup" @@ -26,6 +27,7 @@ import ( ) func (s *composeService) Ps(ctx context.Context, projectName string, options api.PsOptions) ([]api.ContainerSummary, error) { + projectName = strings.ToLower(projectName) oneOff := oneOffExclude if options.All { oneOff = oneOffInclude @@ -53,7 +55,7 @@ func (s *composeService) Ps(ctx context.Context, projectName string, options api }) } - inspect, err := s.apiClient.ContainerInspect(ctx, container.ID) + inspect, err := s.apiClient().ContainerInspect(ctx, container.ID) if err != nil { return err } diff --git a/pkg/compose/ps_test.go b/pkg/compose/ps_test.go index 5de34672..2f17616e 100644 --- a/pkg/compose/ps_test.go +++ b/pkg/compose/ps_test.go @@ -34,8 +34,11 @@ import ( func TestPs(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() + api := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = api + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(api).AnyTimes() ctx := context.Background() args := filters.NewArgs(projectFilter(strings.ToLower(testProject))) diff --git a/pkg/compose/pull.go b/pkg/compose/pull.go index 62fddbc4..e244de81 100644 --- a/pkg/compose/pull.go +++ b/pkg/compose/pull.go @@ -37,17 +37,17 @@ import ( "github.com/docker/compose/v2/pkg/progress" ) -func (s *composeService) Pull(ctx context.Context, project *types.Project, opts api.PullOptions) error { - if opts.Quiet { - return s.pull(ctx, project, opts) +func (s *composeService) Pull(ctx context.Context, project *types.Project, options api.PullOptions) error { + if options.Quiet { + return s.pull(ctx, project, options) } return progress.Run(ctx, func(ctx context.Context) error { - return s.pull(ctx, project, opts) + return s.pull(ctx, project, options) }) } func (s *composeService) pull(ctx context.Context, project *types.Project, opts api.PullOptions) error { - info, err := s.apiClient.Info(ctx) + info, err := s.apiClient().Info(ctx) if err != nil { return err } @@ -56,16 +56,16 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts info.IndexServerAddress = registry.IndexServer } - w := progress.ContextWriter(ctx) - eg, ctx := errgroup.WithContext(ctx) - - var mustBuild []string - images, err := s.getLocalImagesDigests(ctx, project) if err != nil { return err } + w := progress.ContextWriter(ctx) + eg, ctx := errgroup.WithContext(ctx) + + var mustBuild []string + imagesBeingPulled := map[string]string{} for _, service := range project.Services { @@ -79,13 +79,23 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts continue } - if _, ok := images[service.Image]; ok { + switch service.PullPolicy { + case types.PullPolicyNever, types.PullPolicyBuild: w.Event(progress.Event{ ID: service.Name, Status: progress.Done, - Text: "Skipped - Image is already present locally", + Text: "Skipped", }) continue + case types.PullPolicyMissing, types.PullPolicyIfNotPresent: + if _, ok := images[service.Image]; ok { + w.Event(progress.Event{ + ID: service.Name, + Status: progress.Done, + Text: "Exists", + }) + continue + } } if s, ok := imagesBeingPulled[service.Image]; ok { @@ -98,8 +108,9 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts } imagesBeingPulled[service.Image] = service.Name + eg.Go(func() error { - err := s.pullServiceImage(ctx, service, info, s.configFile, w, false) + _, err := s.pullServiceImage(ctx, service, info, s.configFile(), w, false) if err != nil { if !opts.IgnoreFailures { if service.Build != nil { @@ -122,7 +133,7 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts return err } -func (s *composeService) pullServiceImage(ctx context.Context, service types.ServiceConfig, info moby.Info, configFile driver.Auth, w progress.Writer, quietPull bool) error { +func (s *composeService) pullServiceImage(ctx context.Context, service types.ServiceConfig, info moby.Info, configFile driver.Auth, w progress.Writer, quietPull bool) (string, error) { w.Event(progress.Event{ ID: service.Name, Status: progress.Working, @@ -130,12 +141,12 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser }) ref, err := reference.ParseNormalizedNamed(service.Image) if err != nil { - return err + return "", err } repoInfo, err := registry.ParseRepositoryInfo(ref) if err != nil { - return err + return "", err } key := repoInfo.Index.Name @@ -145,15 +156,15 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser authConfig, err := configFile.GetAuthConfig(key) if err != nil { - return err + return "", err } buf, err := json.Marshal(authConfig) if err != nil { - return err + return "", err } - stream, err := s.apiClient.ImagePull(ctx, service.Image, moby.ImagePullOptions{ + stream, err := s.apiClient().ImagePull(ctx, service.Image, moby.ImagePullOptions{ RegistryAuth: base64.URLEncoding.EncodeToString(buf), Platform: service.Platform, }) @@ -163,7 +174,7 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser Status: progress.Error, Text: "Error", }) - return WrapCategorisedComposeError(err, PullFailure) + return "", WrapCategorisedComposeError(err, PullFailure) } dec := json.NewDecoder(stream) @@ -173,10 +184,10 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser if err == io.EOF { break } - return WrapCategorisedComposeError(err, PullFailure) + return "", WrapCategorisedComposeError(err, PullFailure) } if jm.Error != nil { - return WrapCategorisedComposeError(errors.New(jm.Error.Message), PullFailure) + return "", WrapCategorisedComposeError(errors.New(jm.Error.Message), PullFailure) } if !quietPull { toPullProgressEvent(service.Name, jm, w) @@ -187,11 +198,16 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser Status: progress.Done, Text: "Pulled", }) - return nil + + inspected, _, err := s.dockerCli.Client().ImageInspectWithRaw(ctx, service.Image) + if err != nil { + return "", err + } + return inspected.ID, nil } func (s *composeService) pullRequiredImages(ctx context.Context, project *types.Project, images map[string]string, quietPull bool) error { - info, err := s.apiClient.Info(ctx) + info, err := s.apiClient().Info(ctx) if err != nil { return err } @@ -224,10 +240,12 @@ func (s *composeService) pullRequiredImages(ctx context.Context, project *types. return progress.Run(ctx, func(ctx context.Context) error { w := progress.ContextWriter(ctx) eg, ctx := errgroup.WithContext(ctx) - for _, service := range needPull { - service := service + pulledImages := make([]string, len(needPull)) + for i, service := range needPull { + i, service := i, service eg.Go(func() error { - err := s.pullServiceImage(ctx, service, info, s.configFile, w, quietPull) + id, err := s.pullServiceImage(ctx, service, info, s.configFile(), w, quietPull) + pulledImages[i] = id if err != nil && service.Build != nil { // image can be built, so we can ignore pull failure return nil @@ -235,7 +253,16 @@ func (s *composeService) pullRequiredImages(ctx context.Context, project *types. return err }) } - return eg.Wait() + for i, service := range needPull { + if pulledImages[i] != "" { + images[service.Image] = pulledImages[i] + } + } + err := eg.Wait() + if err != nil { + return err + } + return err }) } diff --git a/pkg/compose/push.go b/pkg/compose/push.go index 3e7b1513..d76d1371 100644 --- a/pkg/compose/push.go +++ b/pkg/compose/push.go @@ -45,7 +45,7 @@ func (s *composeService) Push(ctx context.Context, project *types.Project, optio func (s *composeService) push(ctx context.Context, project *types.Project, options api.PushOptions) error { eg, ctx := errgroup.WithContext(ctx) - info, err := s.apiClient.Info(ctx) + info, err := s.apiClient().Info(ctx) if err != nil { return err } @@ -65,7 +65,7 @@ func (s *composeService) push(ctx context.Context, project *types.Project, optio } service := service eg.Go(func() error { - err := s.pushServiceImage(ctx, service, info, s.configFile, w) + err := s.pushServiceImage(ctx, service, info, s.configFile(), w) if err != nil { if !options.IgnoreFailures { return err @@ -103,7 +103,7 @@ func (s *composeService) pushServiceImage(ctx context.Context, service types.Ser return err } - stream, err := s.apiClient.ImagePush(ctx, service.Image, moby.ImagePushOptions{ + stream, err := s.apiClient().ImagePush(ctx, service.Image, moby.ImagePushOptions{ RegistryAuth: base64.URLEncoding.EncodeToString(buf), }) if err != nil { diff --git a/pkg/compose/remove.go b/pkg/compose/remove.go index ea30bd97..cc10b71a 100644 --- a/pkg/compose/remove.go +++ b/pkg/compose/remove.go @@ -21,7 +21,6 @@ import ( "fmt" "strings" - "github.com/compose-spec/compose-go/types" "github.com/docker/compose/v2/pkg/api" moby "github.com/docker/docker/api/types" "golang.org/x/sync/errgroup" @@ -30,14 +29,14 @@ import ( "github.com/docker/compose/v2/pkg/prompt" ) -func (s *composeService) Remove(ctx context.Context, project *types.Project, options api.RemoveOptions) error { - services := options.Services - if len(services) == 0 { - services = project.ServiceNames() - } - - containers, err := s.getContainers(ctx, project.Name, oneOffInclude, true, services...) +func (s *composeService) Remove(ctx context.Context, projectName string, options api.RemoveOptions) error { + projectName = strings.ToLower(projectName) + containers, _, err := s.actualState(ctx, projectName, options.Services) if err != nil { + if api.IsNotFoundError(err) { + fmt.Fprintln(s.stderr(), "No stopped containers") + return nil + } return err } @@ -51,7 +50,7 @@ func (s *composeService) Remove(ctx context.Context, project *types.Project, opt }) if len(names) == 0 { - fmt.Println("No stopped containers") + fmt.Fprintln(s.stderr(), "No stopped containers") return nil } msg := fmt.Sprintf("Going to remove %s", strings.Join(names, ", ")) @@ -79,7 +78,7 @@ func (s *composeService) remove(ctx context.Context, containers Containers, opti eg.Go(func() error { eventName := getContainerProgressName(container) w.Event(progress.RemovingEvent(eventName)) - err := s.apiClient.ContainerRemove(ctx, container.ID, moby.ContainerRemoveOptions{ + err := s.apiClient().ContainerRemove(ctx, container.ID, moby.ContainerRemoveOptions{ RemoveVolumes: options.Volumes, Force: options.Force, }) diff --git a/pkg/compose/resize.go b/pkg/compose/resize.go deleted file mode 100644 index 0c972381..00000000 --- a/pkg/compose/resize.go +++ /dev/null @@ -1,74 +0,0 @@ -/* - Copyright 2020 Docker Compose CLI authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package compose - -import ( - "context" - "os" - gosignal "os/signal" - "runtime" - "time" - - "github.com/buger/goterm" - moby "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/signal" -) - -func (s *composeService) monitorTTySize(ctx context.Context, container string, resize func(context.Context, string, moby.ResizeOptions) error) { - err := resize(ctx, container, moby.ResizeOptions{ // nolint:errcheck - Height: uint(goterm.Height()), - Width: uint(goterm.Width()), - }) - if err != nil { - return - } - - sigchan := make(chan os.Signal, 1) - gosignal.Notify(sigchan, signal.SIGWINCH) - - if runtime.GOOS == "windows" { - // Windows has no SIGWINCH support, so we have to poll tty size ¯\_(ツ)_/¯ - go func() { - prevH := goterm.Height() - prevW := goterm.Width() - for { - time.Sleep(time.Millisecond * 250) - h := goterm.Height() - w := goterm.Width() - if prevW != w || prevH != h { - sigchan <- signal.SIGWINCH - } - prevH = h - prevW = w - } - }() - } - - go func() { - for { - select { - case <-sigchan: - resize(ctx, container, moby.ResizeOptions{ // nolint:errcheck - Height: uint(goterm.Height()), - Width: uint(goterm.Width()), - }) - case <-ctx.Done(): - return - } - } - }() -} diff --git a/pkg/compose/restart.go b/pkg/compose/restart.go index 306b4d41..87d236cc 100644 --- a/pkg/compose/restart.go +++ b/pkg/compose/restart.go @@ -18,6 +18,7 @@ package compose import ( "context" + "strings" "github.com/docker/compose/v2/pkg/api" "golang.org/x/sync/errgroup" @@ -28,13 +29,13 @@ import ( func (s *composeService) Restart(ctx context.Context, projectName string, options api.RestartOptions) error { return progress.Run(ctx, func(ctx context.Context) error { - return s.restart(ctx, projectName, options) + return s.restart(ctx, strings.ToLower(projectName), options) }) } func (s *composeService) restart(ctx context.Context, projectName string, options api.RestartOptions) error { - observedState, err := s.getContainers(ctx, projectName, oneOffInclude, true) + observedState, err := s.getContainers(ctx, projectName, oneOffExclude, true) if err != nil { return err } @@ -59,7 +60,7 @@ func (s *composeService) restart(ctx context.Context, projectName string, option eg.Go(func() error { eventName := getContainerProgressName(container) w.Event(progress.RestartingEvent(eventName)) - err := s.apiClient.ContainerRestart(ctx, container.ID, options.Timeout) + err := s.apiClient().ContainerRestart(ctx, container.ID, options.Timeout) if err == nil { w.Event(progress.StartedEvent(eventName)) } diff --git a/pkg/compose/run.go b/pkg/compose/run.go index ac088831..7b1295ab 100644 --- a/pkg/compose/run.go +++ b/pkg/compose/run.go @@ -19,17 +19,12 @@ package compose import ( "context" "fmt" - "io" "github.com/compose-spec/compose-go/types" - "github.com/docker/cli/cli/streams" + "github.com/docker/cli/cli" + cmd "github.com/docker/cli/cli/command/container" "github.com/docker/compose/v2/pkg/api" - moby "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/pkg/ioutils" - "github.com/docker/docker/pkg/stdcopy" "github.com/docker/docker/pkg/stringid" - "github.com/moby/term" ) func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts api.RunOptions) (int, error) { @@ -38,98 +33,16 @@ func (s *composeService) RunOneOffContainer(ctx context.Context, project *types. return 0, err } - if opts.Detach { - err := s.apiClient.ContainerStart(ctx, containerID, moby.ContainerStartOptions{}) - if err != nil { - return 0, err - } - fmt.Fprintln(opts.Stdout, containerID) - return 0, nil + start := cmd.NewStartOptions() + start.OpenStdin = !opts.Detach && opts.Interactive + start.Attach = !opts.Detach + start.Containers = []string{containerID} + + err = cmd.RunStart(s.dockerCli, &start) + if sterr, ok := err.(cli.StatusError); ok { + return sterr.StatusCode, nil } - - return s.runInteractive(ctx, containerID, opts) -} - -func (s *composeService) runInteractive(ctx context.Context, containerID string, opts api.RunOptions) (int, error) { - r, err := s.getEscapeKeyProxy(opts.Stdin, opts.Tty) - if err != nil { - return 0, err - } - - stdin, stdout, err := s.getContainerStreams(ctx, containerID) - if err != nil { - return 0, err - } - - in := streams.NewIn(opts.Stdin) - if in.IsTerminal() && opts.Tty { - state, err := term.SetRawTerminal(in.FD()) - if err != nil { - return 0, err - } - defer term.RestoreTerminal(in.FD(), state) //nolint:errcheck - } - - outputDone := make(chan error) - inputDone := make(chan error) - - go func() { - if opts.Tty { - _, err := io.Copy(opts.Stdout, stdout) //nolint:errcheck - outputDone <- err - } else { - _, err := stdcopy.StdCopy(opts.Stdout, opts.Stderr, stdout) //nolint:errcheck - outputDone <- err - } - stdout.Close() //nolint:errcheck - }() - - go func() { - _, err := io.Copy(stdin, r) - inputDone <- err - stdin.Close() //nolint:errcheck - }() - - err = s.apiClient.ContainerStart(ctx, containerID, moby.ContainerStartOptions{}) - if err != nil { - return 0, err - } - - s.monitorTTySize(ctx, containerID, s.apiClient.ContainerResize) - - for { - select { - case err := <-outputDone: - if err != nil { - return 0, err - } - return s.terminateRun(ctx, containerID, opts) - case err := <-inputDone: - if _, ok := err.(term.EscapeError); ok { - return 0, nil - } - if err != nil { - return 0, err - } - // Wait for output to complete streaming - case <-ctx.Done(): - return 0, ctx.Err() - } - } -} - -func (s *composeService) terminateRun(ctx context.Context, containerID string, opts api.RunOptions) (exitCode int, err error) { - exitCh, errCh := s.apiClient.ContainerWait(ctx, containerID, container.WaitConditionNotRunning) - select { - case exit := <-exitCh: - exitCode = int(exit.StatusCode) - case err = <-errCh: - return - } - if opts.AutoRemove { - err = s.apiClient.ContainerRemove(ctx, containerID, moby.ContainerRemoveOptions{}) - } - return + return 0, err } func (s *composeService) prepareRun(ctx context.Context, project *types.Project, opts api.RunOptions) (string, error) { @@ -143,12 +56,15 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project, applyRunOptions(project, &service, opts) + if err := s.dockerCli.In().CheckTty(opts.Interactive, service.Tty); err != nil { + return "", err + } + slug := stringid.GenerateRandomID() if service.ContainerName == "" { service.ContainerName = fmt.Sprintf("%s_%s_run_%s", project.Name, service.Name, stringid.TruncateID(slug)) } service.Scale = 1 - service.StdinOpen = true service.Restart = "" if service.Deploy != nil { service.Deploy.RestartPolicy = nil @@ -172,32 +88,17 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project, } updateServices(&service, observedState) - created, err := s.createContainer(ctx, project, service, service.ContainerName, 1, opts.Detach && opts.AutoRemove, opts.UseNetworkAliases, true) + created, err := s.createContainer(ctx, project, service, service.ContainerName, 1, + opts.AutoRemove, opts.UseNetworkAliases, opts.Interactive) if err != nil { return "", err } - containerID := created.ID - return containerID, nil -} - -func (s *composeService) getEscapeKeyProxy(r io.ReadCloser, isTty bool) (io.ReadCloser, error) { - if !isTty { - return r, nil - } - var escapeKeys = []byte{16, 17} - if s.configFile.DetachKeys != "" { - customEscapeKeys, err := term.ToBytes(s.configFile.DetachKeys) - if err != nil { - return nil, err - } - escapeKeys = customEscapeKeys - } - return ioutils.NewReadCloserWrapper(term.NewEscapeProxy(r, escapeKeys), r.Close), nil + return created.ID, nil } func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts api.RunOptions) { service.Tty = opts.Tty - service.StdinOpen = true + service.StdinOpen = opts.Interactive service.ContainerName = opts.Name if len(opts.Command) > 0 { @@ -215,6 +116,9 @@ func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts if len(opts.Environment) > 0 { env := types.NewMappingWithEquals(opts.Environment) projectEnv := env.Resolve(func(s string) (string, bool) { + if _, ok := service.Environment[s]; ok { + return "", false + } v, ok := project.Environment[s] return v, ok }).RemoveEmpty() diff --git a/pkg/compose/secrets.go b/pkg/compose/secrets.go new file mode 100644 index 00000000..a7114cbb --- /dev/null +++ b/pkg/compose/secrets.go @@ -0,0 +1,88 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package compose + +import ( + "archive/tar" + "bytes" + "context" + "fmt" + "time" + + "github.com/compose-spec/compose-go/types" + moby "github.com/docker/docker/api/types" +) + +func (s *composeService) injectSecrets(ctx context.Context, project *types.Project, service types.ServiceConfig, id string) error { + for _, config := range service.Secrets { + secret := project.Secrets[config.Source] + if secret.Environment == "" { + continue + } + + env, ok := project.Environment[secret.Environment] + if !ok { + return fmt.Errorf("environment variable %q required by secret %q is not set", secret.Environment, secret.Name) + } + b, err := createTar(env, config) + if err != nil { + return err + } + + err = s.apiClient().CopyToContainer(ctx, id, "/", &b, moby.CopyToContainerOptions{ + CopyUIDGID: true, + }) + if err != nil { + return err + } + } + return nil +} + +func createTar(env string, config types.ServiceSecretConfig) (bytes.Buffer, error) { + value := []byte(env) + b := bytes.Buffer{} + tarWriter := tar.NewWriter(&b) + mode := uint32(0400) + if config.Mode != nil { + mode = *config.Mode + } + + target := config.Target + if config.Target == "" { + target = "/run/secrets/" + config.Source + } else if !isUnixAbs(config.Target) { + target = "/run/secrets/" + config.Target + } + + header := &tar.Header{ + Name: target, + Size: int64(len(value)), + Mode: int64(mode), + ModTime: time.Now(), + } + err := tarWriter.WriteHeader(header) + if err != nil { + return bytes.Buffer{}, err + } + _, err = tarWriter.Write(value) + if err != nil { + return bytes.Buffer{}, err + } + err = tarWriter.Close() + return b, err +} diff --git a/pkg/compose/start.go b/pkg/compose/start.go index dca5358e..d1af0637 100644 --- a/pkg/compose/start.go +++ b/pkg/compose/start.go @@ -18,6 +18,7 @@ package compose import ( "context" + "strings" "github.com/compose-spec/compose-go/types" moby "github.com/docker/docker/api/types" @@ -30,20 +31,23 @@ import ( func (s *composeService) Start(ctx context.Context, projectName string, options api.StartOptions) error { return progress.Run(ctx, func(ctx context.Context) error { - return s.start(ctx, projectName, options, nil) + return s.start(ctx, strings.ToLower(projectName), options, nil) }) } func (s *composeService) start(ctx context.Context, projectName string, options api.StartOptions, listener api.ContainerEventListener) error { - var containers Containers - containers, err := s.getContainers(ctx, projectName, oneOffExclude, true) - if err != nil { - return err - } + project := options.Project + if project == nil { + var containers Containers + containers, err := s.getContainers(ctx, projectName, oneOffExclude, true) + if err != nil { + return err + } - project, err := s.projectFromName(containers, projectName, options.AttachTo...) - if err != nil { - return err + project, err = s.projectFromName(containers, projectName, options.AttachTo...) + if err != nil { + return err + } } eg, ctx := errgroup.WithContext(ctx) @@ -55,12 +59,12 @@ func (s *composeService) start(ctx context.Context, projectName string, options eg.Go(func() error { return s.watchContainers(context.Background(), project.Name, options.AttachTo, listener, attached, func(container moby.Container) error { - return s.attachContainer(ctx, container, listener, project) + return s.attachContainer(ctx, container, listener) }) }) } - err = InDependencyOrder(ctx, project, func(c context.Context, name string) error { + err := InDependencyOrder(ctx, project, func(c context.Context, name string) error { service, err := project.GetService(name) if err != nil { return err @@ -76,7 +80,7 @@ func (s *composeService) start(ctx context.Context, projectName string, options depends := types.DependsOnConfig{} for _, s := range project.Services { depends[s.Name] = types.ServiceDependency{ - Condition: ServiceConditionRunningOrHealthy, + Condition: getDependencyCondition(s, project), } } err = s.waitDependencies(ctx, project, depends) @@ -88,6 +92,20 @@ func (s *composeService) start(ctx context.Context, projectName string, options return eg.Wait() } +// getDependencyCondition checks if service is depended on by other services +// with service_completed_successfully condition, and applies that condition +// instead, or --wait will never finish waiting for one-shot containers +func getDependencyCondition(service types.ServiceConfig, project *types.Project) string { + for _, services := range project.Services { + for dependencyService, dependencyConfig := range services.DependsOn { + if dependencyService == service.Name && dependencyConfig.Condition == types.ServiceConditionCompletedSuccessfully { + return types.ServiceConditionCompletedSuccessfully + } + } + } + return ServiceConditionRunningOrHealthy +} + type containerWatchFn func(container moby.Container) error // watchContainers uses engine events to capture container start/die and notify ContainerEventListener @@ -107,7 +125,7 @@ func (s *composeService) watchContainers(ctx context.Context, projectName string return nil } - inspected, err := s.apiClient.ContainerInspect(ctx, event.Container) + inspected, err := s.apiClient().ContainerInspect(ctx, event.Container) if err != nil { return err } diff --git a/pkg/compose/stop.go b/pkg/compose/stop.go index 9f394378..d17e01a9 100644 --- a/pkg/compose/stop.go +++ b/pkg/compose/stop.go @@ -18,6 +18,7 @@ package compose import ( "context" + "strings" "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/progress" @@ -25,30 +26,20 @@ import ( func (s *composeService) Stop(ctx context.Context, projectName string, options api.StopOptions) error { return progress.Run(ctx, func(ctx context.Context) error { - return s.stop(ctx, projectName, options) + return s.stop(ctx, strings.ToLower(projectName), options) }) } func (s *composeService) stop(ctx context.Context, projectName string, options api.StopOptions) error { w := progress.ContextWriter(ctx) - services := options.Services - if len(services) == 0 { - services = []string{} - } - - var containers Containers - containers, err := s.getContainers(ctx, projectName, oneOffInclude, true, services...) - if err != nil { - return err - } - - project, err := s.projectFromName(containers, projectName, services...) + containers, project, err := s.actualState(ctx, projectName, options.Services) if err != nil { return err } return InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error { - return s.stopContainers(ctx, w, containers.filter(isService(service)), options.Timeout) + containersToStop := containers.filter(isService(service)).filter(isNotOneOff) + return s.stopContainers(ctx, w, containersToStop, options.Timeout) }) } diff --git a/pkg/compose/stop_test.go b/pkg/compose/stop_test.go index 29cecbd3..e5848780 100644 --- a/pkg/compose/stop_test.go +++ b/pkg/compose/stop_test.go @@ -33,8 +33,11 @@ import ( func TestStopTimeout(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() + api := mocks.NewMockAPIClient(mockCtrl) - tested.apiClient = api + cli := mocks.NewMockCli(mockCtrl) + tested.dockerCli = cli + cli.EXPECT().Client().Return(api).AnyTimes() ctx := context.Background() api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return( diff --git a/pkg/compose/top.go b/pkg/compose/top.go index dc28e3b3..1ac4cd4c 100644 --- a/pkg/compose/top.go +++ b/pkg/compose/top.go @@ -18,12 +18,14 @@ package compose import ( "context" + "strings" "github.com/docker/compose/v2/pkg/api" "golang.org/x/sync/errgroup" ) func (s *composeService) Top(ctx context.Context, projectName string, services []string) ([]api.ContainerProcSummary, error) { + projectName = strings.ToLower(projectName) var containers Containers containers, err := s.getContainers(ctx, projectName, oneOffInclude, false) if err != nil { @@ -37,7 +39,7 @@ func (s *composeService) Top(ctx context.Context, projectName string, services [ for i, container := range containers { i, container := i, container eg.Go(func() error { - topContent, err := s.apiClient.ContainerTop(ctx, container.ID, []string{}) + topContent, err := s.apiClient().ContainerTop(ctx, container.ID, []string{}) if err != nil { return err } diff --git a/pkg/compose/up.go b/pkg/compose/up.go index 3ee07f1c..a20591b1 100644 --- a/pkg/compose/up.go +++ b/pkg/compose/up.go @@ -60,13 +60,13 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options return progress.Run(ctx, func(ctx context.Context) error { go func() { <-signalChan - s.Kill(ctx, project, api.KillOptions{ // nolint:errcheck - Services: options.Create.Services, + s.Kill(ctx, project.Name, api.KillOptions{ // nolint:errcheck + Services: project.ServiceNames(), }) }() return s.Stop(ctx, project.Name, api.StopOptions{ - Services: options.Create.Services, + Services: project.ServiceNames(), }) }) } diff --git a/pkg/e2e/build_test.go b/pkg/e2e/build_test.go new file mode 100644 index 00000000..c7ea531b --- /dev/null +++ b/pkg/e2e/build_test.go @@ -0,0 +1,240 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "net/http" + "strings" + "testing" + "time" + + "gotest.tools/v3/assert" + "gotest.tools/v3/icmd" +) + +func TestLocalComposeBuild(t *testing.T) { + c := NewParallelCLI(t) + + t.Run("build named and unnamed images", func(t *testing.T) { + // ensure local test run does not reuse previously build image + c.RunDockerOrExitError(t, "rmi", "build-test_nginx") + c.RunDockerOrExitError(t, "rmi", "custom-nginx") + + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "build") + + res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) + c.RunDockerCmd(t, "image", "inspect", "build-test_nginx") + c.RunDockerCmd(t, "image", "inspect", "custom-nginx") + }) + + t.Run("build with build-arg", func(t *testing.T) { + // ensure local test run does not reuse previously build image + c.RunDockerOrExitError(t, "rmi", "build-test_nginx") + c.RunDockerOrExitError(t, "rmi", "custom-nginx") + + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "build", "--build-arg", "FOO=BAR") + + res := c.RunDockerCmd(t, "image", "inspect", "build-test_nginx") + res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`}) + }) + + t.Run("build with build-arg set by env", func(t *testing.T) { + // ensure local test run does not reuse previously build image + c.RunDockerOrExitError(t, "rmi", "build-test_nginx") + c.RunDockerOrExitError(t, "rmi", "custom-nginx") + + icmd.RunCmd(c.NewDockerComposeCmd(t, + "--project-directory", + "fixtures/build-test", + "build", + "--build-arg", + "FOO"), + func(cmd *icmd.Cmd) { + cmd.Env = append(cmd.Env, "FOO=BAR") + }) + + res := c.RunDockerCmd(t, "image", "inspect", "build-test_nginx") + res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`}) + }) + + t.Run("build with multiple build-args ", func(t *testing.T) { + // ensure local test run does not reuse previously build image + c.RunDockerOrExitError(t, "rmi", "-f", "multi-args_multiargs") + cmd := c.NewDockerComposeCmd(t, "--project-directory", "fixtures/build-test/multi-args", "build") + + icmd.RunCmd(cmd, func(cmd *icmd.Cmd) { + cmd.Env = append(cmd.Env, "DOCKER_BUILDKIT=0") + }) + + res := c.RunDockerCmd(t, "image", "inspect", "multi-args_multiargs") + res.Assert(t, icmd.Expected{Out: `"RESULT": "SUCCESS"`}) + }) + + t.Run("build failed with ssh default value", func(t *testing.T) { + res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test", "build", "--ssh", "") + res.Assert(t, icmd.Expected{ + ExitCode: 1, + Err: "invalid empty ssh agent socket: make sure SSH_AUTH_SOCK is set", + }) + + }) + + t.Run("build succeed with ssh from Compose file", func(t *testing.T) { + c.RunDockerOrExitError(t, "rmi", "build-test-ssh") + + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test/ssh", "build") + c.RunDockerCmd(t, "image", "inspect", "build-test-ssh") + }) + + t.Run("build succeed with ssh from CLI", func(t *testing.T) { + c.RunDockerOrExitError(t, "rmi", "build-test-ssh") + + c.RunDockerComposeCmd(t, "-f", "fixtures/build-test/ssh/compose-without-ssh.yaml", "--project-directory", + "fixtures/build-test/ssh", "build", "--no-cache", "--ssh", "fake-ssh=./fixtures/build-test/ssh/fake_rsa") + c.RunDockerCmd(t, "image", "inspect", "build-test-ssh") + }) + + t.Run("build failed with wrong ssh key id from CLI", func(t *testing.T) { + c.RunDockerOrExitError(t, "rmi", "build-test-ssh") + + res := c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/build-test/ssh/compose-without-ssh.yaml", + "--project-directory", "fixtures/build-test/ssh", "build", "--no-cache", "--ssh", + "wrong-ssh=./fixtures/build-test/ssh/fake_rsa") + res.Assert(t, icmd.Expected{ + ExitCode: 17, + Err: "failed to solve: rpc error: code = Unknown desc = unset ssh forward key fake-ssh", + }) + }) + + t.Run("build succeed as part of up with ssh from Compose file", func(t *testing.T) { + c.RunDockerOrExitError(t, "rmi", "build-test-ssh") + + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test/ssh", "up", "-d", "--build") + t.Cleanup(func() { + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test/ssh", "down") + }) + c.RunDockerCmd(t, "image", "inspect", "build-test-ssh") + }) + + t.Run("build as part of up", func(t *testing.T) { + c.RunDockerOrExitError(t, "rmi", "build-test_nginx") + c.RunDockerOrExitError(t, "rmi", "custom-nginx") + + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d") + t.Cleanup(func() { + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down") + }) + + res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) + res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"}) + + output := HTTPGetWithRetry(t, "http://localhost:8070", http.StatusOK, 2*time.Second, 20*time.Second) + assert.Assert(t, strings.Contains(output, "Hello from Nginx container")) + + c.RunDockerCmd(t, "image", "inspect", "build-test_nginx") + c.RunDockerCmd(t, "image", "inspect", "custom-nginx") + }) + + t.Run("no rebuild when up again", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d") + + assert.Assert(t, !strings.Contains(res.Stdout(), "COPY static"), res.Stdout()) + }) + + t.Run("rebuild when up --build", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--workdir", "fixtures/build-test", "up", "-d", "--build") + + res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) + res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"}) + }) + + t.Run("cleanup build project", func(t *testing.T) { + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down") + c.RunDockerCmd(t, "rmi", "build-test_nginx") + c.RunDockerCmd(t, "rmi", "custom-nginx") + }) +} + +func TestBuildSecrets(t *testing.T) { + c := NewParallelCLI(t) + + t.Run("build with secrets", func(t *testing.T) { + // ensure local test run does not reuse previously build image + c.RunDockerOrExitError(t, "rmi", "build-test-secret") + + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test/secrets", "build") + res.Assert(t, icmd.Success) + }) +} + +func TestBuildTags(t *testing.T) { + c := NewParallelCLI(t) + + t.Run("build with tags", func(t *testing.T) { + + // ensure local test run does not reuse previously build image + c.RunDockerOrExitError(t, "rmi", "build-test-tags") + + c.RunDockerComposeCmd(t, "--project-directory", "./fixtures/build-test/tags", "build", "--no-cache") + + res := c.RunDockerCmd(t, "image", "inspect", "build-test-tags") + expectedOutput := `"RepoTags": [ + "docker/build-test-tags:1.0.0", + "build-test-tags:latest", + "other-image-name:v1.0.0" + ], +` + res.Assert(t, icmd.Expected{Out: expectedOutput}) + }) +} + +func TestBuildImageDependencies(t *testing.T) { + doTest := func(t *testing.T, cli *CLI) { + resetState := func() { + cli.RunDockerComposeCmd(t, "down", "--rmi=all", "-t=0") + } + resetState() + t.Cleanup(resetState) + + // the image should NOT exist now + res := cli.RunDockerOrExitError(t, "image", "inspect", "build-dependencies_service") + res.Assert(t, icmd.Expected{ + ExitCode: 1, + Err: "Error: No such image: build-dependencies_service", + }) + + res = cli.RunDockerComposeCmd(t, "build") + t.Log(res.Combined()) + + res = cli.RunDockerCmd(t, + "image", "inspect", "--format={{ index .RepoTags 0 }}", + "build-dependencies_service") + res.Assert(t, icmd.Expected{Out: "build-dependencies_service:latest"}) + } + + t.Run("ClassicBuilder", func(t *testing.T) { + cli := NewParallelCLI(t, WithEnv( + "DOCKER_BUILDKIT=0", + "COMPOSE_FILE=./fixtures/build-dependencies/compose.yaml", + )) + doTest(t, cli) + }) + + t.Run("BuildKit", func(t *testing.T) { + t.Skip("See https://github.com/docker/compose/issues/9232") + }) +} diff --git a/pkg/e2e/cancel_test.go b/pkg/e2e/cancel_test.go index 4696024d..d64305a3 100644 --- a/pkg/e2e/cancel_test.go +++ b/pkg/e2e/cancel_test.go @@ -33,30 +33,34 @@ import ( ) func TestComposeCancel(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) t.Run("metrics on cancel Compose build", func(t *testing.T) { - c.RunDockerComposeCmd("ls") + c.RunDockerComposeCmd(t, "ls") buildProjectPath := "fixtures/build-infinite/compose.yaml" // require a separate groupID from the process running tests, in order to simulate ctrl+C from a terminal. // sending kill signal - cmd, stdout, stderr, err := StartWithNewGroupID(c.NewDockerCmd("compose", "-f", buildProjectPath, "build", "--progress", "plain")) + cmd, stdout, stderr, err := StartWithNewGroupID(c.NewDockerComposeCmd(t, "-f", buildProjectPath, "build", + "--progress", "plain")) assert.NilError(t, err) - c.WaitForCondition(func() (bool, string) { + c.WaitForCondition(t, func() (bool, string) { out := stdout.String() errors := stderr.String() - return strings.Contains(out, "RUN sleep infinity"), fmt.Sprintf("'RUN sleep infinity' not found in : \n%s\nStderr: \n%s\n", out, errors) + return strings.Contains(out, + "RUN sleep infinity"), fmt.Sprintf("'RUN sleep infinity' not found in : \n%s\nStderr: \n%s\n", out, + errors) }, 30*time.Second, 1*time.Second) err = syscall.Kill(-cmd.Process.Pid, syscall.SIGINT) // simulate Ctrl-C : send signal to processGroup, children will have same groupId by default assert.NilError(t, err) - c.WaitForCondition(func() (bool, string) { + c.WaitForCondition(t, func() (bool, string) { out := stdout.String() errors := stderr.String() - return strings.Contains(out, "CANCELED"), fmt.Sprintf("'CANCELED' not found in : \n%s\nStderr: \n%s\n", out, errors) + return strings.Contains(out, "CANCELED"), fmt.Sprintf("'CANCELED' not found in : \n%s\nStderr: \n%s\n", out, + errors) }, 10*time.Second, 1*time.Second) }) } diff --git a/pkg/e2e/cascade_stop_test.go b/pkg/e2e/cascade_stop_test.go index e949fb4c..d5ca0845 100644 --- a/pkg/e2e/cascade_stop_test.go +++ b/pkg/e2e/cascade_stop_test.go @@ -23,28 +23,28 @@ import ( ) func TestCascadeStop(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) const projectName = "e2e-cascade-stop" t.Run("abort-on-container-exit", func(t *testing.T) { - res := c.RunDockerOrExitError("compose", "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--abort-on-container-exit") + res := c.RunDockerComposeCmdNoCheck(t, "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--abort-on-container-exit") res.Assert(t, icmd.Expected{ExitCode: 1, Out: `should_fail-1 exited with code 1`}) res.Assert(t, icmd.Expected{ExitCode: 1, Out: `Aborting on container exit...`}) }) t.Run("exit-code-from", func(t *testing.T) { - res := c.RunDockerOrExitError("compose", "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--exit-code-from=sleep") + res := c.RunDockerComposeCmdNoCheck(t, "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--exit-code-from=sleep") res.Assert(t, icmd.Expected{ExitCode: 137, Out: `should_fail-1 exited with code 1`}) res.Assert(t, icmd.Expected{ExitCode: 137, Out: `Aborting on container exit...`}) }) t.Run("exit-code-from unknown", func(t *testing.T) { - res := c.RunDockerOrExitError("compose", "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--exit-code-from=unknown") + res := c.RunDockerComposeCmdNoCheck(t, "-f", "./fixtures/cascade-stop-test/compose.yaml", "--project-name", projectName, "up", "--exit-code-from=unknown") res.Assert(t, icmd.Expected{ExitCode: 1, Err: `no such service: unknown`}) }) t.Run("down", func(t *testing.T) { - _ = c.RunDockerComposeCmd("--project-name", projectName, "down") + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) } diff --git a/pkg/e2e/compose_build_test.go b/pkg/e2e/compose_build_test.go deleted file mode 100644 index 71965395..00000000 --- a/pkg/e2e/compose_build_test.go +++ /dev/null @@ -1,119 +0,0 @@ -/* - Copyright 2020 Docker Compose CLI authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package e2e - -import ( - "net/http" - "strings" - "testing" - "time" - - "gotest.tools/v3/assert" - "gotest.tools/v3/icmd" -) - -func TestLocalComposeBuild(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) - - t.Run("build named and unnamed images", func(t *testing.T) { - // ensure local test run does not reuse previously build image - c.RunDockerOrExitError("rmi", "build-test_nginx") - c.RunDockerOrExitError("rmi", "custom-nginx") - - res := c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "build") - - res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) - c.RunDockerCmd("image", "inspect", "build-test_nginx") - c.RunDockerCmd("image", "inspect", "custom-nginx") - }) - - t.Run("build with build-arg", func(t *testing.T) { - // ensure local test run does not reuse previously build image - c.RunDockerOrExitError("rmi", "build-test_nginx") - c.RunDockerOrExitError("rmi", "custom-nginx") - - c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "build", "--build-arg", "FOO=BAR") - - res := c.RunDockerCmd("image", "inspect", "build-test_nginx") - res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`}) - }) - - t.Run("build with build-arg set by env", func(t *testing.T) { - // ensure local test run does not reuse previously build image - c.RunDockerOrExitError("rmi", "build-test_nginx") - c.RunDockerOrExitError("rmi", "custom-nginx") - - icmd.RunCmd(c.NewDockerCmd("compose", "--project-directory", "fixtures/build-test", "build", "--build-arg", "FOO"), - func(cmd *icmd.Cmd) { - cmd.Env = append(cmd.Env, "FOO=BAR") - }) - - res := c.RunDockerCmd("image", "inspect", "build-test_nginx") - res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`}) - }) - - t.Run("build with multiple build-args ", func(t *testing.T) { - // ensure local test run does not reuse previously build image - c.RunDockerOrExitError("rmi", "-f", "multi-args_multiargs") - cmd := c.NewDockerCmd("compose", "--project-directory", "fixtures/build-test/multi-args", "build") - - icmd.RunCmd(cmd, func(cmd *icmd.Cmd) { - cmd.Env = append(cmd.Env, "DOCKER_BUILDKIT=0") - }) - - res := c.RunDockerCmd("image", "inspect", "multi-args_multiargs") - res.Assert(t, icmd.Expected{Out: `"RESULT": "SUCCESS"`}) - }) - - t.Run("build as part of up", func(t *testing.T) { - c.RunDockerOrExitError("rmi", "build-test_nginx") - c.RunDockerOrExitError("rmi", "custom-nginx") - - res := c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "up", "-d") - t.Cleanup(func() { - c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "down") - }) - - res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) - res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"}) - - output := HTTPGetWithRetry(t, "http://localhost:8070", http.StatusOK, 2*time.Second, 20*time.Second) - assert.Assert(t, strings.Contains(output, "Hello from Nginx container")) - - c.RunDockerCmd("image", "inspect", "build-test_nginx") - c.RunDockerCmd("image", "inspect", "custom-nginx") - }) - - t.Run("no rebuild when up again", func(t *testing.T) { - res := c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "up", "-d") - - assert.Assert(t, !strings.Contains(res.Stdout(), "COPY static"), res.Stdout()) - }) - - t.Run("rebuild when up --build", func(t *testing.T) { - res := c.RunDockerComposeCmd("--workdir", "fixtures/build-test", "up", "-d", "--build") - - res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) - res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"}) - }) - - t.Run("cleanup build project", func(t *testing.T) { - c.RunDockerComposeCmd("--project-directory", "fixtures/build-test", "down") - c.RunDockerCmd("rmi", "build-test_nginx") - c.RunDockerCmd("rmi", "custom-nginx") - }) -} diff --git a/pkg/e2e/compose_down_test.go b/pkg/e2e/compose_down_test.go new file mode 100644 index 00000000..9819b28a --- /dev/null +++ b/pkg/e2e/compose_down_test.go @@ -0,0 +1,34 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "testing" + + "gotest.tools/v3/icmd" +) + +func TestDown(t *testing.T) { + c := NewParallelCLI(t) + + const projectName = "e2e-down" + + t.Run("no resource to remove", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "down") + res.Assert(t, icmd.Expected{ExitCode: 0, Err: `No resource found to remove for project "e2e-down"`}) + }) +} diff --git a/pkg/e2e/compose_environment_test.go b/pkg/e2e/compose_environment_test.go new file mode 100644 index 00000000..3314617c --- /dev/null +++ b/pkg/e2e/compose_environment_test.go @@ -0,0 +1,163 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "strings" + "testing" + + "gotest.tools/v3/assert" + "gotest.tools/v3/icmd" +) + +func TestEnvPriority(t *testing.T) { + c := NewParallelCLI(t) + + projectDir := "./fixtures/environment/env-priority" + + t.Run("up", func(t *testing.T) { + c.RunDockerOrExitError(t, "rmi", "env-compose-priority") + c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml", + "--project-directory", projectDir, "up", "-d", "--build") + }) + + // Full options activated + // 1. Compose file <-- Result expected + // 2. Shell environment variables + // 3. Environment file + // 4. Dockerfile + // 5. Variable is not defined + t.Run("compose file priority", func(t *testing.T) { + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml", + "--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", + "--rm", "-e", "WHEREAMI", "env-compose-priority") + cmd.Env = append(cmd.Env, "WHEREAMI=shell") + res := icmd.RunCmd(cmd) + assert.Equal(t, strings.TrimSpace(res.Stdout()), "Compose File") + }) + + // No Compose file, all other options + // 1. Compose file + // 2. Shell environment variables <-- Result expected + // 3. Environment file + // 4. Dockerfile + // 5. Variable is not defined + t.Run("shell priority", func(t *testing.T) { + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", + projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e", + "WHEREAMI", "env-compose-priority") + cmd.Env = append(cmd.Env, "WHEREAMI=shell") + res := icmd.RunCmd(cmd) + assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell") + }) + + // No Compose file and env variable pass to the run command + // 1. Compose file + // 2. Shell environment variables <-- Result expected + // 3. Environment file + // 4. Dockerfile + // 5. Variable is not defined + t.Run("shell priority from run command", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", + projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e", + "WHEREAMI=shell-run", "env-compose-priority") + assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell-run") + }) + + // No Compose file & no env variable but override env file + // 1. Compose file + // 2. Shell environment variables + // 3. Environment file <-- Result expected + // 4. Dockerfile + // 5. Variable is not defined + t.Run("override env file", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", + projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e", + "WHEREAMI", "env-compose-priority") + assert.Equal(t, strings.TrimSpace(res.Stdout()), "override") + }) + + // No Compose file & no env variable but override env file + // 1. Compose file + // 2. Shell environment variables + // 3. Environment file <-- Result expected + // 4. Dockerfile + // 5. Variable is not defined + t.Run("env file", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", + projectDir, "run", "--rm", "-e", "WHEREAMI", "env-compose-priority") + assert.Equal(t, strings.TrimSpace(res.Stdout()), "Env File") + }) + + // No Compose file & no env variable, using an empty override env file + // 1. Compose file + // 2. Shell environment variables + // 3. Environment file + // 4. Dockerfile <-- Result expected + // 5. Variable is not defined + t.Run("use Dockerfile", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", + projectDir, "--env-file", "./fixtures/environment/env-priority/.env.empty", "run", "--rm", "-e", "WHEREAMI", + "env-compose-priority") + assert.Equal(t, strings.TrimSpace(res.Stdout()), "Dockerfile") + }) + + t.Run("down", func(t *testing.T) { + c.RunDockerComposeCmd(t, "--project-directory", projectDir, "down") + }) +} + +func TestEnvInterpolation(t *testing.T) { + c := NewParallelCLI(t) + + projectDir := "./fixtures/environment/env-interpolation" + + // No variable defined in the Compose file and env variable pass to the run command + // 1. Compose file + // 2. Shell environment variables <-- Result expected + // 3. Environment file + // 4. Dockerfile + // 5. Variable is not defined + t.Run("shell priority from run command", func(t *testing.T) { + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-interpolation/compose.yaml", + "--project-directory", projectDir, "config") + cmd.Env = append(cmd.Env, "WHEREAMI=shell") + res := icmd.RunCmd(cmd) + res.Assert(t, icmd.Expected{Out: `IMAGE: default_env:shell`}) + }) +} + +func TestCommentsInEnvFile(t *testing.T) { + c := NewParallelCLI(t) + + projectDir := "./fixtures/environment/env-file-comments" + + t.Run("comments in env files", func(t *testing.T) { + c.RunDockerOrExitError(t, "rmi", "env-file-comments") + + c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-file-comments/compose.yaml", "--project-directory", + projectDir, "up", "-d", "--build") + + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-file-comments/compose.yaml", + "--project-directory", projectDir, "run", "--rm", "-e", "COMMENT", "-e", "NO_COMMENT", "env-file-comments") + + res.Assert(t, icmd.Expected{Out: `COMMENT=1234`}) + res.Assert(t, icmd.Expected{Out: `NO_COMMENT=1234#5`}) + + c.RunDockerComposeCmd(t, "--project-directory", projectDir, "down", "--rmi", "all") + }) +} diff --git a/pkg/e2e/compose_exec_test.go b/pkg/e2e/compose_exec_test.go index 0a574456..26885f28 100644 --- a/pkg/e2e/compose_exec_test.go +++ b/pkg/e2e/compose_exec_test.go @@ -25,24 +25,29 @@ import ( ) func TestLocalComposeExec(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) const projectName = "compose-e2e-exec" - c.RunDockerComposeCmd("--project-directory", "fixtures/simple-composefile", "--project-name", projectName, "up", "-d") + cmdArgs := func(cmd string, args ...string) []string { + ret := []string{"--project-directory", "fixtures/simple-composefile", "--project-name", projectName, cmd} + ret = append(ret, args...) + return ret + } + + c.RunDockerComposeCmd(t, cmdArgs("up", "-d")...) t.Run("exec true", func(t *testing.T) { - res := c.RunDockerOrExitError("exec", "compose-e2e-exec-simple-1", "/bin/true") - res.Assert(t, icmd.Expected{ExitCode: 0}) + c.RunDockerComposeCmd(t, cmdArgs("exec", "simple", "/bin/true")...) }) t.Run("exec false", func(t *testing.T) { - res := c.RunDockerOrExitError("exec", "compose-e2e-exec-simple-1", "/bin/false") + res := c.RunDockerComposeCmdNoCheck(t, cmdArgs("exec", "simple", "/bin/false")...) res.Assert(t, icmd.Expected{ExitCode: 1}) }) t.Run("exec with env set", func(t *testing.T) { - res := icmd.RunCmd(c.NewDockerCmd("exec", "-e", "FOO", "compose-e2e-exec-simple-1", "/usr/bin/env"), + res := icmd.RunCmd(c.NewDockerComposeCmd(t, cmdArgs("exec", "-e", "FOO", "simple", "/usr/bin/env")...), func(cmd *icmd.Cmd) { cmd.Env = append(cmd.Env, "FOO=BAR") }) @@ -50,8 +55,7 @@ func TestLocalComposeExec(t *testing.T) { }) t.Run("exec without env set", func(t *testing.T) { - res := c.RunDockerOrExitError("exec", "-e", "FOO", "compose-e2e-exec-simple-1", "/usr/bin/env") - res.Assert(t, icmd.Expected{ExitCode: 0}) - assert.Check(t, !strings.Contains(res.Stdout(), "FOO=")) + res := c.RunDockerComposeCmd(t, cmdArgs("exec", "-e", "FOO", "simple", "/usr/bin/env")...) + assert.Check(t, !strings.Contains(res.Stdout(), "FOO="), res.Combined()) }) } diff --git a/pkg/e2e/compose_run_test.go b/pkg/e2e/compose_run_test.go index 9940c298..e1abb581 100644 --- a/pkg/e2e/compose_run_test.go +++ b/pkg/e2e/compose_run_test.go @@ -26,21 +26,22 @@ import ( ) func TestLocalComposeRun(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) t.Run("compose run", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "back") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "back") lines := Lines(res.Stdout()) assert.Equal(t, lines[len(lines)-1], "Hello there!!", res.Stdout()) assert.Assert(t, !strings.Contains(res.Combined(), "orphan")) - res = c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo", "Hello one more time") + res = c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo", + "Hello one more time") lines = Lines(res.Stdout()) assert.Equal(t, lines[len(lines)-1], "Hello one more time", res.Stdout()) assert.Assert(t, !strings.Contains(res.Combined(), "orphan")) }) t.Run("check run container exited", func(t *testing.T) { - res := c.RunDockerCmd("ps", "--all") + res := c.RunDockerCmd(t, "ps", "--all") lines := Lines(res.Stdout()) var runContainerID string var truncatedSlug string @@ -59,7 +60,7 @@ func TestLocalComposeRun(t *testing.T) { } } assert.Assert(t, runContainerID != "") - res = c.RunDockerCmd("inspect", runContainerID) + res = c.RunDockerCmd(t, "inspect", runContainerID) res.Assert(t, icmd.Expected{Out: ` "Status": "exited"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.container-number": "1"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": "run-test"`}) @@ -68,39 +69,70 @@ func TestLocalComposeRun(t *testing.T) { }) t.Run("compose run --rm", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "--rm", "back", "echo", "Hello again") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "--rm", "back", "echo", + "Hello again") lines := Lines(res.Stdout()) assert.Equal(t, lines[len(lines)-1], "Hello again", res.Stdout()) - res = c.RunDockerCmd("ps", "--all") + res = c.RunDockerCmd(t, "ps", "--all") assert.Assert(t, strings.Contains(res.Stdout(), "run-test_back"), res.Stdout()) }) t.Run("down", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "down") - res := c.RunDockerCmd("ps", "--all") + c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "down") + res := c.RunDockerCmd(t, "ps", "--all") assert.Assert(t, !strings.Contains(res.Stdout(), "run-test"), res.Stdout()) }) t.Run("compose run --volumes", func(t *testing.T) { wd, err := os.Getwd() assert.NilError(t, err) - res := c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "--volumes", wd+":/foo", "back", "/bin/sh", "-c", "ls /foo") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "--volumes", wd+":/foo", + "back", "/bin/sh", "-c", "ls /foo") res.Assert(t, icmd.Expected{Out: "compose_run_test.go"}) - res = c.RunDockerCmd("ps", "--all") + res = c.RunDockerCmd(t, "ps", "--all") assert.Assert(t, strings.Contains(res.Stdout(), "run-test_back"), res.Stdout()) }) t.Run("compose run --publish", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "run", "--publish", "8081:80", "-d", "back", "/bin/sh", "-c", "sleep 1") - res := c.RunDockerCmd("ps") + c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "--publish", "8081:80", "-d", "back", + "/bin/sh", "-c", "sleep 1") + res := c.RunDockerCmd(t, "ps") assert.Assert(t, strings.Contains(res.Stdout(), "8081->80/tcp"), res.Stdout()) }) + t.Run("compose run orphan", func(t *testing.T) { + // Use different compose files to get an orphan container + c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/orphan.yaml", "run", "simple") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo", "Hello") + assert.Assert(t, strings.Contains(res.Combined(), "orphan")) + + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "back", "echo", "Hello") + res = icmd.RunCmd(cmd, func(cmd *icmd.Cmd) { + cmd.Env = append(cmd.Env, "COMPOSE_IGNORE_ORPHANS=True") + }) + assert.Assert(t, !strings.Contains(res.Combined(), "orphan")) + }) + t.Run("down", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/run-test/compose.yaml", "down") - res := c.RunDockerCmd("ps", "--all") + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "down") + icmd.RunCmd(cmd, func(c *icmd.Cmd) { + c.Env = append(c.Env, "COMPOSE_REMOVE_ORPHANS=True") + }) + res := c.RunDockerCmd(t, "ps", "--all") assert.Assert(t, !strings.Contains(res.Stdout(), "run-test"), res.Stdout()) }) + + t.Run("run starts only container and dependencies", func(t *testing.T) { + // ensure that even if another service is up run does not start it: https://github.com/docker/compose/issues/9459 + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/deps.yaml", "up", "service_b") + res.Assert(t, icmd.Success) + + res = c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/deps.yaml", "run", "service_a") + assert.Assert(t, strings.Contains(res.Combined(), "shared_dep"), res.Combined()) + assert.Assert(t, !strings.Contains(res.Combined(), "service_b"), res.Combined()) + + c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/deps.yaml", "down", "--remove-orphans") + }) } diff --git a/pkg/e2e/compose_test.go b/pkg/e2e/compose_test.go index 81de2396..7f2b9604 100644 --- a/pkg/e2e/compose_test.go +++ b/pkg/e2e/compose_test.go @@ -18,7 +18,6 @@ package e2e import ( "fmt" - "io/ioutil" "net/http" "os" "path/filepath" @@ -31,31 +30,30 @@ import ( "gotest.tools/v3/icmd" ) -var binDir string - func TestLocalComposeUp(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + // this test shares a fixture with TestCompatibility and can't run at the same time + c := NewCLI(t) const projectName = "compose-e2e-demo" t.Run("up", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/sentences/compose.yaml", "--project-name", projectName, "up", "-d") + c.RunDockerComposeCmd(t, "-f", "./fixtures/sentences/compose.yaml", "--project-name", projectName, "up", "-d") }) t.Run("check accessing running app", func(t *testing.T) { - res := c.RunDockerComposeCmd("-p", projectName, "ps") + res := c.RunDockerComposeCmd(t, "-p", projectName, "ps") res.Assert(t, icmd.Expected{Out: `web`}) endpoint := "http://localhost:90" output := HTTPGetWithRetry(t, endpoint+"/words/noun", http.StatusOK, 2*time.Second, 20*time.Second) assert.Assert(t, strings.Contains(output, `"word":`)) - res = c.RunDockerCmd("network", "ls") + res = c.RunDockerCmd(t, "network", "ls") res.Assert(t, icmd.Expected{Out: projectName + "_default"}) }) t.Run("top", func(t *testing.T) { - res := c.RunDockerComposeCmd("-p", projectName, "top") + res := c.RunDockerComposeCmd(t, "-p", projectName, "top") output := res.Stdout() head := []string{"UID", "PID", "PPID", "C", "STIME", "TTY", "TIME", "CMD"} for _, h := range head { @@ -66,7 +64,7 @@ func TestLocalComposeUp(t *testing.T) { }) t.Run("check compose labels", func(t *testing.T) { - res := c.RunDockerCmd("inspect", projectName+"-web-1") + res := c.RunDockerCmd(t, "inspect", projectName+"-web-1") res.Assert(t, icmd.Expected{Out: `"com.docker.compose.container-number": "1"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": "compose-e2e-demo"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.oneoff": "False",`}) @@ -76,55 +74,55 @@ func TestLocalComposeUp(t *testing.T) { res.Assert(t, icmd.Expected{Out: `"com.docker.compose.service": "web"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.version":`}) - res = c.RunDockerCmd("network", "inspect", projectName+"_default") + res = c.RunDockerCmd(t, "network", "inspect", projectName+"_default") res.Assert(t, icmd.Expected{Out: `"com.docker.compose.network": "default"`}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": `}) res.Assert(t, icmd.Expected{Out: `"com.docker.compose.version": `}) }) t.Run("check user labels", func(t *testing.T) { - res := c.RunDockerCmd("inspect", projectName+"-web-1") + res := c.RunDockerCmd(t, "inspect", projectName+"-web-1") res.Assert(t, icmd.Expected{Out: `"my-label": "test"`}) }) t.Run("check healthcheck output", func(t *testing.T) { - c.WaitForCmdResult(c.NewDockerCmd("compose", "-p", projectName, "ps", "--format", "json"), + c.WaitForCmdResult(t, c.NewDockerComposeCmd(t, "-p", projectName, "ps", "--format", "json"), StdoutContains(`"Name":"compose-e2e-demo-web-1","Command":"/dispatcher","Project":"compose-e2e-demo","Service":"web","State":"running","Health":"healthy"`), 5*time.Second, 1*time.Second) - res := c.RunDockerComposeCmd("-p", projectName, "ps") + res := c.RunDockerComposeCmd(t, "-p", projectName, "ps") res.Assert(t, icmd.Expected{Out: `NAME COMMAND SERVICE STATUS PORTS`}) - res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-web-1 "/dispatcher" web running (healthy) 0.0.0.0:90->80/tcp, :::90->80/tcp`}) + res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-web-1 "/dispatcher" web running (healthy) 0.0.0.0:90->80/tcp`}) res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-db-1 "docker-entrypoint.s…" db running 5432/tcp`}) }) t.Run("images", func(t *testing.T) { - res := c.RunDockerComposeCmd("-p", projectName, "images") + res := c.RunDockerComposeCmd(t, "-p", projectName, "images") res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-db-1 gtardif/sentences-db latest`}) res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-web-1 gtardif/sentences-web latest`}) res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-words-1 gtardif/sentences-api latest`}) }) t.Run("down", func(t *testing.T) { - _ = c.RunDockerComposeCmd("--project-name", projectName, "down") + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) t.Run("check containers after down", func(t *testing.T) { - res := c.RunDockerCmd("ps", "--all") + res := c.RunDockerCmd(t, "ps", "--all") assert.Assert(t, !strings.Contains(res.Combined(), projectName), res.Combined()) }) t.Run("check networks after down", func(t *testing.T) { - res := c.RunDockerCmd("network", "ls") + res := c.RunDockerCmd(t, "network", "ls") assert.Assert(t, !strings.Contains(res.Combined(), projectName), res.Combined()) }) } func TestComposePull(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) - res := c.RunDockerOrExitError("compose", "--project-directory", "fixtures/simple-composefile", "pull") + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/simple-composefile", "pull") output := res.Combined() expected := []string{ @@ -152,97 +150,108 @@ func contains(str string, array []string) bool { } func TestDownComposefileInParentFolder(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) - tmpFolder, err := ioutil.TempDir("fixtures/simple-composefile", "test-tmp") + tmpFolder, err := os.MkdirTemp("fixtures/simple-composefile", "test-tmp") assert.NilError(t, err) defer os.Remove(tmpFolder) // nolint: errcheck projectName := filepath.Base(tmpFolder) - res := c.RunDockerComposeCmd("--project-directory", tmpFolder, "up", "-d") + res := c.RunDockerComposeCmd(t, "--project-directory", tmpFolder, "up", "-d") res.Assert(t, icmd.Expected{Err: "Started", ExitCode: 0}) - res = c.RunDockerComposeCmd("-p", projectName, "down") + res = c.RunDockerComposeCmd(t, "-p", projectName, "down") res.Assert(t, icmd.Expected{Err: "Removed", ExitCode: 0}) } func TestAttachRestart(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) - cmd := c.NewDockerCmd("compose", "--ansi=never", "--project-directory", "./fixtures/attach-restart", "up") + cmd := c.NewDockerComposeCmd(t, "--ansi=never", "--project-directory", "./fixtures/attach-restart", "up") res := icmd.StartCmd(cmd) - defer c.RunDockerOrExitError("compose", "-p", "attach-restart", "down") + defer c.RunDockerComposeCmd(t, "-p", "attach-restart", "down") - c.WaitForCondition(func() (bool, string) { + c.WaitForCondition(t, func() (bool, string) { debug := res.Combined() - return strings.Count(res.Stdout(), "failing-1 exited with code 1") == 3, fmt.Sprintf("'failing-1 exited with code 1' not found 3 times in : \n%s\n", debug) + return strings.Count(res.Stdout(), + "failing-1 exited with code 1") == 3, fmt.Sprintf("'failing-1 exited with code 1' not found 3 times in : \n%s\n", + debug) }, 2*time.Minute, 2*time.Second) assert.Equal(t, strings.Count(res.Stdout(), "failing-1 | world"), 3, res.Combined()) } func TestInitContainer(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) - res := c.RunDockerOrExitError("compose", "--ansi=never", "--project-directory", "./fixtures/init-container", "up") - defer c.RunDockerOrExitError("compose", "-p", "init-container", "down") + res := c.RunDockerComposeCmd(t, "--ansi=never", "--project-directory", "./fixtures/init-container", "up") + defer c.RunDockerComposeCmd(t, "-p", "init-container", "down") testify.Regexp(t, "foo-1 | hello(?m:.*)bar-1 | world", res.Stdout()) } func TestRm(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) const projectName = "compose-e2e-rm" t.Run("up", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "up", "-d") + c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "up", "-d") }) t.Run("rm -sf", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "rm", "-sf", "simple") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "rm", + "-sf", "simple") res.Assert(t, icmd.Expected{Err: "Removed", ExitCode: 0}) }) t.Run("check containers after rm -sf", func(t *testing.T) { - res := c.RunDockerCmd("ps", "--all") + res := c.RunDockerCmd(t, "ps", "--all") assert.Assert(t, !strings.Contains(res.Combined(), projectName+"_simple"), res.Combined()) }) + t.Run("rm -sf ", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-composefile/compose.yaml", "-p", projectName, "rm", + "-sf", "simple") + res.Assert(t, icmd.Expected{ExitCode: 0}) + }) + t.Run("down", func(t *testing.T) { - c.RunDockerComposeCmd("-p", projectName, "down") + c.RunDockerComposeCmd(t, "-p", projectName, "down") }) } func TestCompatibility(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + // this test shares a fixture with TestLocalComposeUp and can't run at the same time + c := NewCLI(t) const projectName = "compose-e2e-compatibility" t.Run("up", func(t *testing.T) { - c.RunDockerComposeCmd("--compatibility", "-f", "./fixtures/sentences/compose.yaml", "--project-name", projectName, "up", "-d") + c.RunDockerComposeCmd(t, "--compatibility", "-f", "./fixtures/sentences/compose.yaml", "--project-name", + projectName, "up", "-d") }) t.Run("check container names", func(t *testing.T) { - res := c.RunDockerCmd("ps", "--format", "{{.Names}}") + res := c.RunDockerCmd(t, "ps", "--format", "{{.Names}}") res.Assert(t, icmd.Expected{Out: "compose-e2e-compatibility_web_1"}) res.Assert(t, icmd.Expected{Out: "compose-e2e-compatibility_words_1"}) res.Assert(t, icmd.Expected{Out: "compose-e2e-compatibility_db_1"}) }) t.Run("down", func(t *testing.T) { - c.RunDockerComposeCmd("-p", projectName, "down") + c.RunDockerComposeCmd(t, "-p", projectName, "down") }) } func TestConvert(t *testing.T) { const projectName = "compose-e2e-convert" - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) wd, err := os.Getwd() assert.NilError(t, err) t.Run("up", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/simple-build-test/compose.yaml", "-p", projectName, "convert") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/simple-build-test/compose.yaml", "-p", projectName, "convert") res.Assert(t, icmd.Expected{Out: fmt.Sprintf(`services: nginx: build: diff --git a/pkg/e2e/compose_up_test.go b/pkg/e2e/compose_up_test.go new file mode 100644 index 00000000..f96e7f0b --- /dev/null +++ b/pkg/e2e/compose_up_test.go @@ -0,0 +1,47 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "strings" + "testing" + "time" + + "gotest.tools/v3/assert" +) + +func TestUpWait(t *testing.T) { + c := NewParallelCLI(t) + const projectName = "e2e-deps-wait" + + timeout := time.After(30 * time.Second) + done := make(chan bool) + go func() { + res := c.RunDockerComposeCmd(t, "-f", "fixtures/dependencies/deps-completed-successfully.yaml", "--project-name", projectName, "up", "--wait", "-d") + assert.Assert(t, strings.Contains(res.Combined(), "e2e-deps-wait-oneshot-1"), res.Combined()) + done <- true + }() + + select { + case <-timeout: + t.Fatal("test did not finish in time") + case <-done: + break + } + + c.RunDockerComposeCmd(t, "--project-name", projectName, "down") +} diff --git a/pkg/e2e/cp_test.go b/pkg/e2e/cp_test.go index 661e5bee..ab187e7e 100644 --- a/pkg/e2e/cp_test.go +++ b/pkg/e2e/cp_test.go @@ -26,12 +26,12 @@ import ( ) func TestCopy(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) const projectName = "copy_e2e" t.Cleanup(func() { - c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "--project-name", projectName, "down") + c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "--project-name", projectName, "down") os.Remove("./fixtures/cp-test/from-default.txt") //nolint:errcheck os.Remove("./fixtures/cp-test/from-indexed.txt") //nolint:errcheck @@ -39,52 +39,45 @@ func TestCopy(t *testing.T) { }) t.Run("start service", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "--project-name", projectName, "up", "--scale", "nginx=5", "-d") + c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "--project-name", projectName, "up", + "--scale", "nginx=5", "-d") }) t.Run("make sure service is running", func(t *testing.T) { - res := c.RunDockerComposeCmd("-p", projectName, "ps") + res := c.RunDockerComposeCmd(t, "-p", projectName, "ps") res.Assert(t, icmd.Expected{Out: `nginx running`}) }) - t.Run("copy to container copies the file to the first container by default", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/default.txt") + t.Run("copy to container copies the file to the all containers by default", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", + "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/default.txt") res.Assert(t, icmd.Expected{ExitCode: 0}) - output := c.RunDockerCmd("exec", projectName+"-nginx-1", "cat", "/tmp/default.txt").Stdout() + output := c.RunDockerCmd(t, "exec", projectName+"-nginx-1", "cat", "/tmp/default.txt").Stdout() assert.Assert(t, strings.Contains(output, `hello world`), output) - res = c.RunDockerOrExitError("exec", projectName+"_nginx_2", "cat", "/tmp/default.txt") - res.Assert(t, icmd.Expected{ExitCode: 1}) + output = c.RunDockerCmd(t, "exec", projectName+"-nginx-2", "cat", "/tmp/default.txt").Stdout() + assert.Assert(t, strings.Contains(output, `hello world`), output) + + output = c.RunDockerCmd(t, "exec", projectName+"-nginx-3", "cat", "/tmp/default.txt").Stdout() + assert.Assert(t, strings.Contains(output, `hello world`), output) }) t.Run("copy to container with a given index copies the file to the given container", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "--index=3", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/indexed.txt") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "--index=3", + "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/indexed.txt") res.Assert(t, icmd.Expected{ExitCode: 0}) - output := c.RunDockerCmd("exec", projectName+"-nginx-3", "cat", "/tmp/indexed.txt").Stdout() + output := c.RunDockerCmd(t, "exec", projectName+"-nginx-3", "cat", "/tmp/indexed.txt").Stdout() assert.Assert(t, strings.Contains(output, `hello world`), output) - res = c.RunDockerOrExitError("exec", projectName+"-nginx-2", "cat", "/tmp/indexed.txt") + res = c.RunDockerOrExitError(t, "exec", projectName+"-nginx-2", "cat", "/tmp/indexed.txt") res.Assert(t, icmd.Expected{ExitCode: 1}) }) - t.Run("copy to container with the all flag copies the file to all containers", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "--all", "./fixtures/cp-test/cp-me.txt", "nginx:/tmp/all.txt") - res.Assert(t, icmd.Expected{ExitCode: 0}) - - output := c.RunDockerCmd("exec", projectName+"-nginx-1", "cat", "/tmp/all.txt").Stdout() - assert.Assert(t, strings.Contains(output, `hello world`), output) - - output = c.RunDockerCmd("exec", projectName+"-nginx-2", "cat", "/tmp/all.txt").Stdout() - assert.Assert(t, strings.Contains(output, `hello world`), output) - - output = c.RunDockerCmd("exec", projectName+"-nginx-3", "cat", "/tmp/all.txt").Stdout() - assert.Assert(t, strings.Contains(output, `hello world`), output) - }) - t.Run("copy from a container copies the file to the host from the first container by default", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "nginx:/tmp/default.txt", "./fixtures/cp-test/from-default.txt") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", + "nginx:/tmp/default.txt", "./fixtures/cp-test/from-default.txt") res.Assert(t, icmd.Expected{ExitCode: 0}) data, err := os.ReadFile("./fixtures/cp-test/from-default.txt") @@ -93,7 +86,8 @@ func TestCopy(t *testing.T) { }) t.Run("copy from a container with a given index copies the file to host", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "--index=3", "nginx:/tmp/indexed.txt", "./fixtures/cp-test/from-indexed.txt") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "--index=3", + "nginx:/tmp/indexed.txt", "./fixtures/cp-test/from-indexed.txt") res.Assert(t, icmd.Expected{ExitCode: 0}) data, err := os.ReadFile("./fixtures/cp-test/from-indexed.txt") @@ -102,13 +96,15 @@ func TestCopy(t *testing.T) { }) t.Run("copy to and from a container also work with folder", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "./fixtures/cp-test/cp-folder", "nginx:/tmp") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", + "./fixtures/cp-test/cp-folder", "nginx:/tmp") res.Assert(t, icmd.Expected{ExitCode: 0}) - output := c.RunDockerCmd("exec", projectName+"-nginx-1", "cat", "/tmp/cp-folder/cp-me.txt").Stdout() + output := c.RunDockerCmd(t, "exec", projectName+"-nginx-1", "cat", "/tmp/cp-folder/cp-me.txt").Stdout() assert.Assert(t, strings.Contains(output, `hello world from folder`), output) - res = c.RunDockerComposeCmd("-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", "nginx:/tmp/cp-folder", "./fixtures/cp-test/cp-folder2") + res = c.RunDockerComposeCmd(t, "-f", "./fixtures/cp-test/compose.yaml", "-p", projectName, "cp", + "nginx:/tmp/cp-folder", "./fixtures/cp-test/cp-folder2") res.Assert(t, icmd.Expected{ExitCode: 0}) data, err := os.ReadFile("./fixtures/cp-test/cp-folder2/cp-me.txt") diff --git a/pkg/e2e/ddev_test.go b/pkg/e2e/ddev_test.go new file mode 100644 index 00000000..00b890d1 --- /dev/null +++ b/pkg/e2e/ddev_test.go @@ -0,0 +1,106 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "gotest.tools/v3/assert" +) + +const ddevVersion = "v1.19.1" + +func TestComposeRunDdev(t *testing.T) { + if !composeStandaloneMode { + t.Skip("Not running in plugin mode - ddev only supports invoking standalone `docker-compose`") + } + if runtime.GOOS == "windows" { + t.Skip("Running on Windows. Skipping...") + } + + // ddev shells out to `docker` and `docker-compose` (standalone), so a + // temporary directory is created with symlinks to system Docker and the + // locally-built standalone Compose binary to use as PATH + requiredTools := []string{ + findToolInPath(t, DockerExecutableName), + ComposeStandalonePath(t), + findToolInPath(t, "tar"), + findToolInPath(t, "gzip"), + } + pathDir := t.TempDir() + for _, tool := range requiredTools { + require.NoError(t, os.Symlink(tool, filepath.Join(pathDir, filepath.Base(tool))), + "Could not create symlink for %q", tool) + } + + c := NewCLI(t, WithEnv( + "DDEV_DEBUG=true", + fmt.Sprintf("PATH=%s", pathDir), + )) + + ddevDir := t.TempDir() + siteName := filepath.Base(ddevDir) + + t.Cleanup(func() { + _ = c.RunCmdInDir(t, ddevDir, "./ddev", "delete", "-Oy") + _ = c.RunCmdInDir(t, ddevDir, "./ddev", "poweroff") + }) + + osName := "linux" + if runtime.GOOS == "darwin" { + osName = "macos" + } + + compressedFilename := fmt.Sprintf("ddev_%s-%s.%s.tar.gz", osName, runtime.GOARCH, ddevVersion) + c.RunCmdInDir(t, ddevDir, "curl", "-LO", fmt.Sprintf("https://github.com/drud/ddev/releases/download/%s/%s", + ddevVersion, + compressedFilename)) + + c.RunCmdInDir(t, ddevDir, "tar", "-xzf", compressedFilename) + + // Create a simple index.php we can test against. + c.RunCmdInDir(t, ddevDir, "sh", "-c", "echo 'index.php") + + c.RunCmdInDir(t, ddevDir, "./ddev", "config", "--auto") + c.RunCmdInDir(t, ddevDir, "./ddev", "config", "global", "--use-docker-compose-from-path") + vRes := c.RunCmdInDir(t, ddevDir, "./ddev", "version") + out := vRes.Stdout() + fmt.Printf("ddev version: %s\n", out) + + c.RunCmdInDir(t, ddevDir, "./ddev", "poweroff") + + c.RunCmdInDir(t, ddevDir, "./ddev", "start", "-y") + + curlRes := c.RunCmdInDir(t, ddevDir, "curl", "-sSL", fmt.Sprintf("http://%s.ddev.site", siteName)) + out = curlRes.Stdout() + fmt.Println(out) + assert.Assert(t, strings.Contains(out, "ddev is working"), "Could not start project") +} + +func findToolInPath(t testing.TB, name string) string { + t.Helper() + binPath, err := exec.LookPath(name) + require.NoError(t, err, "Could not find %q in path", name) + return binPath +} diff --git a/pkg/e2e/fixtures/build-dependencies/base.dockerfile b/pkg/e2e/fixtures/build-dependencies/base.dockerfile new file mode 100644 index 00000000..9dce0b74 --- /dev/null +++ b/pkg/e2e/fixtures/build-dependencies/base.dockerfile @@ -0,0 +1,19 @@ +# Copyright 2020 Docker Compose CLI authors + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM alpine + +COPY hello.txt /hello.txt + +CMD [ "/bin/true" ] diff --git a/pkg/e2e/fixtures/build-dependencies/compose.yaml b/pkg/e2e/fixtures/build-dependencies/compose.yaml new file mode 100644 index 00000000..7de1960b --- /dev/null +++ b/pkg/e2e/fixtures/build-dependencies/compose.yaml @@ -0,0 +1,12 @@ +services: + base: + image: base + build: + context: . + dockerfile: base.dockerfile + service: + depends_on: + - base + build: + context: . + dockerfile: service.dockerfile diff --git a/pkg/e2e/fixtures/build-dependencies/hello.txt b/pkg/e2e/fixtures/build-dependencies/hello.txt new file mode 100644 index 00000000..810e7ba6 --- /dev/null +++ b/pkg/e2e/fixtures/build-dependencies/hello.txt @@ -0,0 +1 @@ +this file was copied from base -> service diff --git a/pkg/e2e/fixtures/build-dependencies/service.dockerfile b/pkg/e2e/fixtures/build-dependencies/service.dockerfile new file mode 100644 index 00000000..95abc433 --- /dev/null +++ b/pkg/e2e/fixtures/build-dependencies/service.dockerfile @@ -0,0 +1,19 @@ +# Copyright 2020 Docker Compose CLI authors + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM alpine + +COPY --from=base /hello.txt /hello.txt + +CMD [ "cat", "/hello.txt" ] diff --git a/pkg/e2e/fixtures/build-test/secrets/Dockerfile b/pkg/e2e/fixtures/build-test/secrets/Dockerfile new file mode 100644 index 00000000..ff47d7ba --- /dev/null +++ b/pkg/e2e/fixtures/build-test/secrets/Dockerfile @@ -0,0 +1,22 @@ +# syntax=docker/dockerfile:1.2 + + +# Copyright 2020 Docker Compose CLI authors + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM alpine + +RUN echo "foo" > /tmp/expected +RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret > /tmp/actual +RUN diff /tmp/expected /tmp/actual diff --git a/pkg/e2e/fixtures/build-test/secrets/compose.yml b/pkg/e2e/fixtures/build-test/secrets/compose.yml new file mode 100644 index 00000000..1bb96d31 --- /dev/null +++ b/pkg/e2e/fixtures/build-test/secrets/compose.yml @@ -0,0 +1,11 @@ +services: + ssh: + image: build-test-secret + build: + context: . + secrets: + - mysecret + +secrets: + mysecret: + file: ./secret.txt diff --git a/pkg/e2e/fixtures/build-test/secrets/secret.txt b/pkg/e2e/fixtures/build-test/secrets/secret.txt new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/pkg/e2e/fixtures/build-test/secrets/secret.txt @@ -0,0 +1 @@ +foo diff --git a/pkg/e2e/fixtures/build-test/ssh/Dockerfile b/pkg/e2e/fixtures/build-test/ssh/Dockerfile new file mode 100644 index 00000000..1a1831af --- /dev/null +++ b/pkg/e2e/fixtures/build-test/ssh/Dockerfile @@ -0,0 +1,24 @@ +# syntax=docker/dockerfile:1.2 + + +# Copyright 2020 Docker Compose CLI authors + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM alpine +RUN apk add --no-cache openssh-client + +WORKDIR /compose +COPY fake_rsa.pub /compose/ + +RUN --mount=type=ssh,id=fake-ssh,required=true diff <(ssh-add -L) <(cat /compose/fake_rsa.pub) \ No newline at end of file diff --git a/pkg/e2e/fixtures/build-test/ssh/compose-without-ssh.yaml b/pkg/e2e/fixtures/build-test/ssh/compose-without-ssh.yaml new file mode 100644 index 00000000..cce1bb88 --- /dev/null +++ b/pkg/e2e/fixtures/build-test/ssh/compose-without-ssh.yaml @@ -0,0 +1,5 @@ +services: + ssh: + image: build-test-ssh + build: + context: . diff --git a/pkg/e2e/fixtures/build-test/ssh/compose.yaml b/pkg/e2e/fixtures/build-test/ssh/compose.yaml new file mode 100644 index 00000000..27052a95 --- /dev/null +++ b/pkg/e2e/fixtures/build-test/ssh/compose.yaml @@ -0,0 +1,7 @@ +services: + ssh: + image: build-test-ssh + build: + context: . + ssh: + - fake-ssh=./fixtures/build-test/ssh/fake_rsa diff --git a/pkg/e2e/fixtures/build-test/ssh/fake_rsa b/pkg/e2e/fixtures/build-test/ssh/fake_rsa new file mode 100644 index 00000000..0e797265 --- /dev/null +++ b/pkg/e2e/fixtures/build-test/ssh/fake_rsa @@ -0,0 +1,49 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAgEA7nJ4xAhJ7VwI63tuay3DCHaTXeEY92H6YNZ8ptAIBY0mUn6Gc9ms +94HvcAKemCJkO0fy6U2JOoST+q1YPAJf86NrIU41hZdzrw2QdqG/A3ja4VTAaOJbH9wafK +HpWLs6kyigGti3KSBabm4HARU8lgtRE6AuCC1+mw821FzTsMWMxRp/rKVxgsiMUsdd57WR +KOdn8TRm6NHcEsy7X7zAJ7+Ch/muGGCCk3Z9+YUzoVVtY/wGYmWXXj/NUzxnEq0XLyO8HC ++QU/9dWlh1OLmoMuxN1lYtHRFWWstCboKNsOcIiJsLKfQ1t4z4jXq5P7JTLE5Pngemrr4x +K21RFjVaGQpOjyQgZn1o0wAvy78KORwgN0Elwcb/XIKJepzzezCIyXlSafeXuHP+oMjM2s +2MXNHlMKv6Jwh4QYwUQ61+bAcPkcmIdltiAMNLcxYiqEud85EQQl9ciuhMKa0bZl1OEILw +VSIasEu9BEKVrz52ZZVLGMchqOV/4f1PqPEagnfnRYEttJ6AuaYUaJXvSQP6Zj4AFb6WrP +wEBIFOuAH9i4WtG52QAK6uc1wsPZlHm8J+VnTEBKFuGERu/uJBWPo43Lju8VrHuZU8QeON +ERKfJbc1EI9XpqWi+3VcWT0QJtxEGW2YmD505+cKNc31xwOtcqwogtwT0wnuj0BAf33HY3 +8AAAc465v1nOub9ZwAAAAHc3NoLXJzYQAAAgEA7nJ4xAhJ7VwI63tuay3DCHaTXeEY92H6 +YNZ8ptAIBY0mUn6Gc9ms94HvcAKemCJkO0fy6U2JOoST+q1YPAJf86NrIU41hZdzrw2Qdq +G/A3ja4VTAaOJbH9wafKHpWLs6kyigGti3KSBabm4HARU8lgtRE6AuCC1+mw821FzTsMWM +xRp/rKVxgsiMUsdd57WRKOdn8TRm6NHcEsy7X7zAJ7+Ch/muGGCCk3Z9+YUzoVVtY/wGYm +WXXj/NUzxnEq0XLyO8HC+QU/9dWlh1OLmoMuxN1lYtHRFWWstCboKNsOcIiJsLKfQ1t4z4 +jXq5P7JTLE5Pngemrr4xK21RFjVaGQpOjyQgZn1o0wAvy78KORwgN0Elwcb/XIKJepzzez +CIyXlSafeXuHP+oMjM2s2MXNHlMKv6Jwh4QYwUQ61+bAcPkcmIdltiAMNLcxYiqEud85EQ +Ql9ciuhMKa0bZl1OEILwVSIasEu9BEKVrz52ZZVLGMchqOV/4f1PqPEagnfnRYEttJ6Aua +YUaJXvSQP6Zj4AFb6WrPwEBIFOuAH9i4WtG52QAK6uc1wsPZlHm8J+VnTEBKFuGERu/uJB +WPo43Lju8VrHuZU8QeONERKfJbc1EI9XpqWi+3VcWT0QJtxEGW2YmD505+cKNc31xwOtcq +wogtwT0wnuj0BAf33HY38AAAADAQABAAACAGK7A0YoKHQfp5HZid7XE+ptLpewnKXR69os +9XAcszWZPETsHr/ZYcUaCApZC1Hy642gPPRdJnUUcDFblS1DzncTM0iXGZI3I69X7nkwf+ +bwI7EpZoIHN7P5bv4sDHKxE4/bQm/bS/u7abZP2JaaNHvsM6XsrSK1s7aAljNYPE71fVQf +pL3Xwyhj4bZk1n0asQA+0MsO541/V6BxJSR/AxFyOpoSyANP8sEcTw0CGl6zAJhlwj770b +E0uc+9MvCIuxDJuxnwl9Iv6nd+KQtT1FFBhvk4tXVTuG3fu6IGbKTTBLWLfRPiClv2AvSR +3CKDs+ykgFLu2BWCqtlQakLH1IW9DTkPExV4ZjkGCRWHEvmJxxOqL6B48tBjwa5gBuPJRA +aYRi15Z3sprsqCBfp+aHPkMXkkNGSe5ROj8lFFY/f50ZS/9DSlyuUURFLtIGe5XuPNJk7L +xJkYJAdNbgvk4IPgzsU2EuYvSja5mtuo3dVyEIRtsIAN4xl01edDAxHEow6ar4gZCtXnBb +WqeqchEi4zVTdkkuDP3SF362pktdY7Op0mS/yFd8LFrca3VCy2PqNhKvlxClRqM9Tlp9cY +qDuyS9AGT1QO4BMtvSJGFa3P+h76rQsNldC+nGa4wNWvpAUcT5NS8W9QnGp7ah/qOK07t7 +fwYYENeRaAK3OItBABAAABAFjyDlnERaZ+/23B+zN0kQhCvmiNS5HE2+ooR5ofX08F3Uar +VPevy9p6s2LA+AlXY1ZZ1k0p5MI+4TkAbcB/VXaxrRUw9633p9rAgyumFGhK3i0M4whOCO +MJxmlp5sz5Qea+YzIa9z0F4ZwwvdHt7cp5joYBZoQ+Kv9OUy4xCs1zZ4ZbEsakGBrtLiTo +H3odXSg0mXQf10Ae3WkvAJ8M1xL/z1ryFeCvyv1sGwEx+5gvmZ6nnuJEEuXUBlpOwhPlST +4X9VL7gmdH9OoHnhUn3q2JEBQdVTegGij9wvoYT1bdzwBN/Amisn29K9w1aNdrNbYUJ6PO +0kE2lotSJ11qD8MAAAEBAP6IRuU25yj7zv0mEsaRWoQ5v3fYKKn4C6Eg3DbzKXybZkLyX7 +6QlyO7uWf54SdXM7sQW8KoXaMu9qbo/o+4o3m7YfOY1MYeTz3yICYObVA7Fc9ZHwKzc1PB +dFNzy6/G+2niNQF3Q1Fjp31Ve9LwKJK8Kj/eUYZ3QiUIropkw4ppA8q3h+nkVGS23xSrTM +kGLugBjcnWUfuN0tKx/b5mqziRoyzr5u0qzFDtx97QAyETo/onFrd1bMGED2BHVyrCwtqI +p6SXo2uFzwm/nLtOMlmfpixNcK6dtql/brx3Lsu18a+0a42O5Q/TYRdRq8D60O16rUS/LN +sFOjIYSA3spnUAAAEBAO/Sc3NTarFylk+yhOTE8G9xDt5ndbY0gsfhM9D4byKlY4yYIvs+ +yQAq3UHgSoN2f087zNubXSNiLJ8TOIPpbk8MzdvjqcpmnBhHcd4V2FLe9+hC8zEBf8MPPf +Cy1kXdCZ0bDMLTdgONiDTIc/0YXhFLZherXNIF1o/7Pcnu6IPwMDl/gcG3H1ncDxaLqxAm +L29SDXLX2hH9k+YJr9kFaho7PZBAwNYnMooupROSbQ9/lmfCt09ep/83n5G0mo93uGkyV2 +1wcQw9X2ZT8eVHZ4ni3ACC6VYbUn2M3Z+e3tpGaYzKXd/yq0YyppoRvEaxM/ewXappUJul +Xsd/RqSc66MAAAAAAQID +-----END OPENSSH PRIVATE KEY----- diff --git a/pkg/e2e/fixtures/build-test/ssh/fake_rsa.pub b/pkg/e2e/fixtures/build-test/ssh/fake_rsa.pub new file mode 100644 index 00000000..e43add2b --- /dev/null +++ b/pkg/e2e/fixtures/build-test/ssh/fake_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDucnjECEntXAjre25rLcMIdpNd4Rj3Yfpg1nym0AgFjSZSfoZz2az3ge9wAp6YImQ7R/LpTYk6hJP6rVg8Al/zo2shTjWFl3OvDZB2ob8DeNrhVMBo4lsf3Bp8oelYuzqTKKAa2LcpIFpubgcBFTyWC1EToC4ILX6bDzbUXNOwxYzFGn+spXGCyIxSx13ntZEo52fxNGbo0dwSzLtfvMAnv4KH+a4YYIKTdn35hTOhVW1j/AZiZZdeP81TPGcSrRcvI7wcL5BT/11aWHU4uagy7E3WVi0dEVZay0Jugo2w5wiImwsp9DW3jPiNerk/slMsTk+eB6auvjErbVEWNVoZCk6PJCBmfWjTAC/Lvwo5HCA3QSXBxv9cgol6nPN7MIjJeVJp95e4c/6gyMzazYxc0eUwq/onCHhBjBRDrX5sBw+RyYh2W2IAw0tzFiKoS53zkRBCX1yK6EwprRtmXU4QgvBVIhqwS70EQpWvPnZllUsYxyGo5X/h/U+o8RqCd+dFgS20noC5phRole9JA/pmPgAVvpas/AQEgU64Af2Lha0bnZAArq5zXCw9mUebwn5WdMQEoW4YRG7+4kFY+jjcuO7xWse5lTxB440REp8ltzUQj1empaL7dVxZPRAm3EQZbZiYPnTn5wo1zfXHA61yrCiC3BPTCe6PQEB/fcdjfw== diff --git a/pkg/e2e/fixtures/build-test/tags/Dockerfile b/pkg/e2e/fixtures/build-test/tags/Dockerfile new file mode 100644 index 00000000..09b9df4a --- /dev/null +++ b/pkg/e2e/fixtures/build-test/tags/Dockerfile @@ -0,0 +1,17 @@ +# Copyright 2020 Docker Compose CLI authors + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM nginx:alpine + +RUN echo "SUCCESS" diff --git a/pkg/e2e/fixtures/build-test/tags/compose.yaml b/pkg/e2e/fixtures/build-test/tags/compose.yaml new file mode 100644 index 00000000..de017802 --- /dev/null +++ b/pkg/e2e/fixtures/build-test/tags/compose.yaml @@ -0,0 +1,9 @@ +services: + nginx: + image: build-test-tags + build: + context: . + tags: + - docker.io/docker/build-test-tags:1.0.0 + - other-image-name:v1.0.0 + diff --git a/pkg/e2e/fixtures/dependencies/compose.yaml b/pkg/e2e/fixtures/dependencies/compose.yaml new file mode 100644 index 00000000..82d3e4e8 --- /dev/null +++ b/pkg/e2e/fixtures/dependencies/compose.yaml @@ -0,0 +1,8 @@ +services: + foo: + image: nginx:alpine + depends_on: + - bar + + bar: + image: nginx:alpine diff --git a/pkg/e2e/fixtures/dependencies/deps-completed-successfully.yaml b/pkg/e2e/fixtures/dependencies/deps-completed-successfully.yaml new file mode 100644 index 00000000..5d547ee1 --- /dev/null +++ b/pkg/e2e/fixtures/dependencies/deps-completed-successfully.yaml @@ -0,0 +1,10 @@ +services: + oneshot: + image: alpine + command: echo 'hello world' + longrunning: + image: alpine + depends_on: + oneshot: + condition: service_completed_successfully + command: sleep infinity diff --git a/pkg/e2e/fixtures/env-secret/compose.yaml b/pkg/e2e/fixtures/env-secret/compose.yaml new file mode 100644 index 00000000..159dcac7 --- /dev/null +++ b/pkg/e2e/fixtures/env-secret/compose.yaml @@ -0,0 +1,11 @@ +services: + foo: + image: alpine + secrets: + - bar + command: cat /run/secrets/bar + +secrets: + bar: + environment: SECRET + diff --git a/pkg/e2e/fixtures/environment/env-file-comments/.env b/pkg/e2e/fixtures/environment/env-file-comments/.env new file mode 100644 index 00000000..068e52be --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-file-comments/.env @@ -0,0 +1,2 @@ +COMMENT=1234#5 +NO_COMMENT="1234#5" diff --git a/pkg/e2e/fixtures/environment/env-file-comments/Dockerfile b/pkg/e2e/fixtures/environment/env-file-comments/Dockerfile new file mode 100644 index 00000000..6c6972d6 --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-file-comments/Dockerfile @@ -0,0 +1,18 @@ +# Copyright 2020 Docker Compose CLI authors + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM alpine +ENV COMMENT=Dockerfile +ENV NO_COMMENT=Dockerfile +CMD ["sh", "-c", "printenv", "|", "grep", "COMMENT"] diff --git a/pkg/e2e/fixtures/environment/env-file-comments/compose.yaml b/pkg/e2e/fixtures/environment/env-file-comments/compose.yaml new file mode 100644 index 00000000..71896866 --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-file-comments/compose.yaml @@ -0,0 +1,5 @@ +services: + env-file-comments: + build: + context: . + image: env-file-comments \ No newline at end of file diff --git a/pkg/e2e/fixtures/environment/env-interpolation/.env b/pkg/e2e/fixtures/environment/env-interpolation/.env new file mode 100644 index 00000000..87bc8ee7 --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-interpolation/.env @@ -0,0 +1,2 @@ +WHEREAMI=Env File +IMAGE=default_env:${WHEREAMI} \ No newline at end of file diff --git a/pkg/e2e/fixtures/environment/env-interpolation/compose.yaml b/pkg/e2e/fixtures/environment/env-interpolation/compose.yaml new file mode 100644 index 00000000..7a4b3865 --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-interpolation/compose.yaml @@ -0,0 +1,6 @@ +services: + env-interpolation: + image: bash + environment: + IMAGE: ${IMAGE} + command: echo "$IMAGE" \ No newline at end of file diff --git a/pkg/e2e/fixtures/environment/env-priority/.env b/pkg/e2e/fixtures/environment/env-priority/.env new file mode 100644 index 00000000..c93127ac --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-priority/.env @@ -0,0 +1 @@ +WHEREAMI=Env File diff --git a/pkg/e2e/fixtures/environment/env-priority/.env.empty b/pkg/e2e/fixtures/environment/env-priority/.env.empty new file mode 100644 index 00000000..e69de29b diff --git a/pkg/e2e/fixtures/environment/env-priority/.env.override b/pkg/e2e/fixtures/environment/env-priority/.env.override new file mode 100644 index 00000000..398fa51b --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-priority/.env.override @@ -0,0 +1 @@ +WHEREAMI=override diff --git a/pkg/e2e/fixtures/environment/env-priority/Dockerfile b/pkg/e2e/fixtures/environment/env-priority/Dockerfile new file mode 100644 index 00000000..0901119f --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-priority/Dockerfile @@ -0,0 +1,17 @@ +# Copyright 2020 Docker Compose CLI authors + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM alpine +ENV WHEREAMI=Dockerfile +CMD ["printenv", "WHEREAMI"] diff --git a/pkg/e2e/fixtures/environment/env-priority/compose-with-env.yaml b/pkg/e2e/fixtures/environment/env-priority/compose-with-env.yaml new file mode 100644 index 00000000..d8cdc140 --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-priority/compose-with-env.yaml @@ -0,0 +1,7 @@ +services: + env-compose-priority: + image: env-compose-priority + build: + context: . + environment: + WHEREAMI: "Compose File" diff --git a/pkg/e2e/fixtures/environment/env-priority/compose.yaml b/pkg/e2e/fixtures/environment/env-priority/compose.yaml new file mode 100644 index 00000000..0ccade6a --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-priority/compose.yaml @@ -0,0 +1,3 @@ +services: + env-compose-priority: + image: env-compose-priority diff --git a/pkg/e2e/fixtures/links/compose.yaml b/pkg/e2e/fixtures/links/compose.yaml new file mode 100644 index 00000000..8c182c4d --- /dev/null +++ b/pkg/e2e/fixtures/links/compose.yaml @@ -0,0 +1,8 @@ +services: + foo: + image: nginx:alpine + links: + - bar + + bar: + image: nginx:alpine diff --git a/pkg/e2e/fixtures/network-links/compose.yaml b/pkg/e2e/fixtures/network-links/compose.yaml new file mode 100644 index 00000000..c09a33fc --- /dev/null +++ b/pkg/e2e/fixtures/network-links/compose.yaml @@ -0,0 +1,9 @@ +services: + container1: + image: nginx + network_mode: bridge + container2: + image: nginx + network_mode: bridge + links: + - container1 diff --git a/pkg/e2e/fixtures/pause/compose.yaml b/pkg/e2e/fixtures/pause/compose.yaml new file mode 100644 index 00000000..f41461fd --- /dev/null +++ b/pkg/e2e/fixtures/pause/compose.yaml @@ -0,0 +1,9 @@ +services: + a: + image: nginx:alpine + ports: [80] + b: + image: nginx:alpine + ports: [80] + depends_on: + - a diff --git a/pkg/e2e/fixtures/project-volume-bind-test/docker-compose.yml b/pkg/e2e/fixtures/project-volume-bind-test/docker-compose.yml new file mode 100644 index 00000000..aba0bf47 --- /dev/null +++ b/pkg/e2e/fixtures/project-volume-bind-test/docker-compose.yml @@ -0,0 +1,14 @@ +services: + frontend: + image: nginx + container_name: frontend + volumes: + - project_data:/data + +volumes: + project_data: + driver: local + driver_opts: + type: none + o: bind + device: "${TEST_DIR}" diff --git a/pkg/e2e/fixtures/ps-test/compose.yaml b/pkg/e2e/fixtures/ps-test/compose.yaml new file mode 100644 index 00000000..08781e6a --- /dev/null +++ b/pkg/e2e/fixtures/ps-test/compose.yaml @@ -0,0 +1,12 @@ +services: + nginx: + image: nginx:latest + expose: + - '80' + - '443' + - '8080' + busybox: + image: busybox + command: busybox httpd -f -p 8000 + ports: + - '127.0.0.1:8001:8000' diff --git a/pkg/e2e/fixtures/run-test/deps.yaml b/pkg/e2e/fixtures/run-test/deps.yaml new file mode 100644 index 00000000..4b6c5fca --- /dev/null +++ b/pkg/e2e/fixtures/run-test/deps.yaml @@ -0,0 +1,14 @@ +version: "3.6" +services: + service_a: + image: bash + command: echo "a" + depends_on: + - shared_dep + service_b: + image: bash + command: echo "b" + depends_on: + - shared_dep + shared_dep: + image: bash \ No newline at end of file diff --git a/pkg/e2e/fixtures/run-test/orphan.yaml b/pkg/e2e/fixtures/run-test/orphan.yaml new file mode 100644 index 00000000..a2aedb37 --- /dev/null +++ b/pkg/e2e/fixtures/run-test/orphan.yaml @@ -0,0 +1,5 @@ +version: '3.8' +services: + simple: + image: alpine + command: echo "Hi there!!" diff --git a/pkg/e2e/framework.go b/pkg/e2e/framework.go index 7346514c..15eed455 100644 --- a/pkg/e2e/framework.go +++ b/pkg/e2e/framework.go @@ -19,7 +19,6 @@ package e2e import ( "fmt" "io" - "io/ioutil" "net/http" "os" "path" @@ -29,12 +28,13 @@ import ( "testing" "time" - "github.com/docker/compose/v2/cmd/compose" "github.com/pkg/errors" + "github.com/stretchr/testify/require" "gotest.tools/v3/assert" - is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/icmd" "gotest.tools/v3/poll" + + "github.com/docker/compose/v2/cmd/compose" ) var ( @@ -56,54 +56,85 @@ func init() { } } -// E2eCLI is used to wrap the CLI for end to end testing -// nolint stutter -type E2eCLI struct { - BinDir string +// CLI is used to wrap the CLI for end to end testing +type CLI struct { + // ConfigDir for Docker configuration (set as DOCKER_CONFIG) ConfigDir string - test *testing.T + + // HomeDir for tools that look for user files (set as HOME) + HomeDir string + + // env overrides to apply to every invoked command + // + // To populate, use WithEnv when creating a CLI instance. + env []string } -// NewParallelE2eCLI returns a configured TestE2eCLI with t.Parallel() set -func NewParallelE2eCLI(t *testing.T, binDir string) *E2eCLI { +// CLIOption to customize behavior for all commands for a CLI instance. +type CLIOption func(c *CLI) + +// NewParallelCLI marks the parent test as parallel and returns a CLI instance +// suitable for usage across child tests. +func NewParallelCLI(t *testing.T, opts ...CLIOption) *CLI { + t.Helper() t.Parallel() - return newE2eCLI(t, binDir) + return NewCLI(t, opts...) } -func newE2eCLI(t *testing.T, binDir string) *E2eCLI { - d, err := ioutil.TempDir("", "") - assert.Check(t, is.Nil(err)) +// NewCLI creates a CLI instance for running E2E tests. +func NewCLI(t testing.TB, opts ...CLIOption) *CLI { + t.Helper() + + configDir := t.TempDir() + initializePlugins(t, configDir) + + c := &CLI{ + ConfigDir: configDir, + HomeDir: t.TempDir(), + } + + for _, opt := range opts { + opt(c) + } + + return c +} + +// WithEnv sets environment variables that will be passed to commands. +func WithEnv(env ...string) CLIOption { + return func(c *CLI) { + c.env = append(c.env, env...) + } +} + +// initializePlugins copies the necessary plugin files to the temporary config +// directory for the test. +func initializePlugins(t testing.TB, configDir string) { + t.Helper() t.Cleanup(func() { if t.Failed() { - conf, _ := ioutil.ReadFile(filepath.Join(d, "config.json")) - t.Errorf("Config: %s\n", string(conf)) - t.Error("Contents of config dir:") - for _, p := range dirContents(d) { - t.Errorf(p) + if conf, err := os.ReadFile(filepath.Join(configDir, "config.json")); err == nil { + t.Logf("Config: %s\n", string(conf)) + } + t.Log("Contents of config dir:") + for _, p := range dirContents(configDir) { + t.Logf(" - %s", p) } } - _ = os.RemoveAll(d) }) - _ = os.MkdirAll(filepath.Join(d, "cli-plugins"), 0755) + require.NoError(t, os.MkdirAll(filepath.Join(configDir, "cli-plugins"), 0755), + "Failed to create cli-plugins directory") composePlugin, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"}) if os.IsNotExist(err) { - fmt.Println("WARNING: docker-compose cli-plugin not found") + t.Logf("WARNING: docker-compose cli-plugin not found") } if err == nil { - err = CopyFile(composePlugin, filepath.Join(d, "cli-plugins", DockerComposeExecutableName)) - if err != nil { - panic(err) - } + CopyFile(t, composePlugin, filepath.Join(configDir, "cli-plugins", DockerComposeExecutableName)) // We don't need a functional scan plugin, but a valid plugin binary - err = CopyFile(composePlugin, filepath.Join(d, "cli-plugins", DockerScanExecutableName)) - if err != nil { - panic(err) - } + CopyFile(t, composePlugin, filepath.Join(configDir, "cli-plugins", DockerScanExecutableName)) } - - return &E2eCLI{binDir, d, t} } func dirContents(dir string) []string { @@ -133,88 +164,145 @@ func findExecutable(executableName string, paths []string) (string, error) { } // CopyFile copies a file from a sourceFile to a destinationFile setting permissions to 0755 -func CopyFile(sourceFile string, destinationFile string) error { +func CopyFile(t testing.TB, sourceFile string, destinationFile string) { + t.Helper() + src, err := os.Open(sourceFile) - if err != nil { - return err - } + require.NoError(t, err, "Failed to open source file: %s") // nolint: errcheck defer src.Close() dst, err := os.OpenFile(destinationFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - return err - } + require.NoError(t, err, "Failed to open destination file: %s", destinationFile) // nolint: errcheck defer dst.Close() - if _, err = io.Copy(dst, src); err != nil { - return err - } + _, err = io.Copy(dst, src) + require.NoError(t, err, "Failed to copy file: %s", sourceFile) +} - return err +// BaseEnvironment provides the minimal environment variables used across all +// Docker / Compose commands. +func (c *CLI) BaseEnvironment() []string { + return []string{ + "HOME=" + c.HomeDir, + "USER=" + os.Getenv("USER"), + "DOCKER_CONFIG=" + c.ConfigDir, + "KUBECONFIG=invalid", + } } // NewCmd creates a cmd object configured with the test environment set -func (c *E2eCLI) NewCmd(command string, args ...string) icmd.Cmd { - env := append(os.Environ(), - "DOCKER_CONFIG="+c.ConfigDir, - "KUBECONFIG=invalid", - ) +func (c *CLI) NewCmd(command string, args ...string) icmd.Cmd { return icmd.Cmd{ Command: append([]string{command}, args...), - Env: env, + Env: append(c.BaseEnvironment(), c.env...), + } +} + +// NewCmdWithEnv creates a cmd object configured with the test environment set with additional env vars +func (c *CLI) NewCmdWithEnv(envvars []string, command string, args ...string) icmd.Cmd { + // base env -> CLI overrides -> cmd overrides + cmdEnv := append(c.BaseEnvironment(), c.env...) + cmdEnv = append(cmdEnv, envvars...) + return icmd.Cmd{ + Command: append([]string{command}, args...), + Env: cmdEnv, } } // MetricsSocket get the path where test metrics will be sent -func (c *E2eCLI) MetricsSocket() string { +func (c *CLI) MetricsSocket() string { return filepath.Join(c.ConfigDir, "./docker-cli.sock") } // NewDockerCmd creates a docker cmd without running it -func (c *E2eCLI) NewDockerCmd(args ...string) icmd.Cmd { +func (c *CLI) NewDockerCmd(t testing.TB, args ...string) icmd.Cmd { + t.Helper() + for _, arg := range args { + if arg == compose.PluginName { + t.Fatal("This test called 'RunDockerCmd' for 'compose'. Please prefer 'RunDockerComposeCmd' to be able to test as a plugin and standalone") + } + } return c.NewCmd(DockerExecutableName, args...) } // RunDockerOrExitError runs a docker command and returns a result -func (c *E2eCLI) RunDockerOrExitError(args ...string) *icmd.Result { - fmt.Printf("\t[%s] docker %s\n", c.test.Name(), strings.Join(args, " ")) - return icmd.RunCmd(c.NewDockerCmd(args...)) +func (c *CLI) RunDockerOrExitError(t testing.TB, args ...string) *icmd.Result { + t.Helper() + t.Logf("\t[%s] docker %s\n", t.Name(), strings.Join(args, " ")) + return icmd.RunCmd(c.NewDockerCmd(t, args...)) } // RunCmd runs a command, expects no error and returns a result -func (c *E2eCLI) RunCmd(args ...string) *icmd.Result { - fmt.Printf("\t[%s] %s\n", c.test.Name(), strings.Join(args, " ")) - assert.Assert(c.test, len(args) >= 1, "require at least one command in parameters") +func (c *CLI) RunCmd(t testing.TB, args ...string) *icmd.Result { + t.Helper() + t.Logf("\t[%s] %s\n", t.Name(), strings.Join(args, " ")) + assert.Assert(t, len(args) >= 1, "require at least one command in parameters") res := icmd.RunCmd(c.NewCmd(args[0], args[1:]...)) - res.Assert(c.test, icmd.Success) + res.Assert(t, icmd.Success) + return res +} + +// RunCmdInDir runs a command in a given dir, expects no error and returns a result +func (c *CLI) RunCmdInDir(t testing.TB, dir string, args ...string) *icmd.Result { + t.Helper() + t.Logf("\t[%s] %s\n", t.Name(), strings.Join(args, " ")) + assert.Assert(t, len(args) >= 1, "require at least one command in parameters") + cmd := c.NewCmd(args[0], args[1:]...) + cmd.Dir = dir + res := icmd.RunCmd(cmd) + res.Assert(t, icmd.Success) return res } // RunDockerCmd runs a docker command, expects no error and returns a result -func (c *E2eCLI) RunDockerCmd(args ...string) *icmd.Result { - if len(args) > 0 && args[0] == compose.PluginName { - c.test.Fatal("This test called 'RunDockerCmd' for 'compose'. Please prefer 'RunDockerComposeCmd' to be able to test as a plugin and standalone") - } - res := c.RunDockerOrExitError(args...) - res.Assert(c.test, icmd.Success) +func (c *CLI) RunDockerCmd(t testing.TB, args ...string) *icmd.Result { + t.Helper() + res := c.RunDockerOrExitError(t, args...) + res.Assert(t, icmd.Success) return res } // RunDockerComposeCmd runs a docker compose command, expects no error and returns a result -func (c *E2eCLI) RunDockerComposeCmd(args ...string) *icmd.Result { +func (c *CLI) RunDockerComposeCmd(t testing.TB, args ...string) *icmd.Result { + t.Helper() + res := c.RunDockerComposeCmdNoCheck(t, args...) + res.Assert(t, icmd.Success) + return res +} + +// RunDockerComposeCmdNoCheck runs a docker compose command, don't presume of any expectation and returns a result +func (c *CLI) RunDockerComposeCmdNoCheck(t testing.TB, args ...string) *icmd.Result { + t.Helper() + return icmd.RunCmd(c.NewDockerComposeCmd(t, args...)) +} + +// NewDockerComposeCmd creates a command object for Compose, either in plugin +// or standalone mode (based on build tags). +func (c *CLI) NewDockerComposeCmd(t testing.TB, args ...string) icmd.Cmd { + t.Helper() if composeStandaloneMode { - composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"}) - assert.NilError(c.test, err) - res := icmd.RunCmd(c.NewCmd(composeBinary, args...)) - res.Assert(c.test, icmd.Success) - return res + return c.NewCmd(ComposeStandalonePath(t), args...) } args = append([]string{"compose"}, args...) - res := icmd.RunCmd(c.NewCmd(DockerExecutableName, args...)) - res.Assert(c.test, icmd.Success) - return res + return c.NewCmd(DockerExecutableName, args...) +} + +// ComposeStandalonePath returns the path to the locally-built Compose +// standalone binary from the repo. +// +// This function will fail the test immediately if invoked when not running +// in standalone test mode. +func ComposeStandalonePath(t testing.TB) string { + t.Helper() + if !composeStandaloneMode { + require.Fail(t, "Not running in standalone mode") + } + composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"}) + require.NoError(t, err, "Could not find standalone Compose binary (%q)", + DockerComposeExecutableName) + return composeBinary } // StdoutContains returns a predicate on command result expecting a string in stdout @@ -225,22 +313,35 @@ func StdoutContains(expected string) func(*icmd.Result) bool { } // WaitForCmdResult try to execute a cmd until resulting output matches given predicate -func (c *E2eCLI) WaitForCmdResult(command icmd.Cmd, predicate func(*icmd.Result) bool, timeout time.Duration, delay time.Duration) { - assert.Assert(c.test, timeout.Nanoseconds() > delay.Nanoseconds(), "timeout must be greater than delay") +func (c *CLI) WaitForCmdResult( + t testing.TB, + command icmd.Cmd, + predicate func(*icmd.Result) bool, + timeout time.Duration, + delay time.Duration, +) { + t.Helper() + assert.Assert(t, timeout.Nanoseconds() > delay.Nanoseconds(), "timeout must be greater than delay") var res *icmd.Result checkStopped := func(logt poll.LogT) poll.Result { - fmt.Printf("\t[%s] %s\n", c.test.Name(), strings.Join(command.Command, " ")) + fmt.Printf("\t[%s] %s\n", t.Name(), strings.Join(command.Command, " ")) res = icmd.RunCmd(command) if !predicate(res) { return poll.Continue("Cmd output did not match requirement: %q", res.Combined()) } return poll.Success() } - poll.WaitOn(c.test, checkStopped, poll.WithDelay(delay), poll.WithTimeout(timeout)) + poll.WaitOn(t, checkStopped, poll.WithDelay(delay), poll.WithTimeout(timeout)) } // WaitForCondition wait for predicate to execute to true -func (c *E2eCLI) WaitForCondition(predicate func() (bool, string), timeout time.Duration, delay time.Duration) { +func (c *CLI) WaitForCondition( + t testing.TB, + predicate func() (bool, string), + timeout time.Duration, + delay time.Duration, +) { + t.Helper() checkStopped := func(logt poll.LogT) poll.Result { pass, description := predicate() if !pass { @@ -248,7 +349,7 @@ func (c *E2eCLI) WaitForCondition(predicate func() (bool, string), timeout time. } return poll.Success() } - poll.WaitOn(c.test, checkStopped, poll.WithDelay(delay), poll.WithTimeout(timeout)) + poll.WaitOn(t, checkStopped, poll.WithDelay(delay), poll.WithTimeout(timeout)) } // Lines split output into lines @@ -257,9 +358,16 @@ func Lines(output string) []string { } // HTTPGetWithRetry performs an HTTP GET on an `endpoint`, using retryDelay also as a request timeout. -// In the case of an error or the response status is not the expeted one, it retries the same request, +// In the case of an error or the response status is not the expected one, it retries the same request, // returning the response body as a string (empty if we could not reach it) -func HTTPGetWithRetry(t *testing.T, endpoint string, expectedStatus int, retryDelay time.Duration, timeout time.Duration) string { +func HTTPGetWithRetry( + t testing.TB, + endpoint string, + expectedStatus int, + retryDelay time.Duration, + timeout time.Duration, +) string { + t.Helper() var ( r *http.Response err error @@ -280,7 +388,7 @@ func HTTPGetWithRetry(t *testing.T, endpoint string, expectedStatus int, retryDe } poll.WaitOn(t, checkUp, poll.WithDelay(retryDelay), poll.WithTimeout(timeout)) if r != nil { - b, err := ioutil.ReadAll(r.Body) + b, err := io.ReadAll(r.Body) assert.NilError(t, err) return string(b) } diff --git a/pkg/e2e/ipc_test.go b/pkg/e2e/ipc_test.go index e28bcbc9..7a46192a 100644 --- a/pkg/e2e/ipc_test.go +++ b/pkg/e2e/ipc_test.go @@ -25,39 +25,40 @@ import ( ) func TestIPC(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) const projectName = "ipc_e2e" var cid string t.Run("create ipc mode container", func(t *testing.T) { - res := c.RunDockerCmd("run", "-d", "--rm", "--ipc=shareable", "--name", "ipc_mode_container", "alpine", "top") + res := c.RunDockerCmd(t, "run", "-d", "--rm", "--ipc=shareable", "--name", "ipc_mode_container", "alpine", + "top") cid = strings.Trim(res.Stdout(), "\n") }) t.Run("up", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/ipc-test/compose.yaml", "--project-name", projectName, "up", "-d") + c.RunDockerComposeCmd(t, "-f", "./fixtures/ipc-test/compose.yaml", "--project-name", projectName, "up", "-d") }) t.Run("check running project", func(t *testing.T) { - res := c.RunDockerComposeCmd("-p", projectName, "ps") + res := c.RunDockerComposeCmd(t, "-p", projectName, "ps") res.Assert(t, icmd.Expected{Out: `shareable`}) }) t.Run("check ipcmode in container inspect", func(t *testing.T) { - res := c.RunDockerCmd("inspect", projectName+"-shareable-1") + res := c.RunDockerCmd(t, "inspect", projectName+"-shareable-1") res.Assert(t, icmd.Expected{Out: `"IpcMode": "shareable",`}) - res = c.RunDockerCmd("inspect", projectName+"-service-1") + res = c.RunDockerCmd(t, "inspect", projectName+"-service-1") res.Assert(t, icmd.Expected{Out: `"IpcMode": "container:`}) - res = c.RunDockerCmd("inspect", projectName+"-container-1") + res = c.RunDockerCmd(t, "inspect", projectName+"-container-1") res.Assert(t, icmd.Expected{Out: fmt.Sprintf(`"IpcMode": "container:%s",`, cid)}) }) t.Run("down", func(t *testing.T) { - _ = c.RunDockerComposeCmd("--project-name", projectName, "down") + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) t.Run("remove ipc mode container", func(t *testing.T) { - _ = c.RunDockerCmd("rm", "-f", "ipc_mode_container") + _ = c.RunDockerCmd(t, "rm", "-f", "ipc_mode_container") }) } diff --git a/pkg/e2e/logs_test.go b/pkg/e2e/logs_test.go index a744d89f..42d47d05 100644 --- a/pkg/e2e/logs_test.go +++ b/pkg/e2e/logs_test.go @@ -26,33 +26,33 @@ import ( ) func TestLocalComposeLogs(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) const projectName = "compose-e2e-logs" t.Run("up", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/logs-test/compose.yaml", "--project-name", projectName, "up", "-d") + c.RunDockerComposeCmd(t, "-f", "./fixtures/logs-test/compose.yaml", "--project-name", projectName, "up", "-d") }) t.Run("logs", func(t *testing.T) { - res := c.RunDockerComposeCmd("--project-name", projectName, "logs") + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "logs") res.Assert(t, icmd.Expected{Out: `PING localhost (127.0.0.1)`}) res.Assert(t, icmd.Expected{Out: `hello`}) }) t.Run("logs ping", func(t *testing.T) { - res := c.RunDockerComposeCmd("--project-name", projectName, "logs", "ping") + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "logs", "ping") res.Assert(t, icmd.Expected{Out: `PING localhost (127.0.0.1)`}) assert.Assert(t, !strings.Contains(res.Stdout(), "hello")) }) t.Run("logs hello", func(t *testing.T) { - res := c.RunDockerComposeCmd("--project-name", projectName, "logs", "hello", "ping") + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "logs", "hello", "ping") res.Assert(t, icmd.Expected{Out: `PING localhost (127.0.0.1)`}) res.Assert(t, icmd.Expected{Out: `hello`}) }) t.Run("down", func(t *testing.T) { - _ = c.RunDockerComposeCmd("--project-name", projectName, "down") + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) } diff --git a/pkg/e2e/metrics_test.go b/pkg/e2e/metrics_test.go index b1a9e667..adee7da5 100644 --- a/pkg/e2e/metrics_test.go +++ b/pkg/e2e/metrics_test.go @@ -24,32 +24,32 @@ import ( ) func TestComposeMetrics(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) t.Run("catch specific failure metrics", func(t *testing.T) { - res := c.RunDockerOrExitError("compose", "-f", "fixtures/does-not-exist/compose.yaml", "build") + res := c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/does-not-exist/compose.yaml", "build") expectedErr := "fixtures/does-not-exist/compose.yaml: no such file or directory" if runtime.GOOS == "windows" { expectedErr = "does-not-exist\\compose.yaml: The system cannot find the path specified" } res.Assert(t, icmd.Expected{ExitCode: 14, Err: expectedErr}) - res = c.RunDockerOrExitError("compose", "-f", "fixtures/wrong-composefile/compose.yaml", "up", "-d") + res = c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/wrong-composefile/compose.yaml", "up", "-d") res.Assert(t, icmd.Expected{ExitCode: 15, Err: "services.simple Additional property wrongField is not allowed"}) - res = c.RunDockerOrExitError("compose", "up") + res = c.RunDockerComposeCmdNoCheck(t, "up") res.Assert(t, icmd.Expected{ExitCode: 14, Err: "no configuration file provided: not found"}) - res = c.RunDockerOrExitError("compose", "up", "-f", "fixtures/wrong-composefile/compose.yaml") + res = c.RunDockerComposeCmdNoCheck(t, "up", "-f", "fixtures/wrong-composefile/compose.yaml") res.Assert(t, icmd.Expected{ExitCode: 16, Err: "unknown shorthand flag: 'f' in -f"}) - res = c.RunDockerOrExitError("compose", "up", "--file", "fixtures/wrong-composefile/compose.yaml") + res = c.RunDockerComposeCmdNoCheck(t, "up", "--file", "fixtures/wrong-composefile/compose.yaml") res.Assert(t, icmd.Expected{ExitCode: 16, Err: "unknown flag: --file"}) - res = c.RunDockerOrExitError("compose", "donw", "--file", "fixtures/wrong-composefile/compose.yaml") + res = c.RunDockerComposeCmdNoCheck(t, "donw", "--file", "fixtures/wrong-composefile/compose.yaml") res.Assert(t, icmd.Expected{ExitCode: 16, Err: `unknown docker command: "compose donw"`}) - res = c.RunDockerOrExitError("compose", "--file", "fixtures/wrong-composefile/build-error.yml", "build") + res = c.RunDockerComposeCmdNoCheck(t, "--file", "fixtures/wrong-composefile/build-error.yml", "build") res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`}) - res = c.RunDockerOrExitError("compose", "--file", "fixtures/wrong-composefile/build-error.yml", "up") + res = c.RunDockerComposeCmdNoCheck(t, "--file", "fixtures/wrong-composefile/build-error.yml", "up") res.Assert(t, icmd.Expected{ExitCode: 17, Err: `line 17: unknown instruction: WRONG`}) - res = c.RunDockerOrExitError("compose", "--file", "fixtures/wrong-composefile/unknown-image.yml", "pull") + res = c.RunDockerComposeCmdNoCheck(t, "--file", "fixtures/wrong-composefile/unknown-image.yml", "pull") res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`}) - res = c.RunDockerOrExitError("compose", "--file", "fixtures/wrong-composefile/unknown-image.yml", "up") + res = c.RunDockerComposeCmdNoCheck(t, "--file", "fixtures/wrong-composefile/unknown-image.yml", "up") res.Assert(t, icmd.Expected{ExitCode: 18, Err: `pull access denied for unknownimage, repository does not exist or may require 'docker login'`}) }) } diff --git a/pkg/e2e/networks_test.go b/pkg/e2e/networks_test.go index 36582dfc..2fa84bd6 100644 --- a/pkg/e2e/networks_test.go +++ b/pkg/e2e/networks_test.go @@ -27,107 +27,135 @@ import ( ) func TestNetworks(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + // fixture is shared with TestNetworkModes and is not safe to run concurrently + c := NewCLI(t) const projectName = "network_e2e" t.Run("ensure we do not reuse previous networks", func(t *testing.T) { - c.RunDockerOrExitError("network", "rm", projectName+"_dbnet") - c.RunDockerOrExitError("network", "rm", "microservices") + c.RunDockerOrExitError(t, "network", "rm", projectName+"_dbnet") + c.RunDockerOrExitError(t, "network", "rm", "microservices") }) t.Run("up", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/network-test/compose.yaml", "--project-name", projectName, "up", "-d") + c.RunDockerComposeCmd(t, "-f", "./fixtures/network-test/compose.yaml", "--project-name", projectName, "up", + "-d") }) t.Run("check running project", func(t *testing.T) { - res := c.RunDockerComposeCmd("-p", projectName, "ps") + res := c.RunDockerComposeCmd(t, "-p", projectName, "ps") res.Assert(t, icmd.Expected{Out: `web`}) endpoint := "http://localhost:80" output := HTTPGetWithRetry(t, endpoint+"/words/noun", http.StatusOK, 2*time.Second, 20*time.Second) assert.Assert(t, strings.Contains(output, `"word":`)) - res = c.RunDockerCmd("network", "ls") + res = c.RunDockerCmd(t, "network", "ls") res.Assert(t, icmd.Expected{Out: projectName + "_dbnet"}) res.Assert(t, icmd.Expected{Out: "microservices"}) }) t.Run("port", func(t *testing.T) { - res := c.RunDockerComposeCmd("--project-name", projectName, "port", "words", "8080") + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "port", "words", "8080") res.Assert(t, icmd.Expected{Out: `0.0.0.0:8080`}) }) t.Run("down", func(t *testing.T) { - _ = c.RunDockerComposeCmd("--project-name", projectName, "down") + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) t.Run("check networks after down", func(t *testing.T) { - res := c.RunDockerCmd("network", "ls") + res := c.RunDockerCmd(t, "network", "ls") assert.Assert(t, !strings.Contains(res.Combined(), projectName), res.Combined()) assert.Assert(t, !strings.Contains(res.Combined(), "microservices"), res.Combined()) }) } -func TestNetworkAliassesAndLinks(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) +func TestNetworkAliases(t *testing.T) { + c := NewParallelCLI(t) const projectName = "network_alias_e2e" t.Run("up", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, "up", "-d") + c.RunDockerComposeCmd(t, "-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, "up", + "-d") }) t.Run("curl alias", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, "exec", "-T", "container1", "curl", "http://alias-of-container2/") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, + "exec", "-T", "container1", "curl", "http://alias-of-container2/") assert.Assert(t, strings.Contains(res.Stdout(), "Welcome to nginx!"), res.Stdout()) }) t.Run("curl links", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, "exec", "-T", "container1", "curl", "http://container/") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/network-alias/compose.yaml", "--project-name", projectName, + "exec", "-T", "container1", "curl", "http://container/") assert.Assert(t, strings.Contains(res.Stdout(), "Welcome to nginx!"), res.Stdout()) }) t.Run("down", func(t *testing.T) { - _ = c.RunDockerComposeCmd("--project-name", projectName, "down") + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") + }) +} + +func TestNetworkLinks(t *testing.T) { + c := NewParallelCLI(t) + + const projectName = "network_link_e2e" + + t.Run("up", func(t *testing.T) { + c.RunDockerComposeCmd(t, "-f", "./fixtures/network-links/compose.yaml", "--project-name", projectName, "up", + "-d") + }) + + t.Run("curl links in default bridge network", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/network-links/compose.yaml", "--project-name", projectName, + "exec", "-T", "container2", "curl", "http://container1/") + assert.Assert(t, strings.Contains(res.Stdout(), "Welcome to nginx!"), res.Stdout()) + }) + + t.Run("down", func(t *testing.T) { + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) } func TestIPAMConfig(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) const projectName = "ipam_e2e" t.Run("ensure we do not reuse previous networks", func(t *testing.T) { - c.RunDockerOrExitError("network", "rm", projectName+"_default") + c.RunDockerOrExitError(t, "network", "rm", projectName+"_default") }) t.Run("up", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/ipam/compose.yaml", "--project-name", projectName, "up", "-d") + c.RunDockerComposeCmd(t, "-f", "./fixtures/ipam/compose.yaml", "--project-name", projectName, "up", "-d") }) t.Run("ensure service get fixed IP assigned", func(t *testing.T) { - res := c.RunDockerCmd("inspect", projectName+"-foo-1", "-f", "{{ .NetworkSettings.Networks."+projectName+"_default.IPAddress }}") + res := c.RunDockerCmd(t, "inspect", projectName+"-foo-1", "-f", + "{{ .NetworkSettings.Networks."+projectName+"_default.IPAddress }}") res.Assert(t, icmd.Expected{Out: "10.1.0.100"}) }) t.Run("down", func(t *testing.T) { - _ = c.RunDockerComposeCmd("--project-name", projectName, "down") + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) } func TestNetworkModes(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + // fixture is shared with TestNetworks and is not safe to run concurrently + c := NewCLI(t) const projectName = "network_mode_service_run" t.Run("run with service mode dependency", func(t *testing.T) { - res := c.RunDockerOrExitError("compose", "-f", "./fixtures/network-test/compose.yaml", "--project-name", projectName, "run", "-T", "mydb", "echo", "success") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/network-test/compose.yaml", "--project-name", projectName, "run", "-T", "mydb", "echo", "success") res.Assert(t, icmd.Expected{Out: "success"}) }) t.Run("down", func(t *testing.T) { - _ = c.RunDockerComposeCmd("--project-name", projectName, "down") + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) } diff --git a/pkg/e2e/pause_test.go b/pkg/e2e/pause_test.go new file mode 100644 index 00000000..a91c7a20 --- /dev/null +++ b/pkg/e2e/pause_test.go @@ -0,0 +1,155 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "encoding/json" + "fmt" + "net" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/require" + "gotest.tools/v3/icmd" +) + +func TestPause(t *testing.T) { + cli := NewParallelCLI(t, WithEnv( + "COMPOSE_PROJECT_NAME=e2e-pause", + "COMPOSE_FILE=./fixtures/pause/compose.yaml")) + + cleanup := func() { + cli.RunDockerComposeCmd(t, "down", "-v", "--remove-orphans", "-t", "0") + } + cleanup() + t.Cleanup(cleanup) + + // launch both services and verify that they are accessible + cli.RunDockerComposeCmd(t, "up", "-d") + urls := map[string]string{ + "a": urlForService(t, cli, "a", 80), + "b": urlForService(t, cli, "b", 80), + } + for _, url := range urls { + HTTPGetWithRetry(t, url, http.StatusOK, 50*time.Millisecond, 5*time.Second) + } + + // pause a and verify that it can no longer be hit but b still can + cli.RunDockerComposeCmd(t, "pause", "a") + httpClient := http.Client{Timeout: 250 * time.Millisecond} + resp, err := httpClient.Get(urls["a"]) + if resp != nil { + _ = resp.Body.Close() + } + require.Error(t, err, "a should no longer respond") + require.True(t, err.(net.Error).Timeout(), "Error should have indicated a timeout") + HTTPGetWithRetry(t, urls["b"], http.StatusOK, 50*time.Millisecond, 5*time.Second) + + // unpause a and verify that both containers work again + cli.RunDockerComposeCmd(t, "unpause", "a") + for _, url := range urls { + HTTPGetWithRetry(t, url, http.StatusOK, 50*time.Millisecond, 5*time.Second) + } +} + +func TestPauseServiceNotRunning(t *testing.T) { + cli := NewParallelCLI(t, WithEnv( + "COMPOSE_PROJECT_NAME=e2e-pause-svc-not-running", + "COMPOSE_FILE=./fixtures/pause/compose.yaml")) + + cleanup := func() { + cli.RunDockerComposeCmd(t, "down", "-v", "--remove-orphans", "-t", "0") + } + cleanup() + t.Cleanup(cleanup) + + // pause a and verify that it can no longer be hit but b still can + res := cli.RunDockerComposeCmdNoCheck(t, "pause", "a") + + // TODO: `docker pause` errors in this case, should Compose be consistent? + res.Assert(t, icmd.Expected{ExitCode: 0}) +} + +func TestPauseServiceAlreadyPaused(t *testing.T) { + cli := NewParallelCLI(t, WithEnv( + "COMPOSE_PROJECT_NAME=e2e-pause-svc-already-paused", + "COMPOSE_FILE=./fixtures/pause/compose.yaml")) + + cleanup := func() { + cli.RunDockerComposeCmd(t, "down", "-v", "--remove-orphans", "-t", "0") + } + cleanup() + t.Cleanup(cleanup) + + // launch a and wait for it to come up + cli.RunDockerComposeCmd(t, "up", "-d", "a") + HTTPGetWithRetry(t, urlForService(t, cli, "a", 80), http.StatusOK, 50*time.Millisecond, 5*time.Second) + + // pause a twice - first time should pass, second time fail + cli.RunDockerComposeCmd(t, "pause", "a") + res := cli.RunDockerComposeCmdNoCheck(t, "pause", "a") + res.Assert(t, icmd.Expected{ExitCode: 1, Err: "already paused"}) +} + +func TestPauseServiceDoesNotExist(t *testing.T) { + cli := NewParallelCLI(t, WithEnv( + "COMPOSE_PROJECT_NAME=e2e-pause-svc-not-exist", + "COMPOSE_FILE=./fixtures/pause/compose.yaml")) + + cleanup := func() { + cli.RunDockerComposeCmd(t, "down", "-v", "--remove-orphans", "-t", "0") + } + cleanup() + t.Cleanup(cleanup) + + // pause a and verify that it can no longer be hit but b still can + res := cli.RunDockerComposeCmdNoCheck(t, "pause", "does_not_exist") + // TODO: `compose down does_not_exist` and similar error, this should too + res.Assert(t, icmd.Expected{ExitCode: 0}) +} + +func urlForService(t testing.TB, cli *CLI, service string, targetPort int) string { + t.Helper() + return fmt.Sprintf( + "http://localhost:%d", + publishedPortForService(t, cli, service, targetPort), + ) +} + +func publishedPortForService(t testing.TB, cli *CLI, service string, targetPort int) int { + t.Helper() + res := cli.RunDockerComposeCmd(t, "ps", "--format=json", service) + var psOut []struct { + Publishers []struct { + TargetPort int + PublishedPort int + } + } + require.NoError(t, json.Unmarshal([]byte(res.Stdout()), &psOut), + "Failed to parse `%s` output", res.Cmd.String()) + require.Len(t, psOut, 1, "Expected exactly 1 service") + svc := psOut[0] + for _, pp := range svc.Publishers { + if pp.TargetPort == targetPort { + return pp.PublishedPort + } + } + require.Failf(t, "No published port for target port", + "Target port: %d\nService: %s", targetPort, res.Combined()) + return -1 +} diff --git a/pkg/e2e/ps_test.go b/pkg/e2e/ps_test.go new file mode 100644 index 00000000..04289211 --- /dev/null +++ b/pkg/e2e/ps_test.go @@ -0,0 +1,97 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "encoding/json" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/docker/compose/v2/pkg/api" +) + +func TestPs(t *testing.T) { + c := NewParallelCLI(t) + const projectName = "e2e-ps" + + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "up", "-d") + if assert.NoError(t, res.Error) { + t.Cleanup(func() { + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") + }) + } + + assert.Contains(t, res.Combined(), "Container e2e-ps-busybox-1 Started", res.Combined()) + + t.Run("pretty", func(t *testing.T) { + res = c.RunDockerComposeCmd(t, "-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "ps") + lines := strings.Split(res.Stdout(), "\n") + assert.Equal(t, 4, len(lines)) + count := 0 + for _, line := range lines[1:3] { + if strings.Contains(line, "e2e-ps-busybox-1") { + assert.True(t, strings.Contains(line, "127.0.0.1:8001->8000/tcp")) + count++ + } + if strings.Contains(line, "e2e-ps-nginx-1") { + assert.True(t, strings.Contains(line, "80/tcp, 443/tcp, 8080/tcp")) + count++ + } + } + assert.Equal(t, 2, count, "Did not match both services:\n"+res.Combined()) + }) + + t.Run("json", func(t *testing.T) { + res = c.RunDockerComposeCmd(t, "-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "ps", + "--format", "json") + var output []api.ContainerSummary + err := json.Unmarshal([]byte(res.Stdout()), &output) + require.NoError(t, err, "Failed to unmarshal ps JSON output") + + count := 0 + assert.Equal(t, 2, len(output)) + for _, service := range output { + publishers := service.Publishers + if service.Name == "e2e-ps-busybox-1" { + assert.Equal(t, 1, len(publishers)) + assert.Equal(t, api.PortPublishers{ + { + URL: "127.0.0.1", + TargetPort: 8000, + PublishedPort: 8001, + Protocol: "tcp", + }, + }, publishers) + count++ + } + if service.Name == "e2e-ps-nginx-1" { + assert.Equal(t, 3, len(publishers)) + assert.Equal(t, api.PortPublishers{ + {TargetPort: 80, Protocol: "tcp"}, + {TargetPort: 443, Protocol: "tcp"}, + {TargetPort: 8080, Protocol: "tcp"}, + }, publishers) + + count++ + } + } + assert.Equal(t, 2, count, "Did not match both services:\n"+res.Combined()) + }) +} diff --git a/pkg/e2e/restart_test.go b/pkg/e2e/restart_test.go index 9b2e2ccf..6ce62bdd 100644 --- a/pkg/e2e/restart_test.go +++ b/pkg/e2e/restart_test.go @@ -27,7 +27,7 @@ import ( ) func TestRestart(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) const projectName = "e2e-restart" getServiceRegx := func(service string, status string) string { @@ -38,27 +38,27 @@ func TestRestart(t *testing.T) { t.Run("Up a project", func(t *testing.T) { // This is just to ensure the containers do NOT exist - c.RunDockerOrExitError("compose", "--project-name", projectName, "down") + c.RunDockerComposeCmd(t, "--project-name", projectName, "down") - res := c.RunDockerOrExitError("compose", "-f", "./fixtures/restart-test/compose.yaml", "--project-name", projectName, "up", "-d") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/restart-test/compose.yaml", "--project-name", projectName, "up", "-d") assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-restart-restart-1 Started"), res.Combined()) - c.WaitForCmdResult(c.NewDockerCmd("compose", "--project-name", projectName, "ps", "-a", "--format", "json"), - StdoutContains(`"State":"exited"`), - 10*time.Second, 1*time.Second) + c.WaitForCmdResult(t, c.NewDockerComposeCmd(t, "--project-name", projectName, "ps", "-a", "--format", + "json"), + StdoutContains(`"State":"exited"`), 10*time.Second, 1*time.Second) - res = c.RunDockerOrExitError("compose", "--project-name", projectName, "ps", "-a") + res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "-a") testify.Regexp(t, getServiceRegx("restart", "exited"), res.Stdout()) - _ = c.RunDockerOrExitError("compose", "-f", "./fixtures/restart-test/compose.yaml", "--project-name", projectName, "restart") + c.RunDockerComposeCmd(t, "-f", "./fixtures/restart-test/compose.yaml", "--project-name", projectName, "restart") // Give the same time but it must NOT exit time.Sleep(time.Second) - res = c.RunDockerOrExitError("compose", "--project-name", projectName, "ps") + res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps") testify.Regexp(t, getServiceRegx("restart", "running"), res.Stdout()) // Clean up - c.RunDockerOrExitError("compose", "--project-name", projectName, "down") + c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) } diff --git a/pkg/e2e/scan_message_test.go b/pkg/e2e/scan_message_test.go index 74a4681f..1515efd0 100644 --- a/pkg/e2e/scan_message_test.go +++ b/pkg/e2e/scan_message_test.go @@ -17,7 +17,6 @@ package e2e import ( - "io/ioutil" "os" "path/filepath" "strings" @@ -30,49 +29,54 @@ import ( ) func TestDisplayScanMessageAfterBuild(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) // assert docker scan plugin is available - c.RunDockerOrExitError("scan", "--help") + c.RunDockerOrExitError(t, "scan", "--help") t.Run("display on compose build", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-compose-build", "build") - defer c.RunDockerOrExitError("rmi", "-f", "scan-msg-test-compose-build_nginx") + res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", + "scan-msg-test-compose-build", "build") + defer c.RunDockerOrExitError(t, "rmi", "-f", "scan-msg-test-compose-build_nginx") res.Assert(t, icmd.Expected{Err: utils.ScanSuggestMsg}) }) t.Run("do not display on compose build with quiet flag", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-quiet", "build", "--quiet") + res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-quiet", + "build", "--quiet") assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) - res = c.RunDockerCmd("rmi", "-f", "scan-msg-test-quiet_nginx") + res = c.RunDockerCmd(t, "rmi", "-f", "scan-msg-test-quiet_nginx") assert.Assert(t, !strings.Contains(res.Combined(), "No such image")) - res = c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-q", "build", "-q") - defer c.RunDockerOrExitError("rmi", "-f", "scan-msg-test-q_nginx") + res = c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-q", + "build", "-q") + defer c.RunDockerOrExitError(t, "rmi", "-f", "scan-msg-test-q_nginx") assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) }) - _ = c.RunDockerOrExitError("rmi", "scan-msg-test_nginx") + _ = c.RunDockerOrExitError(t, "rmi", "scan-msg-test_nginx") t.Run("display on compose up if image is built", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "up", "-d") - defer c.RunDockerOrExitError("compose", "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "down") + res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "up", + "-d") + defer c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "down") res.Assert(t, icmd.Expected{Err: utils.ScanSuggestMsg}) }) t.Run("do not display on compose up if no image built", func(t *testing.T) { // re-run the same Compose aproject - res := c.RunDockerComposeCmd("-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "up", "-d") - defer c.RunDockerOrExitError("compose", "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "down", "--rmi", "all") + res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "up", + "-d") + defer c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "down", "--rmi", "all") assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) }) t.Run("do not display if scan already invoked", func(t *testing.T) { _ = os.MkdirAll(filepath.Join(c.ConfigDir, "scan"), 0755) scanConfigFile := filepath.Join(c.ConfigDir, "scan", "config.json") - err := ioutil.WriteFile(scanConfigFile, []byte(`{"optin":true}`), 0644) + err := os.WriteFile(scanConfigFile, []byte(`{"optin":true}`), 0644) assert.NilError(t, err) - res := c.RunDockerCmd("build", "-t", "test-image-scan-msg", "fixtures/simple-build-test/nginx-build") + res := c.RunDockerCmd(t, "build", "-t", "test-image-scan-msg", "fixtures/simple-build-test/nginx-build") assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) }) } diff --git a/pkg/e2e/secrets_test.go b/pkg/e2e/secrets_test.go new file mode 100644 index 00000000..72b47b75 --- /dev/null +++ b/pkg/e2e/secrets_test.go @@ -0,0 +1,35 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "testing" + + "gotest.tools/v3/icmd" +) + +func TestSecretFromEnv(t *testing.T) { + c := NewParallelCLI(t) + + t.Run("compose run", func(t *testing.T) { + res := icmd.RunCmd(c.NewDockerComposeCmd(t, "-f", "./fixtures/env-secret/compose.yaml", "run", "foo"), + func(cmd *icmd.Cmd) { + cmd.Env = append(cmd.Env, "SECRET=BAR") + }) + res.Assert(t, icmd.Expected{Out: "BAR"}) + }) +} diff --git a/pkg/e2e/start_stop_test.go b/pkg/e2e/start_stop_test.go index 0b92160c..bbfade1f 100644 --- a/pkg/e2e/start_stop_test.go +++ b/pkg/e2e/start_stop_test.go @@ -23,11 +23,12 @@ import ( testify "github.com/stretchr/testify/assert" "gotest.tools/v3/assert" + "gotest.tools/v3/icmd" ) func TestStartStop(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) - const projectName = "e2e-start-stop" + c := NewParallelCLI(t) + const projectName = "e2e-start-stop-no-dependencies" getProjectRegx := func(status string) string { // match output with random spaces like: @@ -42,56 +43,206 @@ func TestStartStop(t *testing.T) { } t.Run("Up a project", func(t *testing.T) { - res := c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "up", "-d") - assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-simple-1 Started"), res.Combined()) + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "up", + "-d") + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-no-dependencies-simple-1 Started"), res.Combined()) - res = c.RunDockerComposeCmd("ls", "--all") + res = c.RunDockerComposeCmd(t, "ls", "--all") testify.Regexp(t, getProjectRegx("running"), res.Stdout()) - res = c.RunDockerComposeCmd("--project-name", projectName, "ps") + res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps") testify.Regexp(t, getServiceRegx("simple", "running"), res.Stdout()) testify.Regexp(t, getServiceRegx("another", "running"), res.Stdout()) }) t.Run("stop project", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "stop") + c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "stop") - res := c.RunDockerComposeCmd("ls") - assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop"), res.Combined()) + res := c.RunDockerComposeCmd(t, "ls") + assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies"), res.Combined()) - res = c.RunDockerComposeCmd("ls", "--all") + res = c.RunDockerComposeCmd(t, "ls", "--all") testify.Regexp(t, getProjectRegx("exited"), res.Stdout()) - res = c.RunDockerComposeCmd("--project-name", projectName, "ps") - assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-words-1"), res.Combined()) + res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps") + assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-no-dependencies-words-1"), res.Combined()) - res = c.RunDockerComposeCmd("--project-name", projectName, "ps", "--all") + res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "--all") testify.Regexp(t, getServiceRegx("simple", "exited"), res.Stdout()) testify.Regexp(t, getServiceRegx("another", "exited"), res.Stdout()) }) t.Run("start project", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "start") + c.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "start") - res := c.RunDockerComposeCmd("ls") - testify.Regexp(t, getProjectRegx("running"), res.Stdout()) - }) - - t.Run("pause project", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "pause") - - res := c.RunDockerComposeCmd("ls", "--all") - testify.Regexp(t, getProjectRegx("paused"), res.Stdout()) - }) - - t.Run("unpause project", func(t *testing.T) { - c.RunDockerComposeCmd("-f", "./fixtures/start-stop/compose.yaml", "--project-name", projectName, "unpause") - - res := c.RunDockerComposeCmd("ls") + res := c.RunDockerComposeCmd(t, "ls") testify.Regexp(t, getProjectRegx("running"), res.Stdout()) }) t.Run("down", func(t *testing.T) { - _ = c.RunDockerComposeCmd("--project-name", projectName, "down") + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) } + +func TestStartStopWithDependencies(t *testing.T) { + c := NewParallelCLI(t) + const projectName = "e2e-start-stop-with-dependencies" + + defer c.RunDockerComposeCmd(t, "--project-name", projectName, "rm", "-fsv") + + t.Run("Up", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/dependencies/compose.yaml", "--project-name", projectName, + "up", "-d") + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined()) + }) + + t.Run("stop foo", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "stop", "foo") + + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Stopped"), res.Combined()) + + res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "--status", "running") + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-bar-1"), res.Combined()) + assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-foo-1"), res.Combined()) + }) + + t.Run("start foo", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "stop") + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Stopped"), res.Combined()) + + res = c.RunDockerComposeCmd(t, "--project-name", projectName, "start", "foo") + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined()) + + res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "--status", "running") + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-bar-1"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-dependencies-foo-1"), res.Combined()) + }) + + t.Run("Up no-deps links", func(t *testing.T) { + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/links/compose.yaml", "--project-name", projectName, "up", + "--no-deps", "-d", "foo") + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-foo-1 Started"), res.Combined()) + assert.Assert(t, !strings.Contains(res.Combined(), "Container e2e-start-stop-with-dependencies-bar-1 Started"), res.Combined()) + }) + + t.Run("down", func(t *testing.T) { + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") + }) +} + +func TestStartStopWithOneOffs(t *testing.T) { + c := NewParallelCLI(t) + const projectName = "e2e-start-stop-with-oneoffs" + + t.Run("Up", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/dependencies/compose.yaml", "--project-name", projectName, + "up", "-d") + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-oneoffs-foo-1 Started"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-with-oneoffs-bar-1 Started"), res.Combined()) + }) + + t.Run("run one-off", func(t *testing.T) { + c.RunDockerComposeCmd(t, "-f", "./fixtures/dependencies/compose.yaml", "--project-name", projectName, "run", "-d", "bar", "sleep", "infinity") + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "-a") + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-foo-1"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar-1"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs_bar_run"), res.Combined()) + }) + + t.Run("stop (not one-off containers)", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "stop") + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-foo-1"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar-1"), res.Combined()) + assert.Assert(t, !strings.Contains(res.Combined(), "e2e_start_stop_with_oneoffs_bar_run"), res.Combined()) + + res = c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "-a", "--status", "running") + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs_bar_run"), res.Combined()) + }) + + t.Run("start (not one-off containers)", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "start") + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-foo-1"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar-1"), res.Combined()) + assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs_bar_run"), res.Combined()) + }) + + t.Run("restart (not one-off containers)", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "restart") + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-foo-1"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar-1"), res.Combined()) + assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs_bar_run"), res.Combined()) + }) + + t.Run("down", func(t *testing.T) { + c.RunDockerComposeCmd(t, "--project-name", projectName, "down", "--remove-orphans") + + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "ps", "-a", "--status", "running") + assert.Assert(t, !strings.Contains(res.Combined(), "e2e-start-stop-with-oneoffs-bar"), res.Combined()) + }) +} + +func TestStartAlreadyRunning(t *testing.T) { + cli := NewParallelCLI(t, WithEnv( + "COMPOSE_PROJECT_NAME=e2e-start-stop-svc-already-running", + "COMPOSE_FILE=./fixtures/start-stop/compose.yaml")) + t.Cleanup(func() { + cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0") + }) + + cli.RunDockerComposeCmd(t, "up", "-d", "--wait") + + res := cli.RunDockerComposeCmd(t, "start", "simple") + assert.Equal(t, res.Stdout(), "", "No output should have been written to stdout") +} + +func TestStopAlreadyStopped(t *testing.T) { + cli := NewParallelCLI(t, WithEnv( + "COMPOSE_PROJECT_NAME=e2e-start-stop-svc-already-stopped", + "COMPOSE_FILE=./fixtures/start-stop/compose.yaml")) + t.Cleanup(func() { + cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0") + }) + + cli.RunDockerComposeCmd(t, "up", "-d", "--wait") + + // stop the container + cli.RunDockerComposeCmd(t, "stop", "simple") + + // attempt to stop it again + res := cli.RunDockerComposeCmdNoCheck(t, "stop", "simple") + // TODO: for consistency, this should NOT write any output because the + // container is already stopped + res.Assert(t, icmd.Expected{ + ExitCode: 0, + Err: "Container e2e-start-stop-svc-already-stopped-simple-1 Stopped", + }) +} + +func TestStartStopMultipleServices(t *testing.T) { + cli := NewParallelCLI(t, WithEnv( + "COMPOSE_PROJECT_NAME=e2e-start-stop-svc-multiple", + "COMPOSE_FILE=./fixtures/start-stop/compose.yaml")) + t.Cleanup(func() { + cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0") + }) + + cli.RunDockerComposeCmd(t, "up", "-d", "--wait") + + res := cli.RunDockerComposeCmd(t, "stop", "simple", "another") + services := []string{"simple", "another"} + for _, svc := range services { + stopMsg := fmt.Sprintf("Container e2e-start-stop-svc-multiple-%s-1 Stopped", svc) + assert.Assert(t, strings.Contains(res.Stderr(), stopMsg), + fmt.Sprintf("Missing stop message for %s\n%s", svc, res.Combined())) + } + + res = cli.RunDockerComposeCmd(t, "start", "simple", "another") + for _, svc := range services { + startMsg := fmt.Sprintf("Container e2e-start-stop-svc-multiple-%s-1 Started", svc) + assert.Assert(t, strings.Contains(res.Stderr(), startMsg), + fmt.Sprintf("Missing start message for %s\n%s", svc, res.Combined())) + } +} diff --git a/pkg/e2e/start_fail_test.go b/pkg/e2e/up_test.go similarity index 75% rename from pkg/e2e/start_fail_test.go rename to pkg/e2e/up_test.go index dfc8b143..f0be9151 100644 --- a/pkg/e2e/start_fail_test.go +++ b/pkg/e2e/up_test.go @@ -22,12 +22,12 @@ import ( "gotest.tools/v3/icmd" ) -func TestStartFail(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) +func TestUpServiceUnhealthy(t *testing.T) { + c := NewParallelCLI(t) const projectName = "e2e-start-fail" - res := c.RunDockerOrExitError("compose", "-f", "fixtures/start-fail/compose.yaml", "--project-name", projectName, "up", "-d") + res := c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/start-fail/compose.yaml", "--project-name", projectName, "up", "-d") res.Assert(t, icmd.Expected{ExitCode: 1, Err: `container for service "fail" is unhealthy`}) - c.RunDockerComposeCmd("--project-name", projectName, "down") + c.RunDockerComposeCmd(t, "--project-name", projectName, "down") } diff --git a/pkg/e2e/volumes_test.go b/pkg/e2e/volumes_test.go index 57174490..ecce19e1 100644 --- a/pkg/e2e/volumes_test.go +++ b/pkg/e2e/volumes_test.go @@ -18,24 +18,28 @@ package e2e import ( "net/http" + "os" + "path/filepath" "strings" "testing" "time" "gotest.tools/v3/assert" + "gotest.tools/v3/icmd" ) func TestLocalComposeVolume(t *testing.T) { - c := NewParallelE2eCLI(t, binDir) + c := NewParallelCLI(t) const projectName = "compose-e2e-volume" t.Run("up with build and no image name, volume", func(t *testing.T) { // ensure local test run does not reuse previously build image - c.RunDockerOrExitError("rmi", "compose-e2e-volume_nginx") - c.RunDockerOrExitError("volume", "rm", projectName+"_staticVol") - c.RunDockerOrExitError("volume", "rm", "myvolume") - c.RunDockerComposeCmd("--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "-d") + c.RunDockerOrExitError(t, "rmi", "compose-e2e-volume_nginx") + c.RunDockerOrExitError(t, "volume", "rm", projectName+"_staticVol") + c.RunDockerOrExitError(t, "volume", "rm", "myvolume") + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", + "-d") }) t.Run("access bind mount data", func(t *testing.T) { @@ -44,7 +48,7 @@ func TestLocalComposeVolume(t *testing.T) { }) t.Run("check container volume specs", func(t *testing.T) { - res := c.RunDockerCmd("inspect", "compose-e2e-volume-nginx2-1", "--format", "{{ json .Mounts }}") + res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx2-1", "--format", "{{ json .Mounts }}") output := res.Stdout() // nolint assert.Assert(t, strings.Contains(output, `"Destination":"/usr/src/app/node_modules","Driver":"local","Mode":"z","RW":true,"Propagation":""`), output) @@ -52,17 +56,17 @@ func TestLocalComposeVolume(t *testing.T) { }) t.Run("check config content", func(t *testing.T) { - output := c.RunDockerCmd("exec", "compose-e2e-volume-nginx2-1", "cat", "/myconfig").Stdout() + output := c.RunDockerCmd(t, "exec", "compose-e2e-volume-nginx2-1", "cat", "/myconfig").Stdout() assert.Assert(t, strings.Contains(output, `Hello from Nginx container`), output) }) t.Run("check secrets content", func(t *testing.T) { - output := c.RunDockerCmd("exec", "compose-e2e-volume-nginx2-1", "cat", "/run/secrets/mysecret").Stdout() + output := c.RunDockerCmd(t, "exec", "compose-e2e-volume-nginx2-1", "cat", "/run/secrets/mysecret").Stdout() assert.Assert(t, strings.Contains(output, `Hello from Nginx container`), output) }) t.Run("check container bind-mounts specs", func(t *testing.T) { - res := c.RunDockerCmd("inspect", "compose-e2e-volume-nginx-1", "--format", "{{ json .Mounts }}") + res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx-1", "--format", "{{ json .Mounts }}") output := res.Stdout() // nolint assert.Assert(t, strings.Contains(output, `"Type":"bind"`)) @@ -70,21 +74,48 @@ func TestLocalComposeVolume(t *testing.T) { }) t.Run("should inherit anonymous volumes", func(t *testing.T) { - c.RunDockerOrExitError("exec", "compose-e2e-volume-nginx2-1", "touch", "/usr/src/app/node_modules/test") - c.RunDockerOrExitError("compose", "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "--force-recreate", "-d") - c.RunDockerOrExitError("exec", "compose-e2e-volume-nginx2-1", "ls", "/usr/src/app/node_modules/test") + c.RunDockerOrExitError(t, "exec", "compose-e2e-volume-nginx2-1", "touch", "/usr/src/app/node_modules/test") + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "--force-recreate", "-d") + c.RunDockerOrExitError(t, "exec", "compose-e2e-volume-nginx2-1", "ls", "/usr/src/app/node_modules/test") }) t.Run("should renew anonymous volumes", func(t *testing.T) { - c.RunDockerOrExitError("exec", "compose-e2e-volume-nginx2-1", "touch", "/usr/src/app/node_modules/test") - c.RunDockerOrExitError("compose", "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "--force-recreate", "--renew-anon-volumes", "-d") - c.RunDockerOrExitError("exec", "compose-e2e-volume-nginx2-1", "ls", "/usr/src/app/node_modules/test") + c.RunDockerOrExitError(t, "exec", "compose-e2e-volume-nginx2-1", "touch", "/usr/src/app/node_modules/test") + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "--force-recreate", "--renew-anon-volumes", "-d") + c.RunDockerOrExitError(t, "exec", "compose-e2e-volume-nginx2-1", "ls", "/usr/src/app/node_modules/test") }) t.Run("cleanup volume project", func(t *testing.T) { - c.RunDockerComposeCmd("--project-name", projectName, "down", "--volumes") - ls := c.RunDockerCmd("volume", "ls").Stdout() + c.RunDockerComposeCmd(t, "--project-name", projectName, "down", "--volumes") + ls := c.RunDockerCmd(t, "volume", "ls").Stdout() assert.Assert(t, !strings.Contains(ls, projectName+"_staticVol")) assert.Assert(t, !strings.Contains(ls, "myvolume")) }) } + +func TestProjectVolumeBind(t *testing.T) { + if composeStandaloneMode { + t.Skip() + } + c := NewParallelCLI(t) + const projectName = "compose-e2e-project-volume-bind" + + t.Run("up on project volume with bind specification", func(t *testing.T) { + tmpDir, err := os.MkdirTemp("", projectName) + assert.NilError(t, err) + defer os.RemoveAll(tmpDir) // nolint + + c.RunDockerComposeCmd(t, "--project-name", projectName, "down") + + c.RunDockerOrExitError(t, "volume", "rm", "-f", projectName+"_project_data").Assert(t, icmd.Success) + cmd := c.NewCmdWithEnv([]string{"TEST_DIR=" + tmpDir}, + "docker", "compose", "--project-directory", "fixtures/project-volume-bind-test", "--project-name", projectName, "up", "-d") + icmd.RunCmd(cmd).Assert(t, icmd.Success) + defer c.RunDockerComposeCmd(t, "--project-name", projectName, "down") + + c.RunCmd(t, "sh", "-c", "echo SUCCESS > "+filepath.Join(tmpDir, "resultfile")).Assert(t, icmd.Success) + + ret := c.RunDockerOrExitError(t, "exec", "frontend", "bash", "-c", "cat /data/resultfile").Assert(t, icmd.Success) + assert.Assert(t, strings.Contains(ret.Stdout(), "SUCCESS")) + }) +} diff --git a/pkg/mocks/mock_docker_cli.go b/pkg/mocks/mock_docker_cli.go new file mode 100644 index 00000000..5162883d --- /dev/null +++ b/pkg/mocks/mock_docker_cli.go @@ -0,0 +1,301 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/docker/cli/cli/command (interfaces: Cli) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + io "io" + reflect "reflect" + + command "github.com/docker/cli/cli/command" + configfile "github.com/docker/cli/cli/config/configfile" + docker "github.com/docker/cli/cli/context/docker" + store "github.com/docker/cli/cli/context/store" + store0 "github.com/docker/cli/cli/manifest/store" + client "github.com/docker/cli/cli/registry/client" + streams "github.com/docker/cli/cli/streams" + trust "github.com/docker/cli/cli/trust" + client0 "github.com/docker/docker/client" + gomock "github.com/golang/mock/gomock" + client1 "github.com/theupdateframework/notary/client" +) + +// MockCli is a mock of Cli interface. +type MockCli struct { + ctrl *gomock.Controller + recorder *MockCliMockRecorder +} + +// MockCliMockRecorder is the mock recorder for MockCli. +type MockCliMockRecorder struct { + mock *MockCli +} + +// NewMockCli creates a new mock instance. +func NewMockCli(ctrl *gomock.Controller) *MockCli { + mock := &MockCli{ctrl: ctrl} + mock.recorder = &MockCliMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCli) EXPECT() *MockCliMockRecorder { + return m.recorder +} + +// Apply mocks base method. +func (m *MockCli) Apply(arg0 ...command.DockerCliOption) error { + m.ctrl.T.Helper() + varargs := []interface{}{} + for _, a := range arg0 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Apply", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// Apply indicates an expected call of Apply. +func (mr *MockCliMockRecorder) Apply(arg0 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Apply", reflect.TypeOf((*MockCli)(nil).Apply), arg0...) +} + +// BuildKitEnabled mocks base method. +func (m *MockCli) BuildKitEnabled() (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BuildKitEnabled") + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BuildKitEnabled indicates an expected call of BuildKitEnabled. +func (mr *MockCliMockRecorder) BuildKitEnabled() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildKitEnabled", reflect.TypeOf((*MockCli)(nil).BuildKitEnabled)) +} + +// Client mocks base method. +func (m *MockCli) Client() client0.APIClient { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Client") + ret0, _ := ret[0].(client0.APIClient) + return ret0 +} + +// Client indicates an expected call of Client. +func (mr *MockCliMockRecorder) Client() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Client", reflect.TypeOf((*MockCli)(nil).Client)) +} + +// ClientInfo mocks base method. +func (m *MockCli) ClientInfo() command.ClientInfo { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ClientInfo") + ret0, _ := ret[0].(command.ClientInfo) + return ret0 +} + +// ClientInfo indicates an expected call of ClientInfo. +func (mr *MockCliMockRecorder) ClientInfo() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClientInfo", reflect.TypeOf((*MockCli)(nil).ClientInfo)) +} + +// ConfigFile mocks base method. +func (m *MockCli) ConfigFile() *configfile.ConfigFile { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigFile") + ret0, _ := ret[0].(*configfile.ConfigFile) + return ret0 +} + +// ConfigFile indicates an expected call of ConfigFile. +func (mr *MockCliMockRecorder) ConfigFile() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFile", reflect.TypeOf((*MockCli)(nil).ConfigFile)) +} + +// ContentTrustEnabled mocks base method. +func (m *MockCli) ContentTrustEnabled() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ContentTrustEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// ContentTrustEnabled indicates an expected call of ContentTrustEnabled. +func (mr *MockCliMockRecorder) ContentTrustEnabled() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContentTrustEnabled", reflect.TypeOf((*MockCli)(nil).ContentTrustEnabled)) +} + +// ContextStore mocks base method. +func (m *MockCli) ContextStore() store.Store { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ContextStore") + ret0, _ := ret[0].(store.Store) + return ret0 +} + +// ContextStore indicates an expected call of ContextStore. +func (mr *MockCliMockRecorder) ContextStore() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContextStore", reflect.TypeOf((*MockCli)(nil).ContextStore)) +} + +// CurrentContext mocks base method. +func (m *MockCli) CurrentContext() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CurrentContext") + ret0, _ := ret[0].(string) + return ret0 +} + +// CurrentContext indicates an expected call of CurrentContext. +func (mr *MockCliMockRecorder) CurrentContext() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentContext", reflect.TypeOf((*MockCli)(nil).CurrentContext)) +} + +// DefaultVersion mocks base method. +func (m *MockCli) DefaultVersion() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultVersion") + ret0, _ := ret[0].(string) + return ret0 +} + +// DefaultVersion indicates an expected call of DefaultVersion. +func (mr *MockCliMockRecorder) DefaultVersion() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultVersion", reflect.TypeOf((*MockCli)(nil).DefaultVersion)) +} + +// DockerEndpoint mocks base method. +func (m *MockCli) DockerEndpoint() docker.Endpoint { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DockerEndpoint") + ret0, _ := ret[0].(docker.Endpoint) + return ret0 +} + +// DockerEndpoint indicates an expected call of DockerEndpoint. +func (mr *MockCliMockRecorder) DockerEndpoint() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DockerEndpoint", reflect.TypeOf((*MockCli)(nil).DockerEndpoint)) +} + +// Err mocks base method. +func (m *MockCli) Err() io.Writer { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Err") + ret0, _ := ret[0].(io.Writer) + return ret0 +} + +// Err indicates an expected call of Err. +func (mr *MockCliMockRecorder) Err() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Err", reflect.TypeOf((*MockCli)(nil).Err)) +} + +// In mocks base method. +func (m *MockCli) In() *streams.In { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "In") + ret0, _ := ret[0].(*streams.In) + return ret0 +} + +// In indicates an expected call of In. +func (mr *MockCliMockRecorder) In() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "In", reflect.TypeOf((*MockCli)(nil).In)) +} + +// ManifestStore mocks base method. +func (m *MockCli) ManifestStore() store0.Store { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ManifestStore") + ret0, _ := ret[0].(store0.Store) + return ret0 +} + +// ManifestStore indicates an expected call of ManifestStore. +func (mr *MockCliMockRecorder) ManifestStore() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ManifestStore", reflect.TypeOf((*MockCli)(nil).ManifestStore)) +} + +// NotaryClient mocks base method. +func (m *MockCli) NotaryClient(arg0 trust.ImageRefAndAuth, arg1 []string) (client1.Repository, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NotaryClient", arg0, arg1) + ret0, _ := ret[0].(client1.Repository) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NotaryClient indicates an expected call of NotaryClient. +func (mr *MockCliMockRecorder) NotaryClient(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NotaryClient", reflect.TypeOf((*MockCli)(nil).NotaryClient), arg0, arg1) +} + +// Out mocks base method. +func (m *MockCli) Out() *streams.Out { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Out") + ret0, _ := ret[0].(*streams.Out) + return ret0 +} + +// Out indicates an expected call of Out. +func (mr *MockCliMockRecorder) Out() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Out", reflect.TypeOf((*MockCli)(nil).Out)) +} + +// RegistryClient mocks base method. +func (m *MockCli) RegistryClient(arg0 bool) client.RegistryClient { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RegistryClient", arg0) + ret0, _ := ret[0].(client.RegistryClient) + return ret0 +} + +// RegistryClient indicates an expected call of RegistryClient. +func (mr *MockCliMockRecorder) RegistryClient(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegistryClient", reflect.TypeOf((*MockCli)(nil).RegistryClient), arg0) +} + +// ServerInfo mocks base method. +func (m *MockCli) ServerInfo() command.ServerInfo { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ServerInfo") + ret0, _ := ret[0].(command.ServerInfo) + return ret0 +} + +// ServerInfo indicates an expected call of ServerInfo. +func (mr *MockCliMockRecorder) ServerInfo() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerInfo", reflect.TypeOf((*MockCli)(nil).ServerInfo)) +} + +// SetIn mocks base method. +func (m *MockCli) SetIn(arg0 *streams.In) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetIn", arg0) +} + +// SetIn indicates an expected call of SetIn. +func (mr *MockCliMockRecorder) SetIn(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIn", reflect.TypeOf((*MockCli)(nil).SetIn), arg0) +} diff --git a/pkg/mocks/mock_docker_compose_api.go b/pkg/mocks/mock_docker_compose_api.go new file mode 100644 index 00000000..c33c1140 --- /dev/null +++ b/pkg/mocks/mock_docker_compose_api.go @@ -0,0 +1,441 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./pkg/api/api.go + +// Package mocks is a generated GoMock package. +package mocks + +import ( + context "context" + reflect "reflect" + + types "github.com/compose-spec/compose-go/types" + api "github.com/docker/compose/v2/pkg/api" + gomock "github.com/golang/mock/gomock" +) + +// MockService is a mock of Service interface. +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder +} + +// MockServiceMockRecorder is the mock recorder for MockService. +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance. +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// Build mocks base method. +func (m *MockService) Build(ctx context.Context, project *types.Project, options api.BuildOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Build", ctx, project, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Build indicates an expected call of Build. +func (mr *MockServiceMockRecorder) Build(ctx, project, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Build", reflect.TypeOf((*MockService)(nil).Build), ctx, project, options) +} + +// Convert mocks base method. +func (m *MockService) Convert(ctx context.Context, project *types.Project, options api.ConvertOptions) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Convert", ctx, project, options) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Convert indicates an expected call of Convert. +func (mr *MockServiceMockRecorder) Convert(ctx, project, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Convert", reflect.TypeOf((*MockService)(nil).Convert), ctx, project, options) +} + +// Copy mocks base method. +func (m *MockService) Copy(ctx context.Context, projectName string, options api.CopyOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Copy", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Copy indicates an expected call of Copy. +func (mr *MockServiceMockRecorder) Copy(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Copy", reflect.TypeOf((*MockService)(nil).Copy), ctx, projectName, options) +} + +// Create mocks base method. +func (m *MockService) Create(ctx context.Context, project *types.Project, options api.CreateOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, project, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockServiceMockRecorder) Create(ctx, project, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockService)(nil).Create), ctx, project, options) +} + +// Down mocks base method. +func (m *MockService) Down(ctx context.Context, projectName string, options api.DownOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Down", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Down indicates an expected call of Down. +func (mr *MockServiceMockRecorder) Down(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Down", reflect.TypeOf((*MockService)(nil).Down), ctx, projectName, options) +} + +// Events mocks base method. +func (m *MockService) Events(ctx context.Context, projectName string, options api.EventsOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Events", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Events indicates an expected call of Events. +func (mr *MockServiceMockRecorder) Events(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Events", reflect.TypeOf((*MockService)(nil).Events), ctx, projectName, options) +} + +// Exec mocks base method. +func (m *MockService) Exec(ctx context.Context, projectName string, options api.RunOptions) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Exec", ctx, projectName, options) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Exec indicates an expected call of Exec. +func (mr *MockServiceMockRecorder) Exec(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockService)(nil).Exec), ctx, projectName, options) +} + +// Images mocks base method. +func (m *MockService) Images(ctx context.Context, projectName string, options api.ImagesOptions) ([]api.ImageSummary, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Images", ctx, projectName, options) + ret0, _ := ret[0].([]api.ImageSummary) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Images indicates an expected call of Images. +func (mr *MockServiceMockRecorder) Images(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Images", reflect.TypeOf((*MockService)(nil).Images), ctx, projectName, options) +} + +// Kill mocks base method. +func (m *MockService) Kill(ctx context.Context, projectName string, options api.KillOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Kill", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Kill indicates an expected call of Kill. +func (mr *MockServiceMockRecorder) Kill(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Kill", reflect.TypeOf((*MockService)(nil).Kill), ctx, projectName, options) +} + +// List mocks base method. +func (m *MockService) List(ctx context.Context, options api.ListOptions) ([]api.Stack, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "List", ctx, options) + ret0, _ := ret[0].([]api.Stack) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// List indicates an expected call of List. +func (mr *MockServiceMockRecorder) List(ctx, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockService)(nil).List), ctx, options) +} + +// Logs mocks base method. +func (m *MockService) Logs(ctx context.Context, projectName string, consumer api.LogConsumer, options api.LogOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Logs", ctx, projectName, consumer, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Logs indicates an expected call of Logs. +func (mr *MockServiceMockRecorder) Logs(ctx, projectName, consumer, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Logs", reflect.TypeOf((*MockService)(nil).Logs), ctx, projectName, consumer, options) +} + +// Pause mocks base method. +func (m *MockService) Pause(ctx context.Context, projectName string, options api.PauseOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Pause", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Pause indicates an expected call of Pause. +func (mr *MockServiceMockRecorder) Pause(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pause", reflect.TypeOf((*MockService)(nil).Pause), ctx, projectName, options) +} + +// Port mocks base method. +func (m *MockService) Port(ctx context.Context, projectName, service string, port int, options api.PortOptions) (string, int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Port", ctx, projectName, service, port, options) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(int) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// Port indicates an expected call of Port. +func (mr *MockServiceMockRecorder) Port(ctx, projectName, service, port, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Port", reflect.TypeOf((*MockService)(nil).Port), ctx, projectName, service, port, options) +} + +// Ps mocks base method. +func (m *MockService) Ps(ctx context.Context, projectName string, options api.PsOptions) ([]api.ContainerSummary, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Ps", ctx, projectName, options) + ret0, _ := ret[0].([]api.ContainerSummary) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Ps indicates an expected call of Ps. +func (mr *MockServiceMockRecorder) Ps(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ps", reflect.TypeOf((*MockService)(nil).Ps), ctx, projectName, options) +} + +// Pull mocks base method. +func (m *MockService) Pull(ctx context.Context, project *types.Project, options api.PullOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Pull", ctx, project, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Pull indicates an expected call of Pull. +func (mr *MockServiceMockRecorder) Pull(ctx, project, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pull", reflect.TypeOf((*MockService)(nil).Pull), ctx, project, options) +} + +// Push mocks base method. +func (m *MockService) Push(ctx context.Context, project *types.Project, options api.PushOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Push", ctx, project, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Push indicates an expected call of Push. +func (mr *MockServiceMockRecorder) Push(ctx, project, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Push", reflect.TypeOf((*MockService)(nil).Push), ctx, project, options) +} + +// Remove mocks base method. +func (m *MockService) Remove(ctx context.Context, projectName string, options api.RemoveOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Remove", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Remove indicates an expected call of Remove. +func (mr *MockServiceMockRecorder) Remove(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remove", reflect.TypeOf((*MockService)(nil).Remove), ctx, projectName, options) +} + +// Restart mocks base method. +func (m *MockService) Restart(ctx context.Context, projectName string, options api.RestartOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Restart", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Restart indicates an expected call of Restart. +func (mr *MockServiceMockRecorder) Restart(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Restart", reflect.TypeOf((*MockService)(nil).Restart), ctx, projectName, options) +} + +// RunOneOffContainer mocks base method. +func (m *MockService) RunOneOffContainer(ctx context.Context, project *types.Project, opts api.RunOptions) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RunOneOffContainer", ctx, project, opts) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RunOneOffContainer indicates an expected call of RunOneOffContainer. +func (mr *MockServiceMockRecorder) RunOneOffContainer(ctx, project, opts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunOneOffContainer", reflect.TypeOf((*MockService)(nil).RunOneOffContainer), ctx, project, opts) +} + +// Start mocks base method. +func (m *MockService) Start(ctx context.Context, projectName string, options api.StartOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Start", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Start indicates an expected call of Start. +func (mr *MockServiceMockRecorder) Start(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockService)(nil).Start), ctx, projectName, options) +} + +// Stop mocks base method. +func (m *MockService) Stop(ctx context.Context, projectName string, options api.StopOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stop", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Stop indicates an expected call of Stop. +func (mr *MockServiceMockRecorder) Stop(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockService)(nil).Stop), ctx, projectName, options) +} + +// Top mocks base method. +func (m *MockService) Top(ctx context.Context, projectName string, services []string) ([]api.ContainerProcSummary, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Top", ctx, projectName, services) + ret0, _ := ret[0].([]api.ContainerProcSummary) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Top indicates an expected call of Top. +func (mr *MockServiceMockRecorder) Top(ctx, projectName, services interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Top", reflect.TypeOf((*MockService)(nil).Top), ctx, projectName, services) +} + +// UnPause mocks base method. +func (m *MockService) UnPause(ctx context.Context, projectName string, options api.PauseOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UnPause", ctx, projectName, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// UnPause indicates an expected call of UnPause. +func (mr *MockServiceMockRecorder) UnPause(ctx, projectName, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnPause", reflect.TypeOf((*MockService)(nil).UnPause), ctx, projectName, options) +} + +// Up mocks base method. +func (m *MockService) Up(ctx context.Context, project *types.Project, options api.UpOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Up", ctx, project, options) + ret0, _ := ret[0].(error) + return ret0 +} + +// Up indicates an expected call of Up. +func (mr *MockServiceMockRecorder) Up(ctx, project, options interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Up", reflect.TypeOf((*MockService)(nil).Up), ctx, project, options) +} + +// MockLogConsumer is a mock of LogConsumer interface. +type MockLogConsumer struct { + ctrl *gomock.Controller + recorder *MockLogConsumerMockRecorder +} + +// MockLogConsumerMockRecorder is the mock recorder for MockLogConsumer. +type MockLogConsumerMockRecorder struct { + mock *MockLogConsumer +} + +// NewMockLogConsumer creates a new mock instance. +func NewMockLogConsumer(ctrl *gomock.Controller) *MockLogConsumer { + mock := &MockLogConsumer{ctrl: ctrl} + mock.recorder = &MockLogConsumerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLogConsumer) EXPECT() *MockLogConsumerMockRecorder { + return m.recorder +} + +// Log mocks base method. +func (m *MockLogConsumer) Log(service, container, message string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Log", service, container, message) +} + +// Log indicates an expected call of Log. +func (mr *MockLogConsumerMockRecorder) Log(service, container, message interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Log", reflect.TypeOf((*MockLogConsumer)(nil).Log), service, container, message) +} + +// Register mocks base method. +func (m *MockLogConsumer) Register(container string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Register", container) +} + +// Register indicates an expected call of Register. +func (mr *MockLogConsumerMockRecorder) Register(container interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Register", reflect.TypeOf((*MockLogConsumer)(nil).Register), container) +} + +// Status mocks base method. +func (m *MockLogConsumer) Status(container, msg string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Status", container, msg) +} + +// Status indicates an expected call of Status. +func (mr *MockLogConsumerMockRecorder) Status(container, msg interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockLogConsumer)(nil).Status), container, msg) +} diff --git a/pkg/progress/tty.go b/pkg/progress/tty.go index 25cb7c78..a94d659d 100644 --- a/pkg/progress/tty.go +++ b/pkg/progress/tty.go @@ -83,7 +83,10 @@ func (w *ttyWriter) Event(e Event) { last.Status = e.Status last.Text = e.Text last.StatusText = e.StatusText - last.ParentID = e.ParentID + // allow set/unset of parent, but not swapping otherwise prompt is flickering + if last.ParentID == "" || e.ParentID == "" { + last.ParentID = e.ParentID + } w.events[e.ID] = last } else { e.startTime = time.Now() diff --git a/pkg/progress/writer.go b/pkg/progress/writer.go index 352ecb03..2914364e 100644 --- a/pkg/progress/writer.go +++ b/pkg/progress/writer.go @@ -90,28 +90,45 @@ func RunWithStatus(ctx context.Context, pf progressFuncWithStatus) (string, erro return result, err } +const ( + // ModeAuto detect console capabilities + ModeAuto = "auto" + // ModeTTY use terminal capability for advanced rendering + ModeTTY = "tty" + // ModePlain dump raw events to output + ModePlain = "plain" +) + +// Mode define how progress should be rendered, either as ModePlain or ModeTTY +var Mode = ModeAuto + // NewWriter returns a new multi-progress writer func NewWriter(out console.File) (Writer, error) { _, isTerminal := term.GetFdInfo(out) - - if isTerminal { - con, err := console.ConsoleFromFile(out) - if err != nil { - return nil, err - } - - return &ttyWriter{ - out: con, - eventIDs: []string{}, - events: map[string]Event{}, - repeated: false, - done: make(chan bool), - mtx: &sync.Mutex{}, - }, nil + if Mode == ModeAuto && isTerminal { + return newTTYWriter(out) + } + if Mode == ModeTTY { + return newTTYWriter(out) } - return &plainWriter{ out: out, done: make(chan bool), }, nil } + +func newTTYWriter(out console.File) (Writer, error) { + con, err := console.ConsoleFromFile(out) + if err != nil { + return nil, err + } + + return &ttyWriter{ + out: con, + eventIDs: []string{}, + events: map[string]Event{}, + repeated: false, + done: make(chan bool), + mtx: &sync.Mutex{}, + }, nil +} diff --git a/pkg/utils/scan_suggest.go b/pkg/utils/scan_suggest.go index 93059f80..6452a577 100644 --- a/pkg/utils/scan_suggest.go +++ b/pkg/utils/scan_suggest.go @@ -19,7 +19,6 @@ package utils import ( "encoding/json" "fmt" - "io/ioutil" "os" "path/filepath" @@ -57,7 +56,7 @@ func scanAlreadyInvoked() bool { type scanOptin struct { Optin bool `json:"optin"` } - data, err := ioutil.ReadFile(filename) + data, err := os.ReadFile(filename) if err != nil { return true } diff --git a/pkg/utils/stringutils.go b/pkg/utils/stringutils.go index fd2dd477..01dd4238 100644 --- a/pkg/utils/stringutils.go +++ b/pkg/utils/stringutils.go @@ -16,6 +16,11 @@ package utils +import ( + "strconv" + "strings" +) + // StringContains check if an array contains a specific value func StringContains(array []string, needle string) bool { for _, val := range array { @@ -25,3 +30,9 @@ func StringContains(array []string, needle string) bool { } return false } + +// StringToBool converts a string to a boolean ignoring errors +func StringToBool(s string) bool { + b, _ := strconv.ParseBool(strings.ToLower(strings.TrimSpace(s))) + return b +}