mirror of
https://github.com/docker/compose.git
synced 2026-02-14 20:49:24 +08:00
Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1aceba655 | ||
|
|
a39cf75e86 | ||
|
|
5b0dcc5a44 | ||
|
|
46ba9c99ce | ||
|
|
1148b6765a | ||
|
|
5c5d30c674 | ||
|
|
2068eceee4 | ||
|
|
36fa8d4e71 | ||
|
|
69985b8b89 | ||
|
|
2384635ee1 | ||
|
|
587dba1167 | ||
|
|
2ba5e4c1d0 | ||
|
|
b1a26dac1d | ||
|
|
0ab21a2080 | ||
|
|
5e77ae9247 | ||
|
|
f557220140 | ||
|
|
8e1b32365e | ||
|
|
a1b7bee094 | ||
|
|
7cb1f8baf2 | ||
|
|
cb01186c2b | ||
|
|
efea084df6 | ||
|
|
9c4efbdd92 | ||
|
|
8ea7c9e0d2 | ||
|
|
c16943609c | ||
|
|
254a94b07d | ||
|
|
cf608fa954 | ||
|
|
426377a4c9 | ||
|
|
43c3f54598 | ||
|
|
493f6c8055 | ||
|
|
c1a9ffa07e | ||
|
|
646a8fc0e8 | ||
|
|
2945532f97 | ||
|
|
e5cd265abb | ||
|
|
d646d757a2 | ||
|
|
71237ef62b | ||
|
|
0d905a896d | ||
|
|
b847c7f5a4 | ||
|
|
5e3d8f671d | ||
|
|
6727908803 | ||
|
|
5661fd1bfe | ||
|
|
4cd61957ed | ||
|
|
0d4cbbdbc9 | ||
|
|
9631a49daa | ||
|
|
328ca3f239 | ||
|
|
e1bbfc6376 | ||
|
|
616bba0afd | ||
|
|
ee6e3c2a44 | ||
|
|
c7e31a3c15 | ||
|
|
704a9fd337 | ||
|
|
d9e0e42d95 | ||
|
|
c48e3c4a4f | ||
|
|
dd0803dba1 | ||
|
|
39008c539c | ||
|
|
6ab41d629f | ||
|
|
6c345b3755 | ||
|
|
b8773ad1c5 | ||
|
|
1ffa194e12 | ||
|
|
b92981015e | ||
|
|
af87f10650 | ||
|
|
5e1d3f2b41 | ||
|
|
3d0207ebc8 | ||
|
|
16a7c20960 | ||
|
|
818bc3c34a | ||
|
|
cf3e686d8c | ||
|
|
38bc6d5dbc | ||
|
|
4a2d4c44b2 | ||
|
|
0b6ce6ee42 | ||
|
|
034458dac7 | ||
|
|
ae16bbbf05 | ||
|
|
eb5f01baf4 | ||
|
|
d13ad1f997 | ||
|
|
9b4d577c65 | ||
|
|
b30978fb40 | ||
|
|
14b43c1a93 | ||
|
|
9dd081b92e | ||
|
|
2c0b023273 | ||
|
|
599e4b242a | ||
|
|
fe8c2780c8 | ||
|
|
a345515f91 | ||
|
|
8967df7a91 | ||
|
|
4f694919ff | ||
|
|
6ecab95775 | ||
|
|
12e0ac898a | ||
|
|
a6b7d78575 | ||
|
|
991901f2ef | ||
|
|
bd74a9260d | ||
|
|
2d971fc97d | ||
|
|
78f3361921 | ||
|
|
44d21280e7 | ||
|
|
cd743d17ba | ||
|
|
ff2ff18cdc |
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -138,7 +138,6 @@ jobs:
|
||||
mode:
|
||||
- plugin
|
||||
- standalone
|
||||
- cucumber
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
@@ -198,11 +197,6 @@ jobs:
|
||||
rm -f /usr/local/bin/docker-compose
|
||||
cp bin/build/docker-compose /usr/local/bin
|
||||
make e2e-compose-standalone
|
||||
-
|
||||
name: Run cucumber tests
|
||||
if: ${{ matrix.mode == 'cucumber'}}
|
||||
run: |
|
||||
make test-cucumber
|
||||
|
||||
coverage:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
58
.github/workflows/codeql.yml
vendored
Normal file
58
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: codeql
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
paths-ignore:
|
||||
- '**/*.md'
|
||||
- '**/*.txt'
|
||||
- '**/*.yaml'
|
||||
- '**/*_test.go'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'main'
|
||||
paths-ignore:
|
||||
- '**/*.md'
|
||||
- '**/*.txt'
|
||||
- '**/*.yaml'
|
||||
- '**/*_test.go'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: 'ubuntu-latest'
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language:
|
||||
- go
|
||||
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
check-latest: true
|
||||
-
|
||||
name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
-
|
||||
name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
-
|
||||
name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
42
.github/workflows/docs-upstream.yml
vendored
Normal file
42
.github/workflows/docs-upstream.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# this workflow runs the remote validate bake target from docker/docs
|
||||
# to check if yaml reference docs used in this repo are valid
|
||||
name: docs-upstream
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'v[0-9]*'
|
||||
paths:
|
||||
- '.github/workflows/docs-upstream.yml'
|
||||
- 'docs/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/docs-upstream.yml'
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
docs-yaml:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Upload reference YAML docs
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docs-yaml
|
||||
path: docs/reference
|
||||
retention-days: 1
|
||||
|
||||
validate:
|
||||
uses: docker/docs/.github/workflows/validate-upstream.yml@main
|
||||
needs:
|
||||
- docs-yaml
|
||||
with:
|
||||
module-name: docker/compose
|
||||
56
.github/workflows/docs.yml
vendored
56
.github/workflows/docs.yml
vendored
@@ -1,56 +0,0 @@
|
||||
name: Docs
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions: {}
|
||||
jobs:
|
||||
open-pr:
|
||||
permissions:
|
||||
contents: write # to create branch (peter-evans/create-pull-request)
|
||||
pull-requests: write # to create a PR (peter-evans/create-pull-request)
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout docs repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.GHPAT_DOCS_DISPATCH }}
|
||||
repository: docker/docs
|
||||
ref: main
|
||||
-
|
||||
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 }}
|
||||
push-to-fork: docker-tools-robot/docker.github.io
|
||||
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 }}`
|
||||
draft: false
|
||||
@@ -7,6 +7,7 @@ linters:
|
||||
enable:
|
||||
- depguard
|
||||
- errcheck
|
||||
- errorlint
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
@@ -40,6 +41,11 @@ linters-settings:
|
||||
desc: 'compose-go uses yaml.v3'
|
||||
gomodguard:
|
||||
blocked:
|
||||
modules:
|
||||
- github.com/pkg/errors:
|
||||
recommendations:
|
||||
- errors
|
||||
- fmt
|
||||
versions:
|
||||
- github.com/distribution/distribution:
|
||||
reason: "use distribution/reference"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ARG GO_VERSION=1.21.1
|
||||
ARG GO_VERSION=1.21.4
|
||||
ARG XX_VERSION=1.2.1
|
||||
ARG GOLANGCI_LINT_VERSION=v1.54.2
|
||||
ARG ADDLICENSE_VERSION=v1.0.0
|
||||
@@ -192,9 +192,3 @@ RUN --mount=from=binary \
|
||||
|
||||
FROM scratch AS release
|
||||
COPY --from=releaser /out/ /
|
||||
|
||||
# docs-reference is a target used as remote context to update docs on release
|
||||
# with latest changes on docs.docker.com.
|
||||
# see open-pr job in .github/workflows/docs.yml for more details
|
||||
FROM scratch AS docs-reference
|
||||
COPY docs/reference/*.yaml .
|
||||
|
||||
16
Makefile
16
Makefile
@@ -32,9 +32,13 @@ endif
|
||||
BUILD_FLAGS?=
|
||||
TEST_FLAGS?=
|
||||
E2E_TEST?=
|
||||
ifeq ($(E2E_TEST),)
|
||||
else
|
||||
TEST_FLAGS=-run $(E2E_TEST)
|
||||
ifneq ($(E2E_TEST),)
|
||||
TEST_FLAGS:=$(TEST_FLAGS) -run '$(E2E_TEST)'
|
||||
endif
|
||||
|
||||
EXCLUDE_E2E_TESTS?=
|
||||
ifneq ($(EXCLUDE_E2E_TESTS),)
|
||||
TEST_FLAGS:=$(TEST_FLAGS) -skip '$(EXCLUDE_E2E_TESTS)'
|
||||
endif
|
||||
|
||||
BUILDX_CMD ?= docker buildx
|
||||
@@ -71,16 +75,12 @@ install: binary
|
||||
|
||||
.PHONY: e2e-compose
|
||||
e2e-compose: ## Run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test
|
||||
go test $(TEST_FLAGS) -count=1 ./pkg/e2e
|
||||
go test -v $(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) -v -count=1 -parallel=1 --tags=standalone ./pkg/e2e
|
||||
|
||||
.PHONY: test-cucumber
|
||||
test-cucumber:
|
||||
go test $(TEST_FLAGS) -v -count=1 -parallel=1 ./e2e
|
||||
|
||||
.PHONY: build-and-e2e-compose
|
||||
build-and-e2e-compose: build e2e-compose ## Compile the compose cli-plugin and run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
opts.ssh = "default"
|
||||
}
|
||||
if cmd.Flags().Changed("progress") && opts.ssh == "" {
|
||||
fmt.Fprint(os.Stderr, "--progress is a global compose flag, better use `docker compose --progress xx build ...")
|
||||
fmt.Fprint(os.Stderr, "--progress is a global compose flag, better use `docker compose --progress xx build ...\n")
|
||||
}
|
||||
return runBuild(ctx, dockerCli, backend, opts, args)
|
||||
}),
|
||||
|
||||
@@ -18,6 +18,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
@@ -37,7 +38,6 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/remote"
|
||||
"github.com/morikuni/aec"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
@@ -60,6 +60,8 @@ const (
|
||||
ComposeRemoveOrphans = "COMPOSE_REMOVE_ORPHANS"
|
||||
// ComposeIgnoreOrphans ignore "orphaned" containers
|
||||
ComposeIgnoreOrphans = "COMPOSE_IGNORE_ORPHANS"
|
||||
// ComposeEnvFiles defines the env files to use if --env-file isn't used
|
||||
ComposeEnvFiles = "COMPOSE_ENV_FILES"
|
||||
)
|
||||
|
||||
// Command defines a compose CLI command as a func with args
|
||||
@@ -81,6 +83,8 @@ func AdaptCmd(fn CobraCommand) func(cmd *cobra.Command, args []string) error {
|
||||
go func() {
|
||||
<-s
|
||||
cancel()
|
||||
signal.Stop(s)
|
||||
close(s)
|
||||
}()
|
||||
}
|
||||
err := fn(ctx, cmd, args)
|
||||
@@ -200,11 +204,7 @@ func (o *ProjectOptions) toProjectName(dockerCli command.Cli) (string, error) {
|
||||
|
||||
func (o *ProjectOptions) ToProject(dockerCli command.Cli, services []string, po ...cli.ProjectOptionsFn) (*types.Project, error) {
|
||||
if !o.Offline {
|
||||
var err error
|
||||
po, err = o.configureRemoteLoaders(dockerCli, po)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
po = o.configureRemoteLoaders(dockerCli, po)
|
||||
}
|
||||
|
||||
options, err := o.toProjectOptions(po...)
|
||||
@@ -251,31 +251,12 @@ func (o *ProjectOptions) ToProject(dockerCli command.Cli, services []string, po
|
||||
return project, err
|
||||
}
|
||||
|
||||
func (o *ProjectOptions) configureRemoteLoaders(dockerCli command.Cli, po []cli.ProjectOptionsFn) ([]cli.ProjectOptionsFn, error) {
|
||||
enabled, err := remote.GitRemoteLoaderEnabled()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if enabled {
|
||||
git, err := remote.NewGitRemoteLoader(o.Offline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
po = append(po, cli.WithResourceLoader(git))
|
||||
}
|
||||
func (o *ProjectOptions) configureRemoteLoaders(dockerCli command.Cli, po []cli.ProjectOptionsFn) []cli.ProjectOptionsFn {
|
||||
git := remote.NewGitRemoteLoader(o.Offline)
|
||||
oci := remote.NewOCIRemoteLoader(dockerCli, o.Offline)
|
||||
|
||||
enabled, err = remote.OCIRemoteLoaderEnabled()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if enabled {
|
||||
git, err := remote.NewOCIRemoteLoader(dockerCli, o.Offline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
po = append(po, cli.WithResourceLoader(git))
|
||||
}
|
||||
return po, nil
|
||||
po = append(po, cli.WithResourceLoader(git), cli.WithResourceLoader(oci))
|
||||
return po
|
||||
}
|
||||
|
||||
func (o *ProjectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
|
||||
@@ -517,6 +498,11 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
|
||||
}
|
||||
|
||||
func setEnvWithDotEnv(prjOpts *ProjectOptions) error {
|
||||
if len(prjOpts.EnvFiles) == 0 {
|
||||
if envFiles := os.Getenv(ComposeEnvFiles); envFiles != "" {
|
||||
prjOpts.EnvFiles = strings.Split(envFiles, ",")
|
||||
}
|
||||
}
|
||||
options, err := prjOpts.toProjectOptions()
|
||||
if err != nil {
|
||||
return compose.WrapComposeError(err)
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
|
||||
func TestFilterServices(t *testing.T) {
|
||||
p := &types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "foo",
|
||||
Links: []string{"bar"},
|
||||
|
||||
@@ -186,20 +186,27 @@ func runHash(ctx context.Context, dockerCli command.Cli, opts configOptions) err
|
||||
return err
|
||||
}
|
||||
|
||||
if len(services) > 0 {
|
||||
err = project.ForServices(services, types.IgnoreDependencies)
|
||||
if err := applyPlatforms(project, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(services) == 0 {
|
||||
services = project.ServiceNames()
|
||||
}
|
||||
|
||||
sorted := services
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
return sorted[i] < sorted[j]
|
||||
})
|
||||
|
||||
for _, name := range sorted {
|
||||
s, err := project.GetService(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
sorted := project.Services
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
return sorted[i].Name < sorted[j].Name
|
||||
})
|
||||
|
||||
for _, s := range sorted {
|
||||
hash, err := compose.ServiceHash(s)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -73,7 +74,7 @@ func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVar(&opts.Build, "build", false, "Build images before starting containers.")
|
||||
flags.BoolVar(&opts.noBuild, "no-build", false, "Don't build an image, even if it's policy.")
|
||||
flags.StringVar(&opts.Pull, "pull", "policy", `Pull image before running ("always"|"policy"|"never")`)
|
||||
flags.StringVar(&opts.Pull, "pull", "policy", `Pull image before running ("always"|"missing"|"never"|"build")`)
|
||||
flags.BoolVar(&opts.forceRecreate, "force-recreate", false, "Recreate containers even if their configuration and image haven't changed.")
|
||||
flags.BoolVar(&opts.noRecreate, "no-recreate", false, "If containers already exist, don't recreate them. Incompatible with --force-recreate.")
|
||||
flags.BoolVar(&opts.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file.")
|
||||
@@ -138,6 +139,9 @@ func (opts createOptions) GetTimeout() *time.Duration {
|
||||
|
||||
func (opts createOptions) Apply(project *types.Project) error {
|
||||
if opts.pullChanged {
|
||||
if !opts.isPullPolicyValid() {
|
||||
return fmt.Errorf("invalid --pull option %q", opts.Pull)
|
||||
}
|
||||
for i, service := range project.Services {
|
||||
service.PullPolicy = opts.Pull
|
||||
project.Services[i] = service
|
||||
@@ -187,3 +191,9 @@ func (opts createOptions) Apply(project *types.Project) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (opts createOptions) isPullPolicyValid() bool {
|
||||
pullPolicies := []string{types.PullPolicyAlways, types.PullPolicyNever, types.PullPolicyBuild,
|
||||
types.PullPolicyMissing, types.PullPolicyIfNotPresent}
|
||||
return slices.Contains(pullPolicies, opts.Pull)
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
}
|
||||
|
||||
func runDown(ctx context.Context, dockerCli command.Cli, backend api.Service, opts downOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli)
|
||||
project, name, err := opts.projectOrName(dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -72,12 +72,6 @@ func runList(ctx context.Context, dockerCli command.Cli, backend api.Service, ls
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if lsOpts.Quiet {
|
||||
for _, s := range stackList {
|
||||
fmt.Fprintln(dockerCli.Out(), s.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if filters.Len() > 0 {
|
||||
var filtered []api.Stack
|
||||
@@ -90,6 +84,13 @@ func runList(ctx context.Context, dockerCli command.Cli, backend api.Service, ls
|
||||
stackList = filtered
|
||||
}
|
||||
|
||||
if lsOpts.Quiet {
|
||||
for _, s := range stackList {
|
||||
fmt.Fprintln(dockerCli.Out(), s.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
view := viewFromStackList(stackList)
|
||||
return formatter.Print(view, lsOpts.Format, dockerCli.Out(), func(w io.Writer) {
|
||||
for _, stack := range view {
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
func TestApplyPlatforms_InferFromRuntime(t *testing.T) {
|
||||
makeProject := func() *types.Project {
|
||||
return &types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
@@ -64,7 +64,7 @@ func TestApplyPlatforms_DockerDefaultPlatform(t *testing.T) {
|
||||
Environment: map[string]string{
|
||||
"DOCKER_DEFAULT_PLATFORM": "linux/amd64",
|
||||
},
|
||||
Services: []types.ServiceConfig{
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
@@ -100,7 +100,7 @@ func TestApplyPlatforms_UnsupportedPlatform(t *testing.T) {
|
||||
Environment: map[string]string{
|
||||
"DOCKER_DEFAULT_PLATFORM": "commodore/64",
|
||||
},
|
||||
Services: []types.ServiceConfig{
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
|
||||
@@ -18,6 +18,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -29,7 +30,6 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
cliformatter "github.com/docker/cli/cli/command/formatter"
|
||||
cliflags "github.com/docker/cli/cli/flags"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -41,6 +41,7 @@ type psOptions struct {
|
||||
Services bool
|
||||
Filter string
|
||||
Status []string
|
||||
noTrunc bool
|
||||
}
|
||||
|
||||
func (p *psOptions) parseFilter() error {
|
||||
@@ -84,6 +85,7 @@ func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *c
|
||||
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.BoolVar(&opts.noTrunc, "no-trunc", false, "Don't truncate output")
|
||||
return psCmd
|
||||
}
|
||||
|
||||
@@ -145,6 +147,7 @@ func runPs(ctx context.Context, dockerCli command.Cli, backend api.Service, serv
|
||||
containerCtx := cliformatter.Context{
|
||||
Output: dockerCli.Out(),
|
||||
Format: formatter.NewContainerFormat(opts.Format, opts.Quiet, false),
|
||||
Trunc: !opts.noTrunc,
|
||||
}
|
||||
return formatter.ContainerWrite(containerCtx, containers)
|
||||
}
|
||||
|
||||
@@ -25,11 +25,16 @@ import (
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
type publishOptions struct {
|
||||
*ProjectOptions
|
||||
resolveImageDigests bool
|
||||
}
|
||||
|
||||
func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
opts := pushOptions{
|
||||
opts := publishOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
publishCmd := &cobra.Command{
|
||||
cmd := &cobra.Command{
|
||||
Use: "publish [OPTIONS] [REPOSITORY]",
|
||||
Short: "Publish compose application",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
@@ -37,14 +42,18 @@ func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||
}),
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
return publishCmd
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVar(&opts.resolveImageDigests, "resolve-image-digests", false, "Pin image tags to digests.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Service, opts pushOptions, repository string) error {
|
||||
func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Service, opts publishOptions, repository string) error {
|
||||
project, err := opts.ToProject(dockerCli, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.Publish(ctx, project, repository, api.PublishOptions{})
|
||||
return backend.Publish(ctx, project, repository, api.PublishOptions{
|
||||
ResolveImageDigests: opts.resolveImageDigests,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
|
||||
func TestApplyPullOptions(t *testing.T) {
|
||||
project := &types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "must-build",
|
||||
// No image, local build only
|
||||
|
||||
@@ -80,11 +80,10 @@ func (options runOptions) apply(project *types.Project) error {
|
||||
|
||||
target.Tty = !options.noTty
|
||||
target.StdinOpen = options.interactive
|
||||
|
||||
// --service-ports and --publish are incompatible
|
||||
if !options.servicePorts {
|
||||
target.Ports = []types.ServicePortConfig{}
|
||||
}
|
||||
if len(options.publish) > 0 {
|
||||
target.Ports = []types.ServicePortConfig{}
|
||||
for _, p := range options.publish {
|
||||
config, err := types.ParsePortConfig(p)
|
||||
if err != nil {
|
||||
@@ -93,14 +92,13 @@ func (options runOptions) apply(project *types.Project) error {
|
||||
target.Ports = append(target.Ports, config...)
|
||||
}
|
||||
}
|
||||
if len(options.volumes) > 0 {
|
||||
for _, v := range options.volumes {
|
||||
volume, err := loader.ParseVolume(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target.Volumes = append(target.Volumes, volume)
|
||||
|
||||
for _, v := range options.volumes {
|
||||
volume, err := loader.ParseVolume(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target.Volumes = append(target.Volumes, volume)
|
||||
}
|
||||
|
||||
for i, s := range project.Services {
|
||||
|
||||
@@ -18,13 +18,13 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -95,12 +95,12 @@ func parseServicesReplicasArgs(args []string) (map[string]int, error) {
|
||||
for _, arg := range args {
|
||||
key, val, ok := strings.Cut(arg, "=")
|
||||
if !ok || key == "" || val == "" {
|
||||
return nil, errors.Errorf("invalid scale specifier: %s", arg)
|
||||
return nil, fmt.Errorf("invalid scale specifier: %s", arg)
|
||||
}
|
||||
intValue, err := strconv.Atoi(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("invalid scale specifier: can't parse replica value as int: %v", arg)
|
||||
return nil, fmt.Errorf("invalid scale specifier: can't parse replica value as int: %v", arg)
|
||||
}
|
||||
serviceReplicaTuples[key] = intValue
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *c
|
||||
flags.BoolVarP(&up.Detach, "detach", "d", false, "Detached mode: Run containers in the background")
|
||||
flags.BoolVar(&create.Build, "build", false, "Build images before starting containers.")
|
||||
flags.BoolVar(&create.noBuild, "no-build", false, "Don't build an image, even if it's policy.")
|
||||
flags.StringVar(&create.Pull, "pull", "policy", `Pull image before running ("always"|"policy"|"never")`)
|
||||
flags.StringVar(&create.Pull, "pull", "policy", `Pull image before running ("always"|"missing"|"never")`)
|
||||
flags.BoolVar(&create.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file.")
|
||||
flags.StringArrayVar(&create.scale, "scale", []string{}, "Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present.")
|
||||
flags.BoolVar(&up.noColor, "no-color", false, "Produce monochrome output.")
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
|
||||
func TestApplyScaleOpt(t *testing.T) {
|
||||
p := types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "foo",
|
||||
},
|
||||
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/internal/locker"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -78,13 +80,19 @@ func runWatch(ctx context.Context, dockerCli command.Cli, backend api.Service, w
|
||||
// validation done -- ensure we have the lockfile for this project before doing work
|
||||
l, err := locker.NewPidfile(project.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot take exclusive lock for project %q: %v", project.Name, err)
|
||||
return fmt.Errorf("cannot take exclusive lock for project %q: %w", project.Name, err)
|
||||
}
|
||||
if err := l.Lock(); err != nil {
|
||||
return fmt.Errorf("cannot take exclusive lock for project %q: %v", project.Name, err)
|
||||
return fmt.Errorf("cannot take exclusive lock for project %q: %w", project.Name, err)
|
||||
}
|
||||
|
||||
if !watchOpts.noUp {
|
||||
for index, service := range project.Services {
|
||||
if service.Build != nil && service.Develop != nil {
|
||||
service.PullPolicy = types.PullPolicyBuild
|
||||
}
|
||||
project.Services[index] = service
|
||||
}
|
||||
upOpts := api.UpOptions{
|
||||
Create: api.CreateOptions{
|
||||
Build: &build,
|
||||
|
||||
@@ -23,8 +23,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Print prints formatted lists in different formats
|
||||
@@ -67,7 +65,7 @@ func Print(toJSON interface{}, format string, outWriter io.Writer, writerFn func
|
||||
_, _ = fmt.Fprintln(outWriter, outJSON)
|
||||
}
|
||||
default:
|
||||
return errors.Wrapf(api.ErrParsingFailed, "format value %q could not be parsed", format)
|
||||
return fmt.Errorf("format value %q could not be parsed: %w", format, api.ErrParsingFailed)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ Define and run multi-container applications with Docker.
|
||||
|
||||
## Description
|
||||
|
||||
You can use compose subcommand, `docker compose [-f <arg>...] [options] [COMMAND] [ARGS...]`, to build and manage
|
||||
You can use the compose subcommand, `docker compose [-f <arg>...] [options] [COMMAND] [ARGS...]`, to build and manage
|
||||
multiple services in Docker containers.
|
||||
|
||||
### Use `-f` to specify the name and path of one or more Compose files
|
||||
@@ -146,16 +146,16 @@ 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
|
||||
Calling `docker compose --profile frontend up` starts 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.
|
||||
You can also enable multiple profiles, e.g. with `docker compose --profile frontend --profile debug up` the profiles `frontend` and `debug` is enabled.
|
||||
|
||||
Profiles can also be set by `COMPOSE_PROFILES` environment variable.
|
||||
|
||||
### Configuring parallelism
|
||||
|
||||
Use `--parallel` to specify the maximum level of parallelism for concurrent engine calls.
|
||||
Calling `docker compose --parallel 1 pull` will pull the pullable images defined in the Compose file
|
||||
Calling `docker compose --parallel 1 pull` pulls the pullable images defined in the Compose file
|
||||
one at a time. This can also be used to control build concurrency.
|
||||
|
||||
Parallelism can also be set by the `COMPOSE_PARALLEL_LIMIT` environment variable.
|
||||
@@ -171,7 +171,7 @@ and `COMPOSE_PARALLEL_LIMIT` does the same as the `--parallel` flag.
|
||||
|
||||
If flags are explicitly set on the command line, the associated environment variable is ignored.
|
||||
|
||||
Setting the `COMPOSE_IGNORE_ORPHANS` environment variable to `true` will stop docker compose from detecting orphaned
|
||||
Setting the `COMPOSE_IGNORE_ORPHANS` environment variable to `true` stops docker compose from detecting orphaned
|
||||
containers for the project.
|
||||
|
||||
### Use Dry Run mode to test your command
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# docker compose alpha dry-run
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
EXPERIMENTAL - Dry run command allow you to test a command without applying changes
|
||||
Dry run command allows you to test a command without applying changes.
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -5,9 +5,10 @@ Publish compose application
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-----|:--------|:--------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| Name | Type | Default | Description |
|
||||
|:--------------------------|:-----|:--------|:--------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--resolve-image-digests` | | | Pin image tags to digests. |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# docker compose alpha scale
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Scale services
|
||||
Scale services.
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-----|:--------|:--------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--no-deps` | | | Don't start linked services. |
|
||||
| `--no-deps` | | | Don't start linked services |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -31,6 +31,6 @@ Parse, resolve and render compose file in canonical format
|
||||
|
||||
## Description
|
||||
|
||||
`docker compose config` renders the actual data model to be applied on the Docker engine.
|
||||
it merges the Compose files set by `-f` flags, resolves variables in the Compose file, and expands short-notation into
|
||||
`docker compose config` renders the actual data model to be applied on the Docker Engine.
|
||||
It merges the Compose files set by `-f` flags, resolves variables in the Compose file, and expands short-notation into
|
||||
the canonical format.
|
||||
|
||||
@@ -12,7 +12,7 @@ Creates containers for a service.
|
||||
| `--force-recreate` | | | Recreate containers even if their configuration and image haven't changed. |
|
||||
| `--no-build` | | | Don't build an image, even if it's policy. |
|
||||
| `--no-recreate` | | | If containers already exist, don't recreate them. Incompatible with --force-recreate. |
|
||||
| `--pull` | `string` | `policy` | Pull image before running ("always"\|"policy"\|"never") |
|
||||
| `--pull` | `string` | `policy` | Pull image before running ("always"\|"missing"\|"never"\|"build") |
|
||||
| `--remove-orphans` | | | Remove containers for services not defined in the Compose file. |
|
||||
| `--scale` | `stringArray` | | Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present. |
|
||||
|
||||
|
||||
@@ -22,12 +22,12 @@ Stops containers and removes containers, networks, volumes, and images created b
|
||||
|
||||
By default, the only things removed are:
|
||||
|
||||
- Containers for services defined in the Compose file
|
||||
- Networks defined in the networks section of the Compose file
|
||||
- The default network, if one is used
|
||||
- Containers for services defined in the Compose file.
|
||||
- Networks defined in the networks section of the Compose file.
|
||||
- The default network, if one is used.
|
||||
|
||||
Networks and volumes defined as external are never removed.
|
||||
|
||||
Anonymous volumes are not removed by default. However, as they don’t have a stable name, they will not be automatically
|
||||
Anonymous volumes are not removed by default. However, as they don’t have a stable name, they are not automatically
|
||||
mounted by a subsequent `up`. For data that needs to persist between updates, use explicit paths as bind mounts or
|
||||
named volumes.
|
||||
|
||||
@@ -11,6 +11,7 @@ List containers
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| [`--filter`](#filter) | `string` | | Filter services by a property (supported filters: status). |
|
||||
| [`--format`](#format) | `string` | `table` | Format output using a custom template:<br>'table': Print output in table format with column headers (default)<br>'table TEMPLATE': Print output in table format using the given Go template<br>'json': Print in JSON format<br>'TEMPLATE': Print output using the given Go template.<br>Refer to https://docs.docker.com/go/formatting/ for more information about formatting output with templates |
|
||||
| `--no-trunc` | | | Don't truncate output |
|
||||
| `-q`, `--quiet` | | | Only display IDs |
|
||||
| `--services` | | | Display services |
|
||||
| [`--status`](#status) | `stringArray` | | Filter services by status. Values: [paused \| restarting \| removing \| running \| dead \| created \| exited] |
|
||||
@@ -28,7 +29,7 @@ NAME IMAGE COMMAND SERVICE CREATED STATUS
|
||||
example-foo-1 alpine "/entrypoint.…" foo 4 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp
|
||||
```
|
||||
|
||||
By default, only running containers are shown. `--all` flag can be used to include stopped containers
|
||||
By default, only running containers are shown. `--all` flag can be used to include stopped containers.
|
||||
|
||||
```console
|
||||
$ docker compose ps --all
|
||||
@@ -52,7 +53,7 @@ $ docker compose ps --format json
|
||||
```
|
||||
|
||||
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="_"}
|
||||
processing, for example, using the [`jq` utility](https://stedolan.github.io/jq/)
|
||||
to pretty-print the JSON:
|
||||
|
||||
```console
|
||||
|
||||
@@ -25,7 +25,7 @@ those images.
|
||||
|
||||
## Examples
|
||||
|
||||
suppose you have this `compose.yaml`:
|
||||
Consider the following `compose.yaml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
@@ -66,5 +66,4 @@ $ docker compose pull db
|
||||
⠹ c8752d5b785c Waiting 9.3s
|
||||
```
|
||||
|
||||
`docker compose pull` will try to pull image for services with a build section. If pull fails, it will let
|
||||
user know this service image MUST be built. You can skip this by setting `--ignore-buildable` flag
|
||||
`docker compose pull` tries to pull image for services with a build section. If pull fails, it lets you know this service image must be built. You can skip this by setting `--ignore-buildable` flag.
|
||||
|
||||
@@ -23,6 +23,6 @@ after running this command. For example, changes to environment variables (which
|
||||
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
|
||||
If you are looking to configure a service's restart policy, 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).
|
||||
|
||||
@@ -23,7 +23,7 @@ Create and start containers
|
||||
| `--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. |
|
||||
| `--pull` | `string` | `policy` | Pull image before running ("always"\|"policy"\|"never") |
|
||||
| `--pull` | `string` | `policy` | Pull image before running ("always"\|"missing"\|"never") |
|
||||
| `--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. |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
command: docker compose
|
||||
short: Docker Compose
|
||||
long: |-
|
||||
You can use compose subcommand, `docker compose [-f <arg>...] [options] [COMMAND] [ARGS...]`, to build and manage
|
||||
You can use the compose subcommand, `docker compose [-f <arg>...] [options] [COMMAND] [ARGS...]`, to build and manage
|
||||
multiple services in Docker containers.
|
||||
|
||||
### Use `-f` to specify the name and path of one or more Compose files
|
||||
@@ -90,16 +90,16 @@ long: |-
|
||||
### 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
|
||||
Calling `docker compose --profile frontend up` starts 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.
|
||||
You can also enable multiple profiles, e.g. with `docker compose --profile frontend --profile debug up` the profiles `frontend` and `debug` is enabled.
|
||||
|
||||
Profiles can also be set by `COMPOSE_PROFILES` environment variable.
|
||||
|
||||
### Configuring parallelism
|
||||
|
||||
Use `--parallel` to specify the maximum level of parallelism for concurrent engine calls.
|
||||
Calling `docker compose --parallel 1 pull` will pull the pullable images defined in the Compose file
|
||||
Calling `docker compose --parallel 1 pull` pulls the pullable images defined in the Compose file
|
||||
one at a time. This can also be used to control build concurrency.
|
||||
|
||||
Parallelism can also be set by the `COMPOSE_PARALLEL_LIMIT` environment variable.
|
||||
@@ -115,7 +115,7 @@ long: |-
|
||||
|
||||
If flags are explicitly set on the command line, the associated environment variable is ignored.
|
||||
|
||||
Setting the `COMPOSE_IGNORE_ORPHANS` environment variable to `true` will stop docker compose from detecting orphaned
|
||||
Setting the `COMPOSE_IGNORE_ORPHANS` environment variable to `true` stops docker compose from detecting orphaned
|
||||
containers for the project.
|
||||
|
||||
### Use Dry Run mode to test your command
|
||||
|
||||
@@ -4,6 +4,17 @@ long: Publish compose application
|
||||
usage: docker compose alpha publish [OPTIONS] [REPOSITORY]
|
||||
pname: docker compose alpha
|
||||
plink: docker_compose_alpha.yaml
|
||||
options:
|
||||
- option: resolve-image-digests
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Pin image tags to digests.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
|
||||
@@ -2,8 +2,8 @@ command: docker compose config
|
||||
aliases: docker compose config, docker compose convert
|
||||
short: Parse, resolve and render compose file in canonical format
|
||||
long: |-
|
||||
`docker compose config` renders the actual data model to be applied on the Docker engine.
|
||||
it merges the Compose files set by `-f` flags, resolves variables in the Compose file, and expands short-notation into
|
||||
`docker compose config` renders the actual data model to be applied on the Docker Engine.
|
||||
It merges the Compose files set by `-f` flags, resolves variables in the Compose file, and expands short-notation into
|
||||
the canonical format.
|
||||
usage: docker compose config [OPTIONS] [SERVICE...]
|
||||
pname: docker compose
|
||||
|
||||
@@ -50,7 +50,7 @@ options:
|
||||
- option: pull
|
||||
value_type: string
|
||||
default_value: policy
|
||||
description: Pull image before running ("always"|"policy"|"never")
|
||||
description: Pull image before running ("always"|"missing"|"never"|"build")
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
|
||||
@@ -5,13 +5,13 @@ long: |-
|
||||
|
||||
By default, the only things removed are:
|
||||
|
||||
- Containers for services defined in the Compose file
|
||||
- Networks defined in the networks section of the Compose file
|
||||
- The default network, if one is used
|
||||
- Containers for services defined in the Compose file.
|
||||
- Networks defined in the networks section of the Compose file.
|
||||
- The default network, if one is used.
|
||||
|
||||
Networks and volumes defined as external are never removed.
|
||||
|
||||
Anonymous volumes are not removed by default. However, as they don’t have a stable name, they will not be automatically
|
||||
Anonymous volumes are not removed by default. However, as they don’t have a stable name, they are not automatically
|
||||
mounted by a subsequent `up`. For data that needs to persist between updates, use explicit paths as bind mounts or
|
||||
named volumes.
|
||||
usage: docker compose down [OPTIONS] [SERVICES]
|
||||
|
||||
@@ -9,7 +9,7 @@ long: |-
|
||||
example-foo-1 alpine "/entrypoint.…" foo 4 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp
|
||||
```
|
||||
|
||||
By default, only running containers are shown. `--all` flag can be used to include stopped containers
|
||||
By default, only running containers are shown. `--all` flag can be used to include stopped containers.
|
||||
|
||||
```console
|
||||
$ docker compose ps --all
|
||||
@@ -60,6 +60,16 @@ options:
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: no-trunc
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Don't truncate output
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: quiet
|
||||
shorthand: q
|
||||
value_type: bool
|
||||
@@ -118,7 +128,7 @@ examples: |-
|
||||
```
|
||||
|
||||
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="_"}
|
||||
processing, for example, using the [`jq` utility](https://stedolan.github.io/jq/)
|
||||
to pretty-print the JSON:
|
||||
|
||||
```console
|
||||
|
||||
@@ -89,7 +89,7 @@ inherited_options:
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
examples: |-
|
||||
suppose you have this `compose.yaml`:
|
||||
Consider the following `compose.yaml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
@@ -130,8 +130,7 @@ examples: |-
|
||||
⠹ c8752d5b785c Waiting 9.3s
|
||||
```
|
||||
|
||||
`docker compose pull` will try to pull image for services with a build section. If pull fails, it will let
|
||||
user know this service image MUST be built. You can skip this by setting `--ignore-buildable` flag
|
||||
`docker compose pull` tries to pull image for services with a build section. If pull fails, it lets you know this service image must be built. You can skip this by setting `--ignore-buildable` flag.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
|
||||
@@ -8,7 +8,7 @@ long: |-
|
||||
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
|
||||
If you are looking to configure a service's restart policy, 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 [OPTIONS] [SERVICE...]
|
||||
|
||||
@@ -182,7 +182,7 @@ options:
|
||||
- option: pull
|
||||
value_type: string
|
||||
default_value: policy
|
||||
description: Pull image before running ("always"|"policy"|"never")
|
||||
description: Pull image before running ("always"|"missing"|"never")
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
Feature: Build Contexts
|
||||
|
||||
Background:
|
||||
Given a compose file
|
||||
"""
|
||||
services:
|
||||
a:
|
||||
build:
|
||||
context: .
|
||||
dockerfile_inline: |
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM alpine:latest
|
||||
COPY --from=dep /etc/hostname /
|
||||
additional_contexts:
|
||||
- dep=docker-image://ubuntu:latest
|
||||
"""
|
||||
|
||||
Scenario: Build w/ build context
|
||||
When I run "compose build"
|
||||
Then the exit code is 0
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
Feature: Down
|
||||
|
||||
Scenario: No resources to remove
|
||||
When I run "compose down"
|
||||
Then the output contains "Warning: No resource found to remove for project "no_resources_to_remove""
|
||||
@@ -1,28 +0,0 @@
|
||||
Feature: Report port conflicts
|
||||
|
||||
Background:
|
||||
Given a compose file
|
||||
"""
|
||||
services:
|
||||
web:
|
||||
image: nginx
|
||||
ports:
|
||||
- 31415:80
|
||||
"""
|
||||
And I run "docker rm -f nginx-pi-31415"
|
||||
|
||||
Scenario: Reports a port allocation conflict with another container
|
||||
Given I run "docker run -d -p 31415:80 --name nginx-pi-31415 nginx"
|
||||
When I run "compose up -d"
|
||||
Then the output contains "port is already allocated"
|
||||
And the exit code is 1
|
||||
|
||||
Scenario: Reports a port conflict with some other process
|
||||
Given a process listening on port 31415
|
||||
When I run "compose up -d"
|
||||
Then the output contains "address already in use"
|
||||
And the exit code is 1
|
||||
|
||||
Scenario: Cleanup
|
||||
Given I run "docker rm -f nginx-pi-31415"
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
Feature: PS
|
||||
|
||||
Background:
|
||||
Given a compose file
|
||||
"""
|
||||
services:
|
||||
build:
|
||||
image: test:latest
|
||||
build:
|
||||
context: ./
|
||||
pull:
|
||||
image: alpine
|
||||
command: top
|
||||
"""
|
||||
And a dockerfile
|
||||
"""
|
||||
FROM golang:1.19-alpine
|
||||
"""
|
||||
And I run "docker rm -f external-test"
|
||||
|
||||
Scenario: external container from compose image exists
|
||||
When I run "compose build"
|
||||
Then the exit code is 0
|
||||
And I run "docker run --name external-test test:latest ls"
|
||||
Then the exit code is 0
|
||||
And I run "compose ps -a"
|
||||
Then the output does not contain "external-test"
|
||||
And I run "docker rm -f external-test"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
Feature: Simple service up
|
||||
|
||||
Background:
|
||||
Given a compose file
|
||||
"""
|
||||
services:
|
||||
simple:
|
||||
image: alpine
|
||||
command: top
|
||||
"""
|
||||
|
||||
Scenario: compose up
|
||||
When I run "compose up -d"
|
||||
Then the output contains "simple-1 Started"
|
||||
And service "simple" is "Up"
|
||||
@@ -1,21 +0,0 @@
|
||||
Feature: Start
|
||||
|
||||
Background:
|
||||
Given a compose file
|
||||
"""
|
||||
services:
|
||||
simple:
|
||||
image: alpine
|
||||
command: top
|
||||
another:
|
||||
image: alpine
|
||||
command: top
|
||||
"""
|
||||
|
||||
Scenario: Start single service
|
||||
When I run "compose create"
|
||||
Then the output contains "simple-1 Created"
|
||||
And the output contains "another-1 Created"
|
||||
Then I run "compose start another"
|
||||
And service "another" is "Up"
|
||||
And service "simple" is "Created"
|
||||
@@ -1,38 +0,0 @@
|
||||
Feature: Stop
|
||||
|
||||
Background:
|
||||
Given a compose file
|
||||
"""
|
||||
services:
|
||||
should_fail:
|
||||
image: alpine
|
||||
command: ['sh', '-c', 'exit 123']
|
||||
sleep: # will be killed
|
||||
image: alpine
|
||||
command: ping localhost
|
||||
init: true
|
||||
"""
|
||||
|
||||
Scenario: Cascade stop
|
||||
When I run "compose up --abort-on-container-exit"
|
||||
Then the output contains "should_fail-1 exited with code 123"
|
||||
And the output contains "Aborting on container exit..."
|
||||
And the exit code is 123
|
||||
|
||||
Scenario: Exit code from
|
||||
When I run "compose up --exit-code-from should_fail"
|
||||
Then the output contains "should_fail-1 exited with code 123"
|
||||
And the output contains "Aborting on container exit..."
|
||||
And the exit code is 123
|
||||
|
||||
# TODO: this is currently not working propagating the exit code properly
|
||||
#Scenario: Exit code from (cascade stop)
|
||||
# When I run "compose up --exit-code-from sleep"
|
||||
# Then the output contains "should_fail-1 exited with code 123"
|
||||
# And the output contains "Aborting on container exit..."
|
||||
# And the exit code is 143
|
||||
|
||||
Scenario: Exit code from unknown service
|
||||
When I run "compose up --exit-code-from unknown"
|
||||
Then the output contains "no such service: unknown"
|
||||
And the exit code is 1
|
||||
@@ -1,17 +0,0 @@
|
||||
Feature: Up
|
||||
|
||||
Background:
|
||||
Given a compose file
|
||||
"""
|
||||
services:
|
||||
simple:
|
||||
image: alpine
|
||||
command: top
|
||||
"""
|
||||
|
||||
Scenario: --pull always
|
||||
When I run "compose up --pull=always -d"
|
||||
And the output contains "simple Pulled"
|
||||
Then I run "compose up --pull=always -d"
|
||||
And the output contains "simple Pulled"
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
Feature: Volume: tmpfs
|
||||
|
||||
Background:
|
||||
Given a compose file
|
||||
"""
|
||||
services:
|
||||
svc:
|
||||
image: busybox
|
||||
volumes:
|
||||
- type: tmpfs
|
||||
target: /volumes/tmpfs
|
||||
tmpfs:
|
||||
size: 2M
|
||||
mode: 0o647
|
||||
"""
|
||||
|
||||
Scenario: tmpfs Permissions Set
|
||||
When I run "compose run --rm svc stat -c "%a" /volumes/tmpfs"
|
||||
Then the output contains "647"
|
||||
|
||||
Scenario: tmpfs Size Set
|
||||
When I run "compose run --rm svc sh -c 'df /volumes/tmpfs | tail -n1 | awk '"'"'{print $4}'"'"'' "
|
||||
Then the output contains "2048"
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 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 cucumber
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/loader"
|
||||
"github.com/cucumber/godog"
|
||||
"github.com/cucumber/godog/colors"
|
||||
"github.com/mattn/go-shellwords"
|
||||
"gotest.tools/v3/icmd"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/e2e"
|
||||
)
|
||||
|
||||
func TestCucumber(t *testing.T) {
|
||||
testingOptions := godog.Options{
|
||||
TestingT: t,
|
||||
Paths: []string{"./cucumber-features"},
|
||||
Output: colors.Colored(os.Stdout),
|
||||
Format: "pretty",
|
||||
}
|
||||
|
||||
status := godog.TestSuite{
|
||||
Name: "godogs",
|
||||
Options: &testingOptions,
|
||||
ScenarioInitializer: setup,
|
||||
}.Run()
|
||||
|
||||
if status == 2 {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
if status != 0 {
|
||||
t.Fatalf("zero status code expected, %d received", status)
|
||||
}
|
||||
}
|
||||
|
||||
func setup(s *godog.ScenarioContext) {
|
||||
t := s.TestingT()
|
||||
projectName := loader.NormalizeProjectName(strings.Split(t.Name(), "/")[1])
|
||||
cli := e2e.NewCLI(t, e2e.WithEnv(
|
||||
fmt.Sprintf("COMPOSE_PROJECT_NAME=%s", projectName),
|
||||
))
|
||||
th := testHelper{
|
||||
T: t,
|
||||
CLI: cli,
|
||||
ProjectName: projectName,
|
||||
}
|
||||
|
||||
s.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) {
|
||||
cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0")
|
||||
return ctx, nil
|
||||
})
|
||||
|
||||
s.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
|
||||
cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0")
|
||||
return ctx, nil
|
||||
})
|
||||
|
||||
s.Step(`^a compose file$`, th.setComposeFile)
|
||||
s.Step(`^a dockerfile$`, th.setDockerfile)
|
||||
s.Step(`^I run "compose (.*)"$`, th.runComposeCommand)
|
||||
s.Step(`^I run "docker (.*)"$`, th.runDockerCommand)
|
||||
s.Step(`service "(.*)" is "(.*)"$`, th.serviceIsStatus)
|
||||
s.Step(`output contains "(.*)"$`, th.outputContains(true))
|
||||
s.Step(`output does not contain "(.*)"$`, th.outputContains(false))
|
||||
s.Step(`exit code is (\d+)$`, th.exitCodeIs)
|
||||
s.Step(`a process listening on port (\d+)$`, th.listenerOnPort)
|
||||
}
|
||||
|
||||
type testHelper struct {
|
||||
T *testing.T
|
||||
ProjectName string
|
||||
ComposeFile string
|
||||
TestDir string
|
||||
CommandOutput string
|
||||
CommandExitCode int
|
||||
CLI *e2e.CLI
|
||||
}
|
||||
|
||||
func (th *testHelper) serviceIsStatus(service, status string) error {
|
||||
serviceContainerName := fmt.Sprintf("%s-%s-1", strings.ToLower(th.ProjectName), service)
|
||||
statusRegex := fmt.Sprintf("%s.*%s", serviceContainerName, status)
|
||||
res := th.CLI.RunDockerComposeCmd(th.T, "ps", "-a")
|
||||
r, _ := regexp.Compile(statusRegex)
|
||||
if !r.MatchString(res.Combined()) {
|
||||
return fmt.Errorf("Missing/incorrect ps output:\n%s\nregex:\n%s", res.Combined(), statusRegex)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (th *testHelper) outputContains(expected bool) func(string) error {
|
||||
return func(substring string) error {
|
||||
contains := strings.Contains(th.CommandOutput, substring)
|
||||
if contains && !expected {
|
||||
return fmt.Errorf("Unexpected substring in output: %s\noutput: %s", substring, th.CommandOutput)
|
||||
} else if !contains && expected {
|
||||
return fmt.Errorf("Missing substring in output: %s\noutput: %s", substring, th.CommandOutput)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (th *testHelper) exitCodeIs(exitCode int) error {
|
||||
if exitCode != th.CommandExitCode {
|
||||
return fmt.Errorf("Wrong exit code: %d expected: %d || command output: %s", th.CommandExitCode, exitCode, th.CommandOutput)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (th *testHelper) runComposeCommand(command string) error {
|
||||
commandArgs, err := shellwords.Parse(command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandArgs = append([]string{"-f", "-"}, commandArgs...)
|
||||
|
||||
cmd := th.CLI.NewDockerComposeCmd(th.T, commandArgs...)
|
||||
cmd.Stdin = strings.NewReader(th.ComposeFile)
|
||||
cmd.Dir = th.TestDir
|
||||
res := icmd.RunCmd(cmd)
|
||||
th.CommandOutput = res.Combined()
|
||||
th.CommandExitCode = res.ExitCode
|
||||
return nil
|
||||
}
|
||||
|
||||
func (th *testHelper) runDockerCommand(command string) error {
|
||||
commandArgs, err := shellwords.Parse(command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := th.CLI.NewDockerCmd(th.T, commandArgs...)
|
||||
cmd.Dir = th.TestDir
|
||||
res := icmd.RunCmd(cmd)
|
||||
th.CommandOutput = res.Combined()
|
||||
th.CommandExitCode = res.ExitCode
|
||||
return nil
|
||||
}
|
||||
|
||||
func (th *testHelper) setComposeFile(composeString string) error {
|
||||
th.ComposeFile = composeString
|
||||
return nil
|
||||
}
|
||||
|
||||
func (th *testHelper) setDockerfile(dockerfileString string) error {
|
||||
tempDir := th.T.TempDir()
|
||||
th.TestDir = tempDir
|
||||
|
||||
err := os.WriteFile(filepath.Join(tempDir, "Dockerfile"), []byte(dockerfileString), 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (th *testHelper) listenerOnPort(port int) error {
|
||||
l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
th.T.Cleanup(func() {
|
||||
_ = l.Close()
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
57
go.mod
57
go.mod
@@ -5,37 +5,35 @@ go 1.21
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||
github.com/Microsoft/go-winio v0.6.1
|
||||
github.com/adrg/xdg v0.4.0
|
||||
github.com/buger/goterm v1.0.4
|
||||
github.com/compose-spec/compose-go v1.19.0
|
||||
github.com/compose-spec/compose-go v1.20.2
|
||||
github.com/containerd/console v1.0.3
|
||||
github.com/containerd/containerd v1.7.6
|
||||
github.com/cucumber/godog v0.0.0-00010101000000-000000000000 // replaced; see replace for the actual version used
|
||||
github.com/containerd/containerd v1.7.7
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/distribution/reference v0.5.0
|
||||
github.com/docker/buildx v0.11.2
|
||||
github.com/docker/cli v24.0.6+incompatible
|
||||
github.com/docker/cli v24.0.7+incompatible
|
||||
github.com/docker/cli-docs-tool v0.6.0
|
||||
github.com/docker/docker v24.0.6+incompatible
|
||||
github.com/docker/docker v24.0.7+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/fsnotify/fsevents v0.1.1
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-version v1.6.0
|
||||
github.com/jonboulle/clockwork v0.4.0
|
||||
github.com/mattn/go-shellwords v1.0.12
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/moby/buildkit v0.12.2
|
||||
github.com/moby/buildkit v0.12.3
|
||||
github.com/moby/patternmatcher v0.6.0
|
||||
github.com/moby/term v0.5.0
|
||||
github.com/morikuni/aec v1.0.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/otiai10/copy v1.14.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/theupdateframework/notary v0.7.0
|
||||
@@ -45,19 +43,19 @@ require (
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0
|
||||
go.opentelemetry.io/otel/sdk v1.14.0
|
||||
go.opentelemetry.io/otel/trace v1.14.0
|
||||
go.uber.org/goleak v1.2.1
|
||||
golang.org/x/sync v0.3.0
|
||||
google.golang.org/grpc v1.58.1
|
||||
go.uber.org/goleak v1.3.0
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1
|
||||
golang.org/x/sync v0.5.0
|
||||
golang.org/x/sys v0.14.0
|
||||
google.golang.org/grpc v1.59.0
|
||||
gotest.tools/v3 v3.5.1
|
||||
)
|
||||
|
||||
require golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1
|
||||
|
||||
require (
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.0 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.1 // indirect
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.16 // indirect
|
||||
@@ -75,9 +73,8 @@ require (
|
||||
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/containerd/continuity v0.4.2 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
||||
github.com/cucumber/gherkin-go/v19 v19.0.3 // indirect
|
||||
github.com/cucumber/messages-go/v16 v16.0.1 // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
@@ -102,9 +99,6 @@ require (
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-memdb v1.3.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.5.0 // indirect
|
||||
@@ -132,6 +126,7 @@ require (
|
||||
github.com/opencontainers/runc v1.1.7 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
@@ -156,19 +151,18 @@ require (
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.37.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
|
||||
golang.org/x/crypto v0.11.0 // indirect
|
||||
golang.org/x/crypto v0.12.0 // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/net v0.12.0 // indirect
|
||||
golang.org/x/oauth2 v0.10.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/term v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/net v0.14.0 // indirect
|
||||
golang.org/x/oauth2 v0.11.0 // indirect
|
||||
golang.org/x/term v0.11.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
@@ -184,6 +178,3 @@ require (
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
// Override for e2e tests
|
||||
replace github.com/cucumber/godog => github.com/laurazard/godog v0.0.0-20220922095256-4c4b17abdae7
|
||||
|
||||
133
go.sum
133
go.sum
@@ -17,15 +17,15 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk=
|
||||
cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o=
|
||||
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=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk=
|
||||
cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
|
||||
cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
|
||||
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
@@ -55,16 +55,14 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/hcsshim v0.11.0 h1:7EFNIY4igHEXUdj1zXgAyU3fLc7QfOKHbkldRVTBdiM=
|
||||
github.com/Microsoft/hcsshim v0.11.0/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM=
|
||||
github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA=
|
||||
github.com/Microsoft/hcsshim v0.11.1/go.mod h1:nFJmaO4Zr5Y7eADdFOpYswDDlNVbvcIJJNJLECr5JQg=
|
||||
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/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/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc=
|
||||
@@ -139,18 +137,20 @@ github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+g
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
|
||||
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
|
||||
github.com/compose-spec/compose-go v1.19.0 h1:t68gAcwStDg0hy2kFvqHJIksf6xkqRnlSKfL45/ETqo=
|
||||
github.com/compose-spec/compose-go v1.19.0/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
|
||||
github.com/compose-spec/compose-go v1.20.2 h1:u/yfZHn4EaHGdidrZycWpxXgFffjYULlTbRfJ51ykjQ=
|
||||
github.com/compose-spec/compose-go v1.20.2/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
||||
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.7.6 h1:oNAVsnhPoy4BTPQivLgTzI9Oleml9l/+eYIDYXRCYo8=
|
||||
github.com/containerd/containerd v1.7.6/go.mod h1:SY6lrkkuJT40BVNO37tlYTSnKJnP5AXBc0fhx0q+TJ4=
|
||||
github.com/containerd/containerd v1.7.7 h1:QOC2K4A42RQpcrZyptP6z9EJZnlHfHJUfZrAAHe15q4=
|
||||
github.com/containerd/containerd v1.7.7/go.mod h1:3c4XZv6VeT9qgf9GMTxNTMFxGJrGpI2vz1yk4ye+YY8=
|
||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
|
||||
github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/nydus-snapshotter v0.8.2 h1:7SOrMU2YmLzfbsr5J7liMZJlNi5WT6vtIOxLGv+iz7E=
|
||||
github.com/containerd/nydus-snapshotter v0.8.2/go.mod h1:UJILTN5LVBRY+dt8BGJbp72Xy729hUZsOugObEI3/O8=
|
||||
github.com/containerd/stargz-snapshotter v0.14.3 h1:OTUVZoPSPs8mGgmQUE1dqw3WX/3nrsmsurW7UPLWl1U=
|
||||
@@ -160,17 +160,11 @@ github.com/containerd/ttrpc v1.2.2 h1:9vqZr0pxwOF5koz6N0N3kJ0zDHokrcPxIR/ZR2YFtO
|
||||
github.com/containerd/ttrpc v1.2.2/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak=
|
||||
github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
|
||||
github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0=
|
||||
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/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/cucumber/gherkin-go/v19 v19.0.3 h1:mMSKu1077ffLbTJULUfM5HPokgeBcIGboyeNUof1MdE=
|
||||
github.com/cucumber/gherkin-go/v19 v19.0.3/go.mod h1:jY/NP6jUtRSArQQJ5h1FXOUgk5fZK24qtE7vKi776Vw=
|
||||
github.com/cucumber/messages-go/v16 v16.0.0/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g=
|
||||
github.com/cucumber/messages-go/v16 v16.0.1 h1:fvkpwsLgnIm0qugftrw2YwNlio+ABe2Iu94Ap8GMYIY=
|
||||
github.com/cucumber/messages-go/v16 v16.0.1/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g=
|
||||
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=
|
||||
@@ -179,15 +173,15 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/buildx v0.11.2 h1:R3p9F0gnI4FwvQ0p40UwdX1T4ugap4UWxY3TFHoP4Ws=
|
||||
github.com/docker/buildx v0.11.2/go.mod h1:CWAABt10iIuGpleypA3103mplDfcGu0A2AvT03xfpTc=
|
||||
github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY=
|
||||
github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg=
|
||||
github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli-docs-tool v0.6.0 h1:Z9x10SaZgFaB6jHgz3OWooynhSa40CsWkpe5hEnG/qA=
|
||||
github.com/docker/cli-docs-tool v0.6.0/go.mod h1:zMjqTFCU361PRh8apiXzeAZ1Q/xupbIwTusYpzCXS/o=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE=
|
||||
github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
|
||||
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||
@@ -257,7 +251,6 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
|
||||
@@ -269,8 +262,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
|
||||
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/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
|
||||
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
|
||||
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
|
||||
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -322,8 +315,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -344,13 +337,11 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.1.2/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/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
@@ -366,22 +357,12 @@ github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMW
|
||||
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-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-memdb v1.3.2 h1:RBKHOsnSszpU6vxq80LzC2BaQjuuvoyaQbkLTf7V7g8=
|
||||
github.com/hashicorp/go-memdb v1.3.2/go.mod h1:Mluclgwib3R93Hk5fxEfiRhB+6Dar64wWh71LpNSe3g=
|
||||
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-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
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/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.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
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/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
||||
@@ -415,8 +396,6 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
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 h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
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/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
||||
@@ -439,8 +418,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
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/laurazard/godog v0.0.0-20220922095256-4c4b17abdae7 h1:R/J7xECY9oHrAg+4QjC38EoXaYysNLzhvXhH/SXcsVc=
|
||||
github.com/laurazard/godog v0.0.0-20220922095256-4c4b17abdae7/go.mod h1:Y02TTpimPXDb70PnG6M3zpODXm1+bjCsuZzcW76xAww=
|
||||
github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.5.3 h1:C8fxWnhYyME3n0klPOhVM7PtYUB3eV1W3DeFmN3j53Y=
|
||||
github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
@@ -471,8 +448,8 @@ github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WT
|
||||
github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
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/moby/buildkit v0.12.2 h1:B7guBgY6sfk4dBlv/ORUxyYlp0UojYaYyATgtNwSCXc=
|
||||
github.com/moby/buildkit v0.12.2/go.mod h1:adB4y0SxxX8trnrY+oEulb48ODLqPO6pKMF0ppGcCoI=
|
||||
github.com/moby/buildkit v0.12.3 h1:cFaPVnyC0PwAP5xHHfzdU5v9rgQrCi6HnGSg3WuFKp4=
|
||||
github.com/moby/buildkit v0.12.3/go.mod h1:adB4y0SxxX8trnrY+oEulb48ODLqPO6pKMF0ppGcCoI=
|
||||
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/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
@@ -525,6 +502,10 @@ github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaL
|
||||
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
|
||||
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
|
||||
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
|
||||
github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
@@ -576,10 +557,6 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spdx/tools-golang v0.5.1 h1:fJg3SVOGG+eIva9ZUBm/hvyA7PIPVFjRxUKe6fdAgwE=
|
||||
github.com/spdx/tools-golang v0.5.1/go.mod h1:/DRDQuBfB37HctM29YtrX1v+bXiVmT2OpQDalRmX9aU=
|
||||
@@ -588,9 +565,8 @@ github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcD
|
||||
github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94 h1:JmfC365KywYwHB946TTiQWEb8kqPY+pybPLoGE9GgVk=
|
||||
github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
||||
github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431 h1:XTHrT015sxHyJ5FnQ0AeemSspZWaDq7DoTRW0EVsDCE=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
@@ -675,8 +651,8 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
|
||||
go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
|
||||
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -691,8 +667,8 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -768,8 +744,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -780,8 +756,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
|
||||
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
|
||||
golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
|
||||
golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -794,8 +770,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -849,13 +825,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
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=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -865,8 +841,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -878,7 +854,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
@@ -997,12 +972,12 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g=
|
||||
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
||||
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
@@ -1024,8 +999,8 @@ 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.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58=
|
||||
google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||
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=
|
||||
|
||||
@@ -19,8 +19,8 @@ package locker
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/docker/docker/pkg/pidfile"
|
||||
)
|
||||
|
||||
@@ -29,10 +29,11 @@ type Pidfile struct {
|
||||
}
|
||||
|
||||
func NewPidfile(projectName string) (*Pidfile, error) {
|
||||
path, err := xdg.RuntimeFile(fmt.Sprintf("docker-compose.%s.pid", projectName))
|
||||
run, err := runDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := filepath.Join(run, fmt.Sprintf("%s.pid", projectName))
|
||||
return &Pidfile{path: path}, nil
|
||||
}
|
||||
|
||||
|
||||
35
internal/locker/runtime.go
Normal file
35
internal/locker/runtime.go
Normal file
@@ -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 locker
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func runDir() (string, error) {
|
||||
run, ok := os.LookupEnv("XDG_RUNTIME_DIR")
|
||||
if ok {
|
||||
return run, nil
|
||||
}
|
||||
|
||||
path, err := osDependentRunDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = os.MkdirAll(path, 0o700)
|
||||
return path, err
|
||||
}
|
||||
34
internal/locker/runtime_darwin.go
Normal file
34
internal/locker/runtime_darwin.go
Normal file
@@ -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 locker
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Based on https://github.com/adrg/xdg
|
||||
// Licensed under MIT License (MIT)
|
||||
// Copyright (c) 2014 Adrian-George Bostan <adrg@epistack.com>
|
||||
|
||||
func osDependentRunDir() (string, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(home, "Library", "Application Support", "com.docker.compose"), nil
|
||||
}
|
||||
43
internal/locker/runtime_unix.go
Normal file
43
internal/locker/runtime_unix.go
Normal file
@@ -0,0 +1,43 @@
|
||||
//go:build linux
|
||||
|
||||
/*
|
||||
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 locker
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Based on https://github.com/adrg/xdg
|
||||
// Licensed under MIT License (MIT)
|
||||
// Copyright (c) 2014 Adrian-George Bostan <adrg@epistack.com>
|
||||
|
||||
func osDependentRunDir() (string, error) {
|
||||
run := filepath.Join("run", "user", strconv.Itoa(os.Getuid()))
|
||||
if _, err := os.Stat(run); err == nil {
|
||||
return run, nil
|
||||
}
|
||||
|
||||
// /run/user/$uid is set by pam_systemd, but might not be present, especially in containerized environments
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(home, ".docker", "docker-compose"), nil
|
||||
}
|
||||
49
internal/locker/runtime_windows.go
Normal file
49
internal/locker/runtime_windows.go
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
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 locker
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Based on https://github.com/adrg/xdg
|
||||
// Licensed under MIT License (MIT)
|
||||
// Copyright (c) 2014 Adrian-George Bostan <adrg@epistack.com>
|
||||
|
||||
func osDependentRunDir() (string, error) {
|
||||
flags := []uint32{windows.KF_FLAG_DEFAULT, windows.KF_FLAG_DEFAULT_PATH}
|
||||
for _, flag := range flags {
|
||||
p, _ := windows.KnownFolderPath(windows.FOLDERID_LocalAppData, flag|windows.KF_FLAG_DONT_VERIFY)
|
||||
if p != "" {
|
||||
return filepath.Join(p, "docker-compose"), nil
|
||||
}
|
||||
}
|
||||
|
||||
appData, ok := os.LookupEnv("LOCALAPPDATA")
|
||||
if ok {
|
||||
return filepath.Join(appData, "docker-compose"), nil
|
||||
}
|
||||
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(home, "AppData", "Local", "docker-compose"), nil
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
@@ -30,7 +31,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
@@ -212,7 +212,7 @@ func (a *ArchiveBuilder) writeEntry(entry archiveEntry) error {
|
||||
if useBuf {
|
||||
a.copyBuf.Reset()
|
||||
_, err = io.Copy(a.copyBuf, file)
|
||||
if err != nil && err != io.EOF {
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return fmt.Errorf("copying %q: %w", pathInTar, err)
|
||||
}
|
||||
header.Size = int64(len(a.copyBuf.Bytes()))
|
||||
@@ -232,7 +232,7 @@ func (a *ArchiveBuilder) writeEntry(entry archiveEntry) error {
|
||||
_, err = io.Copy(a.tw, file)
|
||||
}
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return fmt.Errorf("copying %q: %w", pathInTar, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ package sync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -115,7 +115,7 @@ func (b *bufReader) consume() {
|
||||
b.data = append(b.data, buf[:n]...)
|
||||
b.mu.Unlock()
|
||||
}
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -39,7 +39,7 @@ func traceClientFromDockerContext(dockerCli command.Cli, otelEnv envMap) (otlptr
|
||||
// automatic integration with Docker Desktop;
|
||||
cfg, err := ConfigFromDockerContext(dockerCli.ContextStore(), dockerCli.CurrentContext())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading otel config from docker context metadata: %v", err)
|
||||
return nil, fmt.Errorf("loading otel config from docker context metadata: %w", err)
|
||||
}
|
||||
|
||||
if cfg.Endpoint == "" {
|
||||
@@ -52,13 +52,13 @@ func traceClientFromDockerContext(dockerCli command.Cli, otelEnv envMap) (otlptr
|
||||
defer func() {
|
||||
for k, v := range otelEnv {
|
||||
if err := os.Setenv(k, v); err != nil {
|
||||
panic(fmt.Errorf("restoring env for %q: %v", k, err))
|
||||
panic(fmt.Errorf("restoring env for %q: %w", k, err))
|
||||
}
|
||||
}
|
||||
}()
|
||||
for k := range otelEnv {
|
||||
if err := os.Unsetenv(k); err != nil {
|
||||
return nil, fmt.Errorf("stashing env for %q: %v", k, err)
|
||||
return nil, fmt.Errorf("stashing env for %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func traceClientFromDockerContext(dockerCli command.Cli, otelEnv envMap) (otlptr
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing otel connection from docker context metadata: %v", err)
|
||||
return nil, fmt.Errorf("initializing otel connection from docker context metadata: %w", err)
|
||||
}
|
||||
|
||||
client := otlptracegrpc.NewClient(otlptracegrpc.WithGRPCConn(conn))
|
||||
|
||||
@@ -111,7 +111,7 @@ func InitProvider(dockerCli command.Cli) (ShutdownFunc, error) {
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create resource: %v", err)
|
||||
return nil, fmt.Errorf("failed to create resource: %w", err)
|
||||
}
|
||||
|
||||
muxExporter := MuxExporter{exporters: exporters}
|
||||
|
||||
@@ -363,6 +363,7 @@ type PortOptions struct {
|
||||
|
||||
// PublishOptions group options of the Publish API
|
||||
type PublishOptions struct {
|
||||
ResolveImageDigests bool
|
||||
}
|
||||
|
||||
func (e Event) String() string {
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@@ -44,7 +45,6 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -17,35 +17,36 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestIsNotFound(t *testing.T) {
|
||||
err := errors.Wrap(ErrNotFound, `object "name"`)
|
||||
err := fmt.Errorf(`object "name": %w`, ErrNotFound)
|
||||
assert.Assert(t, IsNotFoundError(err))
|
||||
|
||||
assert.Assert(t, !IsNotFoundError(errors.New("another error")))
|
||||
}
|
||||
|
||||
func TestIsAlreadyExists(t *testing.T) {
|
||||
err := errors.Wrap(ErrAlreadyExists, `object "name"`)
|
||||
err := fmt.Errorf(`object "name": %w`, ErrAlreadyExists)
|
||||
assert.Assert(t, IsAlreadyExistsError(err))
|
||||
|
||||
assert.Assert(t, !IsAlreadyExistsError(errors.New("another error")))
|
||||
}
|
||||
|
||||
func TestIsForbidden(t *testing.T) {
|
||||
err := errors.Wrap(ErrForbidden, `object "name"`)
|
||||
err := fmt.Errorf(`object "name": %w`, ErrForbidden)
|
||||
assert.Assert(t, IsForbiddenError(err))
|
||||
|
||||
assert.Assert(t, !IsForbiddenError(errors.New("another error")))
|
||||
}
|
||||
|
||||
func TestIsUnknown(t *testing.T) {
|
||||
err := errors.Wrap(ErrUnknown, `object "name"`)
|
||||
err := fmt.Errorf(`object "name": %w`, ErrUnknown)
|
||||
assert.Assert(t, IsUnknownError(err))
|
||||
|
||||
assert.Assert(t, !IsUnknownError(errors.New("another error")))
|
||||
|
||||
@@ -18,6 +18,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
@@ -132,7 +133,8 @@ func (s *composeService) attachContainerStreams(ctx context.Context, container s
|
||||
if streamIn != nil && stdin != nil {
|
||||
go func() {
|
||||
_, err := io.Copy(streamIn, stdin)
|
||||
if _, ok := err.(term.EscapeError); ok {
|
||||
var escapeErr term.EscapeError
|
||||
if errors.As(err, &escapeErr) {
|
||||
close(detached)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
@@ -32,11 +33,13 @@ import (
|
||||
"github.com/docker/buildx/util/buildflags"
|
||||
xprogress "github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/command"
|
||||
cliopts "github.com/docker/cli/opts"
|
||||
"github.com/docker/compose/v2/internal/tracing"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
"github.com/docker/docker/builder/remotecontext/urlutil"
|
||||
"github.com/docker/go-units"
|
||||
bclient "github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/session/auth/authprovider"
|
||||
@@ -61,6 +64,11 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti
|
||||
}, s.stdinfo(), "Building")
|
||||
}
|
||||
|
||||
type serviceToBuild struct {
|
||||
idx int
|
||||
service types.ServiceConfig
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions, localImages map[string]string) (map[string]string, error) {
|
||||
buildkitEnabled, err := s.dockerCli.BuildKitEnabled()
|
||||
@@ -68,6 +76,36 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
||||
return nil, err
|
||||
}
|
||||
|
||||
imageIDs := map[string]string{}
|
||||
serviceToBeBuild := map[string]serviceToBuild{}
|
||||
mapServiceMutx := sync.Mutex{}
|
||||
err = InDependencyOrder(ctx, project, func(ctx context.Context, name string) error {
|
||||
if len(options.Services) > 0 && !utils.Contains(options.Services, name) {
|
||||
return nil
|
||||
}
|
||||
service, idx := getServiceIndex(project, name)
|
||||
|
||||
if service.Build == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
image := api.GetImageNameOrDefault(service, project.Name)
|
||||
_, localImagePresent := localImages[image]
|
||||
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
|
||||
return nil
|
||||
}
|
||||
mapServiceMutx.Lock()
|
||||
serviceToBeBuild[name] = serviceToBuild{idx: idx, service: service}
|
||||
mapServiceMutx.Unlock()
|
||||
return nil
|
||||
}, func(traversal *graphTraversal) {
|
||||
traversal.maxConcurrency = s.maxConcurrency
|
||||
})
|
||||
|
||||
if err != nil || len(serviceToBeBuild) == 0 {
|
||||
return imageIDs, err
|
||||
}
|
||||
|
||||
// Initialize buildkit nodes
|
||||
var (
|
||||
b *builder.Builder
|
||||
@@ -111,17 +149,12 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
||||
if len(options.Services) > 0 && !utils.Contains(options.Services, name) {
|
||||
return nil
|
||||
}
|
||||
service, idx := getServiceIndex(project, name)
|
||||
|
||||
if service.Build == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
image := api.GetImageNameOrDefault(service, project.Name)
|
||||
_, localImagePresent := localImages[image]
|
||||
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
|
||||
serviceToBuild, ok := serviceToBeBuild[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
service := serviceToBuild.service
|
||||
idx := serviceToBuild.idx
|
||||
|
||||
if !buildkitEnabled {
|
||||
id, err := s.doBuildClassic(ctx, project, service, options)
|
||||
@@ -167,7 +200,6 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
||||
return nil, err
|
||||
}
|
||||
|
||||
imageIDs := map[string]string{}
|
||||
for i, imageDigest := range builtDigests {
|
||||
if imageDigest != "" {
|
||||
imageRef := api.GetImageNameOrDefault(project.Services[i], project.Name)
|
||||
@@ -407,11 +439,24 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
|
||||
Labels: imageLabels,
|
||||
NetworkMode: service.Build.Network,
|
||||
ExtraHosts: service.Build.ExtraHosts.AsList(),
|
||||
Ulimits: toUlimitOpt(service.Build.Ulimits),
|
||||
Session: sessionConfig,
|
||||
Allow: allow,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toUlimitOpt(ulimits map[string]*types.UlimitsConfig) *cliopts.UlimitOpt {
|
||||
ref := map[string]*units.Ulimit{}
|
||||
for _, limit := range toUlimits(ulimits) {
|
||||
ref[limit.Name] = &units.Ulimit{
|
||||
Name: limit.Name,
|
||||
Hard: limit.Hard,
|
||||
Soft: limit.Soft,
|
||||
}
|
||||
}
|
||||
return cliopts.NewUlimitOpt(&ref)
|
||||
}
|
||||
|
||||
func flatten(in types.MappingWithEquals) types.Mapping {
|
||||
out := types.Mapping{}
|
||||
if len(in) == 0 {
|
||||
|
||||
@@ -19,6 +19,7 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -41,7 +42,6 @@ import (
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
@@ -64,19 +64,19 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
|
||||
buildBuff := s.stdout()
|
||||
|
||||
if len(service.Build.Platforms) > 1 {
|
||||
return "", errors.Errorf("the classic builder doesn't support multi-arch build, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
return "", fmt.Errorf("the classic builder doesn't support multi-arch build, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
}
|
||||
if service.Build.Privileged {
|
||||
return "", errors.Errorf("the classic builder doesn't support privileged mode, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
return "", fmt.Errorf("the classic builder doesn't support privileged mode, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
}
|
||||
if len(service.Build.AdditionalContexts) > 0 {
|
||||
return "", errors.Errorf("the classic builder doesn't support additional contexts, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
return "", fmt.Errorf("the classic builder doesn't support additional contexts, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
}
|
||||
if len(service.Build.SSH) > 0 {
|
||||
return "", errors.Errorf("the classic builder doesn't support SSH keys, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
return "", fmt.Errorf("the classic builder doesn't support SSH keys, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
}
|
||||
if len(service.Build.Secrets) > 0 {
|
||||
return "", errors.Errorf("the classic builder doesn't support secrets, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
return "", fmt.Errorf("the classic builder doesn't support secrets, set DOCKER_BUILDKIT=1 to use BuildKit")
|
||||
}
|
||||
|
||||
if service.Build.Labels == nil {
|
||||
@@ -91,7 +91,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
|
||||
// Dockerfile is outside of build-context; read the Dockerfile and pass it as dockerfileCtx
|
||||
dockerfileCtx, err = os.Open(dockerfileName)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("unable to open Dockerfile: %v", err)
|
||||
return "", fmt.Errorf("unable to open Dockerfile: %w", err)
|
||||
}
|
||||
defer dockerfileCtx.Close() //nolint:errcheck
|
||||
}
|
||||
@@ -100,11 +100,11 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
|
||||
case urlutil.IsURL(specifiedContext):
|
||||
buildCtx, relDockerfile, err = build.GetContextFromURL(progBuff, specifiedContext, dockerfileName)
|
||||
default:
|
||||
return "", errors.Errorf("unable to prepare context: path %q not found", specifiedContext)
|
||||
return "", fmt.Errorf("unable to prepare context: path %q not found", specifiedContext)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", errors.Errorf("unable to prepare context: %s", err)
|
||||
return "", fmt.Errorf("unable to prepare context: %w", err)
|
||||
}
|
||||
|
||||
if tempDir != "" {
|
||||
@@ -120,7 +120,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
|
||||
}
|
||||
|
||||
if err := build.ValidateContextDirectory(contextDir, excludes); err != nil {
|
||||
return "", errors.Wrap(err, "checking context")
|
||||
return "", fmt.Errorf("checking context: %w", err)
|
||||
}
|
||||
|
||||
// And canonicalize dockerfile name to a platform-independent one
|
||||
@@ -188,7 +188,8 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
|
||||
|
||||
err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, progBuff.FD(), true, aux)
|
||||
if err != nil {
|
||||
if jerr, ok := err.(*jsonmessage.JSONError); ok {
|
||||
var jerr *jsonmessage.JSONError
|
||||
if errors.As(err, &jerr) {
|
||||
// If no error code is set, default to 1
|
||||
if jerr.Code == 0 {
|
||||
jerr.Code = 1
|
||||
|
||||
@@ -41,7 +41,6 @@ import (
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var stdioToStdout bool
|
||||
@@ -137,13 +136,14 @@ func getCanonicalContainerName(c moby.Container) string {
|
||||
}
|
||||
|
||||
func getContainerNameWithoutProject(c moby.Container) string {
|
||||
name := getCanonicalContainerName(c)
|
||||
project := c.Labels[api.ProjectLabel]
|
||||
prefix := fmt.Sprintf("%s_%s_", project, c.Labels[api.ServiceLabel])
|
||||
if strings.HasPrefix(name, prefix) {
|
||||
return name[len(project)+1:]
|
||||
defaultName := getDefaultContainerName(project, c.Labels[api.ServiceLabel], c.Labels[api.ContainerNumberLabel])
|
||||
name := getCanonicalContainerName(c)
|
||||
if name != defaultName {
|
||||
// service declares a custom container_name
|
||||
return name
|
||||
}
|
||||
return name
|
||||
return name[len(project)+1:]
|
||||
}
|
||||
|
||||
func (s *composeService) Config(ctx context.Context, project *types.Project, options api.ConfigOptions) ([]byte, error) {
|
||||
@@ -180,7 +180,7 @@ func (s *composeService) projectFromName(containers Containers, projectName stri
|
||||
Name: projectName,
|
||||
}
|
||||
if len(containers) == 0 {
|
||||
return project, errors.Wrap(api.ErrNotFound, fmt.Sprintf("no container found for project %q", projectName))
|
||||
return project, fmt.Errorf("no container found for project %q: %w", projectName, api.ErrNotFound)
|
||||
}
|
||||
set := map[string]*types.ServiceConfig{}
|
||||
for _, c := range containers {
|
||||
@@ -226,7 +226,7 @@ SERVICES:
|
||||
continue SERVICES
|
||||
}
|
||||
}
|
||||
return project, errors.Wrapf(api.ErrNotFound, "no such service: %q", qs)
|
||||
return project, fmt.Errorf("no such service: %q: %w", qs, api.ErrNotFound)
|
||||
}
|
||||
err := project.ForServices(services)
|
||||
if err != nil {
|
||||
@@ -295,5 +295,22 @@ func (s *composeService) isSWarmEnabled(ctx context.Context) (bool, error) {
|
||||
}
|
||||
})
|
||||
return swarmEnabled.val, swarmEnabled.err
|
||||
}
|
||||
|
||||
var runtimeVersion = struct {
|
||||
once sync.Once
|
||||
val string
|
||||
err error
|
||||
}{}
|
||||
|
||||
func (s *composeService) RuntimeVersion(ctx context.Context) (string, error) {
|
||||
runtimeVersion.once.Do(func() {
|
||||
version, err := s.dockerCli.Client().ServerVersion(ctx)
|
||||
if err != nil {
|
||||
runtimeVersion.err = err
|
||||
}
|
||||
runtimeVersion.val = version.APIVersion
|
||||
})
|
||||
return runtimeVersion.val, runtimeVersion.err
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
@@ -123,6 +124,21 @@ func isNotService(services ...string) containerPredicate {
|
||||
}
|
||||
}
|
||||
|
||||
// isOrphaned is a predicate to select containers without a matching service definition in compose project
|
||||
func isOrphaned(project *types.Project) containerPredicate {
|
||||
var services []string
|
||||
for _, s := range project.Services {
|
||||
services = append(services, s.Name)
|
||||
}
|
||||
for _, s := range project.DisabledServices {
|
||||
services = append(services, s.Name)
|
||||
}
|
||||
return func(c moby.Container) bool {
|
||||
service := c.Labels[api.ServiceLabel]
|
||||
return !utils.StringContains(services, service)
|
||||
}
|
||||
}
|
||||
|
||||
func isNotOneOff(c moby.Container) bool {
|
||||
v, ok := c.Labels[api.OneoffLabel]
|
||||
return !ok || v == "False"
|
||||
|
||||
@@ -18,6 +18,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -34,7 +35,6 @@ import (
|
||||
moby "github.com/docker/docker/api/types"
|
||||
containerType "github.com/docker/docker/api/types/container"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
@@ -287,13 +287,17 @@ func mustRecreate(expected types.ServiceConfig, actual moby.Container, policy st
|
||||
}
|
||||
|
||||
func getContainerName(projectName string, service types.ServiceConfig, number int) string {
|
||||
name := strings.Join([]string{projectName, service.Name, strconv.Itoa(number)}, api.Separator)
|
||||
name := getDefaultContainerName(projectName, service.Name, strconv.Itoa(number))
|
||||
if service.ContainerName != "" {
|
||||
name = service.ContainerName
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func getDefaultContainerName(projectName, serviceName, index string) string {
|
||||
return strings.Join([]string{projectName, serviceName, index}, api.Separator)
|
||||
}
|
||||
|
||||
func getContainerProgressName(container moby.Container) string {
|
||||
return "Container " + getCanonicalContainerName(container)
|
||||
}
|
||||
@@ -318,7 +322,7 @@ func containerReasonEvents(containers Containers, eventFunc func(string, string)
|
||||
const ServiceConditionRunningOrHealthy = "running_or_healthy"
|
||||
|
||||
//nolint:gocyclo
|
||||
func (s *composeService) waitDependencies(ctx context.Context, project *types.Project, dependencies types.DependsOnConfig, containers Containers) error {
|
||||
func (s *composeService) waitDependencies(ctx context.Context, project *types.Project, dependant string, dependencies types.DependsOnConfig, containers Containers) error {
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
w := progress.ContextWriter(ctx)
|
||||
for dep, config := range dependencies {
|
||||
@@ -330,6 +334,13 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
|
||||
|
||||
waitingFor := containers.filter(isService(dep))
|
||||
w.Events(containerEvents(waitingFor, progress.Waiting))
|
||||
if len(waitingFor) == 0 {
|
||||
if config.Required {
|
||||
return fmt.Errorf("%s is missing dependency %s", dependant, dep)
|
||||
}
|
||||
logrus.Warnf("%s is missing dependency %s", dependant, dep)
|
||||
continue
|
||||
}
|
||||
|
||||
dep, config := dep, config
|
||||
eg.Go(func() error {
|
||||
@@ -365,7 +376,7 @@ func (s *composeService) waitDependencies(ctx context.Context, project *types.Pr
|
||||
return nil
|
||||
}
|
||||
w.Events(containerEvents(waitingFor, progress.ErrorEvent))
|
||||
return errors.Wrap(err, "dependency failed to start")
|
||||
return fmt.Errorf("dependency failed to start: %w", err)
|
||||
}
|
||||
if healthy {
|
||||
w.Events(containerEvents(waitingFor, progress.Healthy))
|
||||
@@ -616,6 +627,11 @@ func (s *composeService) createMobyContainer(ctx context.Context,
|
||||
}
|
||||
|
||||
err = s.injectSecrets(ctx, project, service, created.ID)
|
||||
if err != nil {
|
||||
return created, err
|
||||
}
|
||||
|
||||
err = s.injectConfigs(ctx, project, service, created.ID)
|
||||
return created, err
|
||||
}
|
||||
|
||||
@@ -729,7 +745,7 @@ func (s *composeService) startService(ctx context.Context, project *types.Projec
|
||||
return nil
|
||||
}
|
||||
|
||||
err := s.waitDependencies(ctx, project, service.DependsOn, containers)
|
||||
err := s.waitDependencies(ctx, project, service.Name, service.DependsOn, containers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -224,21 +224,21 @@ func TestWaitDependencies(t *testing.T) {
|
||||
t.Run("should skip dependencies with scale 0", func(t *testing.T) {
|
||||
dbService := types.ServiceConfig{Name: "db", Scale: 0}
|
||||
redisService := types.ServiceConfig{Name: "redis", Scale: 0}
|
||||
project := types.Project{Name: strings.ToLower(testProject), Services: []types.ServiceConfig{dbService, redisService}}
|
||||
project := types.Project{Name: strings.ToLower(testProject), Services: types.Services{dbService, redisService}}
|
||||
dependencies := types.DependsOnConfig{
|
||||
"db": {Condition: ServiceConditionRunningOrHealthy},
|
||||
"redis": {Condition: ServiceConditionRunningOrHealthy},
|
||||
}
|
||||
assert.NilError(t, tested.waitDependencies(context.Background(), &project, dependencies, nil))
|
||||
assert.NilError(t, tested.waitDependencies(context.Background(), &project, "", dependencies, nil))
|
||||
})
|
||||
t.Run("should skip dependencies with condition service_started", func(t *testing.T) {
|
||||
dbService := types.ServiceConfig{Name: "db", Scale: 1}
|
||||
redisService := types.ServiceConfig{Name: "redis", Scale: 1}
|
||||
project := types.Project{Name: strings.ToLower(testProject), Services: []types.ServiceConfig{dbService, redisService}}
|
||||
project := types.Project{Name: strings.ToLower(testProject), Services: types.Services{dbService, redisService}}
|
||||
dependencies := types.DependsOnConfig{
|
||||
"db": {Condition: types.ServiceConditionStarted, Required: true},
|
||||
"redis": {Condition: types.ServiceConditionStarted, Required: true},
|
||||
}
|
||||
assert.NilError(t, tested.waitDependencies(context.Background(), &project, dependencies, nil))
|
||||
assert.NilError(t, tested.waitDependencies(context.Background(), &project, "", dependencies, nil))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -32,7 +33,6 @@ import (
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type copyDirection int
|
||||
@@ -175,7 +175,7 @@ func (s *composeService) copyToContainer(ctx context.Context, containerID string
|
||||
|
||||
// Validate the destination path
|
||||
if err := command.ValidateOutputPathFileMode(dstStat.Mode); err != nil {
|
||||
return errors.Wrapf(err, `destination "%s:%s" must be a directory or a regular file`, containerID, dstPath)
|
||||
return fmt.Errorf(`destination "%s:%s" must be a directory or a regular file: %w`, containerID, dstPath, err)
|
||||
}
|
||||
|
||||
// Ignore any error and assume that the parent directory of the destination
|
||||
@@ -197,7 +197,7 @@ func (s *composeService) copyToContainer(ctx context.Context, containerID string
|
||||
content = s.stdin()
|
||||
resolvedDstPath = dstInfo.Path
|
||||
if !dstInfo.IsDir {
|
||||
return errors.Errorf("destination \"%s:%s\" must be a directory", containerID, dstPath)
|
||||
return fmt.Errorf("destination \"%s:%s\" must be a directory", containerID, dstPath)
|
||||
}
|
||||
} else {
|
||||
// Prepare source copy info.
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
@@ -38,7 +39,6 @@ import (
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
@@ -345,17 +345,17 @@ func parseSecurityOpts(p *types.Project, securityOpts []string) ([]string, bool,
|
||||
if strings.Contains(opt, ":") {
|
||||
con = strings.SplitN(opt, ":", 2)
|
||||
} else {
|
||||
return securityOpts, false, errors.Errorf("Invalid security-opt: %q", opt)
|
||||
return securityOpts, false, fmt.Errorf("Invalid security-opt: %q", opt)
|
||||
}
|
||||
}
|
||||
if con[0] == "seccomp" && con[1] != "unconfined" {
|
||||
f, err := os.ReadFile(p.RelativePath(con[1]))
|
||||
if err != nil {
|
||||
return securityOpts, false, errors.Errorf("opening seccomp profile (%s) failed: %v", con[1], err)
|
||||
return securityOpts, false, fmt.Errorf("opening seccomp profile (%s) failed: %w", con[1], err)
|
||||
}
|
||||
b := bytes.NewBuffer(nil)
|
||||
if err := json.Compact(b, f); err != nil {
|
||||
return securityOpts, false, errors.Errorf("compacting json for seccomp profile (%s) failed: %v", con[1], err)
|
||||
return securityOpts, false, fmt.Errorf("compacting json for seccomp profile (%s) failed: %w", con[1], err)
|
||||
}
|
||||
parsed = append(parsed, fmt.Sprintf("seccomp=%s", b.Bytes()))
|
||||
} else {
|
||||
@@ -521,7 +521,14 @@ func getDeployResources(s types.ServiceConfig) container.Resources {
|
||||
})
|
||||
}
|
||||
|
||||
for name, u := range s.Ulimits {
|
||||
ulimits := toUlimits(s.Ulimits)
|
||||
resources.Ulimits = ulimits
|
||||
return resources
|
||||
}
|
||||
|
||||
func toUlimits(m map[string]*types.UlimitsConfig) []*units.Ulimit {
|
||||
var ulimits []*units.Ulimit
|
||||
for name, u := range m {
|
||||
soft := u.Single
|
||||
if u.Soft != 0 {
|
||||
soft = u.Soft
|
||||
@@ -530,13 +537,13 @@ func getDeployResources(s types.ServiceConfig) container.Resources {
|
||||
if u.Hard != 0 {
|
||||
hard = u.Hard
|
||||
}
|
||||
resources.Ulimits = append(resources.Ulimits, &units.Ulimit{
|
||||
ulimits = append(ulimits, &units.Ulimit{
|
||||
Name: name,
|
||||
Hard: int64(hard),
|
||||
Soft: int64(soft),
|
||||
})
|
||||
}
|
||||
return resources
|
||||
return ulimits
|
||||
}
|
||||
|
||||
func setReservations(reservations *types.Resource, resources *container.Resources) {
|
||||
@@ -805,6 +812,17 @@ func buildContainerConfigMounts(p types.Project, s types.ServiceConfig) ([]mount
|
||||
return nil, fmt.Errorf("unsupported external config %s", definedConfig.Name)
|
||||
}
|
||||
|
||||
if definedConfig.Driver != "" {
|
||||
return nil, errors.New("Docker Compose does not support configs.*.driver")
|
||||
}
|
||||
if definedConfig.TemplateDriver != "" {
|
||||
return nil, errors.New("Docker Compose does not support configs.*.template_driver")
|
||||
}
|
||||
|
||||
if definedConfig.Environment != "" || definedConfig.Content != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
bindMount, err := buildMount(p, types.ServiceVolumeConfig{
|
||||
Type: types.VolumeTypeBind,
|
||||
Source: definedConfig.File,
|
||||
@@ -844,6 +862,13 @@ func buildContainerSecretMounts(p types.Project, s types.ServiceConfig) ([]mount
|
||||
return nil, fmt.Errorf("unsupported external secret %s", definedSecret.Name)
|
||||
}
|
||||
|
||||
if definedSecret.Driver != "" {
|
||||
return nil, errors.New("Docker Compose does not support secrets.*.driver")
|
||||
}
|
||||
if definedSecret.TemplateDriver != "" {
|
||||
return nil, errors.New("Docker Compose does not support secrets.*.template_driver")
|
||||
}
|
||||
|
||||
if definedSecret.Environment != "" {
|
||||
continue
|
||||
}
|
||||
@@ -1111,7 +1136,7 @@ func (s *composeService) resolveOrCreateNetwork(ctx context.Context, n *types.Ne
|
||||
_, err = s.apiClient().NetworkCreate(ctx, n.Name, createOpts)
|
||||
if err != nil {
|
||||
w.Event(progress.ErrorEvent(networkEventName))
|
||||
return errors.Wrapf(err, "failed to create network %s", n.Name)
|
||||
return fmt.Errorf("failed to create network %s: %w", n.Name, err)
|
||||
}
|
||||
w.Event(progress.CreatedEvent(networkEventName))
|
||||
return nil
|
||||
@@ -1125,13 +1150,27 @@ func (s *composeService) resolveExternalNetwork(ctx context.Context, n *types.Ne
|
||||
networks, err := s.apiClient().NetworkList(ctx, moby.NetworkListOptions{
|
||||
Filters: filters.NewArgs(filters.Arg("name", n.Name)),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(networks) == 0 {
|
||||
// in this instance, n.Name is really an ID
|
||||
sn, err := s.apiClient().NetworkInspect(ctx, n.Name, moby.NetworkInspectOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
networks = append(networks, sn)
|
||||
|
||||
}
|
||||
|
||||
// NetworkList API doesn't return the exact name match, so we can retrieve more than one network with a request
|
||||
networks = utils.Filter(networks, func(net moby.NetworkResource) bool {
|
||||
return net.Name == n.Name
|
||||
// later in this function, the name is changed the to ID.
|
||||
// this function is called during the rebuild stage of `compose watch`.
|
||||
// we still require just one network back, but we need to run the search on the ID
|
||||
return net.Name == n.Name || net.ID == n.Name
|
||||
})
|
||||
|
||||
switch len(networks) {
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
@@ -324,10 +323,10 @@ func (g *Graph) AddEdge(source string, destination string) error {
|
||||
destinationVertex := g.Vertices[destination]
|
||||
|
||||
if sourceVertex == nil {
|
||||
return errors.Wrapf(api.ErrNotFound, "could not find %s", source)
|
||||
return fmt.Errorf("could not find %s: %w", source, api.ErrNotFound)
|
||||
}
|
||||
if destinationVertex == nil {
|
||||
return errors.Wrapf(api.ErrNotFound, "could not find %s", destination)
|
||||
return fmt.Errorf("could not find %s: %w", destination, api.ErrNotFound)
|
||||
}
|
||||
|
||||
// If they are already connected
|
||||
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
|
||||
func createTestProject() *types.Project {
|
||||
return &types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "test1",
|
||||
DependsOn: map[string]types.ServiceDependency{
|
||||
@@ -59,7 +59,7 @@ func TestTraversalWithMultipleParents(t *testing.T) {
|
||||
}
|
||||
|
||||
project := types.Project{
|
||||
Services: []types.ServiceConfig{dependent},
|
||||
Services: types.Services{dependent},
|
||||
}
|
||||
|
||||
for i := 1; i <= 100; i++ {
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
containerType "github.com/docker/docker/api/types/container"
|
||||
"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"
|
||||
@@ -84,7 +83,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options a
|
||||
return err
|
||||
}
|
||||
|
||||
orphans := containers.filter(isNotService(project.ServiceNames()...))
|
||||
orphans := containers.filter(isOrphaned(project))
|
||||
if options.RemoveOrphans && len(orphans) > 0 {
|
||||
err := s.removeContainers(ctx, w, orphans, options.Timeout, false)
|
||||
if err != nil {
|
||||
@@ -192,7 +191,7 @@ func (s *composeService) removeNetwork(ctx context.Context, composeNetworkName s
|
||||
networkFilter(composeNetworkName)),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to list networks")
|
||||
return fmt.Errorf("failed to list networks: %w", err)
|
||||
}
|
||||
|
||||
if len(networks) == 0 {
|
||||
@@ -226,7 +225,7 @@ func (s *composeService) removeNetwork(ctx context.Context, composeNetworkName s
|
||||
continue
|
||||
}
|
||||
w.Event(progress.ErrorEvent(eventName))
|
||||
return errors.Wrapf(err, fmt.Sprintf("failed to remove network %s", name))
|
||||
return fmt.Errorf("failed to remove network %s: %w", name, err)
|
||||
}
|
||||
w.Event(progress.RemovedEvent(eventName))
|
||||
found++
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
package compose
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/compose-spec/compose-go/errdefs"
|
||||
)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
@@ -50,7 +51,8 @@ func (s *composeService) Exec(ctx context.Context, projectName string, options a
|
||||
}
|
||||
|
||||
err = container.RunExec(s.dockerCli, exec)
|
||||
if sterr, ok := err.(cli.StatusError); ok {
|
||||
var sterr cli.StatusError
|
||||
if errors.As(err, &sterr) {
|
||||
return sterr.StatusCode, nil
|
||||
}
|
||||
return 0, err
|
||||
|
||||
@@ -90,7 +90,7 @@ func (s *composeService) getImages(ctx context.Context, images []string) (map[st
|
||||
if errdefs.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
return fmt.Errorf("unable to get image '%s': %w", img, err)
|
||||
}
|
||||
tag := ""
|
||||
repository := ""
|
||||
|
||||
@@ -114,7 +114,7 @@ func testContainer(service string, id string, oneOff bool) moby.Container {
|
||||
}
|
||||
|
||||
func containerLabels(service string, oneOff bool) map[string]string {
|
||||
workingdir, _ := filepath.Abs("testdata")
|
||||
workingdir := "/src/pkg/compose/testdata"
|
||||
composefile := filepath.Join(workingdir, "compose.yaml")
|
||||
labels := map[string]string{
|
||||
compose.ServiceLabel: service,
|
||||
|
||||
@@ -18,6 +18,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -56,7 +57,8 @@ func (s *composeService) Logs(
|
||||
c := c
|
||||
eg.Go(func() error {
|
||||
err := s.logContainers(ctx, consumer, c, options)
|
||||
if _, ok := err.(errdefs.ErrNotImplemented); ok {
|
||||
var notImplErr errdefs.ErrNotImplemented
|
||||
if errors.As(err, ¬ImplErr) {
|
||||
logrus.Warnf("Can't retrieve logs for %q: %s", getCanonicalContainerName(c), err.Error())
|
||||
return nil
|
||||
}
|
||||
@@ -97,7 +99,8 @@ func (s *composeService) Logs(
|
||||
Tail: options.Tail,
|
||||
Timestamps: options.Timestamps,
|
||||
})
|
||||
if _, ok := err.(errdefs.ErrNotImplemented); ok {
|
||||
var notImplErr errdefs.ErrNotImplemented
|
||||
if errors.As(err, ¬ImplErr) {
|
||||
// ignore
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/distribution/reference"
|
||||
@@ -61,36 +63,24 @@ func (s *composeService) publish(ctx context.Context, project *types.Project, re
|
||||
return err
|
||||
}
|
||||
|
||||
w.Event(progress.Event{
|
||||
ID: file,
|
||||
Text: "publishing",
|
||||
Status: progress.Working,
|
||||
})
|
||||
layer := v1.Descriptor{
|
||||
MediaType: "application/vnd.docker.compose.file+yaml",
|
||||
Digest: digest.FromString(string(f)),
|
||||
Size: int64(len(f)),
|
||||
Annotations: map[string]string{
|
||||
"com.docker.compose": api.ComposeVersion,
|
||||
},
|
||||
layer, err := s.pushComposeFile(ctx, file, f, resolver, named)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layers = append(layers, layer)
|
||||
err = resolver.Push(ctx, named, layer, f)
|
||||
if err != nil {
|
||||
w.Event(progress.Event{
|
||||
ID: file,
|
||||
Text: "publishing",
|
||||
Status: progress.Error,
|
||||
})
|
||||
}
|
||||
|
||||
if options.ResolveImageDigests {
|
||||
yaml, err := s.generateImageDigestsOverride(ctx, project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.Event(progress.Event{
|
||||
ID: file,
|
||||
Text: "published",
|
||||
Status: progress.Done,
|
||||
})
|
||||
layer, err := s.pushComposeFile(ctx, "image-digests.yaml", yaml, resolver, named)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layers = append(layers, layer)
|
||||
}
|
||||
|
||||
emptyConfig, err := json.Marshal(v1.ImageConfig{})
|
||||
@@ -98,27 +88,29 @@ func (s *composeService) publish(ctx context.Context, project *types.Project, re
|
||||
return err
|
||||
}
|
||||
configDescriptor := v1.Descriptor{
|
||||
MediaType: "application/vnd.docker.compose.project",
|
||||
MediaType: "application/vnd.oci.empty.v1+json",
|
||||
Digest: digest.FromBytes(emptyConfig),
|
||||
Size: int64(len(emptyConfig)),
|
||||
Annotations: map[string]string{
|
||||
"com.docker.compose.version": api.ComposeVersion,
|
||||
},
|
||||
}
|
||||
err = resolver.Push(ctx, named, configDescriptor, emptyConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
imageManifest, err := json.Marshal(v1.Manifest{
|
||||
Versioned: specs.Versioned{SchemaVersion: 2},
|
||||
MediaType: v1.MediaTypeImageManifest,
|
||||
ArtifactType: "application/vnd.docker.compose.project",
|
||||
Config: configDescriptor,
|
||||
Layers: layers,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
var imageManifest []byte
|
||||
if !s.dryRun {
|
||||
err = resolver.Push(ctx, named, configDescriptor, emptyConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imageManifest, err = json.Marshal(v1.Manifest{
|
||||
Versioned: specs.Versioned{SchemaVersion: 2},
|
||||
MediaType: v1.MediaTypeImageManifest,
|
||||
ArtifactType: "application/vnd.docker.compose.project",
|
||||
Config: configDescriptor,
|
||||
Layers: layers,
|
||||
Annotations: map[string]string{
|
||||
"org.opencontainers.image.created": time.Now().Format(time.RFC3339),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
w.Event(progress.Event{
|
||||
@@ -126,23 +118,24 @@ func (s *composeService) publish(ctx context.Context, project *types.Project, re
|
||||
Text: "publishing",
|
||||
Status: progress.Working,
|
||||
})
|
||||
|
||||
err = resolver.Push(ctx, named, v1.Descriptor{
|
||||
MediaType: v1.MediaTypeImageManifest,
|
||||
Digest: digest.FromString(string(imageManifest)),
|
||||
Size: int64(len(imageManifest)),
|
||||
Annotations: map[string]string{
|
||||
"com.docker.compose.version": api.ComposeVersion,
|
||||
},
|
||||
ArtifactType: "application/vnd.docker.compose.project",
|
||||
}, imageManifest)
|
||||
if err != nil {
|
||||
w.Event(progress.Event{
|
||||
ID: repository,
|
||||
Text: "publishing",
|
||||
Status: progress.Error,
|
||||
})
|
||||
return err
|
||||
if !s.dryRun {
|
||||
err = resolver.Push(ctx, named, v1.Descriptor{
|
||||
MediaType: v1.MediaTypeImageManifest,
|
||||
Digest: digest.FromString(string(imageManifest)),
|
||||
Size: int64(len(imageManifest)),
|
||||
Annotations: map[string]string{
|
||||
"com.docker.compose.version": api.ComposeVersion,
|
||||
},
|
||||
ArtifactType: "application/vnd.docker.compose.project",
|
||||
}, imageManifest)
|
||||
if err != nil {
|
||||
w.Event(progress.Event{
|
||||
ID: repository,
|
||||
Text: "publishing",
|
||||
Status: progress.Error,
|
||||
})
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.Event(progress.Event{
|
||||
ID: repository,
|
||||
@@ -151,3 +144,61 @@ func (s *composeService) publish(ctx context.Context, project *types.Project, re
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) generateImageDigestsOverride(ctx context.Context, project *types.Project) ([]byte, error) {
|
||||
project.ApplyProfiles([]string{"*"})
|
||||
err := project.ResolveImages(func(named reference.Named) (digest.Digest, error) {
|
||||
auth, err := encodedAuth(named, s.configFile())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
inspect, err := s.apiClient().DistributionInspect(ctx, named.String(), auth)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return inspect.Descriptor.Digest, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
override := types.Project{}
|
||||
for _, service := range project.Services {
|
||||
override.Services = append(override.Services, types.ServiceConfig{
|
||||
Name: service.Name,
|
||||
Image: service.Image,
|
||||
})
|
||||
}
|
||||
return override.MarshalYAML()
|
||||
}
|
||||
|
||||
func (s *composeService) pushComposeFile(ctx context.Context, file string, content []byte, resolver *imagetools.Resolver, named reference.Named) (v1.Descriptor, error) {
|
||||
w := progress.ContextWriter(ctx)
|
||||
w.Event(progress.Event{
|
||||
ID: file,
|
||||
Text: "publishing",
|
||||
Status: progress.Working,
|
||||
})
|
||||
layer := v1.Descriptor{
|
||||
MediaType: "application/vnd.docker.compose.file+yaml",
|
||||
Digest: digest.FromString(string(content)),
|
||||
Size: int64(len(content)),
|
||||
Annotations: map[string]string{
|
||||
"com.docker.compose.version": api.ComposeVersion,
|
||||
"com.docker.compose.file": filepath.Base(file),
|
||||
},
|
||||
}
|
||||
err := resolver.Push(ctx, named, layer, content)
|
||||
w.Event(progress.Event{
|
||||
ID: file,
|
||||
Text: "published",
|
||||
Status: statusFor(err),
|
||||
})
|
||||
return layer, err
|
||||
}
|
||||
|
||||
func statusFor(err error) progress.EventStatus {
|
||||
if err != nil {
|
||||
return progress.Error
|
||||
}
|
||||
return progress.Done
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser
|
||||
for {
|
||||
var jm jsonmessage.JSONMessage
|
||||
if err := dec.Decode(&jm); err != nil {
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
return "", WrapCategorisedComposeError(err, PullFailure)
|
||||
@@ -260,7 +260,7 @@ func encodedAuth(ref reference.Named, configFile driver.Auth) (string, error) {
|
||||
}
|
||||
|
||||
func (s *composeService) pullRequiredImages(ctx context.Context, project *types.Project, images map[string]string, quietPull bool) error {
|
||||
var needPull []types.ServiceConfig
|
||||
var needPull types.Services
|
||||
for _, service := range project.Services {
|
||||
if service.Image == "" {
|
||||
continue
|
||||
@@ -308,7 +308,7 @@ func (s *composeService) pullRequiredImages(ctx context.Context, project *types.
|
||||
}, s.stdinfo())
|
||||
}
|
||||
|
||||
func isServiceImageToBuild(service types.ServiceConfig, services []types.ServiceConfig) bool {
|
||||
func isServiceImageToBuild(service types.ServiceConfig, services types.Services) bool {
|
||||
if service.Build != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/distribution/reference"
|
||||
@@ -29,7 +31,6 @@ import (
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -68,22 +69,30 @@ func (s *composeService) push(ctx context.Context, project *types.Project, optio
|
||||
continue
|
||||
}
|
||||
service := service
|
||||
eg.Go(func() error {
|
||||
err := s.pushServiceImage(ctx, service, info, s.configFile(), w, options.Quiet)
|
||||
if err != nil {
|
||||
if !options.IgnoreFailures {
|
||||
return err
|
||||
tags := []string{service.Image}
|
||||
if service.Build != nil {
|
||||
tags = append(tags, service.Build.Tags...)
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
tag := tag
|
||||
eg.Go(func() error {
|
||||
err := s.pushServiceImage(ctx, tag, info, s.configFile(), w, options.Quiet)
|
||||
if err != nil {
|
||||
if !options.IgnoreFailures {
|
||||
return err
|
||||
}
|
||||
w.TailMsgf("Pushing %s: %s", service.Name, err.Error())
|
||||
}
|
||||
w.TailMsgf("Pushing %s: %s", service.Name, err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func (s *composeService) pushServiceImage(ctx context.Context, service types.ServiceConfig, info moby.Info, configFile driver.Auth, w progress.Writer, quietPush bool) error {
|
||||
ref, err := reference.ParseNormalizedNamed(service.Image)
|
||||
func (s *composeService) pushServiceImage(ctx context.Context, tag string, info moby.Info, configFile driver.Auth, w progress.Writer, quietPush bool) error {
|
||||
ref, err := reference.ParseNormalizedNamed(tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -107,7 +116,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, tag, moby.ImagePushOptions{
|
||||
RegistryAuth: base64.URLEncoding.EncodeToString(buf),
|
||||
})
|
||||
if err != nil {
|
||||
@@ -117,7 +126,7 @@ func (s *composeService) pushServiceImage(ctx context.Context, service types.Ser
|
||||
for {
|
||||
var jm jsonmessage.JSONMessage
|
||||
if err := dec.Decode(&jm); err != nil {
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
return err
|
||||
@@ -127,9 +136,10 @@ func (s *composeService) pushServiceImage(ctx context.Context, service types.Ser
|
||||
}
|
||||
|
||||
if !quietPush {
|
||||
toPushProgressEvent(service.Name, jm, w)
|
||||
toPushProgressEvent(tag, jm, w)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -145,7 +155,7 @@ func toPushProgressEvent(prefix string, jm jsonmessage.JSONMessage, w progress.W
|
||||
current int64
|
||||
percent int
|
||||
)
|
||||
if jm.Status == "Pushed" || jm.Status == "Already exists" {
|
||||
if isDone(jm) {
|
||||
status = progress.Done
|
||||
percent = 100
|
||||
}
|
||||
@@ -174,3 +184,13 @@ func toPushProgressEvent(prefix string, jm jsonmessage.JSONMessage, w progress.W
|
||||
StatusText: text,
|
||||
})
|
||||
}
|
||||
|
||||
func isDone(msg jsonmessage.JSONMessage) bool {
|
||||
// TODO there should be a better way to detect push is done than such a status message check
|
||||
switch strings.ToLower(msg.Status) {
|
||||
case "pushed", "layer already exists":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
|
||||
}
|
||||
|
||||
if !opts.NoDeps {
|
||||
if err := s.waitDependencies(ctx, project, service.DependsOn, observedState); err != nil {
|
||||
if err := s.waitDependencies(ctx, project, service.Name, service.DependsOn, observedState); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (s *composeService) injectSecrets(ctx context.Context, project *types.Proje
|
||||
if !ok {
|
||||
return fmt.Errorf("environment variable %q required by secret %q is not set", secret.Environment, secret.Name)
|
||||
}
|
||||
b, err := createTar(env, config)
|
||||
b, err := createTar(env, types.FileReferenceConfig(config))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -54,7 +54,37 @@ func (s *composeService) injectSecrets(ctx context.Context, project *types.Proje
|
||||
return nil
|
||||
}
|
||||
|
||||
func createTar(env string, config types.ServiceSecretConfig) (bytes.Buffer, error) {
|
||||
func (s *composeService) injectConfigs(ctx context.Context, project *types.Project, service types.ServiceConfig, id string) error {
|
||||
for _, config := range service.Configs {
|
||||
secret := project.Configs[config.Source]
|
||||
content := secret.Content
|
||||
if secret.Environment != "" {
|
||||
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)
|
||||
}
|
||||
content = env
|
||||
}
|
||||
if content == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
b, err := createTar(content, types.FileReferenceConfig(config))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.apiClient().CopyToContainer(ctx, id, "/", &b, moby.CopyToContainerOptions{
|
||||
CopyUIDGID: config.UID != "" || config.GID != "",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createTar(env string, config types.FileReferenceConfig) (bytes.Buffer, error) {
|
||||
value := []byte(env)
|
||||
b := bytes.Buffer{}
|
||||
tarWriter := tar.NewWriter(&b)
|
||||
|
||||
@@ -18,6 +18,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -31,7 +32,6 @@ import (
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@@ -148,9 +148,9 @@ func (s *composeService) start(ctx context.Context, projectName string, options
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
err = s.waitDependencies(ctx, project, depends, containers)
|
||||
err = s.waitDependencies(ctx, project, project.Name, depends, containers)
|
||||
if err != nil {
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
||||
return fmt.Errorf("application not healthy after %s", options.WaitTimeout)
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
@@ -55,76 +54,79 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
|
||||
return err
|
||||
}
|
||||
|
||||
var eg multierror.Group
|
||||
|
||||
// if we get a second signal during shutdown, we kill the services
|
||||
// immediately, so the channel needs to have sufficient capacity or
|
||||
// we might miss a signal while setting up the second channel read
|
||||
// (this is also why signal.Notify is used vs signal.NotifyContext)
|
||||
signalChan := make(chan os.Signal, 2)
|
||||
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
signalCancel := sync.OnceFunc(func() {
|
||||
signal.Stop(signalChan)
|
||||
close(signalChan)
|
||||
defer close(signalChan)
|
||||
var isTerminated bool
|
||||
|
||||
doneCh := make(chan bool)
|
||||
eg.Go(func() error {
|
||||
first := true
|
||||
for {
|
||||
select {
|
||||
case <-doneCh:
|
||||
return nil
|
||||
case <-signalChan:
|
||||
if first {
|
||||
fmt.Fprintln(s.stdinfo(), "Gracefully stopping... (press Ctrl+C again to force)")
|
||||
eg.Go(func() error {
|
||||
err := s.Stop(context.Background(), project.Name, api.StopOptions{
|
||||
Services: options.Create.Services,
|
||||
Project: project,
|
||||
})
|
||||
isTerminated = true
|
||||
close(doneCh)
|
||||
return err
|
||||
})
|
||||
first = false
|
||||
} else {
|
||||
eg.Go(func() error {
|
||||
return s.Kill(context.Background(), project.Name, api.KillOptions{
|
||||
Services: options.Create.Services,
|
||||
Project: project,
|
||||
})
|
||||
})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
defer signalCancel()
|
||||
|
||||
printer := newLogPrinter(options.Start.Attach)
|
||||
stopFunc := func() error {
|
||||
fmt.Fprintln(s.stdinfo(), "Aborting on container exit...")
|
||||
ctx := context.Background()
|
||||
return progress.Run(ctx, func(ctx context.Context) error {
|
||||
// race two goroutines - one that blocks until another signal is received
|
||||
// and then does a Kill() and one that immediately starts a friendly Stop()
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
if _, ok := <-signalChan; !ok {
|
||||
// channel closed, so the outer function is done, which
|
||||
// means the other goroutine (calling Stop()) finished
|
||||
return
|
||||
}
|
||||
errCh <- s.Kill(ctx, project.Name, api.KillOptions{
|
||||
Services: options.Create.Services,
|
||||
Project: project,
|
||||
})
|
||||
}()
|
||||
|
||||
go func() {
|
||||
errCh <- s.Stop(ctx, project.Name, api.StopOptions{
|
||||
Services: options.Create.Services,
|
||||
Project: project,
|
||||
})
|
||||
}()
|
||||
return <-errCh
|
||||
}, s.stdinfo())
|
||||
}
|
||||
|
||||
var isTerminated bool
|
||||
var eg multierror.Group
|
||||
eg.Go(func() error {
|
||||
if _, ok := <-signalChan; !ok {
|
||||
// function finished without receiving a signal
|
||||
return nil
|
||||
}
|
||||
isTerminated = true
|
||||
printer.Cancel()
|
||||
fmt.Fprintln(s.stdinfo(), "Gracefully stopping... (press Ctrl+C again to force)")
|
||||
return stopFunc()
|
||||
})
|
||||
|
||||
var exitCode int
|
||||
eg.Go(func() error {
|
||||
code, err := printer.Run(options.Start.CascadeStop, options.Start.ExitCodeFrom, stopFunc)
|
||||
code, err := printer.Run(options.Start.CascadeStop, options.Start.ExitCodeFrom, func() error {
|
||||
fmt.Fprintln(s.stdinfo(), "Aborting on container exit...")
|
||||
return progress.Run(ctx, func(ctx context.Context) error {
|
||||
return s.Stop(ctx, project.Name, api.StopOptions{
|
||||
Services: options.Create.Services,
|
||||
Project: project,
|
||||
})
|
||||
}, s.stdinfo())
|
||||
})
|
||||
exitCode = code
|
||||
return err
|
||||
})
|
||||
|
||||
err = s.start(ctx, project.Name, options.Start, printer.HandleEvent)
|
||||
// We don't use parent (cancelable) context as we manage sigterm to stop the stack
|
||||
err = s.start(context.Background(), project.Name, options.Start, printer.HandleEvent)
|
||||
if err != nil && !isTerminated { // Ignore error if the process is terminated
|
||||
return err
|
||||
}
|
||||
|
||||
// signal for the goroutines to stop & wait for them to finish any remaining work
|
||||
signalCancel()
|
||||
printer.Stop()
|
||||
|
||||
if !isTerminated {
|
||||
// signal for the signal-handler goroutines to stop
|
||||
close(doneCh)
|
||||
}
|
||||
err = eg.Wait().ErrorOrNil()
|
||||
if exitCode != 0 {
|
||||
errMsg := ""
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestViz(t *testing.T) {
|
||||
project := types.Project{
|
||||
Name: "viz-test",
|
||||
WorkingDir: "/home",
|
||||
Services: []types.ServiceConfig{
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "service1",
|
||||
Image: "image-for-service1",
|
||||
|
||||
@@ -16,6 +16,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -33,7 +34,6 @@ import (
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -121,13 +121,14 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
|
||||
dotGitIgnore,
|
||||
)
|
||||
|
||||
var paths []string
|
||||
var paths, pathLogs []string
|
||||
for _, trigger := range config.Watch {
|
||||
if checkIfPathAlreadyBindMounted(trigger.Path, service.Volumes) {
|
||||
logrus.Warnf("path '%s' also declared by a bind mount volume, this path won't be monitored!\n", trigger.Path)
|
||||
continue
|
||||
}
|
||||
paths = append(paths, trigger.Path)
|
||||
pathLogs = append(pathLogs, fmt.Sprintf("Action %s for path %q", trigger.Action, trigger.Path))
|
||||
}
|
||||
|
||||
watcher, err := watch.NewWatcher(paths, ignore)
|
||||
@@ -135,7 +136,12 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(s.stdinfo(), "watching %s\n", paths)
|
||||
fmt.Fprintf(
|
||||
s.stdinfo(),
|
||||
"Watch configuration for service %q:%s\n",
|
||||
service.Name,
|
||||
strings.Join(append([]string{""}, pathLogs...), "\n - "),
|
||||
)
|
||||
err = watcher.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -149,7 +155,7 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
|
||||
}
|
||||
|
||||
if !watching {
|
||||
return fmt.Errorf("none of the selected services is configured for watch, consider setting an 'x-develop' section")
|
||||
return fmt.Errorf("none of the selected services is configured for watch, consider setting an 'develop' section")
|
||||
}
|
||||
|
||||
return eg.Wait()
|
||||
@@ -415,11 +421,12 @@ func (t tarDockerClient) Exec(ctx context.Context, containerID string, cmd []str
|
||||
|
||||
func (s *composeService) handleWatchBatch(ctx context.Context, project *types.Project, serviceName string, build api.BuildOptions, batch []fileEvent, syncer sync.Syncer) error {
|
||||
pathMappings := make([]sync.PathMapping, len(batch))
|
||||
restartService := false
|
||||
for i := range batch {
|
||||
if batch[i].Action == types.WatchActionRebuild {
|
||||
fmt.Fprintf(
|
||||
s.stdinfo(),
|
||||
"Rebuilding %s after changes were detected:%s\n",
|
||||
"Rebuilding service %q after changes were detected:%s\n",
|
||||
serviceName,
|
||||
strings.Join(append([]string{""}, batch[i].HostPath), "\n - "),
|
||||
)
|
||||
@@ -437,10 +444,13 @@ func (s *composeService) handleWatchBatch(ctx context.Context, project *types.Pr
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(s.stderr(), "Application failed to start after update\n")
|
||||
fmt.Fprintf(s.stderr(), "Application failed to start after update. Error: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if batch[i].Action == types.WatchActionSyncRestart {
|
||||
restartService = true
|
||||
}
|
||||
pathMappings[i] = batch[i].PathMapping
|
||||
}
|
||||
|
||||
@@ -453,6 +463,13 @@ func (s *composeService) handleWatchBatch(ctx context.Context, project *types.Pr
|
||||
if err := syncer.Sync(ctx, service, pathMappings); err != nil {
|
||||
return err
|
||||
}
|
||||
if restartService {
|
||||
return s.Restart(ctx, project.Name, api.RestartOptions{
|
||||
Services: []string{serviceName},
|
||||
Project: project,
|
||||
NoDeps: false,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -466,7 +483,7 @@ func writeWatchSyncMessage(w io.Writer, serviceName string, pathMappings []sync.
|
||||
}
|
||||
fmt.Fprintf(
|
||||
w,
|
||||
"Syncing %s after changes were detected:%s\n",
|
||||
"Syncing %q after changes were detected:%s\n",
|
||||
serviceName,
|
||||
strings.Join(append([]string{""}, hostPathsToSync...), "\n - "),
|
||||
)
|
||||
@@ -477,7 +494,7 @@ func writeWatchSyncMessage(w io.Writer, serviceName string, pathMappings []sync.
|
||||
}
|
||||
fmt.Fprintf(
|
||||
w,
|
||||
"Syncing %s after %d changes were detected\n",
|
||||
"Syncing service %q after %d changes were detected\n",
|
||||
serviceName,
|
||||
len(pathMappings),
|
||||
)
|
||||
|
||||
@@ -105,7 +105,7 @@ func TestWatch_Sync(t *testing.T) {
|
||||
t.Cleanup(cancelFunc)
|
||||
|
||||
proj := types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "test",
|
||||
},
|
||||
|
||||
@@ -333,7 +333,7 @@ func TestBuildPlatformsWithCorrectBuildxConfig(t *testing.T) {
|
||||
t.Run("multi-arch up --build", func(t *testing.T) {
|
||||
res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test/platforms", "up", "--build")
|
||||
assert.NilError(t, res.Error, res.Stderr())
|
||||
res.Assert(t, icmd.Expected{Out: "platforms-platforms-1 exited with code 0"})
|
||||
res.Assert(t, icmd.Expected{Out: "platforms-1 exited with code 0"})
|
||||
})
|
||||
|
||||
t.Run("use DOCKER_DEFAULT_PLATFORM value when up --build", func(t *testing.T) {
|
||||
|
||||
@@ -106,6 +106,20 @@ func TestEnvPriority(t *testing.T) {
|
||||
assert.Equal(t, strings.TrimSpace(res.Stdout()), "EnvFileDefaultValue")
|
||||
})
|
||||
|
||||
// No Compose file, all other options with env variable from OS environment
|
||||
// 1. Command Line (docker compose run --env <KEY[=VAL]>) <-- Result expected (From environment default value from file in COMPOSE_ENV_FILES)
|
||||
// 2. Compose File (service::environment section)
|
||||
// 3. Compose File (service::env_file section file)
|
||||
// 4. Container Image ENV directive
|
||||
// 5. Variable is not defined
|
||||
t.Run("shell priority from COMPOSE_ENV_FILES variable", func(t *testing.T) {
|
||||
cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml",
|
||||
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
|
||||
cmd.Env = append(cmd.Env, "COMPOSE_ENV_FILES=./fixtures/environment/env-priority/.env.override.with.default")
|
||||
res := icmd.RunCmd(cmd)
|
||||
assert.Equal(t, strings.TrimSpace(res.Stdout()), "EnvFileDefaultValue")
|
||||
})
|
||||
|
||||
// No Compose file and env variable pass to the run command
|
||||
// 1. Command Line (docker compose run --env <KEY[=VAL]>) <-- Result expected
|
||||
// 2. Compose File (service::environment section)
|
||||
|
||||
@@ -96,10 +96,18 @@ func TestLocalComposeRun(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("compose run --publish", func(t *testing.T) {
|
||||
c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "run", "--publish", "8081:80", "-d", "back",
|
||||
c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/ports.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())
|
||||
assert.Assert(t, !strings.Contains(res.Stdout(), "8082->80/tcp"), res.Stdout())
|
||||
})
|
||||
|
||||
t.Run("compose run --service-ports", func(t *testing.T) {
|
||||
c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/ports.yaml", "run", "--service-ports", "-d", "back",
|
||||
"/bin/sh", "-c", "sleep 1")
|
||||
res := c.RunDockerCmd(t, "ps")
|
||||
assert.Assert(t, strings.Contains(res.Stdout(), "8082->80/tcp"), res.Stdout())
|
||||
})
|
||||
|
||||
t.Run("compose run orphan", func(t *testing.T) {
|
||||
|
||||
@@ -141,6 +141,8 @@ func TestDownComposefileInParentFolder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAttachRestart(t *testing.T) {
|
||||
t.Skip("Skipping test until we can fix it")
|
||||
|
||||
if _, ok := os.LookupEnv("CI"); ok {
|
||||
t.Skip("Skipping test on CI... flaky")
|
||||
}
|
||||
@@ -290,3 +292,24 @@ func TestStopWithDependenciesAttached(t *testing.T) {
|
||||
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/dependencies/compose.yaml", "-p", projectName, "up", "--attach-dependencies", "foo")
|
||||
res.Assert(t, icmd.Expected{Out: "exited with code 0"})
|
||||
}
|
||||
|
||||
func TestRemoveOrphaned(t *testing.T) {
|
||||
const projectName = "compose-e2e-remove-orphaned"
|
||||
c := NewParallelCLI(t)
|
||||
|
||||
cleanup := func() {
|
||||
c.RunDockerComposeCmd(t, "-p", projectName, "down", "--remove-orphans", "--timeout=0")
|
||||
}
|
||||
cleanup()
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
// run stack
|
||||
c.RunDockerComposeCmd(t, "-f", "./fixtures/sentences/compose.yaml", "-p", projectName, "up", "-d")
|
||||
|
||||
// down "web" service with orphaned removed
|
||||
c.RunDockerComposeCmd(t, "-f", "./fixtures/sentences/compose.yaml", "-p", projectName, "down", "--remove-orphans", "web")
|
||||
|
||||
// check "words" service has not been considered orphaned
|
||||
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/sentences/compose.yaml", "-p", projectName, "ps", "--format", "{{.Name}}")
|
||||
res.Assert(t, icmd.Expected{Out: fmt.Sprintf("%s-words-1", projectName)})
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user