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
+}