mirror of
https://github.com/docker/compose.git
synced 2026-02-11 19:19:23 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00bd108aec |
@@ -36,13 +36,9 @@ linters-settings:
|
||||
deny:
|
||||
- pkg: io/ioutil
|
||||
desc: 'io/ioutil package has been deprecated'
|
||||
- pkg: gopkg.in/yaml.v2
|
||||
desc: 'compose-go uses yaml.v3'
|
||||
gomodguard:
|
||||
blocked:
|
||||
versions:
|
||||
- github.com/distribution/distribution:
|
||||
reason: "use distribution/reference"
|
||||
- gotest.tools:
|
||||
version: "< 3.0.0"
|
||||
reason: "deprecated, pre-modules version"
|
||||
@@ -65,3 +61,5 @@ issues:
|
||||
# golangci hides some golint warnings (the warning about exported things
|
||||
# withtout documentation for example), this will make it show them anyway.
|
||||
exclude-use-default: false
|
||||
exclude:
|
||||
- should not use dot imports
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
# 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.0
|
||||
ARG XX_VERSION=1.2.1
|
||||
ARG GOLANGCI_LINT_VERSION=v1.54.2
|
||||
ARG GOLANGCI_LINT_VERSION=v1.53.2
|
||||
ARG ADDLICENSE_VERSION=v1.0.0
|
||||
|
||||
ARG BUILD_TAGS="e2e"
|
||||
@@ -89,13 +89,10 @@ RUN --mount=type=bind,target=. \
|
||||
|
||||
FROM build-base AS lint
|
||||
ARG BUILD_TAGS
|
||||
ENV GOLANGCI_LINT_CACHE=/cache/golangci-lint
|
||||
RUN --mount=type=bind,target=. \
|
||||
--mount=type=cache,target=/root/.cache \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=cache,target=/cache/golangci-lint \
|
||||
--mount=from=golangci-lint,source=/usr/bin/golangci-lint,target=/usr/bin/golangci-lint \
|
||||
golangci-lint cache status && \
|
||||
golangci-lint run --build-tags "$BUILD_TAGS" ./...
|
||||
|
||||
FROM build-base AS test
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Table of Contents
|
||||
- [Docker Compose v2](#docker-compose-v2)
|
||||
- [About update and backward compatibility](#about-update-and-backward-compatibility)
|
||||
- [Where to get Docker Compose](#where-to-get-docker-compose)
|
||||
+ [Windows and macOS](#windows-and-macos)
|
||||
+ [Linux](#linux)
|
||||
@@ -83,4 +84,4 @@ If you find an issue, please report it on the
|
||||
Legacy
|
||||
-------------
|
||||
|
||||
The Python version of Compose is available under the `v1` [branch](https://github.com/docker/compose/tree/v1).
|
||||
The Python version of Compose is available under the `v1` [branch](https://github.com/docker/compose/tree/v1)
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
commands "github.com/docker/compose/v2/cmd/compose"
|
||||
"github.com/docker/compose/v2/internal/tracing"
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
@@ -43,7 +42,7 @@ import (
|
||||
// vars, creates a root span for the command, and wraps the actual
|
||||
// command invocation to ensure the span is properly finalized and
|
||||
// exported before exit.
|
||||
func Setup(cmd *cobra.Command, dockerCli command.Cli, args []string) error {
|
||||
func Setup(cmd *cobra.Command, dockerCli command.Cli) error {
|
||||
tracingShutdown, err := tracing.InitTracing(dockerCli)
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing tracing: %w", err)
|
||||
@@ -54,9 +53,6 @@ func Setup(cmd *cobra.Command, dockerCli command.Cli, args []string) error {
|
||||
ctx,
|
||||
"cli/"+strings.Join(commandName(cmd), "-"),
|
||||
)
|
||||
cmdSpan.SetAttributes(attribute.StringSlice("cli.args", args))
|
||||
cmdSpan.SetAttributes(attribute.StringSlice("cli.flags", getFlags(cmd.Flags())))
|
||||
|
||||
cmd.SetContext(ctx)
|
||||
wrapRunE(cmd, cmdSpan, tracingShutdown)
|
||||
return nil
|
||||
@@ -133,11 +129,3 @@ func commandName(cmd *cobra.Command) []string {
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(name)))
|
||||
return name
|
||||
}
|
||||
|
||||
func getFlags(fs *flag.FlagSet) []string {
|
||||
var result []string
|
||||
fs.Visit(func(flag *flag.Flag) {
|
||||
result = append(result, flag.Name)
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cmdtrace
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func TestGetFlags(t *testing.T) {
|
||||
// Initialize flagSet with flags
|
||||
fs := flag.NewFlagSet("up", flag.ContinueOnError)
|
||||
var (
|
||||
detach string
|
||||
timeout string
|
||||
)
|
||||
fs.StringVar(&detach, "detach", "d", "")
|
||||
fs.StringVar(&timeout, "timeout", "t", "")
|
||||
_ = fs.Set("detach", "detach")
|
||||
_ = fs.Set("timeout", "timeout")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input *flag.FlagSet
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "NoFlags",
|
||||
input: flag.NewFlagSet("NoFlags", flag.ContinueOnError),
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "Flags",
|
||||
input: fs,
|
||||
expected: []string{"detach", "timeout"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
result := getFlags(test.input)
|
||||
if !reflect.DeepEqual(result, test.expected) {
|
||||
t.Errorf("Expected %v, but got %v", test.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,13 +15,12 @@
|
||||
package compose
|
||||
|
||||
import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// alphaCommand groups all experimental subcommands
|
||||
func alphaCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func alphaCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Short: "Experimental commands",
|
||||
Use: "alpha [COMMAND]",
|
||||
@@ -31,9 +30,9 @@ func alphaCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
},
|
||||
}
|
||||
cmd.AddCommand(
|
||||
watchCommand(p, dockerCli, backend),
|
||||
vizCommand(p, dockerCli, backend),
|
||||
publishCommand(p, dockerCli, backend),
|
||||
watchCommand(p, backend),
|
||||
vizCommand(p, backend),
|
||||
publishCommand(p, backend),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"github.com/compose-spec/compose-go/loader"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
buildx "github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/command"
|
||||
cliopts "github.com/docker/cli/opts"
|
||||
ui "github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -36,6 +35,7 @@ import (
|
||||
|
||||
type buildOptions struct {
|
||||
*ProjectOptions
|
||||
composeOptions
|
||||
quiet bool
|
||||
pull bool
|
||||
push bool
|
||||
@@ -73,7 +73,7 @@ func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func buildCommand(p *ProjectOptions, progress *string, backend api.Service) *cobra.Command {
|
||||
opts := buildOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -98,9 +98,9 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
if cmd.Flags().Changed("progress") && opts.ssh == "" {
|
||||
fmt.Fprint(os.Stderr, "--progress is a global compose flag, better use `docker compose --progress xx build ...")
|
||||
}
|
||||
return runBuild(ctx, dockerCli, backend, opts, args)
|
||||
return runBuild(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
cmd.Flags().BoolVar(&opts.push, "push", false, "Push service images.")
|
||||
cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT")
|
||||
@@ -118,22 +118,18 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
cmd.Flags().Bool("no-rm", false, "Do not remove intermediate containers after a successful build. DEPRECATED")
|
||||
cmd.Flags().MarkHidden("no-rm") //nolint:errcheck
|
||||
cmd.Flags().VarP(&opts.memory, "memory", "m", "Set memory limit for the build container. Not supported by BuildKit.")
|
||||
cmd.Flags().StringVar(&p.Progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of ui output (%s)`, strings.Join(printerModes, ", ")))
|
||||
cmd.Flags().StringVar(progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of ui output (%s)`, strings.Join(printerModes, ", ")))
|
||||
cmd.Flags().MarkHidden("progress") //nolint:errcheck
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runBuild(ctx context.Context, dockerCli command.Cli, backend api.Service, opts buildOptions, services []string) error {
|
||||
project, err := opts.ToProject(dockerCli, services, cli.WithResolvedPaths(true))
|
||||
func runBuild(ctx context.Context, backend api.Service, opts buildOptions, services []string) error {
|
||||
project, err := opts.ToProject(services, cli.WithResolvedPaths(true))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := applyPlatforms(project, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
apiBuildOptions, err := opts.toAPIBuildOptions(services)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -34,10 +33,9 @@ func noCompletion() validArgsFn {
|
||||
}
|
||||
}
|
||||
|
||||
func completeServiceNames(dockerCli command.Cli, p *ProjectOptions) validArgsFn {
|
||||
func completeServiceNames(p *ProjectOptions) validArgsFn {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
p.Offline = true
|
||||
project, err := p.ToProject(dockerCli, nil)
|
||||
project, err := p.ToProject(nil)
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
@@ -69,10 +67,9 @@ func completeProjectNames(backend api.Service) func(cmd *cobra.Command, args []s
|
||||
}
|
||||
}
|
||||
|
||||
func completeProfileNames(dockerCli command.Cli, p *ProjectOptions) validArgsFn {
|
||||
func completeProfileNames(p *ProjectOptions) validArgsFn {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
p.Offline = true
|
||||
project, err := p.ToProject(dockerCli, nil)
|
||||
project, err := p.ToProject(nil)
|
||||
if err != nil {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
@@ -26,16 +26,16 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/dotenv"
|
||||
buildx "github.com/docker/buildx/util/progress"
|
||||
"github.com/docker/cli/cli/command"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
composegoutils "github.com/compose-spec/compose-go/utils"
|
||||
"github.com/docker/buildx/util/logutil"
|
||||
buildx "github.com/docker/buildx/util/progress"
|
||||
dockercli "github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"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"
|
||||
@@ -116,8 +116,6 @@ type ProjectOptions struct {
|
||||
ProjectDir string
|
||||
EnvFiles []string
|
||||
Compatibility bool
|
||||
Progress string
|
||||
Offline bool
|
||||
}
|
||||
|
||||
// ProjectFunc does stuff within a types.Project
|
||||
@@ -127,22 +125,16 @@ type ProjectFunc func(ctx context.Context, project *types.Project) error
|
||||
type ProjectServicesFunc func(ctx context.Context, project *types.Project, services []string) error
|
||||
|
||||
// WithProject creates a cobra run command from a ProjectFunc based on configured project options and selected services
|
||||
func (o *ProjectOptions) WithProject(fn ProjectFunc, dockerCli command.Cli) func(cmd *cobra.Command, args []string) error {
|
||||
return o.WithServices(dockerCli, func(ctx context.Context, project *types.Project, services []string) error {
|
||||
func (o *ProjectOptions) WithProject(fn ProjectFunc) func(cmd *cobra.Command, args []string) error {
|
||||
return o.WithServices(func(ctx context.Context, project *types.Project, services []string) error {
|
||||
return fn(ctx, project)
|
||||
})
|
||||
}
|
||||
|
||||
// WithServices creates a cobra run command from a ProjectFunc based on configured project options and selected services
|
||||
func (o *ProjectOptions) WithServices(dockerCli command.Cli, fn ProjectServicesFunc) func(cmd *cobra.Command, args []string) error {
|
||||
func (o *ProjectOptions) WithServices(fn ProjectServicesFunc) func(cmd *cobra.Command, args []string) error {
|
||||
return Adapt(func(ctx context.Context, args []string) error {
|
||||
options := []cli.ProjectOptionsFn{
|
||||
cli.WithResolvedPaths(true),
|
||||
cli.WithDiscardEnvFile,
|
||||
cli.WithContext(ctx),
|
||||
}
|
||||
|
||||
project, err := o.ToProject(dockerCli, args, options...)
|
||||
project, err := o.ToProject(args, cli.WithResolvedPaths(true), cli.WithDiscardEnvFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -159,15 +151,14 @@ func (o *ProjectOptions) addProjectFlags(f *pflag.FlagSet) {
|
||||
f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
||||
f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
||||
f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
|
||||
f.StringVar(&o.Progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", ")))
|
||||
_ = f.MarkHidden("workdir")
|
||||
}
|
||||
|
||||
func (o *ProjectOptions) projectOrName(dockerCli command.Cli, services ...string) (*types.Project, string, error) {
|
||||
func (o *ProjectOptions) projectOrName(services ...string) (*types.Project, string, error) {
|
||||
name := o.ProjectName
|
||||
var project *types.Project
|
||||
if len(o.ConfigPaths) > 0 || o.ProjectName == "" {
|
||||
p, err := o.ToProject(dockerCli, services, cli.WithDiscardEnvFile)
|
||||
p, err := o.ToProject(services, cli.WithDiscardEnvFile)
|
||||
if err != nil {
|
||||
envProjectName := os.Getenv(ComposeProjectName)
|
||||
if envProjectName != "" {
|
||||
@@ -181,7 +172,7 @@ func (o *ProjectOptions) projectOrName(dockerCli command.Cli, services ...string
|
||||
return project, name, nil
|
||||
}
|
||||
|
||||
func (o *ProjectOptions) toProjectName(dockerCli command.Cli) (string, error) {
|
||||
func (o *ProjectOptions) toProjectName() (string, error) {
|
||||
if o.ProjectName != "" {
|
||||
return o.ProjectName, nil
|
||||
}
|
||||
@@ -191,22 +182,14 @@ func (o *ProjectOptions) toProjectName(dockerCli command.Cli) (string, error) {
|
||||
return envProjectName, nil
|
||||
}
|
||||
|
||||
project, err := o.ToProject(dockerCli, nil)
|
||||
project, err := o.ToProject(nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return project.Name, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ProjectOptions) ToProject(services []string, po ...cli.ProjectOptionsFn) (*types.Project, error) {
|
||||
options, err := o.toProjectOptions(po...)
|
||||
if err != nil {
|
||||
return nil, compose.WrapComposeError(err)
|
||||
@@ -251,33 +234,6 @@ 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))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (o *ProjectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
|
||||
return cli.NewProjectOptions(o.ConfigPaths,
|
||||
append(po,
|
||||
@@ -287,7 +243,7 @@ func (o *ProjectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.Proj
|
||||
cli.WithDotEnv,
|
||||
cli.WithConfigFileEnv,
|
||||
cli.WithDefaultConfigPath,
|
||||
cli.WithDefaultProfiles(o.Profiles...),
|
||||
cli.WithProfiles(o.Profiles),
|
||||
cli.WithName(o.ProjectName))...)
|
||||
}
|
||||
|
||||
@@ -300,7 +256,7 @@ func RunningAsStandalone() bool {
|
||||
}
|
||||
|
||||
// RootCommand returns the compose command with its child commands
|
||||
func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //nolint:gocyclo
|
||||
func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //nolint:gocyclo
|
||||
// filter out useless commandConn.CloseWrite warning message that can occur
|
||||
// when using a remote context that is unreachable: "commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
|
||||
// https://github.com/docker/cli/blob/e1f24d3c93df6752d3c27c8d61d18260f141310c/cli/connhelper/commandconn/commandconn.go#L203-L215
|
||||
@@ -319,6 +275,7 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
|
||||
version bool
|
||||
parallel int
|
||||
dryRun bool
|
||||
progress string
|
||||
)
|
||||
c := &cobra.Command{
|
||||
Short: "Docker Compose",
|
||||
@@ -331,7 +288,7 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
|
||||
return cmd.Help()
|
||||
}
|
||||
if version {
|
||||
return versionCommand(dockerCli).Execute()
|
||||
return versionCommand(streams).Execute()
|
||||
}
|
||||
_ = cmd.Help()
|
||||
return dockercli.StatusError{
|
||||
@@ -369,11 +326,11 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
|
||||
ansi = v
|
||||
}
|
||||
|
||||
formatter.SetANSIMode(dockerCli, ansi)
|
||||
formatter.SetANSIMode(streams, ansi)
|
||||
|
||||
if noColor, ok := os.LookupEnv("NO_COLOR"); ok && noColor != "" {
|
||||
ui.NoColor()
|
||||
formatter.SetANSIMode(dockerCli, formatter.Never)
|
||||
formatter.SetANSIMode(streams, formatter.Never)
|
||||
}
|
||||
|
||||
switch ansi {
|
||||
@@ -383,7 +340,7 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
|
||||
ui.Mode = ui.ModeTTY
|
||||
}
|
||||
|
||||
switch opts.Progress {
|
||||
switch progress {
|
||||
case ui.ModeAuto:
|
||||
ui.Mode = ui.ModeAuto
|
||||
case ui.ModeTTY:
|
||||
@@ -399,7 +356,7 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
|
||||
case ui.ModeQuiet, "none":
|
||||
ui.Mode = ui.ModeQuiet
|
||||
default:
|
||||
return fmt.Errorf("unsupported --progress value %q", opts.Progress)
|
||||
return fmt.Errorf("unsupported --progress value %q", progress)
|
||||
}
|
||||
|
||||
if opts.WorkDir != "" {
|
||||
@@ -450,35 +407,33 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
|
||||
}
|
||||
|
||||
c.AddCommand(
|
||||
upCommand(&opts, dockerCli, backend),
|
||||
downCommand(&opts, dockerCli, backend),
|
||||
startCommand(&opts, dockerCli, backend),
|
||||
restartCommand(&opts, dockerCli, backend),
|
||||
stopCommand(&opts, dockerCli, backend),
|
||||
psCommand(&opts, dockerCli, backend),
|
||||
listCommand(dockerCli, backend),
|
||||
logsCommand(&opts, dockerCli, backend),
|
||||
configCommand(&opts, dockerCli, backend),
|
||||
killCommand(&opts, dockerCli, backend),
|
||||
runCommand(&opts, dockerCli, backend),
|
||||
removeCommand(&opts, dockerCli, backend),
|
||||
execCommand(&opts, dockerCli, backend),
|
||||
pauseCommand(&opts, dockerCli, backend),
|
||||
unpauseCommand(&opts, dockerCli, backend),
|
||||
topCommand(&opts, dockerCli, backend),
|
||||
eventsCommand(&opts, dockerCli, backend),
|
||||
portCommand(&opts, dockerCli, backend),
|
||||
imagesCommand(&opts, dockerCli, backend),
|
||||
versionCommand(dockerCli),
|
||||
buildCommand(&opts, dockerCli, backend),
|
||||
pushCommand(&opts, dockerCli, backend),
|
||||
pullCommand(&opts, dockerCli, backend),
|
||||
createCommand(&opts, dockerCli, backend),
|
||||
copyCommand(&opts, dockerCli, backend),
|
||||
waitCommand(&opts, dockerCli, backend),
|
||||
scaleCommand(&opts, dockerCli, backend),
|
||||
watchCommand(&opts, dockerCli, backend),
|
||||
alphaCommand(&opts, dockerCli, backend),
|
||||
upCommand(&opts, streams, backend),
|
||||
downCommand(&opts, backend),
|
||||
startCommand(&opts, backend),
|
||||
restartCommand(&opts, backend),
|
||||
stopCommand(&opts, backend),
|
||||
psCommand(&opts, streams, backend),
|
||||
listCommand(streams, backend),
|
||||
logsCommand(&opts, streams, backend),
|
||||
configCommand(&opts, streams, backend),
|
||||
killCommand(&opts, backend),
|
||||
runCommand(&opts, streams, backend),
|
||||
removeCommand(&opts, backend),
|
||||
execCommand(&opts, streams, backend),
|
||||
pauseCommand(&opts, backend),
|
||||
unpauseCommand(&opts, backend),
|
||||
topCommand(&opts, streams, backend),
|
||||
eventsCommand(&opts, streams, backend),
|
||||
portCommand(&opts, streams, backend),
|
||||
imagesCommand(&opts, streams, backend),
|
||||
versionCommand(streams),
|
||||
buildCommand(&opts, &progress, backend),
|
||||
pushCommand(&opts, backend),
|
||||
pullCommand(&opts, backend),
|
||||
createCommand(&opts, backend),
|
||||
copyCommand(&opts, backend),
|
||||
waitCommand(&opts, backend),
|
||||
alphaCommand(&opts, backend),
|
||||
)
|
||||
|
||||
c.Flags().SetInterspersed(false)
|
||||
@@ -501,9 +456,11 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
|
||||
)
|
||||
c.RegisterFlagCompletionFunc( //nolint:errcheck
|
||||
"profile",
|
||||
completeProfileNames(dockerCli, &opts),
|
||||
completeProfileNames(&opts),
|
||||
)
|
||||
|
||||
c.Flags().StringVar(&progress, "progress", buildx.PrinterModeAuto, fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", ")))
|
||||
|
||||
c.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`)
|
||||
c.Flags().IntVar(¶llel, "parallel", -1, `Control max parallelism, -1 for unlimited`)
|
||||
c.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information")
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -50,19 +49,17 @@ type configOptions struct {
|
||||
noConsistency bool
|
||||
}
|
||||
|
||||
func (o *configOptions) ToProject(ctx context.Context, dockerCli command.Cli, services []string, po ...cli.ProjectOptionsFn) (*types.Project, error) {
|
||||
po = append(po,
|
||||
func (o *configOptions) ToProject(services []string) (*types.Project, error) {
|
||||
return o.ProjectOptions.ToProject(services,
|
||||
cli.WithInterpolation(!o.noInterpolate),
|
||||
cli.WithResolvedPaths(!o.noResolvePath),
|
||||
cli.WithNormalization(!o.noNormalize),
|
||||
cli.WithConsistency(!o.noConsistency),
|
||||
cli.WithDefaultProfiles(o.Profiles...),
|
||||
cli.WithDiscardEnvFile,
|
||||
cli.WithContext(ctx))
|
||||
return o.ProjectOptions.ToProject(dockerCli, services, po...)
|
||||
cli.WithProfiles(o.Profiles),
|
||||
cli.WithDiscardEnvFile)
|
||||
}
|
||||
|
||||
func configCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func configCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
opts := configOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -85,24 +82,24 @@ func configCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
if opts.services {
|
||||
return runServices(ctx, dockerCli, opts)
|
||||
return runServices(streams, opts)
|
||||
}
|
||||
if opts.volumes {
|
||||
return runVolumes(ctx, dockerCli, opts)
|
||||
return runVolumes(streams, opts)
|
||||
}
|
||||
if opts.hash != "" {
|
||||
return runHash(ctx, dockerCli, opts)
|
||||
return runHash(streams, opts)
|
||||
}
|
||||
if opts.profiles {
|
||||
return runProfiles(ctx, dockerCli, opts, args)
|
||||
return runProfiles(streams, opts, args)
|
||||
}
|
||||
if opts.images {
|
||||
return runConfigImages(ctx, dockerCli, opts, args)
|
||||
return runConfigImages(streams, opts, args)
|
||||
}
|
||||
|
||||
return runConfig(ctx, dockerCli, backend, opts, args)
|
||||
return runConfig(ctx, streams, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.StringVar(&opts.Format, "format", "yaml", "Format the output. Values: [yaml | json]")
|
||||
@@ -123,9 +120,9 @@ func configCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runConfig(ctx context.Context, dockerCli command.Cli, backend api.Service, opts configOptions, services []string) error {
|
||||
func runConfig(ctx context.Context, streams api.Streams, backend api.Service, opts configOptions, services []string) error {
|
||||
var content []byte
|
||||
project, err := opts.ToProject(ctx, dockerCli, services)
|
||||
project, err := opts.ToProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -150,38 +147,38 @@ func runConfig(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
if opts.Output != "" && len(content) > 0 {
|
||||
return os.WriteFile(opts.Output, content, 0o666)
|
||||
}
|
||||
_, err = fmt.Fprint(dockerCli.Out(), string(content))
|
||||
_, err = fmt.Fprint(streams.Out(), string(content))
|
||||
return err
|
||||
}
|
||||
|
||||
func runServices(ctx context.Context, dockerCli command.Cli, opts configOptions) error {
|
||||
project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution)
|
||||
func runServices(streams api.Streams, opts configOptions) error {
|
||||
project, err := opts.ToProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return project.WithServices(project.ServiceNames(), func(s types.ServiceConfig) error {
|
||||
fmt.Fprintln(dockerCli.Out(), s.Name)
|
||||
fmt.Fprintln(streams.Out(), s.Name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func runVolumes(ctx context.Context, dockerCli command.Cli, opts configOptions) error {
|
||||
project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution)
|
||||
func runVolumes(streams api.Streams, opts configOptions) error {
|
||||
project, err := opts.ToProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for n := range project.Volumes {
|
||||
fmt.Fprintln(dockerCli.Out(), n)
|
||||
fmt.Fprintln(streams.Out(), n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runHash(ctx context.Context, dockerCli command.Cli, opts configOptions) error {
|
||||
func runHash(streams api.Streams, opts configOptions) error {
|
||||
var services []string
|
||||
if opts.hash != "*" {
|
||||
services = append(services, strings.Split(opts.hash, ",")...)
|
||||
}
|
||||
project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution)
|
||||
project, err := opts.ToProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -203,14 +200,14 @@ func runHash(ctx context.Context, dockerCli command.Cli, opts configOptions) err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(dockerCli.Out(), "%s %s\n", s.Name, hash)
|
||||
fmt.Fprintf(streams.Out(), "%s %s\n", s.Name, hash)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runProfiles(ctx context.Context, dockerCli command.Cli, opts configOptions, services []string) error {
|
||||
func runProfiles(streams api.Streams, opts configOptions, services []string) error {
|
||||
set := map[string]struct{}{}
|
||||
project, err := opts.ToProject(ctx, dockerCli, services, cli.WithoutEnvironmentResolution)
|
||||
project, err := opts.ToProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -225,18 +222,18 @@ func runProfiles(ctx context.Context, dockerCli command.Cli, opts configOptions,
|
||||
}
|
||||
sort.Strings(profiles)
|
||||
for _, p := range profiles {
|
||||
fmt.Fprintln(dockerCli.Out(), p)
|
||||
fmt.Fprintln(streams.Out(), p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runConfigImages(ctx context.Context, dockerCli command.Cli, opts configOptions, services []string) error {
|
||||
project, err := opts.ToProject(ctx, dockerCli, services, cli.WithoutEnvironmentResolution)
|
||||
func runConfigImages(streams api.Streams, opts configOptions, services []string) error {
|
||||
project, err := opts.ToProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range project.Services {
|
||||
fmt.Fprintln(dockerCli.Out(), api.GetImageNameOrDefault(s, project.Name))
|
||||
fmt.Fprintln(streams.Out(), api.GetImageNameOrDefault(s, project.Name))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -38,7 +37,7 @@ type copyOptions struct {
|
||||
copyUIDGID bool
|
||||
}
|
||||
|
||||
func copyCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func copyCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := copyOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -59,9 +58,9 @@ func copyCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
RunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
|
||||
opts.source = args[0]
|
||||
opts.destination = args[1]
|
||||
return runCopy(ctx, dockerCli, backend, opts)
|
||||
return runCopy(ctx, backend, opts)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
|
||||
flags := copyCmd.Flags()
|
||||
@@ -75,8 +74,8 @@ func copyCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return copyCmd
|
||||
}
|
||||
|
||||
func runCopy(ctx context.Context, dockerCli command.Cli, backend api.Service, opts copyOptions) error {
|
||||
name, err := opts.toProjectName(dockerCli)
|
||||
func runCopy(ctx context.Context, backend api.Service, opts copyOptions) error {
|
||||
name, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -47,11 +46,8 @@ type createOptions struct {
|
||||
scale []string
|
||||
}
|
||||
|
||||
func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func createCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := createOptions{}
|
||||
buildOpts := buildOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "create [OPTIONS] [SERVICE...]",
|
||||
Short: "Creates containers for a service.",
|
||||
@@ -65,15 +61,26 @@ func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
RunE: p.WithServices(dockerCli, func(ctx context.Context, project *types.Project, services []string) error {
|
||||
return runCreate(ctx, dockerCli, backend, opts, buildOpts, project, services)
|
||||
RunE: p.WithProject(func(ctx context.Context, project *types.Project) error {
|
||||
if err := opts.Apply(project); err != nil {
|
||||
return err
|
||||
}
|
||||
return backend.Create(ctx, project, api.CreateOptions{
|
||||
RemoveOrphans: opts.removeOrphans,
|
||||
IgnoreOrphans: opts.ignoreOrphans,
|
||||
Recreate: opts.recreateStrategy(),
|
||||
RecreateDependencies: opts.dependenciesRecreateStrategy(),
|
||||
Inherit: !opts.noInherit,
|
||||
Timeout: opts.GetTimeout(),
|
||||
QuietPull: false,
|
||||
})
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
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.BoolVar(&opts.noBuild, "no-build", false, "Don't build an image, even if it's missing.")
|
||||
flags.StringVar(&opts.Pull, "pull", "missing", `Pull image before running ("always"|"missing"|"never")`)
|
||||
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.")
|
||||
@@ -81,33 +88,6 @@ func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runCreate(ctx context.Context, _ command.Cli, backend api.Service, createOpts createOptions, buildOpts buildOptions, project *types.Project, services []string) error {
|
||||
if err := createOpts.Apply(project); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var build *api.BuildOptions
|
||||
if !createOpts.noBuild {
|
||||
bo, err := buildOpts.toAPIBuildOptions(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
build = &bo
|
||||
}
|
||||
|
||||
return backend.Create(ctx, project, api.CreateOptions{
|
||||
Build: build,
|
||||
Services: services,
|
||||
RemoveOrphans: createOpts.removeOrphans,
|
||||
IgnoreOrphans: createOpts.ignoreOrphans,
|
||||
Recreate: createOpts.recreateStrategy(),
|
||||
RecreateDependencies: createOpts.dependenciesRecreateStrategy(),
|
||||
Inherit: !createOpts.noInherit,
|
||||
Timeout: createOpts.GetTimeout(),
|
||||
QuietPull: false,
|
||||
})
|
||||
}
|
||||
|
||||
func (opts createOptions) recreateStrategy() string {
|
||||
if opts.noRecreate {
|
||||
return api.RecreateNever
|
||||
@@ -143,9 +123,6 @@ func (opts createOptions) Apply(project *types.Project) error {
|
||||
project.Services[i] = service
|
||||
}
|
||||
}
|
||||
// N.B. opts.Build means "force build all", but images can still be built
|
||||
// when this is false
|
||||
// e.g. if a service has pull_policy: build or its local image is policy
|
||||
if opts.Build {
|
||||
for i, service := range project.Services {
|
||||
if service.Build == nil {
|
||||
@@ -155,7 +132,6 @@ func (opts createOptions) Apply(project *types.Project) error {
|
||||
project.Services[i] = service
|
||||
}
|
||||
}
|
||||
// opts.noBuild, however, means do not perform ANY builds
|
||||
if opts.noBuild {
|
||||
for i, service := range project.Services {
|
||||
service.Build = nil
|
||||
@@ -165,11 +141,6 @@ func (opts createOptions) Apply(project *types.Project) error {
|
||||
project.Services[i] = service
|
||||
}
|
||||
}
|
||||
|
||||
if err := applyPlatforms(project, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, scale := range opts.scale {
|
||||
split := strings.Split(scale, "=")
|
||||
if len(split) != 2 {
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/mocks"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRunCreate(t *testing.T) {
|
||||
ctrl, ctx := gomock.WithContext(context.Background(), t)
|
||||
backend := mocks.NewMockService(ctrl)
|
||||
backend.EXPECT().Create(
|
||||
gomock.Eq(ctx),
|
||||
pullPolicy(""),
|
||||
deepEqual(defaultCreateOptions(true)),
|
||||
)
|
||||
|
||||
createOpts := createOptions{}
|
||||
buildOpts := buildOptions{}
|
||||
project := sampleProject()
|
||||
err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRunCreate_Build(t *testing.T) {
|
||||
ctrl, ctx := gomock.WithContext(context.Background(), t)
|
||||
backend := mocks.NewMockService(ctrl)
|
||||
backend.EXPECT().Create(
|
||||
gomock.Eq(ctx),
|
||||
pullPolicy("build"),
|
||||
deepEqual(defaultCreateOptions(true)),
|
||||
)
|
||||
|
||||
createOpts := createOptions{
|
||||
Build: true,
|
||||
}
|
||||
buildOpts := buildOptions{}
|
||||
project := sampleProject()
|
||||
err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRunCreate_NoBuild(t *testing.T) {
|
||||
ctrl, ctx := gomock.WithContext(context.Background(), t)
|
||||
backend := mocks.NewMockService(ctrl)
|
||||
backend.EXPECT().Create(
|
||||
gomock.Eq(ctx),
|
||||
pullPolicy(""),
|
||||
deepEqual(defaultCreateOptions(false)),
|
||||
)
|
||||
|
||||
createOpts := createOptions{
|
||||
noBuild: true,
|
||||
}
|
||||
buildOpts := buildOptions{}
|
||||
project := sampleProject()
|
||||
err := runCreate(ctx, nil, backend, createOpts, buildOpts, project, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func sampleProject() *types.Project {
|
||||
return &types.Project{
|
||||
Name: "test",
|
||||
Services: types.Services{
|
||||
{
|
||||
Name: "svc",
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func defaultCreateOptions(includeBuild bool) api.CreateOptions {
|
||||
var build *api.BuildOptions
|
||||
if includeBuild {
|
||||
bo := defaultBuildOptions()
|
||||
build = &bo
|
||||
}
|
||||
return api.CreateOptions{
|
||||
Build: build,
|
||||
Services: nil,
|
||||
RemoveOrphans: false,
|
||||
IgnoreOrphans: false,
|
||||
Recreate: "diverged",
|
||||
RecreateDependencies: "diverged",
|
||||
Inherit: true,
|
||||
Timeout: nil,
|
||||
QuietPull: false,
|
||||
}
|
||||
}
|
||||
|
||||
func defaultBuildOptions() api.BuildOptions {
|
||||
return api.BuildOptions{
|
||||
Args: make(types.MappingWithEquals),
|
||||
Progress: "auto",
|
||||
}
|
||||
}
|
||||
|
||||
// deepEqual returns a nice diff on failure vs gomock.Eq when used
|
||||
// on structs.
|
||||
func deepEqual(x interface{}) gomock.Matcher {
|
||||
return gomock.GotFormatterAdapter(
|
||||
gomock.GotFormatterFunc(func(got interface{}) string {
|
||||
return cmp.Diff(x, got)
|
||||
}),
|
||||
gomock.Eq(x),
|
||||
)
|
||||
}
|
||||
|
||||
func spewAdapter(m gomock.Matcher) gomock.Matcher {
|
||||
return gomock.GotFormatterAdapter(
|
||||
gomock.GotFormatterFunc(func(got interface{}) string {
|
||||
return spew.Sdump(got)
|
||||
}),
|
||||
m,
|
||||
)
|
||||
}
|
||||
|
||||
type withPullPolicy struct {
|
||||
policy string
|
||||
}
|
||||
|
||||
func pullPolicy(policy string) gomock.Matcher {
|
||||
return spewAdapter(withPullPolicy{policy: policy})
|
||||
}
|
||||
|
||||
func (w withPullPolicy) Matches(x interface{}) bool {
|
||||
proj, ok := x.(*types.Project)
|
||||
if !ok || proj == nil || len(proj.Services) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, svc := range proj.Services {
|
||||
if svc.PullPolicy != w.policy {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (w withPullPolicy) String() string {
|
||||
return fmt.Sprintf("has pull policy %q for all services", w.policy)
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -40,7 +39,7 @@ type downOptions struct {
|
||||
images string
|
||||
}
|
||||
|
||||
func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func downCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := downOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -57,7 +56,7 @@ func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runDown(ctx, dockerCli, backend, opts, args)
|
||||
return runDown(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: noCompletion(),
|
||||
}
|
||||
@@ -77,8 +76,8 @@ func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return downCmd
|
||||
}
|
||||
|
||||
func runDown(ctx context.Context, dockerCli command.Cli, backend api.Service, opts downOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli)
|
||||
func runDown(ctx context.Context, backend api.Service, opts downOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -32,7 +31,7 @@ type eventsOpts struct {
|
||||
json bool
|
||||
}
|
||||
|
||||
func eventsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func eventsCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
opts := eventsOpts{
|
||||
composeOptions: &composeOptions{
|
||||
ProjectOptions: p,
|
||||
@@ -42,17 +41,17 @@ func eventsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
Use: "events [OPTIONS] [SERVICE...]",
|
||||
Short: "Receive real time events from containers.",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runEvents(ctx, dockerCli, backend, opts, args)
|
||||
return runEvents(ctx, streams, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVar(&opts.json, "json", false, "Output events as a stream of json objects")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runEvents(ctx context.Context, dockerCli command.Cli, backend api.Service, opts eventsOpts, services []string) error {
|
||||
name, err := opts.toProjectName(dockerCli)
|
||||
func runEvents(ctx context.Context, streams api.Streams, backend api.Service, opts eventsOpts, services []string) error {
|
||||
name, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -72,9 +71,9 @@ func runEvents(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(dockerCli.Out(), string(marshal))
|
||||
fmt.Fprintln(streams.Out(), string(marshal))
|
||||
} else {
|
||||
fmt.Fprintln(dockerCli.Out(), event)
|
||||
fmt.Fprintln(streams.Out(), event)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/compose"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -43,7 +42,7 @@ type execOpts struct {
|
||||
interactive bool
|
||||
}
|
||||
|
||||
func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func execCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
opts := execOpts{
|
||||
composeOptions: &composeOptions{
|
||||
ProjectOptions: p,
|
||||
@@ -59,9 +58,9 @@ func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runExec(ctx, dockerCli, backend, opts)
|
||||
return runExec(ctx, backend, opts)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
|
||||
runCmd.Flags().BoolVarP(&opts.detach, "detach", "d", false, "Detached mode: Run command in the background.")
|
||||
@@ -69,7 +68,7 @@ func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
runCmd.Flags().IntVar(&opts.index, "index", 0, "index of the container if service has multiple replicas")
|
||||
runCmd.Flags().BoolVarP(&opts.privileged, "privileged", "", false, "Give extended privileges to the process.")
|
||||
runCmd.Flags().StringVarP(&opts.user, "user", "u", "", "Run the command as this user.")
|
||||
runCmd.Flags().BoolVarP(&opts.noTty, "no-TTY", "T", !dockerCli.Out().IsTerminal(), "Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY.")
|
||||
runCmd.Flags().BoolVarP(&opts.noTty, "no-TTY", "T", !streams.Out().IsTerminal(), "Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY.")
|
||||
runCmd.Flags().StringVarP(&opts.workingDir, "workdir", "w", "", "Path to workdir directory for this command.")
|
||||
|
||||
runCmd.Flags().BoolVarP(&opts.interactive, "interactive", "i", true, "Keep STDIN open even if not attached.")
|
||||
@@ -81,8 +80,8 @@ func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return runCmd
|
||||
}
|
||||
|
||||
func runExec(ctx context.Context, dockerCli command.Cli, backend api.Service, opts execOpts) error {
|
||||
projectName, err := opts.toProjectName(dockerCli)
|
||||
func runExec(ctx context.Context, backend api.Service, opts execOpts) error {
|
||||
projectName, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -39,7 +38,7 @@ type imageOptions struct {
|
||||
Format string
|
||||
}
|
||||
|
||||
func imagesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func imagesCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
opts := imageOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -47,17 +46,17 @@ func imagesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
Use: "images [OPTIONS] [SERVICE...]",
|
||||
Short: "List images used by the created containers",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runImages(ctx, dockerCli, backend, opts, args)
|
||||
return runImages(ctx, streams, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
imgCmd.Flags().StringVar(&opts.Format, "format", "table", "Format the output. Values: [table | json].")
|
||||
imgCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")
|
||||
return imgCmd
|
||||
}
|
||||
|
||||
func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service, opts imageOptions, services []string) error {
|
||||
projectName, err := opts.toProjectName(dockerCli)
|
||||
func runImages(ctx context.Context, streams api.Streams, backend api.Service, opts imageOptions, services []string) error {
|
||||
projectName, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -81,7 +80,7 @@ func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
}
|
||||
}
|
||||
for _, img := range ids {
|
||||
fmt.Fprintln(dockerCli.Out(), img)
|
||||
fmt.Fprintln(streams.Out(), img)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -90,7 +89,7 @@ func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
return images[i].ContainerName < images[j].ContainerName
|
||||
})
|
||||
|
||||
return formatter.Print(images, opts.Format, dockerCli.Out(),
|
||||
return formatter.Print(images, opts.Format, streams.Out(),
|
||||
func(w io.Writer) {
|
||||
for _, img := range images {
|
||||
id := stringid.TruncateID(img.ID)
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -33,7 +32,7 @@ type killOptions struct {
|
||||
signal string
|
||||
}
|
||||
|
||||
func killCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func killCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := killOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -41,9 +40,9 @@ func killCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
Use: "kill [OPTIONS] [SERVICE...]",
|
||||
Short: "Force stop service containers.",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runKill(ctx, dockerCli, backend, opts, args)
|
||||
return runKill(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
@@ -54,8 +53,8 @@ func killCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runKill(ctx context.Context, dockerCli command.Cli, backend api.Service, opts killOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli, services...)
|
||||
func runKill(ctx context.Context, backend api.Service, opts killOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
|
||||
"github.com/docker/cli/opts"
|
||||
@@ -38,13 +37,13 @@ type lsOptions struct {
|
||||
Filter opts.FilterOpt
|
||||
}
|
||||
|
||||
func listCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func listCommand(streams api.Streams, backend api.Service) *cobra.Command {
|
||||
lsOpts := lsOptions{Filter: opts.NewFilterOpt()}
|
||||
lsCmd := &cobra.Command{
|
||||
Use: "ls [OPTIONS]",
|
||||
Short: "List running compose projects",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runList(ctx, dockerCli, backend, lsOpts)
|
||||
return runList(ctx, streams, backend, lsOpts)
|
||||
}),
|
||||
Args: cobra.NoArgs,
|
||||
ValidArgsFunction: noCompletion(),
|
||||
@@ -61,7 +60,7 @@ var acceptedListFilters = map[string]bool{
|
||||
"name": true,
|
||||
}
|
||||
|
||||
func runList(ctx context.Context, dockerCli command.Cli, backend api.Service, lsOpts lsOptions) error {
|
||||
func runList(ctx context.Context, streams api.Streams, backend api.Service, lsOpts lsOptions) error {
|
||||
filters := lsOpts.Filter.Value()
|
||||
err := filters.Validate(acceptedListFilters)
|
||||
if err != nil {
|
||||
@@ -74,7 +73,7 @@ func runList(ctx context.Context, dockerCli command.Cli, backend api.Service, ls
|
||||
}
|
||||
if lsOpts.Quiet {
|
||||
for _, s := range stackList {
|
||||
fmt.Fprintln(dockerCli.Out(), s.Name)
|
||||
fmt.Fprintln(streams.Out(), s.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -91,7 +90,7 @@ func runList(ctx context.Context, dockerCli command.Cli, backend api.Service, ls
|
||||
}
|
||||
|
||||
view := viewFromStackList(stackList)
|
||||
return formatter.Print(view, lsOpts.Format, dockerCli.Out(), func(w io.Writer) {
|
||||
return formatter.Print(view, lsOpts.Format, streams.Out(), func(w io.Writer) {
|
||||
for _, stack := range view {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\n", stack.Name, stack.Status, stack.ConfigFiles)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
@@ -38,7 +37,7 @@ type logsOptions struct {
|
||||
timestamps bool
|
||||
}
|
||||
|
||||
func logsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func logsCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
opts := logsOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -46,9 +45,9 @@ func logsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
Use: "logs [OPTIONS] [SERVICE...]",
|
||||
Short: "View output from containers",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runLogs(ctx, dockerCli, backend, opts, args)
|
||||
return runLogs(ctx, streams, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
flags := logsCmd.Flags()
|
||||
flags.BoolVarP(&opts.follow, "follow", "f", false, "Follow log output.")
|
||||
@@ -61,12 +60,12 @@ func logsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return logsCmd
|
||||
}
|
||||
|
||||
func runLogs(ctx context.Context, dockerCli command.Cli, backend api.Service, opts logsOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli, services...)
|
||||
func runLogs(ctx context.Context, streams api.Streams, backend api.Service, opts logsOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
consumer := formatter.NewLogConsumer(ctx, dockerCli.Out(), dockerCli.Err(), !opts.noColor, !opts.noPrefix, false)
|
||||
consumer := formatter.NewLogConsumer(ctx, streams.Out(), streams.Err(), !opts.noColor, !opts.noPrefix, false)
|
||||
return backend.Logs(ctx, name, consumer, api.LogOptions{
|
||||
Project: project,
|
||||
Services: services,
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
)
|
||||
|
||||
func applyPlatforms(project *types.Project, buildForSinglePlatform bool) error {
|
||||
defaultPlatform := project.Environment["DOCKER_DEFAULT_PLATFORM"]
|
||||
for i := range project.Services {
|
||||
// mutable reference so platform fields can be updated
|
||||
service := &project.Services[i]
|
||||
|
||||
if service.Build == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// default platform only applies if the service doesn't specify
|
||||
if defaultPlatform != "" && service.Platform == "" {
|
||||
if len(service.Build.Platforms) > 0 && !utils.StringContains(service.Build.Platforms, defaultPlatform) {
|
||||
return fmt.Errorf("service %q build.platforms does not support value set by DOCKER_DEFAULT_PLATFORM: %s", service.Name, defaultPlatform)
|
||||
}
|
||||
service.Platform = defaultPlatform
|
||||
}
|
||||
|
||||
if service.Platform != "" {
|
||||
if len(service.Build.Platforms) > 0 {
|
||||
if !utils.StringContains(service.Build.Platforms, service.Platform) {
|
||||
return fmt.Errorf("service %q build configuration does not support platform: %s", service.Name, service.Platform)
|
||||
}
|
||||
}
|
||||
|
||||
if buildForSinglePlatform || len(service.Build.Platforms) == 0 {
|
||||
// if we're building for a single platform, we want to build for the platform we'll use to run the image
|
||||
// similarly, if no build platforms were explicitly specified, it makes sense to build for the platform
|
||||
// the image is designed for rather than allowing the builder to infer the platform
|
||||
service.Build.Platforms = []string{service.Platform}
|
||||
}
|
||||
}
|
||||
|
||||
// services can specify that they should be built for multiple platforms, which can be used
|
||||
// with `docker compose build` to produce a multi-arch image
|
||||
// other cases, such as `up` and `run`, need a single architecture to actually run
|
||||
// if there is only a single platform present (which might have been inferred
|
||||
// from service.Platform above), it will be used, even if it requires emulation.
|
||||
// if there's more than one platform, then the list is cleared so that the builder
|
||||
// can decide.
|
||||
// TODO(milas): there's no validation that the platform the builder will pick is actually one
|
||||
// of the supported platforms from the build definition
|
||||
// e.g. `build.platforms: [linux/arm64, linux/amd64]` on a `linux/ppc64` machine would build
|
||||
// for `linux/ppc64` instead of returning an error that it's not a valid platform for the service.
|
||||
if buildForSinglePlatform && len(service.Build.Platforms) > 1 {
|
||||
// empty indicates that the builder gets to decide
|
||||
service.Build.Platforms = nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestApplyPlatforms_InferFromRuntime(t *testing.T) {
|
||||
makeProject := func() *types.Project {
|
||||
return &types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
Platforms: []string{
|
||||
"linux/amd64",
|
||||
"linux/arm64",
|
||||
"alice/32",
|
||||
},
|
||||
},
|
||||
Platform: "alice/32",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("SinglePlatform", func(t *testing.T) {
|
||||
project := makeProject()
|
||||
require.NoError(t, applyPlatforms(project, true))
|
||||
require.EqualValues(t, []string{"alice/32"}, project.Services[0].Build.Platforms)
|
||||
})
|
||||
|
||||
t.Run("MultiPlatform", func(t *testing.T) {
|
||||
project := makeProject()
|
||||
require.NoError(t, applyPlatforms(project, false))
|
||||
require.EqualValues(t, []string{"linux/amd64", "linux/arm64", "alice/32"},
|
||||
project.Services[0].Build.Platforms)
|
||||
})
|
||||
}
|
||||
|
||||
func TestApplyPlatforms_DockerDefaultPlatform(t *testing.T) {
|
||||
makeProject := func() *types.Project {
|
||||
return &types.Project{
|
||||
Environment: map[string]string{
|
||||
"DOCKER_DEFAULT_PLATFORM": "linux/amd64",
|
||||
},
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
Platforms: []string{
|
||||
"linux/amd64",
|
||||
"linux/arm64",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("SinglePlatform", func(t *testing.T) {
|
||||
project := makeProject()
|
||||
require.NoError(t, applyPlatforms(project, true))
|
||||
require.EqualValues(t, []string{"linux/amd64"}, project.Services[0].Build.Platforms)
|
||||
})
|
||||
|
||||
t.Run("MultiPlatform", func(t *testing.T) {
|
||||
project := makeProject()
|
||||
require.NoError(t, applyPlatforms(project, false))
|
||||
require.EqualValues(t, []string{"linux/amd64", "linux/arm64"},
|
||||
project.Services[0].Build.Platforms)
|
||||
})
|
||||
}
|
||||
|
||||
func TestApplyPlatforms_UnsupportedPlatform(t *testing.T) {
|
||||
makeProject := func() *types.Project {
|
||||
return &types.Project{
|
||||
Environment: map[string]string{
|
||||
"DOCKER_DEFAULT_PLATFORM": "commodore/64",
|
||||
},
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
Platforms: []string{
|
||||
"linux/amd64",
|
||||
"linux/arm64",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("SinglePlatform", func(t *testing.T) {
|
||||
project := makeProject()
|
||||
require.EqualError(t, applyPlatforms(project, true),
|
||||
`service "test" build.platforms does not support value set by DOCKER_DEFAULT_PLATFORM: commodore/64`)
|
||||
})
|
||||
|
||||
t.Run("MultiPlatform", func(t *testing.T) {
|
||||
project := makeProject()
|
||||
require.EqualError(t, applyPlatforms(project, false),
|
||||
`service "test" build.platforms does not support value set by DOCKER_DEFAULT_PLATFORM: commodore/64`)
|
||||
})
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -29,7 +28,7 @@ type pauseOptions struct {
|
||||
*ProjectOptions
|
||||
}
|
||||
|
||||
func pauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func pauseCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := pauseOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -37,15 +36,15 @@ func pauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
Use: "pause [SERVICE...]",
|
||||
Short: "Pause services",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPause(ctx, dockerCli, backend, opts, args)
|
||||
return runPause(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPause(ctx context.Context, dockerCli command.Cli, backend api.Service, opts pauseOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli, services...)
|
||||
func runPause(ctx context.Context, backend api.Service, opts pauseOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -60,7 +59,7 @@ type unpauseOptions struct {
|
||||
*ProjectOptions
|
||||
}
|
||||
|
||||
func unpauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func unpauseCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := unpauseOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -68,15 +67,15 @@ func unpauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||
Use: "unpause [SERVICE...]",
|
||||
Short: "Unpause services",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runUnPause(ctx, dockerCli, backend, opts, args)
|
||||
return runUnPause(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runUnPause(ctx context.Context, dockerCli command.Cli, backend api.Service, opts unpauseOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli, services...)
|
||||
func runUnPause(ctx context.Context, backend api.Service, opts unpauseOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -35,7 +34,7 @@ type portOptions struct {
|
||||
index int
|
||||
}
|
||||
|
||||
func portCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func portCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
opts := portOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -53,17 +52,17 @@ func portCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPort(ctx, dockerCli, backend, opts, args[0])
|
||||
return runPort(ctx, streams, backend, opts, args[0])
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
cmd.Flags().StringVar(&opts.protocol, "protocol", "tcp", "tcp or udp")
|
||||
cmd.Flags().IntVar(&opts.index, "index", 0, "index of the container if service has multiple replicas")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPort(ctx context.Context, dockerCli command.Cli, backend api.Service, opts portOptions, service string) error {
|
||||
projectName, err := opts.toProjectName(dockerCli)
|
||||
func runPort(ctx context.Context, streams api.Streams, backend api.Service, opts portOptions, service string) error {
|
||||
projectName, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -75,6 +74,6 @@ func runPort(ctx context.Context, dockerCli command.Cli, backend api.Service, op
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(dockerCli.Out(), "%s:%d\n", ip, port)
|
||||
fmt.Fprintf(streams.Out(), "%s:%d\n", ip, port)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -19,18 +19,22 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
cliformatter "github.com/docker/cli/cli/command/formatter"
|
||||
cliflags "github.com/docker/cli/cli/flags"
|
||||
formatter2 "github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
type psOptions struct {
|
||||
@@ -62,7 +66,7 @@ func (p *psOptions) parseFilter() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func psCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
opts := psOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -73,12 +77,12 @@ func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *c
|
||||
return opts.parseFilter()
|
||||
},
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPs(ctx, dockerCli, backend, args, opts)
|
||||
return runPs(ctx, streams, backend, args, opts)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
flags := psCmd.Flags()
|
||||
flags.StringVar(&opts.Format, "format", "table", cliflags.FormatHelp)
|
||||
flags.StringVar(&opts.Format, "format", "table", "Format the output. Values: [table | json]")
|
||||
flags.StringVar(&opts.Filter, "filter", "", "Filter services by a property (supported filters: status).")
|
||||
flags.StringArrayVar(&opts.Status, "status", []string{}, "Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited]")
|
||||
flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")
|
||||
@@ -87,8 +91,8 @@ func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *c
|
||||
return psCmd
|
||||
}
|
||||
|
||||
func runPs(ctx context.Context, dockerCli command.Cli, backend api.Service, services []string, opts psOptions) error {
|
||||
project, name, err := opts.projectOrName(dockerCli, services...)
|
||||
func runPs(ctx context.Context, streams api.Streams, backend api.Service, services []string, opts psOptions) error {
|
||||
project, name, err := opts.projectOrName(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -121,32 +125,38 @@ func runPs(ctx context.Context, dockerCli command.Cli, backend api.Service, serv
|
||||
|
||||
if opts.Quiet {
|
||||
for _, c := range containers {
|
||||
fmt.Fprintln(dockerCli.Out(), c.ID)
|
||||
fmt.Fprintln(streams.Out(), c.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if opts.Services {
|
||||
services := []string{}
|
||||
for _, c := range containers {
|
||||
s := c.Service
|
||||
if !utils.StringContains(services, s) {
|
||||
services = append(services, s)
|
||||
for _, s := range containers {
|
||||
if !utils.StringContains(services, s.Service) {
|
||||
services = append(services, s.Service)
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(dockerCli.Out(), strings.Join(services, "\n"))
|
||||
fmt.Fprintln(streams.Out(), strings.Join(services, "\n"))
|
||||
return nil
|
||||
}
|
||||
|
||||
if opts.Format == "" {
|
||||
opts.Format = dockerCli.ConfigFile().PsFormat
|
||||
}
|
||||
return formatter.Print(containers, opts.Format, streams.Out(),
|
||||
writer(containers),
|
||||
"NAME", "IMAGE", "COMMAND", "SERVICE", "CREATED", "STATUS", "PORTS")
|
||||
}
|
||||
|
||||
containerCtx := cliformatter.Context{
|
||||
Output: dockerCli.Out(),
|
||||
Format: formatter.NewContainerFormat(opts.Format, opts.Quiet, false),
|
||||
func writer(containers []api.ContainerSummary) func(w io.Writer) {
|
||||
return func(w io.Writer) {
|
||||
for _, container := range containers {
|
||||
ports := displayablePorts(container)
|
||||
createdAt := time.Unix(container.Created, 0)
|
||||
created := units.HumanDuration(time.Now().UTC().Sub(createdAt)) + " ago"
|
||||
status := container.Status
|
||||
command := formatter2.Ellipsis(container.Command, 20)
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", container.Name, container.Image, strconv.Quote(command), container.Service, created, status, ports)
|
||||
}
|
||||
}
|
||||
return formatter.ContainerWrite(containerCtx, containers)
|
||||
}
|
||||
|
||||
func filterByStatus(containers []api.ContainerSummary, statuses []string) []api.ContainerSummary {
|
||||
@@ -167,3 +177,21 @@ func hasStatus(c api.ContainerSummary, statuses []string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func displayablePorts(c api.ContainerSummary) string {
|
||||
if c.Publishers == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
ports := make([]types.Port, len(c.Publishers))
|
||||
for i, pub := range c.Publishers {
|
||||
ports[i] = types.Port{
|
||||
IP: pub.URL,
|
||||
PrivatePort: uint16(pub.TargetPort),
|
||||
PublicPort: uint16(pub.PublishedPort),
|
||||
Type: pub.Protocol,
|
||||
}
|
||||
}
|
||||
|
||||
return formatter2.DisplayablePorts(ports)
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/mocks"
|
||||
@@ -69,11 +69,7 @@ func TestPsTable(t *testing.T) {
|
||||
}).AnyTimes()
|
||||
|
||||
opts := psOptions{ProjectOptions: &ProjectOptions{ProjectName: "test"}}
|
||||
stdout := streams.NewOut(f)
|
||||
cli := mocks.NewMockCli(ctrl)
|
||||
cli.EXPECT().Out().Return(stdout).AnyTimes()
|
||||
cli.EXPECT().ConfigFile().Return(&configfile.ConfigFile{}).AnyTimes()
|
||||
err = runPs(ctx, cli, backend, nil, opts)
|
||||
err = runPs(ctx, stream{out: streams.NewOut(f)}, backend, nil, opts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = f.Seek(0, 0)
|
||||
@@ -84,3 +80,21 @@ func TestPsTable(t *testing.T) {
|
||||
|
||||
assert.Contains(t, string(output), "8080/tcp, 8443/tcp")
|
||||
}
|
||||
|
||||
type stream struct {
|
||||
out *streams.Out
|
||||
err io.Writer
|
||||
in *streams.In
|
||||
}
|
||||
|
||||
func (s stream) Out() *streams.Out {
|
||||
return s.out
|
||||
}
|
||||
|
||||
func (s stream) Err() io.Writer {
|
||||
return s.err
|
||||
}
|
||||
|
||||
func (s stream) In() *streams.In {
|
||||
return s.in
|
||||
}
|
||||
|
||||
@@ -19,13 +19,12 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func publishCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := pushOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -33,18 +32,18 @@ func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||
Use: "publish [OPTIONS] [REPOSITORY]",
|
||||
Short: "Publish compose application",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPublish(ctx, dockerCli, backend, opts, args[0])
|
||||
return runPublish(ctx, backend, opts, args[0])
|
||||
}),
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
return publishCmd
|
||||
}
|
||||
|
||||
func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Service, opts pushOptions, repository string) error {
|
||||
project, err := opts.ToProject(dockerCli, nil)
|
||||
func runPublish(ctx context.Context, backend api.Service, opts pushOptions, repository string) error {
|
||||
project, err := opts.ToProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.Publish(ctx, project, repository, api.PublishOptions{})
|
||||
return backend.Publish(ctx, project, repository)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/morikuni/aec"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
@@ -38,10 +37,9 @@ type pullOptions struct {
|
||||
includeDeps bool
|
||||
ignorePullFailures bool
|
||||
noBuildable bool
|
||||
policy string
|
||||
}
|
||||
|
||||
func pullCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func pullCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := pullOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -55,9 +53,9 @@ func pullCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPull(ctx, dockerCli, backend, opts, args)
|
||||
return runPull(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Pull without printing progress information.")
|
||||
@@ -68,11 +66,15 @@ func pullCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
flags.MarkHidden("no-parallel") //nolint:errcheck
|
||||
cmd.Flags().BoolVar(&opts.ignorePullFailures, "ignore-pull-failures", false, "Pull what it can and ignores images with pull failures.")
|
||||
cmd.Flags().BoolVar(&opts.noBuildable, "ignore-buildable", false, "Ignore images that can be built.")
|
||||
cmd.Flags().StringVar(&opts.policy, "policy", "", `Apply pull policy ("missing"|"always").`)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (opts pullOptions) apply(project *types.Project, services []string) error {
|
||||
func runPull(ctx context.Context, backend api.Service, opts pullOptions, services []string) error {
|
||||
project, err := opts.ToProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !opts.includeDeps {
|
||||
err := project.ForServices(services, types.IgnoreDependencies)
|
||||
if err != nil {
|
||||
@@ -80,29 +82,6 @@ func (opts pullOptions) apply(project *types.Project, services []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
if opts.policy != "" {
|
||||
for i, service := range project.Services {
|
||||
if service.Image == "" {
|
||||
continue
|
||||
}
|
||||
service.PullPolicy = opts.policy
|
||||
project.Services[i] = service
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runPull(ctx context.Context, dockerCli command.Cli, backend api.Service, opts pullOptions, services []string) error {
|
||||
project, err := opts.ToProject(dockerCli, services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = opts.apply(project, services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return backend.Pull(ctx, project, api.PullOptions{
|
||||
Quiet: opts.quiet,
|
||||
IgnoreFailures: opts.ignorePullFailures,
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestApplyPullOptions(t *testing.T) {
|
||||
project := &types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "must-build",
|
||||
// No image, local build only
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "has-build",
|
||||
Image: "registry.example.com/myservice",
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "must-pull",
|
||||
Image: "registry.example.com/another-service",
|
||||
},
|
||||
},
|
||||
}
|
||||
err := pullOptions{
|
||||
policy: types.PullPolicyMissing,
|
||||
}.apply(project, nil)
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, project.Services[0].PullPolicy, "") // still default
|
||||
assert.Equal(t, project.Services[1].PullPolicy, types.PullPolicyMissing)
|
||||
assert.Equal(t, project.Services[2].PullPolicy, types.PullPolicyMissing)
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -34,7 +33,7 @@ type pushOptions struct {
|
||||
Quiet bool
|
||||
}
|
||||
|
||||
func pushCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func pushCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := pushOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -42,9 +41,9 @@ func pushCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
Use: "push [OPTIONS] [SERVICE...]",
|
||||
Short: "Push service images",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runPush(ctx, dockerCli, backend, opts, args)
|
||||
return runPush(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
pushCmd.Flags().BoolVar(&opts.Ignorefailures, "ignore-push-failures", false, "Push what it can and ignores images with push failures")
|
||||
pushCmd.Flags().BoolVar(&opts.IncludeDeps, "include-deps", false, "Also push images of services declared as dependencies")
|
||||
@@ -53,8 +52,8 @@ func pushCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return pushCmd
|
||||
}
|
||||
|
||||
func runPush(ctx context.Context, dockerCli command.Cli, backend api.Service, opts pushOptions, services []string) error {
|
||||
project, err := opts.ToProject(dockerCli, services)
|
||||
func runPush(ctx context.Context, backend api.Service, opts pushOptions, services []string) error {
|
||||
project, err := opts.ToProject(services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -31,7 +30,7 @@ type removeOptions struct {
|
||||
volumes bool
|
||||
}
|
||||
|
||||
func removeCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func removeCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := removeOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -45,9 +44,9 @@ can override this with -v. To list all volumes, use "docker volume ls".
|
||||
|
||||
Any data which is not in a volume will be lost.`,
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runRemove(ctx, dockerCli, backend, opts, args)
|
||||
return runRemove(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
f := cmd.Flags()
|
||||
f.BoolVarP(&opts.force, "force", "f", false, "Don't ask to confirm removal")
|
||||
@@ -59,8 +58,8 @@ Any data which is not in a volume will be lost.`,
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runRemove(ctx context.Context, dockerCli command.Cli, backend api.Service, opts removeOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli, services...)
|
||||
func runRemove(ctx context.Context, backend api.Service, opts removeOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -33,7 +33,7 @@ type restartOptions struct {
|
||||
noDeps bool
|
||||
}
|
||||
|
||||
func restartCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func restartCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := restartOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -44,9 +44,9 @@ func restartCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||
opts.timeChanged = cmd.Flags().Changed("timeout")
|
||||
},
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runRestart(ctx, dockerCli, backend, opts, args)
|
||||
return runRestart(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
flags := restartCmd.Flags()
|
||||
flags.IntVarP(&opts.timeout, "timeout", "t", 0, "Specify a shutdown timeout in seconds")
|
||||
@@ -55,29 +55,28 @@ func restartCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||
return restartCmd
|
||||
}
|
||||
|
||||
func runRestart(ctx context.Context, dockerCli command.Cli, backend api.Service, opts restartOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli)
|
||||
func runRestart(ctx context.Context, backend api.Service, opts restartOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if project != nil && len(services) > 0 {
|
||||
err := project.EnableServices(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var timeout *time.Duration
|
||||
if opts.timeChanged {
|
||||
timeoutValue := time.Duration(opts.timeout) * time.Second
|
||||
timeout = &timeoutValue
|
||||
}
|
||||
|
||||
if opts.noDeps {
|
||||
err := project.ForServices(services, types.IgnoreDependencies)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return backend.Restart(ctx, name, api.RestartOptions{
|
||||
Timeout: timeout,
|
||||
Services: services,
|
||||
Project: project,
|
||||
NoDeps: opts.noDeps,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -21,12 +21,9 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
xprogress "github.com/docker/buildx/util/progress"
|
||||
|
||||
cgo "github.com/compose-spec/compose-go/cli"
|
||||
"github.com/compose-spec/compose-go/loader"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/mattn/go-shellwords"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -112,7 +109,7 @@ func (options runOptions) apply(project *types.Project) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func runCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
options := runOptions{
|
||||
composeOptions: &composeOptions{
|
||||
ProjectOptions: p,
|
||||
@@ -121,9 +118,6 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
|
||||
capDrop: opts.NewListOpts(nil),
|
||||
}
|
||||
createOpts := createOptions{}
|
||||
buildOpts := buildOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "run [OPTIONS] SERVICE [COMMAND] [ARGS...]",
|
||||
Short: "Run a one-off command on a service.",
|
||||
@@ -153,26 +147,22 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
project, err := p.ToProject(dockerCli, []string{options.Service}, cgo.WithResolvedPaths(true), cgo.WithDiscardEnvFile)
|
||||
project, err := p.ToProject([]string{options.Service}, cgo.WithResolvedPaths(true), cgo.WithDiscardEnvFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if createOpts.quietPull {
|
||||
buildOpts.Progress = xprogress.PrinterModeQuiet
|
||||
}
|
||||
|
||||
options.ignoreOrphans = utils.StringToBool(project.Environment[ComposeIgnoreOrphans])
|
||||
return runRun(ctx, backend, project, options, createOpts, buildOpts, dockerCli)
|
||||
return runRun(ctx, backend, project, options, createOpts, streams)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVarP(&options.Detach, "detach", "d", false, "Run container in background and print container ID")
|
||||
flags.StringArrayVarP(&options.environment, "env", "e", []string{}, "Set environment variables")
|
||||
flags.StringArrayVarP(&options.labels, "label", "l", []string{}, "Add or override a label")
|
||||
flags.BoolVar(&options.Remove, "rm", false, "Automatically remove the container when it exits")
|
||||
flags.BoolVarP(&options.noTty, "no-TTY", "T", !dockerCli.Out().IsTerminal(), "Disable pseudo-TTY allocation (default: auto-detected).")
|
||||
flags.BoolVarP(&options.noTty, "no-TTY", "T", !streams.Out().IsTerminal(), "Disable pseudo-TTY allocation (default: auto-detected).")
|
||||
flags.StringVar(&options.name, "name", "", "Assign a name to the container")
|
||||
flags.StringVarP(&options.user, "user", "u", "", "Run as specified username or uid")
|
||||
flags.StringVarP(&options.workdir, "workdir", "w", "", "Working directory inside the container")
|
||||
@@ -207,7 +197,7 @@ func normalizeRunFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
return pflag.NormalizedName(name)
|
||||
}
|
||||
|
||||
func runRun(ctx context.Context, backend api.Service, project *types.Project, options runOptions, createOpts createOptions, buildOpts buildOptions, dockerCli command.Cli) error {
|
||||
func runRun(ctx context.Context, backend api.Service, project *types.Project, options runOptions, createOpts createOptions, streams api.Streams) error {
|
||||
err := options.apply(project)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -219,17 +209,8 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op
|
||||
}
|
||||
|
||||
err = progress.Run(ctx, func(ctx context.Context) error {
|
||||
var buildForDeps *api.BuildOptions
|
||||
if !createOpts.noBuild {
|
||||
// allow dependencies needing build to be implicitly selected
|
||||
bo, err := buildOpts.toAPIBuildOptions(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buildForDeps = &bo
|
||||
}
|
||||
return startDependencies(ctx, backend, *project, buildForDeps, options.Service, options.ignoreOrphans)
|
||||
}, dockerCli.Err())
|
||||
return startDependencies(ctx, backend, *project, options.Service, options.ignoreOrphans)
|
||||
}, streams.Err())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -243,20 +224,8 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op
|
||||
labels[parts[0]] = parts[1]
|
||||
}
|
||||
|
||||
var buildForRun *api.BuildOptions
|
||||
if !createOpts.noBuild {
|
||||
// dependencies have already been started above, so only the service
|
||||
// being run might need to be built at this point
|
||||
bo, err := buildOpts.toAPIBuildOptions([]string{options.Service})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buildForRun = &bo
|
||||
}
|
||||
|
||||
// start container and attach to container streams
|
||||
runOpts := api.RunOptions{
|
||||
Build: buildForRun,
|
||||
Name: options.name,
|
||||
Service: options.Service,
|
||||
Command: options.Command,
|
||||
@@ -295,7 +264,7 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op
|
||||
return err
|
||||
}
|
||||
|
||||
func startDependencies(ctx context.Context, backend api.Service, project types.Project, buildOpts *api.BuildOptions, requestedServiceName string, ignoreOrphans bool) error {
|
||||
func startDependencies(ctx context.Context, backend api.Service, project types.Project, requestedServiceName string, ignoreOrphans bool) error {
|
||||
dependencies := types.Services{}
|
||||
var requestedService types.ServiceConfig
|
||||
for _, service := range project.Services {
|
||||
@@ -309,7 +278,6 @@ func startDependencies(ctx context.Context, backend api.Service, project types.P
|
||||
project.Services = dependencies
|
||||
project.DisabledServices = append(project.DisabledServices, requestedService)
|
||||
err := backend.Create(ctx, &project, api.CreateOptions{
|
||||
Build: buildOpts,
|
||||
IgnoreOrphans: ignoreOrphans,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type scaleOptions struct {
|
||||
*ProjectOptions
|
||||
noDeps bool
|
||||
}
|
||||
|
||||
func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
opts := scaleOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
scaleCmd := &cobra.Command{
|
||||
Use: "scale [SERVICE=REPLICAS...]",
|
||||
Short: "Scale services ",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
serviceTuples, err := parseServicesReplicasArgs(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runScale(ctx, dockerCli, backend, opts, serviceTuples)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
}
|
||||
flags := scaleCmd.Flags()
|
||||
flags.BoolVar(&opts.noDeps, "no-deps", false, "Don't start linked services.")
|
||||
|
||||
return scaleCmd
|
||||
}
|
||||
|
||||
func runScale(ctx context.Context, dockerCli command.Cli, backend api.Service, opts scaleOptions, serviceReplicaTuples map[string]int) error {
|
||||
services := maps.Keys(serviceReplicaTuples)
|
||||
project, err := opts.ToProject(dockerCli, services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.noDeps {
|
||||
if err := project.ForServices(services, types.IgnoreDependencies); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for key, value := range serviceReplicaTuples {
|
||||
for i, service := range project.Services {
|
||||
if service.Name != key {
|
||||
continue
|
||||
}
|
||||
if service.Deploy == nil {
|
||||
service.Deploy = &types.DeployConfig{}
|
||||
}
|
||||
scale := uint64(value)
|
||||
service.Deploy.Replicas = &scale
|
||||
project.Services[i] = service
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return backend.Scale(ctx, project, api.ScaleOptions{Services: services})
|
||||
}
|
||||
|
||||
func parseServicesReplicasArgs(args []string) (map[string]int, error) {
|
||||
serviceReplicaTuples := map[string]int{}
|
||||
for _, arg := range args {
|
||||
key, val, ok := strings.Cut(arg, "=")
|
||||
if !ok || key == "" || val == "" {
|
||||
return nil, errors.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)
|
||||
}
|
||||
serviceReplicaTuples[key] = intValue
|
||||
}
|
||||
return serviceReplicaTuples, nil
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -28,7 +27,7 @@ type startOptions struct {
|
||||
*ProjectOptions
|
||||
}
|
||||
|
||||
func startCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func startCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := startOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -36,15 +35,15 @@ func startCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
Use: "start [SERVICE...]",
|
||||
Short: "Start services",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runStart(ctx, dockerCli, backend, opts, args)
|
||||
return runStart(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
return startCmd
|
||||
}
|
||||
|
||||
func runStart(ctx context.Context, dockerCli command.Cli, backend api.Service, opts startOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli, services...)
|
||||
func runStart(ctx context.Context, backend api.Service, opts startOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -32,7 +31,7 @@ type stopOptions struct {
|
||||
timeout int
|
||||
}
|
||||
|
||||
func stopCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func stopCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := stopOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -43,9 +42,9 @@ func stopCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
opts.timeChanged = cmd.Flags().Changed("timeout")
|
||||
},
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runStop(ctx, dockerCli, backend, opts, args)
|
||||
return runStop(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.IntVarP(&opts.timeout, "timeout", "t", 0, "Specify a shutdown timeout in seconds")
|
||||
@@ -53,8 +52,8 @@ func stopCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runStop(ctx context.Context, dockerCli command.Cli, backend api.Service, opts stopOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(dockerCli, services...)
|
||||
func runStop(ctx context.Context, backend api.Service, opts stopOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -34,7 +33,7 @@ type topOptions struct {
|
||||
*ProjectOptions
|
||||
}
|
||||
|
||||
func topCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func topCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
opts := topOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -42,15 +41,15 @@ func topCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
|
||||
Use: "top [SERVICES...]",
|
||||
Short: "Display the running processes",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runTop(ctx, dockerCli, backend, opts, args)
|
||||
return runTop(ctx, streams, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
return topCmd
|
||||
}
|
||||
|
||||
func runTop(ctx context.Context, dockerCli command.Cli, backend api.Service, opts topOptions, services []string) error {
|
||||
projectName, err := opts.toProjectName(dockerCli)
|
||||
func runTop(ctx context.Context, streams api.Streams, backend api.Service, opts topOptions, services []string) error {
|
||||
projectName, err := opts.toProjectName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -64,8 +63,8 @@ func runTop(ctx context.Context, dockerCli command.Cli, backend api.Service, opt
|
||||
})
|
||||
|
||||
for _, container := range containers {
|
||||
fmt.Fprintf(dockerCli.Out(), "%s\n", container.Name)
|
||||
err := psPrinter(dockerCli.Out(), func(w io.Writer) {
|
||||
fmt.Fprintf(streams.Out(), "%s\n", container.Name)
|
||||
err := psPrinter(streams.Out(), func(w io.Writer) {
|
||||
for _, proc := range container.Processes {
|
||||
info := []interface{}{}
|
||||
for _, p := range proc {
|
||||
|
||||
@@ -18,15 +18,10 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
xprogress "github.com/docker/buildx/util/progress"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
@@ -74,10 +69,9 @@ func (opts upOptions) apply(project *types.Project, services []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func upCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
|
||||
up := upOptions{}
|
||||
create := createOptions{}
|
||||
build := buildOptions{ProjectOptions: p}
|
||||
upCmd := &cobra.Command{
|
||||
Use: "up [OPTIONS] [SERVICE...]",
|
||||
Short: "Create and start containers",
|
||||
@@ -86,23 +80,20 @@ func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *c
|
||||
create.timeChanged = cmd.Flags().Changed("timeout")
|
||||
return validateFlags(&up, &create)
|
||||
}),
|
||||
RunE: p.WithServices(dockerCli, func(ctx context.Context, project *types.Project, services []string) error {
|
||||
RunE: p.WithServices(func(ctx context.Context, project *types.Project, services []string) error {
|
||||
create.ignoreOrphans = utils.StringToBool(project.Environment[ComposeIgnoreOrphans])
|
||||
if create.ignoreOrphans && create.removeOrphans {
|
||||
return fmt.Errorf("cannot combine %s and --remove-orphans", ComposeIgnoreOrphans)
|
||||
return fmt.Errorf("%s and --remove-orphans cannot be combined", ComposeIgnoreOrphans)
|
||||
}
|
||||
if len(up.attach) != 0 && up.attachDependencies {
|
||||
return errors.New("cannot combine --attach and --attach-dependencies")
|
||||
}
|
||||
return runUp(ctx, dockerCli, backend, create, up, build, project, services)
|
||||
return runUp(ctx, streams, backend, create, up, project, services)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
flags := upCmd.Flags()
|
||||
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.BoolVar(&create.noBuild, "no-build", false, "Don't build an image, even if it's missing.")
|
||||
flags.StringVar(&create.Pull, "pull", "missing", `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.")
|
||||
@@ -117,12 +108,12 @@ func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *c
|
||||
flags.BoolVar(&up.noDeps, "no-deps", false, "Don't start linked services.")
|
||||
flags.BoolVar(&create.recreateDeps, "always-recreate-deps", false, "Recreate dependent containers. Incompatible with --no-recreate.")
|
||||
flags.BoolVarP(&create.noInherit, "renew-anon-volumes", "V", false, "Recreate anonymous volumes instead of retrieving data from the previous containers.")
|
||||
flags.BoolVar(&up.attachDependencies, "attach-dependencies", false, "Attach to dependent containers.")
|
||||
flags.BoolVar(&create.quietPull, "quiet-pull", false, "Pull without printing progress information.")
|
||||
flags.StringArrayVar(&up.attach, "attach", []string{}, "Restrict attaching to the specified services. Incompatible with --attach-dependencies.")
|
||||
flags.StringArrayVar(&up.noAttach, "no-attach", []string{}, "Do not attach (stream logs) to the specified services.")
|
||||
flags.BoolVar(&up.attachDependencies, "attach-dependencies", false, "Automatically attach to log output of dependent services.")
|
||||
flags.StringArrayVar(&up.attach, "attach", []string{}, "Attach to service output.")
|
||||
flags.StringArrayVar(&up.noAttach, "no-attach", []string{}, "Don't attach to specified service.")
|
||||
flags.BoolVar(&up.wait, "wait", false, "Wait for services to be running|healthy. Implies detached mode.")
|
||||
flags.IntVar(&up.waitTimeout, "wait-timeout", 0, "Maximum duration to wait for the project to be running|healthy.")
|
||||
flags.IntVar(&up.waitTimeout, "wait-timeout", 0, "timeout waiting for application to be running|healthy.")
|
||||
|
||||
return upCmd
|
||||
}
|
||||
@@ -152,16 +143,7 @@ func validateFlags(up *upOptions, create *createOptions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runUp(
|
||||
ctx context.Context,
|
||||
dockerCli command.Cli,
|
||||
backend api.Service,
|
||||
createOptions createOptions,
|
||||
upOptions upOptions,
|
||||
buildOptions buildOptions,
|
||||
project *types.Project,
|
||||
services []string,
|
||||
) error {
|
||||
func runUp(ctx context.Context, streams api.Streams, backend api.Service, createOptions createOptions, upOptions upOptions, project *types.Project, services []string) error {
|
||||
if len(project.Services) == 0 {
|
||||
return fmt.Errorf("no service selected")
|
||||
}
|
||||
@@ -176,26 +158,38 @@ func runUp(
|
||||
return err
|
||||
}
|
||||
|
||||
var build *api.BuildOptions
|
||||
// this check is technically redundant as createOptions::apply()
|
||||
// already removed all the build sections
|
||||
if !createOptions.noBuild {
|
||||
if createOptions.quietPull {
|
||||
buildOptions.Progress = xprogress.PrinterModeQuiet
|
||||
}
|
||||
// BuildOptions here is nested inside CreateOptions, so
|
||||
// no service list is passed, it will implicitly pick all
|
||||
// services being created, which includes any explicitly
|
||||
// specified via "services" arg here as well as deps
|
||||
bo, err := buildOptions.toAPIBuildOptions(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
build = &bo
|
||||
var consumer api.LogConsumer
|
||||
if !upOptions.Detach {
|
||||
consumer = formatter.NewLogConsumer(ctx, streams.Out(), streams.Err(), !upOptions.noColor, !upOptions.noPrefix, upOptions.timestamp)
|
||||
}
|
||||
|
||||
attachTo := utils.Set[string]{}
|
||||
if len(upOptions.attach) > 0 {
|
||||
attachTo.AddAll(upOptions.attach...)
|
||||
}
|
||||
if upOptions.attachDependencies {
|
||||
if err := project.WithServices(attachTo.Elements(), func(s types.ServiceConfig) error {
|
||||
if s.Attach == nil || *s.Attach {
|
||||
attachTo.Add(s.Name)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(attachTo) == 0 {
|
||||
if err := project.WithServices(services, func(s types.ServiceConfig) error {
|
||||
if s.Attach == nil || *s.Attach {
|
||||
attachTo.Add(s.Name)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
attachTo.RemoveAll(upOptions.noAttach...)
|
||||
|
||||
create := api.CreateOptions{
|
||||
Build: build,
|
||||
Services: services,
|
||||
RemoveOrphans: createOptions.removeOrphans,
|
||||
IgnoreOrphans: createOptions.ignoreOrphans,
|
||||
@@ -210,48 +204,14 @@ func runUp(
|
||||
return backend.Create(ctx, project, create)
|
||||
}
|
||||
|
||||
var consumer api.LogConsumer
|
||||
var attach []string
|
||||
if !upOptions.Detach {
|
||||
consumer = formatter.NewLogConsumer(ctx, dockerCli.Out(), dockerCli.Err(), !upOptions.noColor, !upOptions.noPrefix, upOptions.timestamp)
|
||||
|
||||
var attachSet utils.Set[string]
|
||||
if len(upOptions.attach) != 0 {
|
||||
// services are passed explicitly with --attach, verify they're valid and then use them as-is
|
||||
attachSet = utils.NewSet(upOptions.attach...)
|
||||
unexpectedSvcs := attachSet.Diff(utils.NewSet(project.ServiceNames()...))
|
||||
if len(unexpectedSvcs) != 0 {
|
||||
return fmt.Errorf("cannot attach to services not included in up: %s", strings.Join(unexpectedSvcs.Elements(), ", "))
|
||||
}
|
||||
} else {
|
||||
// mark services being launched (and potentially their deps) for attach
|
||||
// if they didn't opt-out via Compose YAML
|
||||
attachSet = utils.NewSet[string]()
|
||||
var dependencyOpt types.DependencyOption = types.IgnoreDependencies
|
||||
if upOptions.attachDependencies {
|
||||
dependencyOpt = types.IncludeDependencies
|
||||
}
|
||||
if err := project.WithServices(services, func(s types.ServiceConfig) error {
|
||||
if s.Attach == nil || *s.Attach {
|
||||
attachSet.Add(s.Name)
|
||||
}
|
||||
return nil
|
||||
}, dependencyOpt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// filter out any services that have been explicitly marked for ignore with `--no-attach`
|
||||
attachSet.RemoveAll(upOptions.noAttach...)
|
||||
attach = attachSet.Elements()
|
||||
}
|
||||
|
||||
timeout := time.Duration(upOptions.waitTimeout) * time.Second
|
||||
|
||||
return backend.Up(ctx, project, api.UpOptions{
|
||||
Create: create,
|
||||
Start: api.StartOptions{
|
||||
Project: project,
|
||||
Attach: consumer,
|
||||
AttachTo: attach,
|
||||
AttachTo: attachTo.Elements(),
|
||||
ExitCodeFrom: upOptions.exitCodeFrom,
|
||||
CascadeStop: upOptions.cascadeStop,
|
||||
Wait: upOptions.wait,
|
||||
|
||||
@@ -33,14 +33,14 @@ type versionOptions struct {
|
||||
short bool
|
||||
}
|
||||
|
||||
func versionCommand(dockerCli command.Cli) *cobra.Command {
|
||||
func versionCommand(streams command.Cli) *cobra.Command {
|
||||
opts := versionOptions{}
|
||||
cmd := &cobra.Command{
|
||||
Use: "version [OPTIONS]",
|
||||
Short: "Show the Docker Compose version information",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
runVersion(opts, dockerCli)
|
||||
runVersion(opts, streams)
|
||||
return nil
|
||||
},
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
@@ -57,14 +57,14 @@ func versionCommand(dockerCli command.Cli) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runVersion(opts versionOptions, dockerCli command.Cli) {
|
||||
func runVersion(opts versionOptions, streams command.Cli) {
|
||||
if opts.short {
|
||||
fmt.Fprintln(dockerCli.Out(), strings.TrimPrefix(internal.Version, "v"))
|
||||
fmt.Fprintln(streams.Out(), strings.TrimPrefix(internal.Version, "v"))
|
||||
return
|
||||
}
|
||||
if opts.format == formatter.JSON {
|
||||
fmt.Fprintf(dockerCli.Out(), "{\"version\":%q}\n", internal.Version)
|
||||
fmt.Fprintf(streams.Out(), "{\"version\":%q}\n", internal.Version)
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(dockerCli.Out(), "Docker Compose version", internal.Version)
|
||||
fmt.Fprintln(streams.Out(), "Docker Compose version", internal.Version)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -35,7 +34,7 @@ type vizOptions struct {
|
||||
indentationStr string
|
||||
}
|
||||
|
||||
func vizCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func vizCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := vizOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -51,7 +50,7 @@ func vizCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
|
||||
return err
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runViz(ctx, dockerCli, backend, &opts)
|
||||
return runViz(ctx, backend, &opts)
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -63,9 +62,9 @@ func vizCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runViz(ctx context.Context, dockerCli command.Cli, backend api.Service, opts *vizOptions) error {
|
||||
func runViz(ctx context.Context, backend api.Service, opts *vizOptions) error {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "viz command is EXPERIMENTAL")
|
||||
project, err := opts.ToProject(dockerCli, nil)
|
||||
project, err := opts.ToProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -34,7 +33,7 @@ type waitOptions struct {
|
||||
downProject bool
|
||||
}
|
||||
|
||||
func waitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func waitCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := waitOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -47,7 +46,7 @@ func waitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
Args: cli.RequiresMinArgs(1),
|
||||
RunE: Adapt(func(ctx context.Context, services []string) error {
|
||||
opts.services = services
|
||||
statusCode, err = runWait(ctx, dockerCli, backend, &opts)
|
||||
statusCode, err = runWait(ctx, backend, &opts)
|
||||
return err
|
||||
}),
|
||||
PostRun: func(cmd *cobra.Command, args []string) {
|
||||
@@ -60,8 +59,8 @@ func waitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runWait(ctx context.Context, dockerCli command.Cli, backend api.Service, opts *waitOptions) (int64, error) {
|
||||
_, name, err := opts.projectOrName(dockerCli)
|
||||
func runWait(ctx context.Context, backend api.Service, opts *waitOptions) (int64, error) {
|
||||
_, name, err := opts.projectOrName()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -19,94 +19,43 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/internal/locker"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type watchOptions struct {
|
||||
*ProjectOptions
|
||||
quiet bool
|
||||
noUp bool
|
||||
}
|
||||
|
||||
func watchCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
watchOpts := watchOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
buildOpts := buildOptions{
|
||||
func watchCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
opts := watchOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "watch [SERVICE...]",
|
||||
Short: "Watch build context for service and rebuild/refresh containers when files are updated",
|
||||
Short: "EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated",
|
||||
PreRunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return nil
|
||||
}),
|
||||
RunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
|
||||
if cmd.Parent().Name() == "alpha" {
|
||||
logrus.Warn("watch command is now available as a top level command")
|
||||
}
|
||||
return runWatch(ctx, dockerCli, backend, watchOpts, buildOpts, args)
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runWatch(ctx, backend, opts, args)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
ValidArgsFunction: completeServiceNames(p),
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVar(&watchOpts.quiet, "quiet", false, "hide build output")
|
||||
cmd.Flags().BoolVar(&watchOpts.noUp, "no-up", false, "Do not build & start services before watching")
|
||||
cmd.Flags().BoolVar(&opts.quiet, "quiet", false, "hide build output")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runWatch(ctx context.Context, dockerCli command.Cli, backend api.Service, watchOpts watchOptions, buildOpts buildOptions, services []string) error {
|
||||
project, err := watchOpts.ToProject(dockerCli, nil)
|
||||
func runWatch(ctx context.Context, backend api.Service, opts watchOptions, services []string) error {
|
||||
fmt.Fprintln(os.Stderr, "watch command is EXPERIMENTAL")
|
||||
project, err := opts.ToProject(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := applyPlatforms(project, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
build, err := buildOpts.toAPIBuildOptions(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
if err := l.Lock(); err != nil {
|
||||
return fmt.Errorf("cannot take exclusive lock for project %q: %v", project.Name, err)
|
||||
}
|
||||
|
||||
if !watchOpts.noUp {
|
||||
upOpts := api.UpOptions{
|
||||
Create: api.CreateOptions{
|
||||
Build: &build,
|
||||
Services: services,
|
||||
RemoveOrphans: false,
|
||||
Recreate: api.RecreateDiverged,
|
||||
RecreateDependencies: api.RecreateNever,
|
||||
Inherit: true,
|
||||
QuietPull: watchOpts.quiet,
|
||||
},
|
||||
Start: api.StartOptions{
|
||||
Project: project,
|
||||
Attach: nil,
|
||||
CascadeStop: false,
|
||||
Services: services,
|
||||
},
|
||||
}
|
||||
if err := backend.Up(ctx, project, upOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return backend.Watch(ctx, project, services, api.WatchOptions{
|
||||
Build: build,
|
||||
})
|
||||
return backend.Watch(ctx, project, services, api.WatchOptions{})
|
||||
}
|
||||
|
||||
@@ -1,281 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultContainerTableFormat = "table {{.Name}}\t{{.Image}}\t{{.Command}}\t{{.Service}}\t{{.RunningFor}}\t{{.Status}}\t{{.Ports}}"
|
||||
|
||||
nameHeader = "NAME"
|
||||
serviceHeader = "SERVICE"
|
||||
commandHeader = "COMMAND"
|
||||
runningForHeader = "CREATED"
|
||||
mountsHeader = "MOUNTS"
|
||||
localVolumes = "LOCAL VOLUMES"
|
||||
networksHeader = "NETWORKS"
|
||||
)
|
||||
|
||||
// NewContainerFormat returns a Format for rendering using a Context
|
||||
func NewContainerFormat(source string, quiet bool, size bool) formatter.Format {
|
||||
switch source {
|
||||
case formatter.TableFormatKey, "": // table formatting is the default if none is set.
|
||||
if quiet {
|
||||
return formatter.DefaultQuietFormat
|
||||
}
|
||||
format := defaultContainerTableFormat
|
||||
if size {
|
||||
format += `\t{{.Size}}`
|
||||
}
|
||||
return formatter.Format(format)
|
||||
case formatter.RawFormatKey:
|
||||
if quiet {
|
||||
return `container_id: {{.ID}}`
|
||||
}
|
||||
format := `container_id: {{.ID}}
|
||||
image: {{.Image}}
|
||||
command: {{.Command}}
|
||||
created_at: {{.CreatedAt}}
|
||||
state: {{- pad .State 1 0}}
|
||||
status: {{- pad .Status 1 0}}
|
||||
names: {{.Names}}
|
||||
labels: {{- pad .Labels 1 0}}
|
||||
ports: {{- pad .Ports 1 0}}
|
||||
`
|
||||
if size {
|
||||
format += `size: {{.Size}}\n`
|
||||
}
|
||||
return formatter.Format(format)
|
||||
default: // custom format
|
||||
if quiet {
|
||||
return formatter.DefaultQuietFormat
|
||||
}
|
||||
return formatter.Format(source)
|
||||
}
|
||||
}
|
||||
|
||||
// ContainerWrite renders the context for a list of containers
|
||||
func ContainerWrite(ctx formatter.Context, containers []api.ContainerSummary) error {
|
||||
render := func(format func(subContext formatter.SubContext) error) error {
|
||||
for _, container := range containers {
|
||||
err := format(&ContainerContext{trunc: ctx.Trunc, c: container})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return ctx.Write(NewContainerContext(), render)
|
||||
}
|
||||
|
||||
// ContainerContext is a struct used for rendering a list of containers in a Go template.
|
||||
type ContainerContext struct {
|
||||
formatter.HeaderContext
|
||||
trunc bool
|
||||
c api.ContainerSummary
|
||||
|
||||
// FieldsUsed is used in the pre-processing step to detect which fields are
|
||||
// used in the template. It's currently only used to detect use of the .Size
|
||||
// field which (if used) automatically sets the '--size' option when making
|
||||
// the API call.
|
||||
FieldsUsed map[string]interface{}
|
||||
}
|
||||
|
||||
// NewContainerContext creates a new context for rendering containers
|
||||
func NewContainerContext() *ContainerContext {
|
||||
containerCtx := ContainerContext{}
|
||||
containerCtx.Header = formatter.SubHeaderContext{
|
||||
"ID": formatter.ContainerIDHeader,
|
||||
"Name": nameHeader,
|
||||
"Service": serviceHeader,
|
||||
"Image": formatter.ImageHeader,
|
||||
"Command": commandHeader,
|
||||
"CreatedAt": formatter.CreatedAtHeader,
|
||||
"RunningFor": runningForHeader,
|
||||
"Ports": formatter.PortsHeader,
|
||||
"State": formatter.StateHeader,
|
||||
"Status": formatter.StatusHeader,
|
||||
"Size": formatter.SizeHeader,
|
||||
"Labels": formatter.LabelsHeader,
|
||||
}
|
||||
return &containerCtx
|
||||
}
|
||||
|
||||
// MarshalJSON makes ContainerContext implement json.Marshaler
|
||||
func (c *ContainerContext) MarshalJSON() ([]byte, error) {
|
||||
return formatter.MarshalJSON(c)
|
||||
}
|
||||
|
||||
// ID returns the container's ID as a string. Depending on the `--no-trunc`
|
||||
// option being set, the full or truncated ID is returned.
|
||||
func (c *ContainerContext) ID() string {
|
||||
if c.trunc {
|
||||
return stringid.TruncateID(c.c.ID)
|
||||
}
|
||||
return c.c.ID
|
||||
}
|
||||
|
||||
func (c *ContainerContext) Name() string {
|
||||
return c.c.Name
|
||||
}
|
||||
|
||||
// Names returns a comma-separated string of the container's names, with their
|
||||
// slash (/) prefix stripped. Additional names for the container (related to the
|
||||
// legacy `--link` feature) are omitted.
|
||||
func (c *ContainerContext) Names() string {
|
||||
names := formatter.StripNamePrefix(c.c.Names)
|
||||
if c.trunc {
|
||||
for _, name := range names {
|
||||
if len(strings.Split(name, "/")) == 1 {
|
||||
names = []string{name}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(names, ",")
|
||||
}
|
||||
|
||||
func (c *ContainerContext) Service() string {
|
||||
return c.c.Service
|
||||
}
|
||||
|
||||
func (c *ContainerContext) Image() string {
|
||||
return c.c.Image
|
||||
}
|
||||
|
||||
func (c *ContainerContext) Command() string {
|
||||
command := c.c.Command
|
||||
if c.trunc {
|
||||
command = formatter.Ellipsis(command, 20)
|
||||
}
|
||||
return strconv.Quote(command)
|
||||
}
|
||||
|
||||
func (c *ContainerContext) CreatedAt() string {
|
||||
return time.Unix(c.c.Created, 0).String()
|
||||
}
|
||||
|
||||
func (c *ContainerContext) RunningFor() string {
|
||||
createdAt := time.Unix(c.c.Created, 0)
|
||||
return units.HumanDuration(time.Now().UTC().Sub(createdAt)) + " ago"
|
||||
}
|
||||
|
||||
func (c *ContainerContext) ExitCode() int {
|
||||
return c.c.ExitCode
|
||||
}
|
||||
|
||||
func (c *ContainerContext) State() string {
|
||||
return c.c.State
|
||||
}
|
||||
|
||||
func (c *ContainerContext) Status() string {
|
||||
return c.c.Status
|
||||
}
|
||||
|
||||
func (c *ContainerContext) Health() string {
|
||||
return c.c.Health
|
||||
}
|
||||
|
||||
func (c *ContainerContext) Publishers() api.PortPublishers {
|
||||
return c.c.Publishers
|
||||
}
|
||||
|
||||
func (c *ContainerContext) Ports() string {
|
||||
var ports []types.Port
|
||||
for _, publisher := range c.c.Publishers {
|
||||
ports = append(ports, types.Port{
|
||||
IP: publisher.URL,
|
||||
PrivatePort: uint16(publisher.TargetPort),
|
||||
PublicPort: uint16(publisher.PublishedPort),
|
||||
Type: publisher.Protocol,
|
||||
})
|
||||
}
|
||||
return formatter.DisplayablePorts(ports)
|
||||
}
|
||||
|
||||
// Labels returns a comma-separated string of labels present on the container.
|
||||
func (c *ContainerContext) Labels() string {
|
||||
if c.c.Labels == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var joinLabels []string
|
||||
for k, v := range c.c.Labels {
|
||||
joinLabels = append(joinLabels, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
return strings.Join(joinLabels, ",")
|
||||
}
|
||||
|
||||
// Label returns the value of the label with the given name or an empty string
|
||||
// if the given label does not exist.
|
||||
func (c *ContainerContext) Label(name string) string {
|
||||
if c.c.Labels == nil {
|
||||
return ""
|
||||
}
|
||||
return c.c.Labels[name]
|
||||
}
|
||||
|
||||
// Mounts returns a comma-separated string of mount names present on the container.
|
||||
// If the trunc option is set, names can be truncated (ellipsized).
|
||||
func (c *ContainerContext) Mounts() string {
|
||||
var mounts []string
|
||||
for _, name := range c.c.Mounts {
|
||||
if c.trunc {
|
||||
name = formatter.Ellipsis(name, 15)
|
||||
}
|
||||
mounts = append(mounts, name)
|
||||
}
|
||||
return strings.Join(mounts, ",")
|
||||
}
|
||||
|
||||
// LocalVolumes returns the number of volumes using the "local" volume driver.
|
||||
func (c *ContainerContext) LocalVolumes() string {
|
||||
return fmt.Sprintf("%d", c.c.LocalVolumes)
|
||||
}
|
||||
|
||||
// Networks returns a comma-separated string of networks that the container is
|
||||
// attached to.
|
||||
func (c *ContainerContext) Networks() string {
|
||||
return strings.Join(c.c.Networks, ",")
|
||||
}
|
||||
|
||||
// Size returns the container's size and virtual size (e.g. "2B (virtual 21.5MB)")
|
||||
func (c *ContainerContext) Size() string {
|
||||
if c.FieldsUsed == nil {
|
||||
c.FieldsUsed = map[string]interface{}{}
|
||||
}
|
||||
c.FieldsUsed["Size"] = struct{}{}
|
||||
srw := units.HumanSizeWithPrecision(float64(c.c.SizeRw), 3)
|
||||
sv := units.HumanSizeWithPrecision(float64(c.c.SizeRootFs), 3)
|
||||
|
||||
sf := srw
|
||||
if c.c.SizeRootFs > 0 {
|
||||
sf = fmt.Sprintf("%s (virtual %s)", srw, sv)
|
||||
}
|
||||
return sf
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func pluginMain() {
|
||||
}
|
||||
// TODO(milas): add an env var to enable logging from the
|
||||
// OTel components for debugging purposes
|
||||
_ = cmdtrace.Setup(cmd, dockerCli, os.Args[1:])
|
||||
_ = cmdtrace.Setup(cmd, dockerCli)
|
||||
|
||||
if originalPreRun != nil {
|
||||
return originalPreRun(cmd, args)
|
||||
|
||||
@@ -5,36 +5,34 @@ Define and run multi-container applications with Docker.
|
||||
|
||||
### Subcommands
|
||||
|
||||
| Name | Description |
|
||||
|:--------------------------------|:--------------------------------------------------------------------------------------|
|
||||
| [`build`](compose_build.md) | Build or rebuild services |
|
||||
| [`config`](compose_config.md) | Parse, resolve and render compose file in canonical format |
|
||||
| [`cp`](compose_cp.md) | Copy files/folders between a service container and the local filesystem |
|
||||
| [`create`](compose_create.md) | Creates containers for a service. |
|
||||
| [`down`](compose_down.md) | Stop and remove containers, networks |
|
||||
| [`events`](compose_events.md) | Receive real time events from containers. |
|
||||
| [`exec`](compose_exec.md) | Execute a command in a running container. |
|
||||
| [`images`](compose_images.md) | List images used by the created containers |
|
||||
| [`kill`](compose_kill.md) | Force stop service containers. |
|
||||
| [`logs`](compose_logs.md) | View output from containers |
|
||||
| [`ls`](compose_ls.md) | List running compose projects |
|
||||
| [`pause`](compose_pause.md) | Pause services |
|
||||
| [`port`](compose_port.md) | Print the public port for a port binding. |
|
||||
| [`ps`](compose_ps.md) | List containers |
|
||||
| [`pull`](compose_pull.md) | Pull service images |
|
||||
| [`push`](compose_push.md) | Push service images |
|
||||
| [`restart`](compose_restart.md) | Restart service containers |
|
||||
| [`rm`](compose_rm.md) | Removes stopped service containers |
|
||||
| [`run`](compose_run.md) | Run a one-off command on a service. |
|
||||
| [`scale`](compose_scale.md) | Scale services |
|
||||
| [`start`](compose_start.md) | Start services |
|
||||
| [`stop`](compose_stop.md) | Stop services |
|
||||
| [`top`](compose_top.md) | Display the running processes |
|
||||
| [`unpause`](compose_unpause.md) | Unpause services |
|
||||
| [`up`](compose_up.md) | Create and start containers |
|
||||
| [`version`](compose_version.md) | Show the Docker Compose version information |
|
||||
| [`wait`](compose_wait.md) | Block until the first service container stops |
|
||||
| [`watch`](compose_watch.md) | Watch build context for service and rebuild/refresh containers when files are updated |
|
||||
| Name | Description |
|
||||
|:--------------------------------|:------------------------------------------------------------------------|
|
||||
| [`build`](compose_build.md) | Build or rebuild services |
|
||||
| [`config`](compose_config.md) | Parse, resolve and render compose file in canonical format |
|
||||
| [`cp`](compose_cp.md) | Copy files/folders between a service container and the local filesystem |
|
||||
| [`create`](compose_create.md) | Creates containers for a service. |
|
||||
| [`down`](compose_down.md) | Stop and remove containers, networks |
|
||||
| [`events`](compose_events.md) | Receive real time events from containers. |
|
||||
| [`exec`](compose_exec.md) | Execute a command in a running container. |
|
||||
| [`images`](compose_images.md) | List images used by the created containers |
|
||||
| [`kill`](compose_kill.md) | Force stop service containers. |
|
||||
| [`logs`](compose_logs.md) | View output from containers |
|
||||
| [`ls`](compose_ls.md) | List running compose projects |
|
||||
| [`pause`](compose_pause.md) | Pause services |
|
||||
| [`port`](compose_port.md) | Print the public port for a port binding. |
|
||||
| [`ps`](compose_ps.md) | List containers |
|
||||
| [`pull`](compose_pull.md) | Pull service images |
|
||||
| [`push`](compose_push.md) | Push service images |
|
||||
| [`restart`](compose_restart.md) | Restart service containers |
|
||||
| [`rm`](compose_rm.md) | Removes stopped service containers |
|
||||
| [`run`](compose_run.md) | Run a one-off command on a service. |
|
||||
| [`start`](compose_start.md) | Start services |
|
||||
| [`stop`](compose_stop.md) | Stop services |
|
||||
| [`top`](compose_top.md) | Display the running processes |
|
||||
| [`unpause`](compose_unpause.md) | Unpause services |
|
||||
| [`up`](compose_up.md) | Create and start containers |
|
||||
| [`version`](compose_version.md) | Show the Docker Compose version information |
|
||||
| [`wait`](compose_wait.md) | Block until the first service container stops |
|
||||
|
||||
|
||||
### Options
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# docker compose alpha scale
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Scale services
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-----|:--------|:--------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--no-deps` | | | Don't start linked services. |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
# docker compose alpha watch
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Watch build context for service and rebuild/refresh containers when files are updated
|
||||
EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-----|:--------|:----------------------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--no-up` | | | Do not build & start services before watching |
|
||||
| `--quiet` | | | hide build output |
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-----|:--------|:--------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--quiet` | | | hide build output |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -5,16 +5,16 @@ Creates containers for a service.
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:-------------------|:--------------|:---------|:----------------------------------------------------------------------------------------------|
|
||||
| `--build` | | | Build images before starting containers. |
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--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") |
|
||||
| `--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. |
|
||||
| Name | Type | Default | Description |
|
||||
|:-------------------|:--------------|:----------|:----------------------------------------------------------------------------------------------|
|
||||
| `--build` | | | Build images before starting containers. |
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--force-recreate` | | | Recreate containers even if their configuration and image haven't changed. |
|
||||
| `--no-build` | | | Don't build an image, even if it's missing. |
|
||||
| `--no-recreate` | | | If containers already exist, don't recreate them. Incompatible with --force-recreate. |
|
||||
| `--pull` | `string` | `missing` | Pull image before running ("always"\|"missing"\|"never") |
|
||||
| `--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. |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -5,15 +5,15 @@ List containers
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------------|:--------------|:--------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `-a`, `--all` | | | Show all stopped containers (including those created by the run command) |
|
||||
| `--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 |
|
||||
| `-q`, `--quiet` | | | Only display IDs |
|
||||
| `--services` | | | Display services |
|
||||
| [`--status`](#status) | `stringArray` | | Filter services by status. Values: [paused \| restarting \| removing \| running \| dead \| created \| exited] |
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------------|:--------------|:--------|:--------------------------------------------------------------------------------------------------------------|
|
||||
| `-a`, `--all` | | | Show all stopped containers (including those created by the run command) |
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| [`--filter`](#filter) | `string` | | Filter services by a property (supported filters: status). |
|
||||
| [`--format`](#format) | `string` | `table` | Format the output. Values: [table \| json] |
|
||||
| `-q`, `--quiet` | | | Only display IDs |
|
||||
| `--services` | | | Display services |
|
||||
| [`--status`](#status) | `stringArray` | | Filter services by status. Values: [paused \| restarting \| removing \| running \| dead \| created \| exited] |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -5,14 +5,13 @@ Pull service images
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:-------------------------|:---------|:--------|:--------------------------------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--ignore-buildable` | | | Ignore images that can be built. |
|
||||
| `--ignore-pull-failures` | | | Pull what it can and ignores images with pull failures. |
|
||||
| `--include-deps` | | | Also pull services declared as dependencies. |
|
||||
| `--policy` | `string` | | Apply pull policy ("missing"\|"always"). |
|
||||
| `-q`, `--quiet` | | | Pull without printing progress information. |
|
||||
| Name | Type | Default | Description |
|
||||
|:-------------------------|:-----|:--------|:--------------------------------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--ignore-buildable` | | | Ignore images that can be built. |
|
||||
| `--ignore-pull-failures` | | | Pull what it can and ignores images with pull failures. |
|
||||
| `--include-deps` | | | Also pull services declared as dependencies. |
|
||||
| `-q`, `--quiet` | | | Pull without printing progress information. |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# docker compose scale
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Scale services
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-----|:--------|:--------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--no-deps` | | | Don't start linked services. |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -5,33 +5,33 @@ Create and start containers
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:-----------------------------|:--------------|:---------|:---------------------------------------------------------------------------------------------------------|
|
||||
| `--abort-on-container-exit` | | | Stops all containers if any container was stopped. Incompatible with -d |
|
||||
| `--always-recreate-deps` | | | Recreate dependent containers. Incompatible with --no-recreate. |
|
||||
| `--attach` | `stringArray` | | Restrict attaching to the specified services. Incompatible with --attach-dependencies. |
|
||||
| `--attach-dependencies` | | | Automatically attach to log output of dependent services. |
|
||||
| `--build` | | | Build images before starting containers. |
|
||||
| `-d`, `--detach` | | | Detached mode: Run containers in the background |
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--exit-code-from` | `string` | | Return the exit code of the selected service container. Implies --abort-on-container-exit |
|
||||
| `--force-recreate` | | | Recreate containers even if their configuration and image haven't changed. |
|
||||
| `--no-attach` | `stringArray` | | Do not attach (stream logs) to the specified services. |
|
||||
| `--no-build` | | | Don't build an image, even if it's policy. |
|
||||
| `--no-color` | | | Produce monochrome output. |
|
||||
| `--no-deps` | | | Don't start linked services. |
|
||||
| `--no-log-prefix` | | | Don't print prefix in logs. |
|
||||
| `--no-recreate` | | | If containers already exist, don't recreate them. Incompatible with --force-recreate. |
|
||||
| `--no-start` | | | Don't start the services after creating them. |
|
||||
| `--pull` | `string` | `policy` | Pull image before running ("always"\|"policy"\|"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. |
|
||||
| `--scale` | `stringArray` | | Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present. |
|
||||
| `-t`, `--timeout` | `int` | `0` | Use this timeout in seconds for container shutdown when attached or when containers are already running. |
|
||||
| `--timestamps` | | | Show timestamps. |
|
||||
| `--wait` | | | Wait for services to be running\|healthy. Implies detached mode. |
|
||||
| `--wait-timeout` | `int` | `0` | Maximum duration to wait for the project to be running\|healthy. |
|
||||
| Name | Type | Default | Description |
|
||||
|:-----------------------------|:--------------|:----------|:---------------------------------------------------------------------------------------------------------|
|
||||
| `--abort-on-container-exit` | | | Stops all containers if any container was stopped. Incompatible with -d |
|
||||
| `--always-recreate-deps` | | | Recreate dependent containers. Incompatible with --no-recreate. |
|
||||
| `--attach` | `stringArray` | | Attach to service output. |
|
||||
| `--attach-dependencies` | | | Attach to dependent containers. |
|
||||
| `--build` | | | Build images before starting containers. |
|
||||
| `-d`, `--detach` | | | Detached mode: Run containers in the background |
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--exit-code-from` | `string` | | Return the exit code of the selected service container. Implies --abort-on-container-exit |
|
||||
| `--force-recreate` | | | Recreate containers even if their configuration and image haven't changed. |
|
||||
| `--no-attach` | `stringArray` | | Don't attach to specified service. |
|
||||
| `--no-build` | | | Don't build an image, even if it's missing. |
|
||||
| `--no-color` | | | Produce monochrome output. |
|
||||
| `--no-deps` | | | Don't start linked services. |
|
||||
| `--no-log-prefix` | | | Don't print prefix in logs. |
|
||||
| `--no-recreate` | | | If containers already exist, don't recreate them. Incompatible with --force-recreate. |
|
||||
| `--no-start` | | | Don't start the services after creating them. |
|
||||
| `--pull` | `string` | `missing` | 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. |
|
||||
| `--scale` | `stringArray` | | Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present. |
|
||||
| `-t`, `--timeout` | `int` | `0` | Use this timeout in seconds for container shutdown when attached or when containers are already running. |
|
||||
| `--timestamps` | | | Show timestamps. |
|
||||
| `--wait` | | | Wait for services to be running\|healthy. Implies detached mode. |
|
||||
| `--wait-timeout` | `int` | `0` | timeout waiting for application to be running\|healthy. |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# docker compose watch
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Watch build context for service and rebuild/refresh containers when files are updated
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-----|:--------|:----------------------------------------------|
|
||||
| `--dry-run` | | | Execute command in dry run mode |
|
||||
| `--no-up` | | | Do not build & start services before watching |
|
||||
| `--quiet` | | | hide build output |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -165,7 +165,6 @@ cname:
|
||||
- docker compose restart
|
||||
- docker compose rm
|
||||
- docker compose run
|
||||
- docker compose scale
|
||||
- docker compose start
|
||||
- docker compose stop
|
||||
- docker compose top
|
||||
@@ -173,7 +172,6 @@ cname:
|
||||
- docker compose up
|
||||
- docker compose version
|
||||
- docker compose wait
|
||||
- docker compose watch
|
||||
clink:
|
||||
- docker_compose_build.yaml
|
||||
- docker_compose_config.yaml
|
||||
@@ -194,7 +192,6 @@ clink:
|
||||
- docker_compose_restart.yaml
|
||||
- docker_compose_rm.yaml
|
||||
- docker_compose_run.yaml
|
||||
- docker_compose_scale.yaml
|
||||
- docker_compose_start.yaml
|
||||
- docker_compose_stop.yaml
|
||||
- docker_compose_top.yaml
|
||||
@@ -202,7 +199,6 @@ clink:
|
||||
- docker_compose_up.yaml
|
||||
- docker_compose_version.yaml
|
||||
- docker_compose_wait.yaml
|
||||
- docker_compose_watch.yaml
|
||||
options:
|
||||
- option: ansi
|
||||
value_type: string
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
command: docker compose alpha scale
|
||||
short: Scale services
|
||||
long: Scale services
|
||||
usage: docker compose alpha scale [SERVICE=REPLICAS...]
|
||||
pname: docker compose alpha
|
||||
plink: docker_compose_alpha.yaml
|
||||
options:
|
||||
- option: no-deps
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Don't start linked services.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Execute command in dry run mode
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: true
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
command: docker compose alpha watch
|
||||
short: |
|
||||
Watch build context for service and rebuild/refresh containers when files are updated
|
||||
EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated
|
||||
long: |
|
||||
Watch build context for service and rebuild/refresh containers when files are updated
|
||||
EXPERIMENTAL - Watch build context for service and rebuild/refresh containers when files are updated
|
||||
usage: docker compose alpha watch [SERVICE...]
|
||||
pname: docker compose alpha
|
||||
plink: docker_compose_alpha.yaml
|
||||
options:
|
||||
- option: no-up
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Do not build & start services before watching
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: quiet
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
|
||||
@@ -29,7 +29,7 @@ options:
|
||||
- option: no-build
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Don't build an image, even if it's policy.
|
||||
description: Don't build an image, even if it's missing.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
@@ -49,8 +49,8 @@ options:
|
||||
swarm: false
|
||||
- option: pull
|
||||
value_type: string
|
||||
default_value: policy
|
||||
description: Pull image before running ("always"|"policy"|"never")
|
||||
default_value: missing
|
||||
description: Pull image before running ("always"|"missing"|"never")
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
|
||||
@@ -46,13 +46,7 @@ options:
|
||||
- option: format
|
||||
value_type: string
|
||||
default_value: table
|
||||
description: |-
|
||||
Format output using a custom template:
|
||||
'table': Print output in table format with column headers (default)
|
||||
'table TEMPLATE': Print output in table format using the given Go template
|
||||
'json': Print in JSON format
|
||||
'TEMPLATE': Print output using the given Go template.
|
||||
Refer to https://docs.docker.com/go/formatting/ for more information about formatting output with templates
|
||||
description: 'Format the output. Values: [table | json]'
|
||||
details_url: '#format'
|
||||
deprecated: false
|
||||
hidden: false
|
||||
|
||||
@@ -57,15 +57,6 @@ options:
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: policy
|
||||
value_type: string
|
||||
description: Apply pull policy ("missing"|"always").
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: quiet
|
||||
shorthand: q
|
||||
value_type: bool
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
command: docker compose scale
|
||||
short: Scale services
|
||||
long: Scale services
|
||||
usage: docker compose scale [SERVICE=REPLICAS...]
|
||||
pname: docker compose
|
||||
plink: docker_compose.yaml
|
||||
options:
|
||||
- option: no-deps
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Don't start linked services.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Execute command in dry run mode
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
|
||||
@@ -48,8 +48,7 @@ options:
|
||||
- option: attach
|
||||
value_type: stringArray
|
||||
default_value: '[]'
|
||||
description: |
|
||||
Restrict attaching to the specified services. Incompatible with --attach-dependencies.
|
||||
description: Attach to service output.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
@@ -59,7 +58,7 @@ options:
|
||||
- option: attach-dependencies
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Automatically attach to log output of dependent services.
|
||||
description: Attach to dependent containers.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
@@ -111,7 +110,7 @@ options:
|
||||
- option: no-attach
|
||||
value_type: stringArray
|
||||
default_value: '[]'
|
||||
description: Do not attach (stream logs) to the specified services.
|
||||
description: Don't attach to specified service.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
@@ -121,7 +120,7 @@ options:
|
||||
- option: no-build
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Don't build an image, even if it's policy.
|
||||
description: Don't build an image, even if it's missing.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
@@ -181,8 +180,8 @@ options:
|
||||
swarm: false
|
||||
- option: pull
|
||||
value_type: string
|
||||
default_value: policy
|
||||
description: Pull image before running ("always"|"policy"|"never")
|
||||
default_value: missing
|
||||
description: Pull image before running ("always"|"missing"|"never")
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
@@ -267,7 +266,7 @@ options:
|
||||
- option: wait-timeout
|
||||
value_type: int
|
||||
default_value: "0"
|
||||
description: Maximum duration to wait for the project to be running|healthy.
|
||||
description: timeout waiting for application to be running|healthy.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
command: docker compose watch
|
||||
short: |
|
||||
Watch build context for service and rebuild/refresh containers when files are updated
|
||||
long: |
|
||||
Watch build context for service and rebuild/refresh containers when files are updated
|
||||
usage: docker compose watch [SERVICE...]
|
||||
pname: docker compose
|
||||
plink: docker_compose.yaml
|
||||
options:
|
||||
- option: no-up
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Do not build & start services before watching
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: quiet
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: hide build output
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Execute command in dry run mode
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
|
||||
65
go.mod
65
go.mod
@@ -5,34 +5,31 @@ 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.18.1
|
||||
github.com/containerd/console v1.0.3
|
||||
github.com/containerd/containerd v1.7.6
|
||||
github.com/containerd/containerd v1.7.3
|
||||
github.com/cucumber/godog v0.0.0-00010101000000-000000000000 // replaced; see replace for the actual version used
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/distribution/reference v0.5.0
|
||||
github.com/distribution/distribution/v3 v3.0.0-20230601133803-97b1d649c493
|
||||
github.com/docker/buildx v0.11.2
|
||||
github.com/docker/cli v24.0.6+incompatible
|
||||
github.com/docker/cli v24.0.5+incompatible
|
||||
github.com/docker/cli-docs-tool v0.6.0
|
||||
github.com/docker/docker v24.0.6+incompatible
|
||||
github.com/docker/docker v24.0.5+incompatible // v24.0.5-dev
|
||||
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/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/patternmatcher v0.6.0
|
||||
github.com/moby/buildkit v0.12.1 // v0.12 release branch
|
||||
github.com/moby/patternmatcher v0.5.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/opencontainers/image-spec v1.1.0-rc4
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.7.0
|
||||
@@ -47,18 +44,15 @@ require (
|
||||
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
|
||||
gotest.tools/v3 v3.5.1
|
||||
google.golang.org/grpc v1.57.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gotest.tools/v3 v3.5.0
|
||||
)
|
||||
|
||||
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/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // 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/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
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.16 // indirect
|
||||
@@ -72,12 +66,16 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 // indirect
|
||||
github.com/aws/smithy-go v1.13.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bugsnag/bugsnag-go v1.5.0 // indirect
|
||||
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/cloudflare/cfssl v1.6.4 // indirect
|
||||
github.com/containerd/continuity v0.4.1 // 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/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.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
|
||||
@@ -96,6 +94,7 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
@@ -109,10 +108,13 @@ require (
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.5.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jinzhu/gorm v1.9.11 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/klauspost/compress v1.16.5 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
@@ -142,6 +144,8 @@ require (
|
||||
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/spf13/afero v1.9.2 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
@@ -149,6 +153,7 @@ require (
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/zmap/zcrypto v0.0.0-20220605182715-4dfcec6e9a8c // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.40.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 // indirect
|
||||
@@ -156,23 +161,23 @@ 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.7.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // 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.9.0 // indirect
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/term v0.7.0 // indirect
|
||||
golang.org/x/text v0.9.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/protobuf v1.31.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.26.2 // indirect
|
||||
k8s.io/apimachinery v0.26.2 // indirect
|
||||
|
||||
189
go.sum
189
go.sum
@@ -1,5 +1,6 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
@@ -17,15 +18,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.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys=
|
||||
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.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY=
|
||||
cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE=
|
||||
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=
|
||||
@@ -41,10 +42,10 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652 h1:+vTEFqeoeur6XSq06bs+roX3YiT49gUniJK7Zky7Xjg=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
@@ -55,21 +56,22 @@ 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.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek=
|
||||
github.com/Microsoft/hcsshim v0.10.0-rc.8/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM=
|
||||
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/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
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=
|
||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aws/aws-sdk-go-v2 v1.17.6 h1:Y773UK7OBqhzi5VDXMi1zVGsoj+CVHs2eaC2bDsLwi0=
|
||||
@@ -107,8 +109,8 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR
|
||||
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
|
||||
github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
|
||||
github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/bugsnag-go v1.4.1 h1:TT3P9AX69w8mbSGE8L7IJOO2KBlPN0iQtYD0dUlrWHc=
|
||||
github.com/bugsnag/bugsnag-go v1.4.1/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/bugsnag-go v1.5.0 h1:tP8hiPv1pGGW3LA6LKy5lW6WG+y9J2xWUdPd3WC452k=
|
||||
github.com/bugsnag/bugsnag-go v1.5.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA=
|
||||
@@ -125,8 +127,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||
github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e h1:Qux+lbuMaRzkQyTdzgtz8MgzPtzmaPQy6DXmxpdxT3U=
|
||||
github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||
github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO8=
|
||||
github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@@ -139,16 +141,16 @@ 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.18.1 h1:YVYYkV8fAHW/eCOgtqSe1tHrlaDVvwS8zgs6F5ukm/Y=
|
||||
github.com/compose-spec/compose-go v1.18.1/go.mod h1:zR2tP1+kZHi5vJz7PjpW6oMoDji/Js3GHjP+hfjf70Q=
|
||||
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/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/containerd v1.7.3 h1:cKwYKkP1eTj54bP3wCdXXBymmKRQMrWjkLSWZZJDa8o=
|
||||
github.com/containerd/containerd v1.7.3/go.mod h1:32FOM4/O0RkNg7AjQj3hDzN9cUGtu+HMvaKUNiqCZB8=
|
||||
github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU=
|
||||
github.com/containerd/continuity v0.4.1/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/nydus-snapshotter v0.8.2 h1:7SOrMU2YmLzfbsr5J7liMZJlNi5WT6vtIOxLGv+iz7E=
|
||||
@@ -171,23 +173,26 @@ github.com/cucumber/gherkin-go/v19 v19.0.3/go.mod h1:jY/NP6jUtRSArQQJ5h1FXOUgk5f
|
||||
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/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20230601133803-97b1d649c493 h1:fm5DpBD+A7o0+x9Nf+o9/4/qPGbfxLpr9qIPVuV8vQc=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20230601133803-97b1d649c493/go.mod h1:+fqBJ4vPYo4Uu1ZE4d+bUtTLRXfdSL3NvCZIZ9GHv58=
|
||||
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.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
|
||||
github.com/docker/cli v24.0.5+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.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=
|
||||
github.com/docker/docker v24.0.5+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=
|
||||
@@ -205,6 +210,9 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8=
|
||||
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
|
||||
@@ -217,8 +225,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
|
||||
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
@@ -252,6 +260,7 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
|
||||
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
@@ -264,6 +273,7 @@ github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0
|
||||
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
|
||||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
@@ -303,6 +313,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||
@@ -351,6 +362,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
||||
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/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
@@ -397,14 +410,17 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
|
||||
github.com/jinzhu/gorm v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw=
|
||||
github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
|
||||
github.com/jinzhu/gorm v1.9.11 h1:gaHGvE+UnWGlbWG4Y3FUwY1EcZ5n6S9WtqBA/uySMLE=
|
||||
github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw=
|
||||
github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k=
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jmoiron/sqlx v1.3.3 h1:j82X0bf7oQ27XeqxicSZsTU5suPwKElg3oyxNn43iTk=
|
||||
github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
||||
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
@@ -433,8 +449,9 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
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=
|
||||
@@ -442,8 +459,10 @@ 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/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
@@ -460,6 +479,7 @@ github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
|
||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
@@ -471,12 +491,12 @@ 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.1 h1:vvMG7EZYCiQZpTtXQkvyeyj7HzT1JHhDWj+/aiGIzLM=
|
||||
github.com/moby/buildkit v0.12.1/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=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
|
||||
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
||||
@@ -498,25 +518,29 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
|
||||
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
|
||||
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk=
|
||||
github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
|
||||
github.com/opencontainers/runtime-spec v1.1.0-rc.2 h1:ucBtEms2tamYYW/SvGpvq9yUN0NEVL6oyLEwDcTSrk8=
|
||||
@@ -525,10 +549,12 @@ 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/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
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=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -538,31 +564,38 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs=
|
||||
@@ -572,6 +605,7 @@ github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh
|
||||
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
|
||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
@@ -585,14 +619,16 @@ github.com/spdx/tools-golang v0.5.1 h1:fJg3SVOGG+eIva9ZUBm/hvyA7PIPVFjRxUKe6fdAg
|
||||
github.com/spdx/tools-golang v0.5.1/go.mod h1:/DRDQuBfB37HctM29YtrX1v+bXiVmT2OpQDalRmX9aU=
|
||||
github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
|
||||
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
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/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
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/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/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
@@ -628,6 +664,8 @@ github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 h1:Y/M5lygoNPKwVN
|
||||
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc=
|
||||
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
|
||||
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
|
||||
github.com/weppos/publicsuffix-go v0.15.1-0.20220329081811-9a40b608a236 h1:vMJBP3PQViZsF6cOINtvyMC8ptpLsyJ4EwyFnzuWNxc=
|
||||
github.com/weppos/publicsuffix-go v0.15.1-0.20220329081811-9a40b608a236/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@@ -641,6 +679,13 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
|
||||
github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
|
||||
github.com/zmap/zcrypto v0.0.0-20220605182715-4dfcec6e9a8c h1:ufDm/IlBYZYLuiqvQuhpTKwrcAS2OlXEzWbDvTVGbSQ=
|
||||
github.com/zmap/zcrypto v0.0.0-20220605182715-4dfcec6e9a8c/go.mod h1:egdRkzUylATvPkWMpebZbXhv0FMEMJGX/ur0D3Csk2s=
|
||||
github.com/zmap/zlint/v3 v3.1.0 h1:WjVytZo79m/L1+/Mlphl09WBob6YTGljN5IGWZFpAv0=
|
||||
github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@@ -688,11 +733,12 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-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.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
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=
|
||||
@@ -737,6 +783,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -763,13 +810,14 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
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.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
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 +828,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.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
|
||||
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
||||
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=
|
||||
@@ -800,6 +848,7 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -849,13 +898,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.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-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.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
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,13 +914,14 @@ 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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
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=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -930,6 +980,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
@@ -959,6 +1010,7 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -997,13 +1049,14 @@ 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-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M=
|
||||
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -1024,8 +1077,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.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
|
||||
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
|
||||
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=
|
||||
@@ -1039,8 +1092,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
|
||||
@@ -1066,14 +1119,16 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
|
||||
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 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 (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/docker/docker/pkg/pidfile"
|
||||
)
|
||||
|
||||
type Pidfile struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func NewPidfile(projectName string) (*Pidfile, error) {
|
||||
path, err := xdg.RuntimeFile(fmt.Sprintf("docker-compose.%s.pid", projectName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Pidfile{path: path}, nil
|
||||
}
|
||||
|
||||
func (f *Pidfile) Lock() error {
|
||||
return pidfile.Write(f.path, os.Getpid())
|
||||
}
|
||||
@@ -20,8 +20,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
@@ -75,7 +73,6 @@ func ProjectOptions(proj *types.Project) SpanOptions {
|
||||
attribute.StringSlice("project.secrets", proj.SecretNames()),
|
||||
attribute.StringSlice("project.configs", proj.ConfigNames()),
|
||||
attribute.StringSlice("project.extensions", keys(proj.Extensions)),
|
||||
attribute.StringSlice("project.includes", flattenIncludeReferences(proj.IncludeReferences)),
|
||||
}
|
||||
return []trace.SpanStartEventOption{
|
||||
trace.WithAttributes(attrs...),
|
||||
@@ -153,13 +150,3 @@ func timeAttr(key string, value time.Time) attribute.KeyValue {
|
||||
func unixTimeAttr(key string, value int64) attribute.KeyValue {
|
||||
return timeAttr(key, time.Unix(value, 0).UTC())
|
||||
}
|
||||
|
||||
func flattenIncludeReferences(includeRefs map[string][]types.IncludeConfig) []string {
|
||||
ret := utils.NewSet[string]()
|
||||
for _, included := range includeRefs {
|
||||
for i := range included {
|
||||
ret.AddAll(included[i].Path...)
|
||||
}
|
||||
}
|
||||
return ret.Elements()
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ type Service interface {
|
||||
// Port executes the equivalent to a `compose port`
|
||||
Port(ctx context.Context, projectName string, service string, port uint16, options PortOptions) (string, int, error)
|
||||
// Publish executes the equivalent to a `compose publish`
|
||||
Publish(ctx context.Context, project *types.Project, repository string, options PublishOptions) error
|
||||
Publish(ctx context.Context, project *types.Project, repository string) error
|
||||
// Images executes the equivalent of a `compose images`
|
||||
Images(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
|
||||
// MaxConcurrency defines upper limit for concurrent operations against engine API
|
||||
@@ -88,12 +88,6 @@ type Service interface {
|
||||
Viz(ctx context.Context, project *types.Project, options VizOptions) (string, error)
|
||||
// Wait blocks until at least one of the services' container exits
|
||||
Wait(ctx context.Context, projectName string, options WaitOptions) (int64, error)
|
||||
// Scale manages numbers of container instances running per service
|
||||
Scale(ctx context.Context, project *types.Project, options ScaleOptions) error
|
||||
}
|
||||
|
||||
type ScaleOptions struct {
|
||||
Services []string
|
||||
}
|
||||
|
||||
type WaitOptions struct {
|
||||
@@ -116,7 +110,6 @@ type VizOptions struct {
|
||||
|
||||
// WatchOptions group options of the Watch API
|
||||
type WatchOptions struct {
|
||||
Build BuildOptions
|
||||
}
|
||||
|
||||
// BuildOptions group options of the Build API
|
||||
@@ -176,7 +169,6 @@ func (o BuildOptions) Apply(project *types.Project) error {
|
||||
|
||||
// CreateOptions group options of the Create API
|
||||
type CreateOptions struct {
|
||||
Build *BuildOptions
|
||||
// Services defines the services user interacts with
|
||||
Services []string
|
||||
// Remove legacy containers for services that are not defined in the project
|
||||
@@ -222,8 +214,6 @@ type RestartOptions struct {
|
||||
Timeout *time.Duration
|
||||
// Services passed in the command line to be restarted
|
||||
Services []string
|
||||
// NoDeps ignores services dependencies
|
||||
NoDeps bool
|
||||
}
|
||||
|
||||
// StopOptions group options of the Stop API
|
||||
@@ -314,7 +304,6 @@ type RemoveOptions struct {
|
||||
|
||||
// RunOptions group options of the Run API
|
||||
type RunOptions struct {
|
||||
Build *BuildOptions
|
||||
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
|
||||
Project *types.Project
|
||||
Name string
|
||||
@@ -361,10 +350,6 @@ type PortOptions struct {
|
||||
Index int
|
||||
}
|
||||
|
||||
// PublishOptions group options of the Publish API
|
||||
type PublishOptions struct {
|
||||
}
|
||||
|
||||
func (e Event) String() string {
|
||||
t := e.Timestamp.Format("2006-01-02 15:04:05.000000")
|
||||
var attr []string
|
||||
@@ -407,25 +392,18 @@ type PortPublisher struct {
|
||||
|
||||
// ContainerSummary hold high-level description of a container
|
||||
type ContainerSummary struct {
|
||||
ID string
|
||||
Name string
|
||||
Names []string
|
||||
Image string
|
||||
Command string
|
||||
Project string
|
||||
Service string
|
||||
Created int64
|
||||
State string
|
||||
Status string
|
||||
Health string
|
||||
ExitCode int
|
||||
Publishers PortPublishers
|
||||
Labels map[string]string
|
||||
SizeRw int64 `json:",omitempty"`
|
||||
SizeRootFs int64 `json:",omitempty"`
|
||||
Mounts []string
|
||||
Networks []string
|
||||
LocalVolumes int
|
||||
ID string
|
||||
Name string
|
||||
Image any
|
||||
Command string
|
||||
Project string
|
||||
Service string
|
||||
Created int64
|
||||
State string
|
||||
Status string
|
||||
Health string
|
||||
ExitCode int
|
||||
Publishers PortPublishers
|
||||
}
|
||||
|
||||
// PortPublishers is a slice of PortPublisher
|
||||
|
||||
@@ -19,7 +19,6 @@ package api
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -32,6 +31,8 @@ import (
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/util/imagetools"
|
||||
"github.com/docker/cli/cli/command"
|
||||
|
||||
"github.com/distribution/distribution/v3/uuid"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
containerType "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
@@ -297,9 +298,7 @@ func (d *DryRunClient) VolumeRemove(ctx context.Context, volumeID string, force
|
||||
}
|
||||
|
||||
func (d *DryRunClient) ContainerExecCreate(ctx context.Context, container string, config moby.ExecConfig) (moby.IDResponse, error) {
|
||||
b := make([]byte, 32)
|
||||
_, _ = rand.Read(b)
|
||||
id := fmt.Sprintf("%x", b)
|
||||
id := uuid.Generate().String()
|
||||
d.execs.Store(id, execDetails{
|
||||
container: container,
|
||||
command: config.Cmd,
|
||||
|
||||
@@ -55,8 +55,7 @@ type ServiceProxy struct {
|
||||
DryRunModeFn func(ctx context.Context, dryRun bool) (context.Context, error)
|
||||
VizFn func(ctx context.Context, project *types.Project, options VizOptions) (string, error)
|
||||
WaitFn func(ctx context.Context, projectName string, options WaitOptions) (int64, error)
|
||||
PublishFn func(ctx context.Context, project *types.Project, repository string, options PublishOptions) error
|
||||
ScaleFn func(ctx context.Context, project *types.Project, options ScaleOptions) error
|
||||
PublishFn func(ctx context.Context, project *types.Project, repository string) error
|
||||
interceptors []Interceptor
|
||||
}
|
||||
|
||||
@@ -100,7 +99,6 @@ func (s *ServiceProxy) WithService(service Service) *ServiceProxy {
|
||||
s.DryRunModeFn = service.DryRunMode
|
||||
s.VizFn = service.Viz
|
||||
s.WaitFn = service.Wait
|
||||
s.ScaleFn = service.Scale
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -315,8 +313,8 @@ func (s *ServiceProxy) Port(ctx context.Context, projectName string, service str
|
||||
return s.PortFn(ctx, projectName, service, port, options)
|
||||
}
|
||||
|
||||
func (s *ServiceProxy) Publish(ctx context.Context, project *types.Project, repository string, options PublishOptions) error {
|
||||
return s.PublishFn(ctx, project, repository, options)
|
||||
func (s *ServiceProxy) Publish(ctx context.Context, project *types.Project, repository string) error {
|
||||
return s.PublishFn(ctx, project, repository)
|
||||
}
|
||||
|
||||
// Images implements Service interface
|
||||
@@ -351,13 +349,6 @@ func (s *ServiceProxy) Wait(ctx context.Context, projectName string, options Wai
|
||||
return s.WaitFn(ctx, projectName, options)
|
||||
}
|
||||
|
||||
func (s *ServiceProxy) Scale(ctx context.Context, project *types.Project, options ScaleOptions) error {
|
||||
if s.ScaleFn == nil {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
return s.ScaleFn(ctx, project, options)
|
||||
}
|
||||
|
||||
func (s *ServiceProxy) MaxConcurrency(i int) {
|
||||
s.MaxConcurrencyFn(i)
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ func (s *composeService) attachContainer(ctx context.Context, container moby.Con
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *composeService) attachContainerStreams(ctx context.Context, container string, tty bool, stdin io.ReadCloser, stdout, stderr io.WriteCloser) (func(), chan bool, error) {
|
||||
func (s *composeService) attachContainerStreams(ctx context.Context, container string, tty bool, stdin io.ReadCloser, stdout, stderr io.Writer) (func(), chan bool, error) {
|
||||
detached := make(chan bool)
|
||||
var (
|
||||
restore = func() { /* noop */ }
|
||||
@@ -140,8 +140,6 @@ func (s *composeService) attachContainerStreams(ctx context.Context, container s
|
||||
|
||||
if stdout != nil {
|
||||
go func() {
|
||||
defer stdout.Close() //nolint:errcheck
|
||||
defer stderr.Close() //nolint:errcheck
|
||||
if tty {
|
||||
io.Copy(stdout, streamOut) //nolint:errcheck
|
||||
} else {
|
||||
|
||||
@@ -18,7 +18,6 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -44,6 +43,7 @@ import (
|
||||
"github.com/moby/buildkit/session/sshforward/sshprovider"
|
||||
"github.com/moby/buildkit/util/entitlements"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
// required to get default driver registered
|
||||
@@ -56,13 +56,13 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti
|
||||
return err
|
||||
}
|
||||
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
|
||||
_, err := s.build(ctx, project, options, nil)
|
||||
_, err := s.build(ctx, project, options)
|
||||
return err
|
||||
}, s.stdinfo(), "Building")
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions, localImages map[string]string) (map[string]string, error) {
|
||||
func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions) (map[string]string, error) {
|
||||
buildkitEnabled, err := s.dockerCli.BuildKitEnabled()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -117,12 +117,6 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
||||
return nil
|
||||
}
|
||||
|
||||
image := api.GetImageNameOrDefault(service, project.Name)
|
||||
_, localImagePresent := localImages[image]
|
||||
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !buildkitEnabled {
|
||||
id, err := s.doBuildClassic(ctx, project, service, options)
|
||||
if err != nil {
|
||||
@@ -189,7 +183,7 @@ func getServiceIndex(project *types.Project, name string) (types.ServiceConfig,
|
||||
return service, idx
|
||||
}
|
||||
|
||||
func (s *composeService) ensureImagesExists(ctx context.Context, project *types.Project, buildOpts *api.BuildOptions, quietPull bool) error {
|
||||
func (s *composeService) ensureImagesExists(ctx context.Context, project *types.Project, quietPull bool) error {
|
||||
for _, service := range project.Services {
|
||||
if service.Image == "" && service.Build == nil {
|
||||
return fmt.Errorf("invalid service %q. Must specify either image or build", service.Name)
|
||||
@@ -210,10 +204,22 @@ func (s *composeService) ensureImagesExists(ctx context.Context, project *types.
|
||||
return err
|
||||
}
|
||||
|
||||
if buildOpts != nil {
|
||||
mode := xprogress.PrinterModeAuto
|
||||
if quietPull {
|
||||
mode = xprogress.PrinterModeQuiet
|
||||
}
|
||||
|
||||
buildRequired, err := s.prepareProjectForBuild(project, images)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if buildRequired {
|
||||
err = tracing.SpanWrapFunc("project/build", tracing.ProjectOptions(project),
|
||||
func(ctx context.Context) error {
|
||||
builtImages, err := s.build(ctx, project, *buildOpts, images)
|
||||
builtImages, err := s.build(ctx, project, api.BuildOptions{
|
||||
Progress: mode,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -243,6 +249,37 @@ func (s *composeService) ensureImagesExists(ctx context.Context, project *types.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) prepareProjectForBuild(project *types.Project, images map[string]string) (bool, error) {
|
||||
buildRequired := false
|
||||
err := api.BuildOptions{}.Apply(project)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for i, service := range project.Services {
|
||||
if service.Build == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
image := api.GetImageNameOrDefault(service, project.Name)
|
||||
_, localImagePresent := images[image]
|
||||
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
|
||||
service.Build = nil
|
||||
project.Services[i] = service
|
||||
continue
|
||||
}
|
||||
|
||||
if service.Platform == "" {
|
||||
// let builder to build for default platform
|
||||
service.Build.Platforms = nil
|
||||
} else {
|
||||
service.Build.Platforms = []string{service.Platform}
|
||||
}
|
||||
project.Services[i] = service
|
||||
buildRequired = true
|
||||
}
|
||||
return buildRequired, nil
|
||||
}
|
||||
|
||||
func (s *composeService) getLocalImagesDigests(ctx context.Context, project *types.Project) (map[string]string, error) {
|
||||
var imageNames []string
|
||||
for _, s := range project.Services {
|
||||
@@ -281,10 +318,8 @@ func (s *composeService) getLocalImagesDigests(ctx context.Context, project *typ
|
||||
Variant: inspect.Variant,
|
||||
}
|
||||
if !platforms.NewMatcher(platform).Match(actual) {
|
||||
// there is a local image, but it's for the wrong platform, so
|
||||
// pretend it doesn't exist so that we can pull/build an image
|
||||
// for the correct platform instead
|
||||
delete(images, imgName)
|
||||
return nil, errors.Errorf("image with reference %s was found but does not match the specified platform: wanted %s, actual: %s",
|
||||
imgName, platforms.Format(platform), platforms.Format(actual))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +362,7 @@ func resolveAndMergeBuildArgs(
|
||||
}
|
||||
|
||||
func (s *composeService) toBuildOptions(project *types.Project, service types.ServiceConfig, options api.BuildOptions) (build.Options, error) {
|
||||
plats, err := parsePlatforms(service)
|
||||
plats, err := addPlatforms(project, service)
|
||||
if err != nil {
|
||||
return build.Options{}, err
|
||||
}
|
||||
@@ -480,6 +515,24 @@ func addSecretsConfig(project *types.Project, service types.ServiceConfig) (sess
|
||||
return secretsprovider.NewSecretProvider(store), nil
|
||||
}
|
||||
|
||||
func addPlatforms(project *types.Project, service types.ServiceConfig) ([]specs.Platform, error) {
|
||||
plats, err := useDockerDefaultOrServicePlatform(project, service, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, buildPlatform := range service.Build.Platforms {
|
||||
p, err := platforms.Parse(buildPlatform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !utils.Contains(plats, p) {
|
||||
plats = append(plats, p)
|
||||
}
|
||||
}
|
||||
return plats, nil
|
||||
}
|
||||
|
||||
func getImageBuildLabels(project *types.Project, service types.ServiceConfig) types.Labels {
|
||||
ret := make(types.Labels)
|
||||
if service.Build != nil {
|
||||
@@ -502,25 +555,37 @@ func toBuildContexts(additionalContexts types.Mapping) map[string]build.NamedCon
|
||||
return namedContexts
|
||||
}
|
||||
|
||||
func parsePlatforms(service types.ServiceConfig) ([]specs.Platform, error) {
|
||||
if service.Build == nil || len(service.Build.Platforms) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var errs []error
|
||||
ret := make([]specs.Platform, len(service.Build.Platforms))
|
||||
for i := range service.Build.Platforms {
|
||||
p, err := platforms.Parse(service.Build.Platforms[i])
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
ret[i] = p
|
||||
func useDockerDefaultPlatform(project *types.Project, platformList types.StringList) ([]specs.Platform, error) {
|
||||
var plats []specs.Platform
|
||||
if platform, ok := project.Environment["DOCKER_DEFAULT_PLATFORM"]; ok {
|
||||
if len(platformList) > 0 && !utils.StringContains(platformList, platform) {
|
||||
return nil, fmt.Errorf("the DOCKER_DEFAULT_PLATFORM %q value should be part of the service.build.platforms: %q", platform, platformList)
|
||||
}
|
||||
p, err := platforms.Parse(platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plats = append(plats, p)
|
||||
}
|
||||
|
||||
if err := errors.Join(errs...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
return plats, nil
|
||||
}
|
||||
|
||||
func useDockerDefaultOrServicePlatform(project *types.Project, service types.ServiceConfig, useOnePlatform bool) ([]specs.Platform, error) {
|
||||
plats, err := useDockerDefaultPlatform(project, service.Build.Platforms)
|
||||
if (len(plats) > 0 && useOnePlatform) || err != nil {
|
||||
return plats, err
|
||||
}
|
||||
|
||||
if service.Platform != "" {
|
||||
if len(service.Build.Platforms) > 0 && !utils.StringContains(service.Build.Platforms, service.Platform) {
|
||||
return nil, fmt.Errorf("service.platform %q should be part of the service.build.platforms: %q", service.Platform, service.Build.Platforms)
|
||||
}
|
||||
// User defined a service platform and no build platforms, so we should keep the one define on the service level
|
||||
p, err := platforms.Parse(service.Platform)
|
||||
if !utils.Contains(plats, p) {
|
||||
plats = append(plats, p)
|
||||
}
|
||||
return plats, err
|
||||
}
|
||||
return plats, nil
|
||||
}
|
||||
|
||||
121
pkg/compose/build_test.go
Normal file
121
pkg/compose/build_test.go
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestPrepareProjectForBuild(t *testing.T) {
|
||||
t.Run("build service platform", func(t *testing.T) {
|
||||
project := types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
Platforms: []string{
|
||||
"linux/amd64",
|
||||
"linux/arm64",
|
||||
"alice/32",
|
||||
},
|
||||
},
|
||||
Platform: "alice/32",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
s := &composeService{}
|
||||
_, err := s.prepareProjectForBuild(&project, nil)
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, project.Services[0].Build.Platforms, types.StringList{"alice/32"})
|
||||
})
|
||||
|
||||
t.Run("build DOCKER_DEFAULT_PLATFORM", func(t *testing.T) {
|
||||
project := types.Project{
|
||||
Environment: map[string]string{
|
||||
"DOCKER_DEFAULT_PLATFORM": "linux/amd64",
|
||||
},
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
Platforms: []string{
|
||||
"linux/amd64",
|
||||
"linux/arm64",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
s := &composeService{}
|
||||
_, err := s.prepareProjectForBuild(&project, nil)
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, project.Services[0].Build.Platforms, types.StringList{"linux/amd64"})
|
||||
})
|
||||
|
||||
t.Run("skip existing image", func(t *testing.T) {
|
||||
project := types.Project{
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
s := &composeService{}
|
||||
_, err := s.prepareProjectForBuild(&project, map[string]string{"foo": "exists"})
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, project.Services[0].Build == nil)
|
||||
})
|
||||
|
||||
t.Run("unsupported build platform", func(t *testing.T) {
|
||||
project := types.Project{
|
||||
Environment: map[string]string{
|
||||
"DOCKER_DEFAULT_PLATFORM": "commodore/64",
|
||||
},
|
||||
Services: []types.ServiceConfig{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "foo",
|
||||
Build: &types.BuildConfig{
|
||||
Context: ".",
|
||||
Platforms: []string{
|
||||
"linux/amd64",
|
||||
"linux/arm64",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
s := &composeService{}
|
||||
_, err := s.prepareProjectForBuild(&project, nil)
|
||||
assert.Check(t, err != nil)
|
||||
})
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -30,18 +31,20 @@ import (
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/docker/cli/cli/flags"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
var stdioToStdout bool
|
||||
@@ -166,9 +169,9 @@ func (s *composeService) Config(ctx context.Context, project *types.Project, opt
|
||||
|
||||
switch options.Format {
|
||||
case "json":
|
||||
return project.MarshalJSON()
|
||||
return json.MarshalIndent(project, "", " ")
|
||||
case "yaml":
|
||||
return project.MarshalYAML()
|
||||
return yaml.Marshal(project)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported format %q", options.Format)
|
||||
}
|
||||
|
||||
@@ -102,13 +102,71 @@ func (c *convergence) apply(ctx context.Context, project *types.Project, options
|
||||
if utils.StringContains(options.Services, name) {
|
||||
strategy = options.Recreate
|
||||
}
|
||||
return c.ensureService(ctx, project, service, strategy, options.Inherit, options.Timeout)
|
||||
err = c.ensureService(ctx, project, service, strategy, options.Inherit, options.Timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.updateProject(project, name)
|
||||
return nil
|
||||
})(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
// updateProject updates project after service converged, so dependent services relying on `service:xx` can refer to actual containers.
|
||||
func (c *convergence) updateProject(project *types.Project, serviceName string) {
|
||||
// operation is protected by a Mutex so that we can safely update project.Services while running concurrent convergence on services
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
cnts := c.getObservedState(serviceName)
|
||||
for i, s := range project.Services {
|
||||
updateServices(&s, cnts)
|
||||
project.Services[i] = s
|
||||
}
|
||||
}
|
||||
|
||||
func updateServices(service *types.ServiceConfig, cnts Containers) {
|
||||
if len(cnts) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, str := range []*string{&service.NetworkMode, &service.Ipc, &service.Pid} {
|
||||
if d := getDependentServiceFromMode(*str); d != "" {
|
||||
if serviceContainers := cnts.filter(isService(d)); len(serviceContainers) > 0 {
|
||||
*str = types.NetworkModeContainerPrefix + serviceContainers[0].ID
|
||||
}
|
||||
}
|
||||
}
|
||||
var links []string
|
||||
for _, serviceLink := range service.Links {
|
||||
parts := strings.Split(serviceLink, ":")
|
||||
serviceName := serviceLink
|
||||
serviceAlias := ""
|
||||
if len(parts) == 2 {
|
||||
serviceName = parts[0]
|
||||
serviceAlias = parts[1]
|
||||
}
|
||||
if serviceName != service.Name {
|
||||
links = append(links, serviceLink)
|
||||
continue
|
||||
}
|
||||
for _, container := range cnts {
|
||||
name := getCanonicalContainerName(container)
|
||||
if serviceAlias != "" {
|
||||
links = append(links,
|
||||
fmt.Sprintf("%s:%s", name, serviceAlias))
|
||||
}
|
||||
links = append(links,
|
||||
fmt.Sprintf("%s:%s", name, name),
|
||||
fmt.Sprintf("%s:%s", name, getContainerNameWithoutProject(container)))
|
||||
}
|
||||
service.Links = links
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convergence) ensureService(ctx context.Context, project *types.Project, service types.ServiceConfig, recreate string, inherit bool, timeout *time.Duration) error {
|
||||
expected, err := getScale(service)
|
||||
if err != nil {
|
||||
@@ -120,11 +178,6 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
||||
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
|
||||
err = c.resolveServiceReferences(&service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sort.Slice(containers, func(i, j int) bool {
|
||||
return containers[i].Created < containers[j].Created
|
||||
})
|
||||
@@ -205,71 +258,6 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
|
||||
return err
|
||||
}
|
||||
|
||||
// resolveServiceReferences replaces reference to another service with reference to an actual container
|
||||
func (c *convergence) resolveServiceReferences(service *types.ServiceConfig) error {
|
||||
err := c.resolveVolumeFrom(service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.resolveSharedNamespaces(service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *convergence) resolveVolumeFrom(service *types.ServiceConfig) error {
|
||||
for i, vol := range service.VolumesFrom {
|
||||
spec := strings.Split(vol, ":")
|
||||
if len(spec) == 0 {
|
||||
continue
|
||||
}
|
||||
if spec[0] == "container" {
|
||||
service.VolumesFrom[i] = spec[1]
|
||||
continue
|
||||
}
|
||||
name := spec[0]
|
||||
dependencies := c.getObservedState(name)
|
||||
if len(dependencies) == 0 {
|
||||
return fmt.Errorf("cannot share volume with service %s: container missing", name)
|
||||
}
|
||||
service.VolumesFrom[i] = dependencies.sorted()[0].ID
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *convergence) resolveSharedNamespaces(service *types.ServiceConfig) error {
|
||||
str := service.NetworkMode
|
||||
if name := getDependentServiceFromMode(str); name != "" {
|
||||
dependencies := c.getObservedState(name)
|
||||
if len(dependencies) == 0 {
|
||||
return fmt.Errorf("cannot share network namespace with service %s: container missing", name)
|
||||
}
|
||||
service.NetworkMode = types.ContainerPrefix + dependencies.sorted()[0].ID
|
||||
}
|
||||
|
||||
str = service.Ipc
|
||||
if name := getDependentServiceFromMode(str); name != "" {
|
||||
dependencies := c.getObservedState(name)
|
||||
if len(dependencies) == 0 {
|
||||
return fmt.Errorf("cannot share IPC namespace with service %s: container missing", name)
|
||||
}
|
||||
service.Ipc = types.ContainerPrefix + dependencies.sorted()[0].ID
|
||||
}
|
||||
|
||||
str = service.Pid
|
||||
if name := getDependentServiceFromMode(str); name != "" {
|
||||
dependencies := c.getObservedState(name)
|
||||
if len(dependencies) == 0 {
|
||||
return fmt.Errorf("cannot share PID namespace with service %s: container missing", name)
|
||||
}
|
||||
service.Pid = types.ContainerPrefix + dependencies.sorted()[0].ID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mustRecreate(expected types.ServiceConfig, actual moby.Container, policy string) (bool, error) {
|
||||
if policy == api.RecreateNever {
|
||||
return false, nil
|
||||
|
||||
@@ -62,9 +62,9 @@ type createConfigs struct {
|
||||
Links []string
|
||||
}
|
||||
|
||||
func (s *composeService) Create(ctx context.Context, project *types.Project, createOpts api.CreateOptions) error {
|
||||
func (s *composeService) Create(ctx context.Context, project *types.Project, options api.CreateOptions) error {
|
||||
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
|
||||
return s.create(ctx, project, createOpts)
|
||||
return s.create(ctx, project, options)
|
||||
}, s.stdinfo(), "Creating")
|
||||
}
|
||||
|
||||
@@ -79,13 +79,18 @@ func (s *composeService) create(ctx context.Context, project *types.Project, opt
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.ensureImagesExists(ctx, project, options.Build, options.QuietPull)
|
||||
err = s.ensureImagesExists(ctx, project, options.QuietPull)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prepareNetworks(project)
|
||||
|
||||
err = prepareVolumes(project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.ensureNetworks(ctx, project.Networks); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -118,6 +123,31 @@ func (s *composeService) create(ctx context.Context, project *types.Project, opt
|
||||
return newConvergence(options.Services, observedState, s).apply(ctx, project, options)
|
||||
}
|
||||
|
||||
func prepareVolumes(p *types.Project) error {
|
||||
for i := range p.Services {
|
||||
volumesFrom, dependServices, err := getVolumesFrom(p, p.Services[i].VolumesFrom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Services[i].VolumesFrom = volumesFrom
|
||||
if len(dependServices) > 0 {
|
||||
if p.Services[i].DependsOn == nil {
|
||||
p.Services[i].DependsOn = make(types.DependsOnConfig, len(dependServices))
|
||||
}
|
||||
for _, service := range p.Services {
|
||||
if utils.StringContains(dependServices, service.Name) &&
|
||||
p.Services[i].DependsOn[service.Name].Condition == "" {
|
||||
p.Services[i].DependsOn[service.Name] = types.ServiceDependency{
|
||||
Condition: types.ServiceConditionStarted,
|
||||
Required: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func prepareNetworks(project *types.Project) {
|
||||
for k, network := range project.Networks {
|
||||
network.Labels = network.Labels.Add(api.NetworkLabel, k)
|
||||
@@ -219,6 +249,13 @@ func (s *composeService) getCreateConfigs(ctx context.Context,
|
||||
if err != nil {
|
||||
return createConfigs{}, err
|
||||
}
|
||||
var volumesFrom []string
|
||||
for _, v := range service.VolumesFrom {
|
||||
if !strings.HasPrefix(v, "container:") {
|
||||
return createConfigs{}, fmt.Errorf("invalid volume_from: %s", v)
|
||||
}
|
||||
volumesFrom = append(volumesFrom, v[len("container:"):])
|
||||
}
|
||||
|
||||
// NETWORKING
|
||||
links, err := s.getLinks(ctx, p.Name, service, number)
|
||||
@@ -259,7 +296,7 @@ func (s *composeService) getCreateConfigs(ctx context.Context,
|
||||
PortBindings: portBindings,
|
||||
Resources: resources,
|
||||
VolumeDriver: service.VolumeDriver,
|
||||
VolumesFrom: service.VolumesFrom,
|
||||
VolumesFrom: volumesFrom,
|
||||
DNS: service.DNS,
|
||||
DNSSearch: service.DNSSearch,
|
||||
DNSOptions: service.DNSOpts,
|
||||
@@ -639,6 +676,40 @@ func buildContainerPortBindingOptions(s types.ServiceConfig) nat.PortMap {
|
||||
return bindings
|
||||
}
|
||||
|
||||
func getVolumesFrom(project *types.Project, volumesFrom []string) ([]string, []string, error) {
|
||||
var volumes = []string{}
|
||||
var services = []string{}
|
||||
// parse volumes_from
|
||||
if len(volumesFrom) == 0 {
|
||||
return volumes, services, nil
|
||||
}
|
||||
for _, vol := range volumesFrom {
|
||||
spec := strings.Split(vol, ":")
|
||||
if len(spec) == 0 {
|
||||
continue
|
||||
}
|
||||
if spec[0] == "container" {
|
||||
volumes = append(volumes, vol)
|
||||
continue
|
||||
}
|
||||
serviceName := spec[0]
|
||||
services = append(services, serviceName)
|
||||
service, err := project.GetService(serviceName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
firstContainer := getContainerName(project.Name, service, 1)
|
||||
v := fmt.Sprintf("container:%s", firstContainer)
|
||||
if len(spec) > 2 {
|
||||
v = fmt.Sprintf("container:%s:%s", firstContainer, strings.Join(spec[1:], ":"))
|
||||
}
|
||||
volumes = append(volumes, v)
|
||||
}
|
||||
return volumes, services, nil
|
||||
|
||||
}
|
||||
|
||||
func getDependentServiceFromMode(mode string) string {
|
||||
if strings.HasPrefix(
|
||||
mode,
|
||||
|
||||
@@ -98,6 +98,46 @@ func TestPrepareNetworkLabels(t *testing.T) {
|
||||
}))
|
||||
}
|
||||
|
||||
func TestPrepareVolumes(t *testing.T) {
|
||||
t.Run("adds dependency condition if service depends on volume from another service", func(t *testing.T) {
|
||||
project := composetypes.Project{
|
||||
Name: "myProject",
|
||||
Services: []composetypes.ServiceConfig{
|
||||
{
|
||||
Name: "aService",
|
||||
VolumesFrom: []string{"anotherService"},
|
||||
},
|
||||
{
|
||||
Name: "anotherService",
|
||||
},
|
||||
},
|
||||
}
|
||||
err := prepareVolumes(&project)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, project.Services[0].DependsOn["anotherService"].Condition, composetypes.ServiceConditionStarted)
|
||||
})
|
||||
t.Run("doesn't overwrite existing dependency condition", func(t *testing.T) {
|
||||
project := composetypes.Project{
|
||||
Name: "myProject",
|
||||
Services: []composetypes.ServiceConfig{
|
||||
{
|
||||
Name: "aService",
|
||||
VolumesFrom: []string{"anotherService"},
|
||||
DependsOn: map[string]composetypes.ServiceDependency{
|
||||
"anotherService": {Condition: composetypes.ServiceConditionHealthy, Required: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "anotherService",
|
||||
},
|
||||
},
|
||||
}
|
||||
err := prepareVolumes(&project)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, project.Services[0].DependsOn["anotherService"].Condition, composetypes.ServiceConditionHealthy)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuildContainerMountOptions(t *testing.T) {
|
||||
project := composetypes.Project{
|
||||
Name: "myProject",
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/errdefs"
|
||||
|
||||
@@ -71,9 +71,9 @@ func TestComposeService_Logs_Demux(t *testing.T) {
|
||||
c1Stdout := stdcopy.NewStdWriter(c1Writer, stdcopy.Stdout)
|
||||
c1Stderr := stdcopy.NewStdWriter(c1Writer, stdcopy.Stderr)
|
||||
go func() {
|
||||
_, err := c1Stdout.Write([]byte("hello stdout\n"))
|
||||
_, err := c1Stdout.Write([]byte("hello\n stdout"))
|
||||
assert.NoError(t, err, "Writing to fake stdout")
|
||||
_, err = c1Stderr.Write([]byte("hello stderr\n"))
|
||||
_, err = c1Stderr.Write([]byte("hello\n stderr"))
|
||||
assert.NoError(t, err, "Writing to fake stderr")
|
||||
_ = c1Writer.Close()
|
||||
}()
|
||||
@@ -94,7 +94,7 @@ func TestComposeService_Logs_Demux(t *testing.T) {
|
||||
|
||||
require.Equal(
|
||||
t,
|
||||
[]string{"hello stdout", "hello stderr"},
|
||||
[]string{"hello", " stdout", "hello", " stderr"},
|
||||
consumer.LogsForContainer("c"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package compose
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
@@ -34,37 +33,32 @@ type logPrinter interface {
|
||||
type printer struct {
|
||||
queue chan api.ContainerEvent
|
||||
consumer api.LogConsumer
|
||||
stopped atomic.Bool
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
// newLogPrinter builds a LogPrinter passing containers logs to LogConsumer
|
||||
func newLogPrinter(consumer api.LogConsumer) logPrinter {
|
||||
queue := make(chan api.ContainerEvent)
|
||||
stopCh := make(chan struct{}, 1) // printer MAY stop on his own, so Stop MUST not be blocking
|
||||
printer := printer{
|
||||
consumer: consumer,
|
||||
queue: queue,
|
||||
stopCh: stopCh,
|
||||
}
|
||||
return &printer
|
||||
}
|
||||
|
||||
func (p *printer) Cancel() {
|
||||
// note: HandleEvent is used to ensure this doesn't deadlock
|
||||
p.HandleEvent(api.ContainerEvent{Type: api.UserCancel})
|
||||
p.queue <- api.ContainerEvent{
|
||||
Type: api.UserCancel,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) Stop() {
|
||||
if p.stopped.CompareAndSwap(false, true) {
|
||||
// only close if this is the first call to stop
|
||||
close(p.queue)
|
||||
}
|
||||
p.stopCh <- struct{}{}
|
||||
}
|
||||
|
||||
func (p *printer) HandleEvent(event api.ContainerEvent) {
|
||||
// prevent deadlocking, if the printer is done, there's no reader for
|
||||
// queue, so this write could block indefinitely
|
||||
if p.stopped.Load() {
|
||||
return
|
||||
}
|
||||
p.queue <- event
|
||||
}
|
||||
|
||||
@@ -75,57 +69,61 @@ func (p *printer) Run(cascadeStop bool, exitCodeFrom string, stopFn func() error
|
||||
exitCode int
|
||||
)
|
||||
containers := map[string]struct{}{}
|
||||
for event := range p.queue {
|
||||
container, id := event.Container, event.ID
|
||||
switch event.Type {
|
||||
case api.UserCancel:
|
||||
aborting = true
|
||||
case api.ContainerEventAttach:
|
||||
if _, ok := containers[id]; ok {
|
||||
continue
|
||||
}
|
||||
containers[id] = struct{}{}
|
||||
p.consumer.Register(container)
|
||||
case api.ContainerEventExit, api.ContainerEventStopped, api.ContainerEventRecreated:
|
||||
if !event.Restarting {
|
||||
delete(containers, id)
|
||||
}
|
||||
if !aborting {
|
||||
p.consumer.Status(container, fmt.Sprintf("exited with code %d", event.ExitCode))
|
||||
if event.Type == api.ContainerEventRecreated {
|
||||
p.consumer.Status(container, "has been recreated")
|
||||
for {
|
||||
select {
|
||||
case <-p.stopCh:
|
||||
return exitCode, nil
|
||||
case event := <-p.queue:
|
||||
container, id := event.Container, event.ID
|
||||
switch event.Type {
|
||||
case api.UserCancel:
|
||||
aborting = true
|
||||
case api.ContainerEventAttach:
|
||||
if _, ok := containers[id]; ok {
|
||||
continue
|
||||
}
|
||||
containers[id] = struct{}{}
|
||||
p.consumer.Register(container)
|
||||
case api.ContainerEventExit, api.ContainerEventStopped, api.ContainerEventRecreated:
|
||||
if !event.Restarting {
|
||||
delete(containers, id)
|
||||
}
|
||||
}
|
||||
if cascadeStop {
|
||||
if !aborting {
|
||||
aborting = true
|
||||
err := stopFn()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
p.consumer.Status(container, fmt.Sprintf("exited with code %d", event.ExitCode))
|
||||
if event.Type == api.ContainerEventRecreated {
|
||||
p.consumer.Status(container, "has been recreated")
|
||||
}
|
||||
}
|
||||
if event.Type == api.ContainerEventExit {
|
||||
if exitCodeFrom == "" {
|
||||
exitCodeFrom = event.Service
|
||||
if cascadeStop {
|
||||
if !aborting {
|
||||
aborting = true
|
||||
err := stopFn()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if exitCodeFrom == event.Service {
|
||||
exitCode = event.ExitCode
|
||||
if event.Type == api.ContainerEventExit {
|
||||
if exitCodeFrom == "" {
|
||||
exitCodeFrom = event.Service
|
||||
}
|
||||
if exitCodeFrom == event.Service {
|
||||
exitCode = event.ExitCode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(containers) == 0 {
|
||||
// Last container terminated, done
|
||||
return exitCode, nil
|
||||
}
|
||||
case api.ContainerEventLog:
|
||||
if !aborting {
|
||||
p.consumer.Log(container, event.Line)
|
||||
}
|
||||
case api.ContainerEventErr:
|
||||
if !aborting {
|
||||
p.consumer.Err(container, event.Line)
|
||||
if len(containers) == 0 {
|
||||
// Last container terminated, done
|
||||
return exitCode, nil
|
||||
}
|
||||
case api.ContainerEventLog:
|
||||
if !aborting {
|
||||
p.consumer.Log(container, event.Line)
|
||||
}
|
||||
case api.ContainerEventErr:
|
||||
if !aborting {
|
||||
p.consumer.Err(container, event.Line)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return exitCode, nil
|
||||
}
|
||||
|
||||
@@ -78,48 +78,19 @@ func (s *composeService) Ps(ctx context.Context, projectName string, options api
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
local int
|
||||
mounts []string
|
||||
)
|
||||
for _, m := range container.Mounts {
|
||||
name := m.Name
|
||||
if name == "" {
|
||||
name = m.Source
|
||||
}
|
||||
if m.Driver == "local" {
|
||||
local++
|
||||
}
|
||||
mounts = append(mounts, name)
|
||||
}
|
||||
|
||||
var networks []string
|
||||
if container.NetworkSettings != nil {
|
||||
for k := range container.NetworkSettings.Networks {
|
||||
networks = append(networks, k)
|
||||
}
|
||||
}
|
||||
|
||||
summary[i] = api.ContainerSummary{
|
||||
ID: container.ID,
|
||||
Name: getCanonicalContainerName(container),
|
||||
Names: container.Names,
|
||||
Image: container.Image,
|
||||
Project: container.Labels[api.ProjectLabel],
|
||||
Service: container.Labels[api.ServiceLabel],
|
||||
Command: container.Command,
|
||||
State: container.State,
|
||||
Status: container.Status,
|
||||
Created: container.Created,
|
||||
Labels: container.Labels,
|
||||
SizeRw: container.SizeRw,
|
||||
SizeRootFs: container.SizeRootFs,
|
||||
Mounts: mounts,
|
||||
LocalVolumes: local,
|
||||
Networks: networks,
|
||||
Health: health,
|
||||
ExitCode: exitCode,
|
||||
Publishers: publishers,
|
||||
ID: container.ID,
|
||||
Name: getCanonicalContainerName(container),
|
||||
Image: container.Image,
|
||||
Project: container.Labels[api.ProjectLabel],
|
||||
Service: container.Labels[api.ServiceLabel],
|
||||
Command: container.Command,
|
||||
State: container.State,
|
||||
Status: container.Status,
|
||||
Created: container.Created,
|
||||
Health: health,
|
||||
ExitCode: exitCode,
|
||||
Publishers: publishers,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -54,34 +54,13 @@ func TestPs(t *testing.T) {
|
||||
containers, err := tested.Ps(ctx, strings.ToLower(testProject), compose.PsOptions{})
|
||||
|
||||
expected := []compose.ContainerSummary{
|
||||
{ID: "123", Name: "123", Names: []string{"/123"}, Image: "foo", Project: strings.ToLower(testProject), Service: "service1",
|
||||
State: "running", Health: "healthy", Publishers: nil,
|
||||
Labels: map[string]string{
|
||||
compose.ProjectLabel: strings.ToLower(testProject),
|
||||
compose.ConfigFilesLabel: "/src/pkg/compose/testdata/compose.yaml",
|
||||
compose.WorkingDirLabel: "/src/pkg/compose/testdata",
|
||||
compose.ServiceLabel: "service1",
|
||||
},
|
||||
},
|
||||
{ID: "456", Name: "456", Names: []string{"/456"}, Image: "foo", Project: strings.ToLower(testProject), Service: "service1",
|
||||
{ID: "123", Name: "123", Image: "foo", Project: strings.ToLower(testProject), Service: "service1",
|
||||
State: "running", Health: "healthy", Publishers: nil},
|
||||
{ID: "456", Name: "456", Image: "foo", Project: strings.ToLower(testProject), Service: "service1",
|
||||
State: "running", Health: "",
|
||||
Publishers: []compose.PortPublisher{{URL: "localhost", TargetPort: 90, PublishedPort: 80}},
|
||||
Labels: map[string]string{
|
||||
compose.ProjectLabel: strings.ToLower(testProject),
|
||||
compose.ConfigFilesLabel: "/src/pkg/compose/testdata/compose.yaml",
|
||||
compose.WorkingDirLabel: "/src/pkg/compose/testdata",
|
||||
compose.ServiceLabel: "service1",
|
||||
},
|
||||
},
|
||||
{ID: "789", Name: "789", Names: []string{"/789"}, Image: "foo", Project: strings.ToLower(testProject), Service: "service2",
|
||||
State: "exited", Health: "", ExitCode: 130, Publishers: nil,
|
||||
Labels: map[string]string{
|
||||
compose.ProjectLabel: strings.ToLower(testProject),
|
||||
compose.ConfigFilesLabel: "/src/pkg/compose/testdata/compose.yaml",
|
||||
compose.WorkingDirLabel: "/src/pkg/compose/testdata",
|
||||
compose.ServiceLabel: "service2",
|
||||
},
|
||||
},
|
||||
Publishers: []compose.PortPublisher{{URL: "localhost", TargetPort: 90, PublishedPort: 80}}},
|
||||
{ID: "789", Name: "789", Image: "foo", Project: strings.ToLower(testProject), Service: "service2",
|
||||
State: "exited", Health: "", ExitCode: 130, Publishers: nil},
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, containers, expected)
|
||||
|
||||
@@ -18,136 +18,24 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/buildx/util/imagetools"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/specs-go"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
func (s *composeService) Publish(ctx context.Context, project *types.Project, repository string, options api.PublishOptions) error {
|
||||
return progress.RunWithTitle(ctx, func(ctx context.Context) error {
|
||||
return s.publish(ctx, project, repository, options)
|
||||
}, s.stdinfo(), "Publishing")
|
||||
}
|
||||
|
||||
func (s *composeService) publish(ctx context.Context, project *types.Project, repository string, options api.PublishOptions) error {
|
||||
func (s *composeService) Publish(ctx context.Context, project *types.Project, repository string) error {
|
||||
err := s.Push(ctx, project, api.PushOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := progress.ContextWriter(ctx)
|
||||
|
||||
named, err := reference.ParseDockerRef(repository)
|
||||
_, err = reference.ParseDockerRef(repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resolver := imagetools.New(imagetools.Opt{
|
||||
Auth: s.configFile(),
|
||||
})
|
||||
// TODO publish project.ComposeFiles
|
||||
|
||||
var layers []v1.Descriptor
|
||||
for _, file := range project.ComposeFiles {
|
||||
f, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
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,
|
||||
},
|
||||
}
|
||||
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,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
w.Event(progress.Event{
|
||||
ID: file,
|
||||
Text: "published",
|
||||
Status: progress.Done,
|
||||
})
|
||||
}
|
||||
|
||||
emptyConfig, err := json.Marshal(v1.ImageConfig{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configDescriptor := v1.Descriptor{
|
||||
MediaType: "application/vnd.docker.compose.project",
|
||||
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
|
||||
}
|
||||
|
||||
w.Event(progress.Event{
|
||||
ID: repository,
|
||||
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
|
||||
}
|
||||
w.Event(progress.Event{
|
||||
ID: repository,
|
||||
Text: "published",
|
||||
Status: progress.Done,
|
||||
})
|
||||
return nil
|
||||
return api.ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
"github.com/docker/buildx/driver"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/distribution/distribution/v3/reference"
|
||||
"github.com/docker/buildx/driver"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
|
||||
@@ -48,13 +48,6 @@ func (s *composeService) restart(ctx context.Context, projectName string, option
|
||||
}
|
||||
}
|
||||
|
||||
if options.NoDeps {
|
||||
err := project.ForServices(options.Services, types.IgnoreDependencies)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// ignore depends_on relations which are not impacted by restarting service or not required
|
||||
for i, service := range project.Services {
|
||||
for name, r := range service.DependsOn {
|
||||
|
||||
@@ -58,6 +58,9 @@ func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.
|
||||
}
|
||||
|
||||
func (s *composeService) prepareRun(ctx context.Context, project *types.Project, opts api.RunOptions) (string, error) {
|
||||
if err := prepareVolumes(project); err != nil { // all dependencies already checked, but might miss service img
|
||||
return "", err
|
||||
}
|
||||
service, err := project.GetService(opts.Service)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -82,7 +85,7 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
|
||||
Add(api.SlugLabel, slug).
|
||||
Add(api.OneoffLabel, "True")
|
||||
|
||||
if err := s.ensureImagesExists(ctx, project, opts.Build, opts.QuietPull); err != nil { // all dependencies already checked, but might miss service img
|
||||
if err := s.ensureImagesExists(ctx, project, opts.QuietPull); err != nil { // all dependencies already checked, but might miss service img
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -90,6 +93,7 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
updateServices(&service, observedState)
|
||||
|
||||
if !opts.NoDeps {
|
||||
if err := s.waitDependencies(ctx, project, service.DependsOn, observedState); err != nil {
|
||||
@@ -103,11 +107,6 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
|
||||
Labels: mergeLabels(service.Labels, service.CustomLabels),
|
||||
}
|
||||
|
||||
err = newConvergence(project.ServiceNames(), observedState, s).resolveServiceReferences(&service)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
created, err := s.createContainer(ctx, project, service, service.ContainerName, 1, createOpts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/internal/tracing"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
)
|
||||
|
||||
func (s *composeService) Scale(ctx context.Context, project *types.Project, options api.ScaleOptions) error {
|
||||
return progress.Run(ctx, tracing.SpanWrapFunc("project/scale", tracing.ProjectOptions(project), func(ctx context.Context) error {
|
||||
err := s.create(ctx, project, api.CreateOptions{Services: options.Services})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.start(ctx, project.Name, api.StartOptions{Project: project, Services: options.Services}, nil)
|
||||
|
||||
}), s.stdinfo())
|
||||
}
|
||||
@@ -56,48 +56,17 @@ func (s *composeService) start(ctx context.Context, projectName string, options
|
||||
}
|
||||
}
|
||||
|
||||
// use an independent context tied to the errgroup for background attach operations
|
||||
// the primary context is still used for other operations
|
||||
// this means that once any attach operation fails, all other attaches are cancelled,
|
||||
// but an attach failing won't interfere with the rest of the start
|
||||
eg, attachCtx := errgroup.WithContext(ctx)
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
if listener != nil {
|
||||
_, err := s.attach(attachCtx, project, listener, options.AttachTo)
|
||||
attached, err := s.attach(ctx, project, listener, options.AttachTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
eg.Go(func() error {
|
||||
// it's possible to have a required service whose log output is not desired
|
||||
// (i.e. it's not in the attach set), so watch everything and then filter
|
||||
// calls to attach; this ensures that `watchContainers` blocks until all
|
||||
// required containers have exited, even if their output is not being shown
|
||||
attachTo := utils.NewSet[string](options.AttachTo...)
|
||||
required := utils.NewSet[string](options.Services...)
|
||||
toWatch := attachTo.Union(required).Elements()
|
||||
|
||||
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true, toWatch...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// N.B. this uses the parent context (instead of attachCtx) so that the watch itself can
|
||||
// continue even if one of the log streams fails
|
||||
return s.watchContainers(ctx, project.Name, toWatch, required.Elements(), listener, containers,
|
||||
return s.watchContainers(context.Background(), project.Name, options.AttachTo, options.Services, listener, attached,
|
||||
func(container moby.Container, _ time.Time) error {
|
||||
svc := container.Labels[api.ServiceLabel]
|
||||
if attachTo.Has(svc) {
|
||||
return s.attachContainer(attachCtx, container, listener)
|
||||
}
|
||||
|
||||
// HACK: simulate an "attach" event
|
||||
listener(api.ContainerEvent{
|
||||
Type: api.ContainerEventAttach,
|
||||
Container: getContainerNameWithoutProject(container),
|
||||
ID: container.ID,
|
||||
Service: svc,
|
||||
})
|
||||
return nil
|
||||
return s.attachContainer(ctx, container, listener)
|
||||
}, func(container moby.Container, _ time.Time) error {
|
||||
listener(api.ContainerEvent{
|
||||
Type: api.ContainerEventAttach,
|
||||
@@ -187,13 +156,6 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
|
||||
required = services
|
||||
}
|
||||
|
||||
unexpected := utils.NewSet[string](required...).Diff(utils.NewSet[string](services...))
|
||||
if len(unexpected) != 0 {
|
||||
return fmt.Errorf(`required service(s) "%s" not present in watched service(s) "%s"`,
|
||||
strings.Join(unexpected.Elements(), ", "),
|
||||
strings.Join(services, ", "))
|
||||
}
|
||||
|
||||
// predicate to tell if a container we receive event for should be considered or ignored
|
||||
ofInterest := func(c moby.Container) bool {
|
||||
if len(services) > 0 {
|
||||
@@ -228,12 +190,6 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
|
||||
err := s.Events(ctx, projectName, api.EventsOptions{
|
||||
Services: services,
|
||||
Consumer: func(event api.Event) error {
|
||||
defer func() {
|
||||
// after consuming each event, check to see if we're done
|
||||
if len(expected) == 0 {
|
||||
stop()
|
||||
}
|
||||
}()
|
||||
inspected, err := s.apiClient().ContainerInspect(ctx, event.Container)
|
||||
if err != nil {
|
||||
if errdefs.IsNotFound(err) {
|
||||
@@ -335,6 +291,9 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(expected) == 0 {
|
||||
stop()
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -21,15 +21,15 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/compose/v2/internal/tracing"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/compose/v2/internal/tracing"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func (s *composeService) Up(ctx context.Context, project *types.Project, options api.UpOptions) error {
|
||||
@@ -55,60 +55,39 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 signalCancel()
|
||||
|
||||
printer := newLogPrinter(options.Start.Attach)
|
||||
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
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{
|
||||
<-signalChan
|
||||
s.Kill(ctx, project.Name, api.KillOptions{ //nolint:errcheck
|
||||
Services: options.Create.Services,
|
||||
Project: project,
|
||||
})
|
||||
}()
|
||||
|
||||
go func() {
|
||||
errCh <- s.Stop(ctx, project.Name, api.StopOptions{
|
||||
Services: options.Create.Services,
|
||||
Project: project,
|
||||
})
|
||||
}()
|
||||
return <-errCh
|
||||
return s.Stop(ctx, project.Name, api.StopOptions{
|
||||
Services: options.Create.Services,
|
||||
Project: project,
|
||||
})
|
||||
}, 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
|
||||
}
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
go func() {
|
||||
<-signalChan
|
||||
isTerminated = true
|
||||
printer.Cancel()
|
||||
fmt.Fprintln(s.stdinfo(), "Gracefully stopping... (press Ctrl+C again to force)")
|
||||
return stopFunc()
|
||||
})
|
||||
eg.Go(stopFunc)
|
||||
}()
|
||||
|
||||
var exitCode int
|
||||
eg.Go(func() error {
|
||||
@@ -122,10 +101,8 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
|
||||
return err
|
||||
}
|
||||
|
||||
// signal for the goroutines to stop & wait for them to finish any remaining work
|
||||
signalCancel()
|
||||
printer.Stop()
|
||||
err = eg.Wait().ErrorOrNil()
|
||||
err = eg.Wait()
|
||||
if exitCode != 0 {
|
||||
errMsg := ""
|
||||
if err != nil {
|
||||
|
||||
@@ -26,24 +26,45 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/internal/sync"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/watch"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
|
||||
"github.com/docker/compose/v2/internal/sync"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/watch"
|
||||
)
|
||||
|
||||
type DevelopmentConfig struct {
|
||||
Watch []Trigger `json:"watch,omitempty"`
|
||||
}
|
||||
|
||||
type WatchAction string
|
||||
|
||||
const (
|
||||
WatchActionSync WatchAction = "sync"
|
||||
WatchActionRebuild WatchAction = "rebuild"
|
||||
)
|
||||
|
||||
type Trigger struct {
|
||||
Path string `json:"path,omitempty"`
|
||||
Action string `json:"action,omitempty"`
|
||||
Target string `json:"target,omitempty"`
|
||||
Ignore []string `json:"ignore,omitempty"`
|
||||
}
|
||||
|
||||
const quietPeriod = 500 * time.Millisecond
|
||||
|
||||
// fileEvent contains the Compose service and modified host system path.
|
||||
type fileEvent struct {
|
||||
sync.PathMapping
|
||||
Action types.WatchAction
|
||||
Action WatchAction
|
||||
}
|
||||
|
||||
// getSyncImplementation returns the the tar-based syncer unless it has been explicitly
|
||||
@@ -63,7 +84,11 @@ func (s *composeService) getSyncImplementation(project *types.Project) sync.Sync
|
||||
return sync.NewDockerCopy(project.Name, s, s.stdinfo())
|
||||
}
|
||||
|
||||
func (s *composeService) Watch(ctx context.Context, project *types.Project, services []string, options api.WatchOptions) error { //nolint: gocyclo
|
||||
func (s *composeService) Watch(ctx context.Context, project *types.Project, services []string, _ api.WatchOptions) error { //nolint: gocyclo
|
||||
_, err := s.prepareProjectForBuild(project, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := project.ForServices(services); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -77,10 +102,6 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
|
||||
return err
|
||||
}
|
||||
|
||||
if service.Develop != nil {
|
||||
config = service.Develop
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
continue
|
||||
}
|
||||
@@ -144,7 +165,7 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
|
||||
|
||||
eg.Go(func() error {
|
||||
defer watcher.Close() //nolint:errcheck
|
||||
return s.watch(ctx, project, service.Name, options, watcher, syncer, config.Watch)
|
||||
return s.watch(ctx, project, service.Name, watcher, syncer, config.Watch)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -155,7 +176,14 @@ func (s *composeService) Watch(ctx context.Context, project *types.Project, serv
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func (s *composeService) watch(ctx context.Context, project *types.Project, name string, options api.WatchOptions, watcher watch.Notify, syncer sync.Syncer, triggers []types.Trigger) error {
|
||||
func (s *composeService) watch(
|
||||
ctx context.Context,
|
||||
project *types.Project,
|
||||
name string,
|
||||
watcher watch.Notify,
|
||||
syncer sync.Syncer,
|
||||
triggers []Trigger,
|
||||
) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
@@ -178,7 +206,7 @@ func (s *composeService) watch(ctx context.Context, project *types.Project, name
|
||||
case batch := <-batchEvents:
|
||||
start := time.Now()
|
||||
logrus.Debugf("batch start: service[%s] count[%d]", name, len(batch))
|
||||
if err := s.handleWatchBatch(ctx, project, name, options.Build, batch, syncer); err != nil {
|
||||
if err := s.handleWatchBatch(ctx, project, name, batch, syncer); err != nil {
|
||||
logrus.Warnf("Error handling changed files for service %s: %v", name, err)
|
||||
}
|
||||
logrus.Debugf("batch complete: service[%s] duration[%s] count[%d]",
|
||||
@@ -209,7 +237,7 @@ func (s *composeService) watch(ctx context.Context, project *types.Project, name
|
||||
// rules.
|
||||
//
|
||||
// Any errors are logged as warnings and nil (no file event) is returned.
|
||||
func maybeFileEvent(trigger types.Trigger, hostPath string, ignore watch.PathMatcher) *fileEvent {
|
||||
func maybeFileEvent(trigger Trigger, hostPath string, ignore watch.PathMatcher) *fileEvent {
|
||||
if !watch.IsChild(trigger.Path, hostPath) {
|
||||
return nil
|
||||
}
|
||||
@@ -236,7 +264,7 @@ func maybeFileEvent(trigger types.Trigger, hostPath string, ignore watch.PathMat
|
||||
}
|
||||
|
||||
return &fileEvent{
|
||||
Action: trigger.Action,
|
||||
Action: WatchAction(trigger.Action),
|
||||
PathMapping: sync.PathMapping{
|
||||
HostPath: hostPath,
|
||||
ContainerPath: containerPath,
|
||||
@@ -244,13 +272,12 @@ func maybeFileEvent(trigger types.Trigger, hostPath string, ignore watch.PathMat
|
||||
}
|
||||
}
|
||||
|
||||
func loadDevelopmentConfig(service types.ServiceConfig, project *types.Project) (*types.DevelopConfig, error) {
|
||||
var config types.DevelopConfig
|
||||
func loadDevelopmentConfig(service types.ServiceConfig, project *types.Project) (*DevelopmentConfig, error) {
|
||||
var config DevelopmentConfig
|
||||
y, ok := service.Extensions["x-develop"]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
logrus.Warnf("x-develop is DEPRECATED, please use the official `develop` attribute")
|
||||
err := mapstructure.Decode(y, &config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -273,7 +300,7 @@ func loadDevelopmentConfig(service types.ServiceConfig, project *types.Project)
|
||||
return nil, errors.New("watch rules MUST define a path")
|
||||
}
|
||||
|
||||
if trigger.Action == types.WatchActionRebuild && service.Build == nil {
|
||||
if trigger.Action == string(WatchActionRebuild) && service.Build == nil {
|
||||
return nil, fmt.Errorf("service %s doesn't have a build section, can't apply 'rebuild' on watch", service.Name)
|
||||
}
|
||||
|
||||
@@ -413,21 +440,24 @@ func (t tarDockerClient) Exec(ctx context.Context, containerID string, cmd []str
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *composeService) handleWatchBatch(ctx context.Context, project *types.Project, serviceName string, build api.BuildOptions, batch []fileEvent, syncer sync.Syncer) error {
|
||||
func (s *composeService) handleWatchBatch(
|
||||
ctx context.Context,
|
||||
project *types.Project,
|
||||
serviceName string,
|
||||
batch []fileEvent,
|
||||
syncer sync.Syncer,
|
||||
) error {
|
||||
pathMappings := make([]sync.PathMapping, len(batch))
|
||||
for i := range batch {
|
||||
if batch[i].Action == types.WatchActionRebuild {
|
||||
if batch[i].Action == WatchActionRebuild {
|
||||
fmt.Fprintf(
|
||||
s.stdinfo(),
|
||||
"Rebuilding %s after changes were detected:%s\n",
|
||||
serviceName,
|
||||
strings.Join(append([]string{""}, batch[i].HostPath), "\n - "),
|
||||
)
|
||||
// restrict the build to ONLY this service, not any of its dependencies
|
||||
build.Services = []string{serviceName}
|
||||
err := s.Up(ctx, project, api.UpOptions{
|
||||
Create: api.CreateOptions{
|
||||
Build: &build,
|
||||
Services: []string{serviceName},
|
||||
Inherit: true,
|
||||
},
|
||||
|
||||
@@ -21,14 +21,16 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/docker/compose/v2/internal/sync"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/mocks"
|
||||
"github.com/docker/compose/v2/pkg/watch"
|
||||
moby "github.com/docker/docker/api/types"
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/docker/compose/v2/internal/sync"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/watch"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
@@ -40,7 +42,7 @@ func TestDebounceBatching(t *testing.T) {
|
||||
|
||||
eventBatchCh := batchDebounceEvents(ctx, clock, quietPeriod, ch)
|
||||
for i := 0; i < 100; i++ {
|
||||
var action types.WatchAction = "a"
|
||||
var action WatchAction = "a"
|
||||
if i%2 == 0 {
|
||||
action = "b"
|
||||
}
|
||||
@@ -124,7 +126,7 @@ func TestWatch_Sync(t *testing.T) {
|
||||
dockerCli: cli,
|
||||
clock: clock,
|
||||
}
|
||||
err := service.watch(ctx, &proj, "test", api.WatchOptions{}, watcher, syncer, []types.Trigger{
|
||||
err := service.watch(ctx, &proj, "test", watcher, syncer, []Trigger{
|
||||
{
|
||||
Path: "/sync",
|
||||
Action: "sync",
|
||||
|
||||
@@ -28,18 +28,19 @@ import (
|
||||
// (running or exited).
|
||||
func RequireServiceState(t testing.TB, cli *CLI, service string, state string) {
|
||||
t.Helper()
|
||||
psRes := cli.RunDockerComposeCmd(t, "ps", "--all", "--format=json", service)
|
||||
var svc map[string]interface{}
|
||||
require.NoError(t, json.Unmarshal([]byte(psRes.Stdout()), &svc),
|
||||
"Invalid `compose ps` JSON: command output: %s",
|
||||
psRes.Combined())
|
||||
psRes := cli.RunDockerComposeCmd(t, "ps", "--format=json", service)
|
||||
var psOut []map[string]interface{}
|
||||
require.NoError(t, json.Unmarshal([]byte(psRes.Stdout()), &psOut),
|
||||
"Invalid `compose ps` JSON output")
|
||||
|
||||
require.Equal(t, service, svc["Service"],
|
||||
"Found ps output for unexpected service")
|
||||
require.Equalf(t,
|
||||
strings.ToLower(state),
|
||||
strings.ToLower(svc["State"].(string)),
|
||||
"Service %q (%s) not in expected state",
|
||||
service, svc["Name"],
|
||||
)
|
||||
for _, svc := range psOut {
|
||||
require.Equal(t, service, svc["Service"],
|
||||
"Found ps output for unexpected service")
|
||||
require.Equalf(t,
|
||||
strings.ToLower(state),
|
||||
strings.ToLower(svc["State"].(string)),
|
||||
"Service %q (%s) not in expected state",
|
||||
service, svc["Name"],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,14 +71,10 @@ func TestPortRange(t *testing.T) {
|
||||
c := NewParallelCLI(t)
|
||||
const projectName = "e2e-port-range"
|
||||
|
||||
reset := func() {
|
||||
c.RunDockerComposeCmd(t, "--project-name", projectName, "down", "--remove-orphans", "--timeout=0")
|
||||
}
|
||||
reset()
|
||||
t.Cleanup(reset)
|
||||
|
||||
res := c.RunDockerComposeCmdNoCheck(t, "-f", "fixtures/port-range/compose.yaml", "--project-name", projectName, "up", "-d")
|
||||
res.Assert(t, icmd.Success)
|
||||
|
||||
c.RunDockerComposeCmd(t, "--project-name", projectName, "down", "--remove-orphans")
|
||||
}
|
||||
|
||||
func TestStdoutStderr(t *testing.T) {
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
services:
|
||||
app:
|
||||
image: nginx:alpine
|
||||
network_mode: service:db
|
||||
|
||||
db:
|
||||
image: nginx:alpine
|
||||
@@ -1,10 +0,0 @@
|
||||
services:
|
||||
app:
|
||||
image: nginx:alpine
|
||||
volumes_from:
|
||||
- db
|
||||
|
||||
db:
|
||||
image: nginx:alpine
|
||||
volumes:
|
||||
- /var/data
|
||||
@@ -3,10 +3,3 @@ services:
|
||||
image: alpine
|
||||
init: true
|
||||
command: ash -c "if [[ -f /tmp/restart.lock ]] ; then sleep infinity; else touch /tmp/restart.lock; fi"
|
||||
|
||||
test:
|
||||
profiles:
|
||||
- test
|
||||
image: alpine
|
||||
init: true
|
||||
command: ash -c "if [[ -f /tmp/restart.lock ]] ; then sleep infinity; else touch /tmp/restart.lock; fi"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
services:
|
||||
back:
|
||||
image: nginx:alpine
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: nginx:alpine
|
||||
front:
|
||||
image: nginx:alpine
|
||||
deploy:
|
||||
replicas: 2
|
||||
dbadmin:
|
||||
image: nginx:alpine
|
||||
deploy:
|
||||
replicas: 0
|
||||
@@ -15,7 +15,7 @@ services:
|
||||
RUN mkdir -p /app/data
|
||||
init: true
|
||||
command: sleep infinity
|
||||
develop: *x-dev
|
||||
x-develop: *x-dev
|
||||
busybox:
|
||||
build:
|
||||
dockerfile_inline: |-
|
||||
@@ -23,7 +23,7 @@ services:
|
||||
RUN mkdir -p /app/data
|
||||
init: true
|
||||
command: sleep infinity
|
||||
develop: *x-dev
|
||||
x-develop: *x-dev
|
||||
debian:
|
||||
build:
|
||||
dockerfile_inline: |-
|
||||
@@ -31,4 +31,4 @@ services:
|
||||
RUN mkdir -p /app/data
|
||||
init: true
|
||||
command: sleep infinity
|
||||
develop: *x-dev
|
||||
x-develop: *x-dev
|
||||
|
||||
@@ -361,14 +361,13 @@ func IsHealthy(service string) func(res *icmd.Result) bool {
|
||||
Health string `json:"health"`
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(strings.NewReader(res.Stdout()))
|
||||
for decoder.More() {
|
||||
ps := state{}
|
||||
err := decoder.Decode(&ps)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if ps.Name == service && ps.Health == "healthy" {
|
||||
ps := []state{}
|
||||
err := json.Unmarshal([]byte(res.Stdout()), &ps)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, state := range ps {
|
||||
if state.Name == service && state.Health == "healthy" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user