| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561 | 
							- /*
 
-    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"
 
- 	"errors"
 
- 	"fmt"
 
- 	"os"
 
- 	"os/signal"
 
- 	"path/filepath"
 
- 	"strconv"
 
- 	"strings"
 
- 	"syscall"
 
- 	"github.com/compose-spec/compose-go/v2/cli"
 
- 	"github.com/compose-spec/compose-go/v2/dotenv"
 
- 	"github.com/compose-spec/compose-go/v2/loader"
 
- 	"github.com/compose-spec/compose-go/v2/types"
 
- 	composegoutils "github.com/compose-spec/compose-go/v2/utils"
 
- 	"github.com/docker/buildx/util/logutil"
 
- 	dockercli "github.com/docker/cli/cli"
 
- 	"github.com/docker/cli/cli-plugins/manager"
 
- 	"github.com/docker/cli/cli/command"
 
- 	"github.com/docker/compose/v2/cmd/formatter"
 
- 	"github.com/docker/compose/v2/internal/tracing"
 
- 	"github.com/docker/compose/v2/pkg/api"
 
- 	"github.com/docker/compose/v2/pkg/compose"
 
- 	ui "github.com/docker/compose/v2/pkg/progress"
 
- 	"github.com/docker/compose/v2/pkg/remote"
 
- 	"github.com/docker/compose/v2/pkg/utils"
 
- 	buildkit "github.com/moby/buildkit/util/progress/progressui"
 
- 	"github.com/morikuni/aec"
 
- 	"github.com/sirupsen/logrus"
 
- 	"github.com/spf13/cobra"
 
- 	"github.com/spf13/pflag"
 
- )
 
- const (
 
- 	// ComposeParallelLimit set the limit running concurrent operation on docker engine
 
- 	ComposeParallelLimit = "COMPOSE_PARALLEL_LIMIT"
 
- 	// ComposeProjectName define the project name to be used, instead of guessing from parent directory
 
- 	ComposeProjectName = "COMPOSE_PROJECT_NAME"
 
- 	// ComposeCompatibility try to mimic compose v1 as much as possible
 
- 	ComposeCompatibility = "COMPOSE_COMPATIBILITY"
 
- 	// ComposeRemoveOrphans remove “orphaned" containers, i.e. containers tagged for current project but not declared as service
 
- 	ComposeRemoveOrphans = "COMPOSE_REMOVE_ORPHANS"
 
- 	// ComposeIgnoreOrphans ignore "orphaned" containers
 
- 	ComposeIgnoreOrphans = "COMPOSE_IGNORE_ORPHANS"
 
- 	// ComposeEnvFiles defines the env files to use if --env-file isn't used
 
- 	ComposeEnvFiles = "COMPOSE_ENV_FILES"
 
- )
 
- // Command defines a compose CLI command as a func with args
 
- type Command func(context.Context, []string) error
 
- // CobraCommand defines a cobra command function
 
- type CobraCommand func(context.Context, *cobra.Command, []string) error
 
- // AdaptCmd adapt a CobraCommand func to cobra library
 
- func AdaptCmd(fn CobraCommand) func(cmd *cobra.Command, args []string) error {
 
- 	return func(cmd *cobra.Command, args []string) error {
 
- 		ctx, cancel := context.WithCancel(cmd.Context())
 
- 		s := make(chan os.Signal, 1)
 
- 		signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
 
- 		go func() {
 
- 			<-s
 
- 			cancel()
 
- 			signal.Stop(s)
 
- 			close(s)
 
- 		}()
 
- 		err := fn(ctx, cmd, args)
 
- 		var composeErr compose.Error
 
- 		if api.IsErrCanceled(err) || errors.Is(ctx.Err(), context.Canceled) {
 
- 			err = dockercli.StatusError{
 
- 				StatusCode: 130,
 
- 				Status:     compose.CanceledStatus,
 
- 			}
 
- 		}
 
- 		if errors.As(err, &composeErr) {
 
- 			err = dockercli.StatusError{
 
- 				StatusCode: composeErr.GetMetricsFailureCategory().ExitCode,
 
- 				Status:     err.Error(),
 
- 			}
 
- 		}
 
- 		return err
 
- 	}
 
- }
 
- // Adapt a Command func to cobra library
 
- func Adapt(fn Command) func(cmd *cobra.Command, args []string) error {
 
- 	return AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
 
- 		return fn(ctx, args)
 
- 	})
 
- }
 
- type ProjectOptions struct {
 
- 	ProjectName   string
 
- 	Profiles      []string
 
- 	ConfigPaths   []string
 
- 	WorkDir       string
 
- 	ProjectDir    string
 
- 	EnvFiles      []string
 
- 	Compatibility bool
 
- 	Progress      string
 
- 	Offline       bool
 
- }
 
- // ProjectFunc does stuff within a types.Project
 
- type ProjectFunc func(ctx context.Context, project *types.Project) error
 
- // ProjectServicesFunc does stuff within a types.Project and a selection of services
 
- 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 {
 
- 		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 {
 
- 	return Adapt(func(ctx context.Context, args []string) error {
 
- 		options := []cli.ProjectOptionsFn{
 
- 			cli.WithResolvedPaths(true),
 
- 			cli.WithDiscardEnvFile,
 
- 		}
 
- 		project, metrics, err := o.ToProject(ctx, dockerCli, args, options...)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 		ctx = context.WithValue(ctx, tracing.MetricsKey{}, metrics)
 
- 		return fn(ctx, project, args)
 
- 	})
 
- }
 
- func (o *ProjectOptions) addProjectFlags(f *pflag.FlagSet) {
 
- 	f.StringArrayVar(&o.Profiles, "profile", []string{}, "Specify a profile to enable")
 
- 	f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name")
 
- 	f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
 
- 	f.StringArrayVar(&o.EnvFiles, "env-file", nil, "Specify an alternate environment file")
 
- 	f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the, first specified, Compose file)")
 
- 	f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the, first specified, Compose file)")
 
- 	f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
 
- 	f.StringVar(&o.Progress, "progress", string(buildkit.AutoMode), fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", ")))
 
- 	_ = f.MarkHidden("workdir")
 
- }
 
- func (o *ProjectOptions) projectOrName(ctx context.Context, dockerCli command.Cli, services ...string) (*types.Project, string, error) {
 
- 	name := o.ProjectName
 
- 	var project *types.Project
 
- 	if len(o.ConfigPaths) > 0 || o.ProjectName == "" {
 
- 		p, _, err := o.ToProject(ctx, dockerCli, services, cli.WithDiscardEnvFile)
 
- 		if err != nil {
 
- 			envProjectName := os.Getenv(ComposeProjectName)
 
- 			if envProjectName != "" {
 
- 				return nil, envProjectName, nil
 
- 			}
 
- 			return nil, "", err
 
- 		}
 
- 		project = p
 
- 		name = p.Name
 
- 	}
 
- 	return project, name, nil
 
- }
 
- func (o *ProjectOptions) toProjectName(ctx context.Context, dockerCli command.Cli) (string, error) {
 
- 	if o.ProjectName != "" {
 
- 		return o.ProjectName, nil
 
- 	}
 
- 	envProjectName := os.Getenv(ComposeProjectName)
 
- 	if envProjectName != "" {
 
- 		return envProjectName, nil
 
- 	}
 
- 	project, _, err := o.ToProject(ctx, dockerCli, nil)
 
- 	if err != nil {
 
- 		return "", err
 
- 	}
 
- 	return project.Name, nil
 
- }
 
- func (o *ProjectOptions) ToProject(ctx context.Context, dockerCli command.Cli, services []string, po ...cli.ProjectOptionsFn) (*types.Project, tracing.Metrics, error) {
 
- 	var metrics tracing.Metrics
 
- 	remotes := o.remoteLoaders(dockerCli)
 
- 	for _, r := range remotes {
 
- 		po = append(po, cli.WithResourceLoader(r))
 
- 	}
 
- 	options, err := o.toProjectOptions(po...)
 
- 	if err != nil {
 
- 		return nil, metrics, compose.WrapComposeError(err)
 
- 	}
 
- 	options.WithListeners(func(event string, metadata map[string]any) {
 
- 		switch event {
 
- 		case "extends":
 
- 			metrics.CountExtends++
 
- 		case "include":
 
- 			paths := metadata["path"].(types.StringList)
 
- 			for _, path := range paths {
 
- 				var isRemote bool
 
- 				for _, r := range remotes {
 
- 					if r.Accept(path) {
 
- 						isRemote = true
 
- 						break
 
- 					}
 
- 				}
 
- 				if isRemote {
 
- 					metrics.CountIncludesRemote++
 
- 				} else {
 
- 					metrics.CountIncludesLocal++
 
- 				}
 
- 			}
 
- 		}
 
- 	})
 
- 	if o.Compatibility || utils.StringToBool(options.Environment[ComposeCompatibility]) {
 
- 		api.Separator = "_"
 
- 	}
 
- 	project, err := cli.ProjectFromOptions(ctx, options)
 
- 	if err != nil {
 
- 		return nil, metrics, compose.WrapComposeError(err)
 
- 	}
 
- 	if project.Name == "" {
 
- 		return nil, metrics, errors.New("project name can't be empty. Use `--project-name` to set a valid name")
 
- 	}
 
- 	project, err = project.WithServicesEnabled(services...)
 
- 	if err != nil {
 
- 		return nil, metrics, err
 
- 	}
 
- 	for name, s := range project.Services {
 
- 		s.CustomLabels = map[string]string{
 
- 			api.ProjectLabel:     project.Name,
 
- 			api.ServiceLabel:     name,
 
- 			api.VersionLabel:     api.ComposeVersion,
 
- 			api.WorkingDirLabel:  project.WorkingDir,
 
- 			api.ConfigFilesLabel: strings.Join(project.ComposeFiles, ","),
 
- 			api.OneoffLabel:      "False", // default, will be overridden by `run` command
 
- 		}
 
- 		if len(o.EnvFiles) != 0 {
 
- 			s.CustomLabels[api.EnvironmentFileLabel] = strings.Join(o.EnvFiles, ",")
 
- 		}
 
- 		project.Services[name] = s
 
- 	}
 
- 	project = project.WithoutUnnecessaryResources()
 
- 	project, err = project.WithSelectedServices(services)
 
- 	return project, metrics, err
 
- }
 
- func (o *ProjectOptions) remoteLoaders(dockerCli command.Cli) []loader.ResourceLoader {
 
- 	if o.Offline {
 
- 		return nil
 
- 	}
 
- 	git := remote.NewGitRemoteLoader(o.Offline)
 
- 	oci := remote.NewOCIRemoteLoader(dockerCli, o.Offline)
 
- 	return []loader.ResourceLoader{git, oci}
 
- }
 
- func (o *ProjectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
 
- 	return cli.NewProjectOptions(o.ConfigPaths,
 
- 		append(po,
 
- 			cli.WithWorkingDirectory(o.ProjectDir),
 
- 			cli.WithOsEnv,
 
- 			cli.WithConfigFileEnv,
 
- 			cli.WithDefaultConfigPath,
 
- 			cli.WithEnvFiles(o.EnvFiles...),
 
- 			cli.WithDotEnv,
 
- 			cli.WithDefaultProfiles(o.Profiles...),
 
- 			cli.WithName(o.ProjectName))...)
 
- }
 
- // PluginName is the name of the plugin
 
- const PluginName = "compose"
 
- // RunningAsStandalone detects when running as a standalone program
 
- func RunningAsStandalone() bool {
 
- 	return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
 
- }
 
- // RootCommand returns the compose command with its child commands
 
- func RootCommand(dockerCli 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
 
- 	logrus.AddHook(logutil.NewFilter([]logrus.Level{
 
- 		logrus.WarnLevel,
 
- 	},
 
- 		"commandConn.CloseWrite:",
 
- 		"commandConn.CloseRead:",
 
- 	))
 
- 	opts := ProjectOptions{}
 
- 	var (
 
- 		ansi     string
 
- 		noAnsi   bool
 
- 		verbose  bool
 
- 		version  bool
 
- 		parallel int
 
- 		dryRun   bool
 
- 	)
 
- 	c := &cobra.Command{
 
- 		Short:            "Docker Compose",
 
- 		Long:             "Define and run multi-container applications with Docker",
 
- 		Use:              PluginName,
 
- 		TraverseChildren: true,
 
- 		// By default (no Run/RunE in parent c) for typos in subcommands, cobra displays the help of parent c but exit(0) !
 
- 		RunE: func(cmd *cobra.Command, args []string) error {
 
- 			if len(args) == 0 {
 
- 				return cmd.Help()
 
- 			}
 
- 			if version {
 
- 				return versionCommand(dockerCli).Execute()
 
- 			}
 
- 			_ = cmd.Help()
 
- 			return dockercli.StatusError{
 
- 				StatusCode: compose.CommandSyntaxFailure.ExitCode,
 
- 				Status:     fmt.Sprintf("unknown docker command: %q", "compose "+args[0]),
 
- 			}
 
- 		},
 
- 		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
 
- 			err := setEnvWithDotEnv(&opts)
 
- 			if err != nil {
 
- 				return err
 
- 			}
 
- 			parent := cmd.Root()
 
- 			if parent != nil {
 
- 				parentPrerun := parent.PersistentPreRunE
 
- 				if parentPrerun != nil {
 
- 					err := parentPrerun(cmd, args)
 
- 					if err != nil {
 
- 						return err
 
- 					}
 
- 				}
 
- 			}
 
- 			if noAnsi {
 
- 				if ansi != "auto" {
 
- 					return errors.New(`cannot specify DEPRECATED "--no-ansi" and "--ansi". Please use only "--ansi"`)
 
- 				}
 
- 				ansi = "never"
 
- 				fmt.Fprint(os.Stderr, "option '--no-ansi' is DEPRECATED ! Please use '--ansi' instead.\n")
 
- 			}
 
- 			if verbose {
 
- 				logrus.SetLevel(logrus.TraceLevel)
 
- 			}
 
- 			if v, ok := os.LookupEnv("COMPOSE_ANSI"); ok && !cmd.Flags().Changed("ansi") {
 
- 				ansi = v
 
- 			}
 
- 			formatter.SetANSIMode(dockerCli, ansi)
 
- 			if noColor, ok := os.LookupEnv("NO_COLOR"); ok && noColor != "" {
 
- 				ui.NoColor()
 
- 				formatter.SetANSIMode(dockerCli, formatter.Never)
 
- 			}
 
- 			switch ansi {
 
- 			case "never":
 
- 				ui.Mode = ui.ModePlain
 
- 			case "always":
 
- 				ui.Mode = ui.ModeTTY
 
- 			}
 
- 			switch opts.Progress {
 
- 			case ui.ModeAuto:
 
- 				ui.Mode = ui.ModeAuto
 
- 				if ansi == "never" {
 
- 					ui.Mode = ui.ModePlain
 
- 				}
 
- 			case ui.ModeTTY:
 
- 				if ansi == "never" {
 
- 					return fmt.Errorf("can't use --progress tty while ANSI support is disabled")
 
- 				}
 
- 				ui.Mode = ui.ModeTTY
 
- 			case ui.ModePlain:
 
- 				if ansi == "always" {
 
- 					return fmt.Errorf("can't use --progress plain while ANSI support is forced")
 
- 				}
 
- 				ui.Mode = ui.ModePlain
 
- 			case ui.ModeQuiet, "none":
 
- 				ui.Mode = ui.ModeQuiet
 
- 			default:
 
- 				return fmt.Errorf("unsupported --progress value %q", opts.Progress)
 
- 			}
 
- 			if opts.WorkDir != "" {
 
- 				if opts.ProjectDir != "" {
 
- 					return errors.New(`cannot specify DEPRECATED "--workdir" and "--project-directory". Please use only "--project-directory" instead`)
 
- 				}
 
- 				opts.ProjectDir = opts.WorkDir
 
- 				fmt.Fprint(os.Stderr, aec.Apply("option '--workdir' is DEPRECATED at root level! Please use '--project-directory' instead.\n", aec.RedF))
 
- 			}
 
- 			for i, file := range opts.EnvFiles {
 
- 				if !filepath.IsAbs(file) {
 
- 					file, err = filepath.Abs(file)
 
- 					if err != nil {
 
- 						return err
 
- 					}
 
- 					opts.EnvFiles[i] = file
 
- 				}
 
- 			}
 
- 			composeCmd := cmd
 
- 			for {
 
- 				if composeCmd.Name() == PluginName {
 
- 					break
 
- 				}
 
- 				if !composeCmd.HasParent() {
 
- 					return fmt.Errorf("error parsing command line, expected %q", PluginName)
 
- 				}
 
- 				composeCmd = composeCmd.Parent()
 
- 			}
 
- 			if v, ok := os.LookupEnv(ComposeParallelLimit); ok && !composeCmd.Flags().Changed("parallel") {
 
- 				i, err := strconv.Atoi(v)
 
- 				if err != nil {
 
- 					return fmt.Errorf("%s must be an integer (found: %q)", ComposeParallelLimit, v)
 
- 				}
 
- 				parallel = i
 
- 			}
 
- 			if parallel > 0 {
 
- 				backend.MaxConcurrency(parallel)
 
- 			}
 
- 			ctx, err := backend.DryRunMode(cmd.Context(), dryRun)
 
- 			if err != nil {
 
- 				return err
 
- 			}
 
- 			cmd.SetContext(ctx)
 
- 			return nil
 
- 		},
 
- 	}
 
- 	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),
 
- 		attachCommand(&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),
 
- 		statsCommand(&opts, dockerCli),
 
- 		watchCommand(&opts, dockerCli, backend),
 
- 		alphaCommand(&opts, dockerCli, backend),
 
- 	)
 
- 	c.Flags().SetInterspersed(false)
 
- 	opts.addProjectFlags(c.Flags())
 
- 	c.RegisterFlagCompletionFunc( //nolint:errcheck
 
- 		"project-name",
 
- 		completeProjectNames(backend),
 
- 	)
 
- 	c.RegisterFlagCompletionFunc( //nolint:errcheck
 
- 		"project-directory",
 
- 		func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 
- 			return []string{}, cobra.ShellCompDirectiveFilterDirs
 
- 		},
 
- 	)
 
- 	c.RegisterFlagCompletionFunc( //nolint:errcheck
 
- 		"file",
 
- 		func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 
- 			return []string{"yaml", "yml"}, cobra.ShellCompDirectiveFilterFileExt
 
- 		},
 
- 	)
 
- 	c.RegisterFlagCompletionFunc( //nolint:errcheck
 
- 		"profile",
 
- 		completeProfileNames(dockerCli, &opts),
 
- 	)
 
- 	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")
 
- 	c.PersistentFlags().BoolVar(&dryRun, "dry-run", false, "Execute command in dry run mode")
 
- 	c.Flags().MarkHidden("version") //nolint:errcheck
 
- 	c.Flags().BoolVar(&noAnsi, "no-ansi", false, `Do not print ANSI control characters (DEPRECATED)`)
 
- 	c.Flags().MarkHidden("no-ansi") //nolint:errcheck
 
- 	c.Flags().BoolVar(&verbose, "verbose", false, "Show more output")
 
- 	c.Flags().MarkHidden("verbose") //nolint:errcheck
 
- 	return c
 
- }
 
- func setEnvWithDotEnv(prjOpts *ProjectOptions) error {
 
- 	if len(prjOpts.EnvFiles) == 0 {
 
- 		if envFiles := os.Getenv(ComposeEnvFiles); envFiles != "" {
 
- 			prjOpts.EnvFiles = strings.Split(envFiles, ",")
 
- 		}
 
- 	}
 
- 	options, err := prjOpts.toProjectOptions()
 
- 	if err != nil {
 
- 		return compose.WrapComposeError(err)
 
- 	}
 
- 	envFromFile, err := dotenv.GetEnvFromFile(composegoutils.GetAsEqualsMap(os.Environ()), options.EnvFiles)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	for k, v := range envFromFile {
 
- 		if _, ok := os.LookupEnv(k); !ok { // Precedence to OS Env
 
- 			if err := os.Setenv(k, v); err != nil {
 
- 				return err
 
- 			}
 
- 		}
 
- 	}
 
- 	return nil
 
- }
 
- var printerModes = []string{
 
- 	ui.ModeAuto,
 
- 	ui.ModeTTY,
 
- 	ui.ModePlain,
 
- 	ui.ModeQuiet,
 
- }
 
 
  |