diff --git a/go.mod b/go.mod index f99d7aa329c7..4605a928b043 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/creack/pty v1.1.24 github.com/davecgh/go-spew v1.1.1 github.com/distribution/reference v0.6.0 - github.com/docker/cli v27.5.1+incompatible + github.com/docker/cli v28.0.0-rc.1+incompatible github.com/docker/cli-docs-tool v0.9.0 github.com/docker/docker v28.0.0-rc.1+incompatible github.com/docker/go-units v0.5.0 diff --git a/go.sum b/go.sum index 4c43e698ae40..265d8ac39a0d 100644 --- a/go.sum +++ b/go.sum @@ -122,8 +122,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v27.5.1+incompatible h1:JB9cieUT9YNiMITtIsguaN55PLOHhBSz3LKVc6cqWaY= -github.com/docker/cli v27.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v28.0.0-rc.1+incompatible h1:4Xkn+JKnvVqDfyL/pZCWaPM9jzPtAJvNu7qKBkotv3I= +github.com/docker/cli v28.0.0-rc.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli-docs-tool v0.9.0 h1:CVwQbE+ZziwlPqrJ7LRyUF6GvCA+6gj7MTCsayaK9t0= github.com/docker/cli-docs-tool v0.9.0/go.mod h1:ClrwlNW+UioiRyH9GiAOe1o3J/TsY3Tr1ipoypjAUtc= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= diff --git a/vendor/github.com/docker/cli/cli-plugins/hooks/printer.go b/vendor/github.com/docker/cli/cli-plugins/hooks/printer.go index bedc87f929b5..f6d4b28ef488 100644 --- a/vendor/github.com/docker/cli/cli-plugins/hooks/printer.go +++ b/vendor/github.com/docker/cli/cli-plugins/hooks/printer.go @@ -11,8 +11,8 @@ func PrintNextSteps(out io.Writer, messages []string) { if len(messages) == 0 { return } - fmt.Fprintln(out, aec.Bold.Apply("\nWhat's next:")) + _, _ = fmt.Fprintln(out, aec.Bold.Apply("\nWhat's next:")) for _, n := range messages { - _, _ = fmt.Fprintf(out, " %s\n", n) + _, _ = fmt.Fprintln(out, " ", n) } } diff --git a/vendor/github.com/docker/cli/cli-plugins/manager/cobra.go b/vendor/github.com/docker/cli/cli-plugins/manager/cobra.go index feff8a8fd6f3..4bfa06fa5c0a 100644 --- a/vendor/github.com/docker/cli/cli-plugins/manager/cobra.go +++ b/vendor/github.com/docker/cli/cli-plugins/manager/cobra.go @@ -52,7 +52,6 @@ func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) (err e return } for _, p := range plugins { - p := p vendor := p.Vendor if vendor == "" { vendor = "unknown" @@ -82,7 +81,7 @@ func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) (err e cmd.HelpFunc()(rootCmd, args) return nil } - return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'", cmd.Name()) + return fmt.Errorf("docker: unknown command: docker %s\n\nRun 'docker --help' for more information", cmd.Name()) }, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { // Delegate completion to plugin diff --git a/vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go b/vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go index 8cce73d9acda..cf57aad5e17c 100644 --- a/vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go +++ b/vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go @@ -3,6 +3,7 @@ package plugin import ( "context" "encoding/json" + "errors" "fmt" "os" "sync" @@ -34,7 +35,7 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager var persistentPreRunOnce sync.Once PersistentPreRunE = func(cmd *cobra.Command, _ []string) error { - var err error + var retErr error persistentPreRunOnce.Do(func() { ctx, cancel := context.WithCancel(cmd.Context()) cmd.SetContext(ctx) @@ -46,7 +47,7 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager opts = append(opts, withPluginClientConn(plugin.Name())) } opts = append(opts, command.WithEnableGlobalMeterProvider(), command.WithEnableGlobalTracerProvider()) - err = tcmd.Initialize(opts...) + retErr = tcmd.Initialize(opts...) ogRunE := cmd.RunE if ogRunE == nil { ogRun := cmd.Run @@ -66,7 +67,7 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager return err } }) - return err + return retErr } cmd, args, err := tcmd.HandleGlobalFlags() @@ -92,18 +93,17 @@ func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) { plugin := makeCmd(dockerCli) if err := RunPlugin(dockerCli, plugin, meta); err != nil { - if sterr, ok := err.(cli.StatusError); ok { - if sterr.Status != "" { - fmt.Fprintln(dockerCli.Err(), sterr.Status) - } + var stErr cli.StatusError + if errors.As(err, &stErr) { // StatusError should only be used for errors, and all errors should // have a non-zero exit status, so never exit with 0 - if sterr.StatusCode == 0 { - os.Exit(1) + if stErr.StatusCode == 0 { // FIXME(thaJeztah): this should never be used with a zero status-code. Check if we do this anywhere. + stErr.StatusCode = 1 } - os.Exit(sterr.StatusCode) + _, _ = fmt.Fprintln(dockerCli.Err(), stErr) + os.Exit(stErr.StatusCode) } - fmt.Fprintln(dockerCli.Err(), err) + _, _ = fmt.Fprintln(dockerCli.Err(), err) os.Exit(1) } } @@ -158,7 +158,7 @@ func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta CompletionOptions: cobra.CompletionOptions{ DisableDefaultCmd: false, HiddenDefaultCmd: true, - DisableDescriptions: true, + DisableDescriptions: os.Getenv("DOCKER_CLI_DISABLE_COMPLETION_DESCRIPTION") != "", }, } opts, _ := cli.SetupPluginRootCommand(cmd) diff --git a/vendor/github.com/docker/cli/cli/cobra.go b/vendor/github.com/docker/cli/cli/cobra.go index f6a69ae0701d..feab2b4a91c8 100644 --- a/vendor/github.com/docker/cli/cli/cobra.go +++ b/vendor/github.com/docker/cli/cli/cobra.go @@ -92,12 +92,8 @@ func FlagErrorFunc(cmd *cobra.Command, err error) error { return nil } - usage := "" - if cmd.HasSubCommands() { - usage = "\n\n" + cmd.UsageString() - } return StatusError{ - Status: fmt.Sprintf("%s\nSee '%s --help'.%s", err, cmd.CommandPath(), usage), + Status: fmt.Sprintf("%s\n\nUsage: %s\n\nRun '%s --help' for more information", err, cmd.UseLine(), cmd.CommandPath()), StatusCode: 125, } } diff --git a/vendor/github.com/docker/cli/cli/command/cli.go b/vendor/github.com/docker/cli/cli/command/cli.go index da0802d54bcb..a8cfd58e4df6 100644 --- a/vendor/github.com/docker/cli/cli/command/cli.go +++ b/vendor/github.com/docker/cli/cli/command/cli.go @@ -114,7 +114,7 @@ func (cli *DockerCli) CurrentVersion() string { // Client returns the APIClient func (cli *DockerCli) Client() client.APIClient { if err := cli.initialize(); err != nil { - _, _ = fmt.Fprintf(cli.Err(), "Failed to initialize: %s\n", err) + _, _ = fmt.Fprintln(cli.Err(), "Failed to initialize:", err) os.Exit(1) } return cli.client @@ -272,7 +272,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption) debug.Enable() } if opts.Context != "" && len(opts.Hosts) > 0 { - return errors.New("conflicting options: either specify --host or --context, not both") + return errors.New("conflicting options: cannot specify both --host and --context") } cli.options = opts @@ -299,7 +299,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption) // NewAPIClientFromFlags creates a new APIClient from command line flags func NewAPIClientFromFlags(opts *cliflags.ClientOptions, configFile *configfile.ConfigFile) (client.APIClient, error) { if opts.Context != "" && len(opts.Hosts) > 0 { - return nil, errors.New("conflicting options: either specify --host or --context, not both") + return nil, errors.New("conflicting options: cannot specify both --host and --context") } storeConfig := DefaultContextStoreConfig() @@ -475,7 +475,7 @@ func (cli *DockerCli) DockerEndpoint() docker.Endpoint { if err := cli.initialize(); err != nil { // Note that we're not terminating here, as this function may be used // in cases where we're able to continue. - _, _ = fmt.Fprintf(cli.Err(), "%v\n", cli.initErr) + _, _ = fmt.Fprintln(cli.Err(), cli.initErr) } return cli.dockerEndpoint } diff --git a/vendor/github.com/docker/cli/cli/command/formatter/container.go b/vendor/github.com/docker/cli/cli/command/formatter/container.go index 10d4e4b4422f..ba62efb2f47c 100644 --- a/vendor/github.com/docker/cli/cli/command/formatter/container.go +++ b/vendor/github.com/docker/cli/cli/command/formatter/container.go @@ -12,7 +12,7 @@ import ( "time" "github.com/distribution/reference" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/pkg/stringid" "github.com/docker/go-units" ) @@ -67,10 +67,10 @@ ports: {{- pad .Ports 1 0}} } // ContainerWrite renders the context for a list of containers -func ContainerWrite(ctx Context, containers []types.Container) error { +func ContainerWrite(ctx Context, containers []container.Summary) error { render := func(format func(subContext SubContext) error) error { - for _, container := range containers { - err := format(&ContainerContext{trunc: ctx.Trunc, c: container}) + for _, ctr := range containers { + err := format(&ContainerContext{trunc: ctx.Trunc, c: ctr}) if err != nil { return err } @@ -84,7 +84,7 @@ func ContainerWrite(ctx Context, containers []types.Container) error { type ContainerContext struct { HeaderContext trunc bool - c types.Container + c container.Summary // 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 @@ -193,7 +193,9 @@ func (c *ContainerContext) Command() string { return strconv.Quote(command) } -// CreatedAt returns the "Created" date/time of the container as a unix timestamp. +// CreatedAt returns the formatted string representing the container's creation date/time. +// The format may include nanoseconds if present. +// e.g. "2006-01-02 15:04:05.999999999 -0700 MST" or "2006-01-02 15:04:05 -0700 MST" func (c *ContainerContext) CreatedAt() string { return time.Unix(c.c.Created, 0).String() } @@ -314,7 +316,7 @@ func (c *ContainerContext) Networks() string { // DisplayablePorts returns formatted string representing open ports of container // e.g. "0.0.0.0:80->9090/tcp, 9988/tcp" // it's used by command 'docker ps' -func DisplayablePorts(ports []types.Port) string { +func DisplayablePorts(ports []container.Port) string { type portGroup struct { first uint16 last uint16 @@ -375,12 +377,12 @@ func formGroup(key string, start, last uint16) string { group = fmt.Sprintf("%s-%d", group, last) } if ip != "" { - group = fmt.Sprintf("%s:%s->%s", ip, group, group) + group = fmt.Sprintf("%s->%s", net.JoinHostPort(ip, group), group) } return group + "/" + groupType } -func comparePorts(i, j types.Port) bool { +func comparePorts(i, j container.Port) bool { if i.PrivatePort != j.PrivatePort { return i.PrivatePort < j.PrivatePort } diff --git a/vendor/github.com/docker/cli/cli/command/formatter/disk_usage.go b/vendor/github.com/docker/cli/cli/command/formatter/disk_usage.go index d91df2fc55fe..18d79d08e6e8 100644 --- a/vendor/github.com/docker/cli/cli/command/formatter/disk_usage.go +++ b/vendor/github.com/docker/cli/cli/command/formatter/disk_usage.go @@ -9,6 +9,7 @@ import ( "github.com/distribution/reference" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/volume" units "github.com/docker/go-units" @@ -36,7 +37,7 @@ type DiskUsageContext struct { Verbose bool LayersSize int64 Images []*image.Summary - Containers []*types.Container + Containers []*container.Summary Volumes []*volume.Volume BuildCache []*types.BuildCache BuilderSize int64 @@ -124,7 +125,7 @@ func (ctx *DiskUsageContext) Write() (err error) { return err } - diskUsageContainersCtx := diskUsageContainersContext{containers: []*types.Container{}} + diskUsageContainersCtx := diskUsageContainersContext{containers: []*container.Summary{}} diskUsageContainersCtx.Header = SubHeaderContext{ "Type": typeHeader, "TotalCount": totalHeader, @@ -236,7 +237,7 @@ func (ctx *DiskUsageContext) verboseWriteTable(duc *diskUsageContext) error { if err != nil { return err } - ctx.Output.Write([]byte("\nLocal Volumes space usage:\n\n")) + _, _ = ctx.Output.Write([]byte("\nLocal Volumes space usage:\n\n")) for _, v := range duc.Volumes { if err := ctx.contextFormat(tmpl, v); err != nil { return err @@ -248,7 +249,7 @@ func (ctx *DiskUsageContext) verboseWriteTable(duc *diskUsageContext) error { if err != nil { return err } - fmt.Fprintf(ctx.Output, "\nBuild cache usage: %s\n\n", units.HumanSize(float64(ctx.BuilderSize))) + _, _ = fmt.Fprintf(ctx.Output, "\nBuild cache usage: %s\n\n", units.HumanSize(float64(ctx.BuilderSize))) for _, v := range duc.BuildCache { if err := ctx.contextFormat(tmpl, v); err != nil { return err @@ -313,7 +314,7 @@ func (c *diskUsageImagesContext) Reclaimable() string { type diskUsageContainersContext struct { HeaderContext - containers []*types.Container + containers []*container.Summary } func (c *diskUsageContainersContext) MarshalJSON() ([]byte, error) { @@ -328,16 +329,16 @@ func (c *diskUsageContainersContext) TotalCount() string { return strconv.Itoa(len(c.containers)) } -func (c *diskUsageContainersContext) isActive(container types.Container) bool { - return strings.Contains(container.State, "running") || - strings.Contains(container.State, "paused") || - strings.Contains(container.State, "restarting") +func (c *diskUsageContainersContext) isActive(ctr container.Summary) bool { + return strings.Contains(ctr.State, "running") || + strings.Contains(ctr.State, "paused") || + strings.Contains(ctr.State, "restarting") } func (c *diskUsageContainersContext) Active() string { used := 0 - for _, container := range c.containers { - if c.isActive(*container) { + for _, ctr := range c.containers { + if c.isActive(*ctr) { used++ } } @@ -348,22 +349,21 @@ func (c *diskUsageContainersContext) Active() string { func (c *diskUsageContainersContext) Size() string { var size int64 - for _, container := range c.containers { - size += container.SizeRw + for _, ctr := range c.containers { + size += ctr.SizeRw } return units.HumanSize(float64(size)) } func (c *diskUsageContainersContext) Reclaimable() string { - var reclaimable int64 - var totalSize int64 + var reclaimable, totalSize int64 - for _, container := range c.containers { - if !c.isActive(*container) { - reclaimable += container.SizeRw + for _, ctr := range c.containers { + if !c.isActive(*ctr) { + reclaimable += ctr.SizeRw } - totalSize += container.SizeRw + totalSize += ctr.SizeRw } if totalSize > 0 { diff --git a/vendor/github.com/docker/cli/cli/command/registry.go b/vendor/github.com/docker/cli/cli/command/registry.go index cb966be1a77f..e2581d574f93 100644 --- a/vendor/github.com/docker/cli/cli/command/registry.go +++ b/vendor/github.com/docker/cli/cli/command/registry.go @@ -13,9 +13,10 @@ import ( configtypes "github.com/docker/cli/cli/config/types" "github.com/docker/cli/cli/hints" "github.com/docker/cli/cli/streams" - "github.com/docker/docker/api/types" + "github.com/docker/cli/internal/tui" registrytypes "github.com/docker/docker/api/types/registry" "github.com/docker/docker/registry" + "github.com/morikuni/aec" "github.com/pkg/errors" ) @@ -29,7 +30,7 @@ const ( // RegistryAuthenticationPrivilegedFunc returns a RequestPrivilegeFunc from the specified registry index info // for the given command. -func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInfo, cmdName string) types.RequestPrivilegeFunc { +func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInfo, cmdName string) registrytypes.RequestAuthConfig { return func(ctx context.Context) (string, error) { _, _ = fmt.Fprintf(cli.Out(), "\nLogin prior to %s:\n", cmdName) indexServer := registry.GetAuthConfigKey(index) @@ -179,6 +180,9 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword } }() + out := tui.NewOutput(cli.Err()) + out.PrintNote("A Personal Access Token (PAT) can be used instead.\n" + + "To create a PAT, visit " + aec.Underline.Apply("https://app.docker.com/settings") + "\n\n") argPassword, err = PromptForInput(ctx, cli.In(), cli.Out(), "Password: ") if err != nil { return registrytypes.AuthConfig{}, err diff --git a/vendor/github.com/docker/cli/cli/command/telemetry.go b/vendor/github.com/docker/cli/cli/command/telemetry.go index d18d94d4a993..d8985234a782 100644 --- a/vendor/github.com/docker/cli/cli/command/telemetry.go +++ b/vendor/github.com/docker/cli/cli/command/telemetry.go @@ -14,7 +14,7 @@ import ( "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.21.0" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" "go.opentelemetry.io/otel/trace" ) diff --git a/vendor/github.com/docker/cli/cli/command/utils.go b/vendor/github.com/docker/cli/cli/command/utils.go index 2b4a885ed9ff..8a8368fbaa69 100644 --- a/vendor/github.com/docker/cli/cli/command/utils.go +++ b/vendor/github.com/docker/cli/cli/command/utils.go @@ -199,7 +199,7 @@ func PruneFilters(dockerCli Cli, pruneFilters filters.Args) filters.Args { // AddPlatformFlag adds `platform` to a set of flags for API version 1.32 and later. func AddPlatformFlag(flags *pflag.FlagSet, target *string) { flags.StringVar(target, "platform", os.Getenv("DOCKER_DEFAULT_PLATFORM"), "Set platform if server is multi-platform capable") - flags.SetAnnotation("platform", "version", []string{"1.32"}) + _ = flags.SetAnnotation("platform", "version", []string{"1.32"}) } // ValidateOutputPath validates the output paths of the `export` and `save` commands. diff --git a/vendor/github.com/docker/cli/cli/config/config.go b/vendor/github.com/docker/cli/cli/config/config.go index 5a518432601d..910b3c0064a1 100644 --- a/vendor/github.com/docker/cli/cli/config/config.go +++ b/vendor/github.com/docker/cli/cli/config/config.go @@ -143,7 +143,7 @@ func load(configDir string) (*configfile.ConfigFile, error) { defer file.Close() err = configFile.LoadFromReader(file) if err != nil { - err = errors.Wrapf(err, "loading config file: %s: ", filename) + err = errors.Wrapf(err, "parsing config file (%s)", filename) } return configFile, err } diff --git a/vendor/github.com/docker/cli/cli/config/credentials/file_store.go b/vendor/github.com/docker/cli/cli/config/credentials/file_store.go index 95406281501c..c69312b01490 100644 --- a/vendor/github.com/docker/cli/cli/config/credentials/file_store.go +++ b/vendor/github.com/docker/cli/cli/config/credentials/file_store.go @@ -1,9 +1,12 @@ package credentials import ( + "fmt" "net" "net/url" + "os" "strings" + "sync/atomic" "github.com/docker/cli/cli/config/types" ) @@ -57,6 +60,21 @@ func (c *fileStore) GetAll() (map[string]types.AuthConfig, error) { return c.file.GetAuthConfigs(), nil } +// unencryptedWarning warns the user when using an insecure credential storage. +// After a deprecation period, user will get prompted if stdin and stderr are a terminal. +// Otherwise, we'll assume they want it (sadly), because people may have been scripting +// insecure logins and we don't want to break them. Maybe they'll see the warning in their +// logs and fix things. +const unencryptedWarning = ` +WARNING! Your credentials are stored unencrypted in '%s'. +Configure a credential helper to remove this warning. See +https://docs.docker.com/go/credential-store/ +` + +// alreadyPrinted ensures that we only print the unencryptedWarning once per +// CLI invocation (no need to warn the user multiple times per command). +var alreadyPrinted atomic.Bool + // Store saves the given credentials in the file store. This function is // idempotent and does not update the file if credentials did not change. func (c *fileStore) Store(authConfig types.AuthConfig) error { @@ -66,15 +84,19 @@ func (c *fileStore) Store(authConfig types.AuthConfig) error { return nil } authConfigs[authConfig.ServerAddress] = authConfig - return c.file.Save() -} + if err := c.file.Save(); err != nil { + return err + } -func (c *fileStore) GetFilename() string { - return c.file.GetFilename() -} + if !alreadyPrinted.Load() && authConfig.Password != "" { + // Display a warning if we're storing the users password (not a token). + // + // FIXME(thaJeztah): make output configurable instead of hardcoding to os.Stderr + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(unencryptedWarning, c.file.GetFilename())) + alreadyPrinted.Store(true) + } -func (c *fileStore) IsFileStore() bool { - return true + return nil } // ConvertToHostname converts a registry url which has http|https prepended diff --git a/vendor/github.com/docker/cli/cli/context/store/metadatastore.go b/vendor/github.com/docker/cli/cli/context/store/metadatastore.go index 6b8975a4ac9c..e8b25675b3fc 100644 --- a/vendor/github.com/docker/cli/cli/context/store/metadatastore.go +++ b/vendor/github.com/docker/cli/cli/context/store/metadatastore.go @@ -12,7 +12,7 @@ import ( "sort" "github.com/docker/docker/errdefs" - "github.com/docker/docker/pkg/ioutils" + "github.com/docker/docker/pkg/atomicwriter" "github.com/fvbommel/sortorder" "github.com/pkg/errors" ) @@ -40,7 +40,7 @@ func (s *metadataStore) createOrUpdate(meta Metadata) error { if err != nil { return err } - return ioutils.AtomicWriteFile(filepath.Join(contextDir, metaFile), bytes, 0o644) + return atomicwriter.WriteFile(filepath.Join(contextDir, metaFile), bytes, 0o644) } func parseTypedOrMap(payload []byte, getter TypeGetter) (any, error) { diff --git a/vendor/github.com/docker/cli/cli/context/store/tlsstore.go b/vendor/github.com/docker/cli/cli/context/store/tlsstore.go index ffbbde7c0dbc..3cbfe627326d 100644 --- a/vendor/github.com/docker/cli/cli/context/store/tlsstore.go +++ b/vendor/github.com/docker/cli/cli/context/store/tlsstore.go @@ -5,7 +5,7 @@ import ( "path/filepath" "github.com/docker/docker/errdefs" - "github.com/docker/docker/pkg/ioutils" + "github.com/docker/docker/pkg/atomicwriter" "github.com/pkg/errors" ) @@ -32,7 +32,7 @@ func (s *tlsStore) createOrUpdate(name, endpointName, filename string, data []by if err := os.MkdirAll(endpointDir, 0o700); err != nil { return err } - return ioutils.AtomicWriteFile(filepath.Join(endpointDir, filename), data, 0o600) + return atomicwriter.WriteFile(filepath.Join(endpointDir, filename), data, 0o600) } func (s *tlsStore) getData(name, endpointName, filename string) ([]byte, error) { diff --git a/vendor/github.com/docker/cli/cli/error.go b/vendor/github.com/docker/cli/cli/error.go index a821f9e5a8c8..1d35b4e77d65 100644 --- a/vendor/github.com/docker/cli/cli/error.go +++ b/vendor/github.com/docker/cli/cli/error.go @@ -1,35 +1,29 @@ package cli import ( - "fmt" - "strings" + "strconv" ) -// Errors is a list of errors. -// Useful in a loop if you don't want to return the error right away and you want to display after the loop, -// all the errors that happened during the loop. -// -// Deprecated: use [errors.Join] instead; will be removed in the next release. -type Errors []error - -func (errList Errors) Error() string { - if len(errList) < 1 { - return "" - } - - out := make([]string, len(errList)) - for i := range errList { - out[i] = errList[i].Error() - } - return strings.Join(out, ", ") -} - // StatusError reports an unsuccessful exit by a command. type StatusError struct { + Cause error Status string StatusCode int } +// Error formats the error for printing. If a custom Status is provided, +// it is returned as-is, otherwise it generates a generic error-message +// based on the StatusCode. func (e StatusError) Error() string { - return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode) + if e.Status != "" { + return e.Status + } + if e.Cause != nil { + return e.Cause.Error() + } + return "exit status " + strconv.Itoa(e.StatusCode) +} + +func (e StatusError) Unwrap() error { + return e.Cause } diff --git a/vendor/github.com/docker/cli/cli/flags/options.go b/vendor/github.com/docker/cli/cli/flags/options.go index 5a6df9c8897d..fc168984b44b 100644 --- a/vendor/github.com/docker/cli/cli/flags/options.go +++ b/vendor/github.com/docker/cli/cli/flags/options.go @@ -138,7 +138,7 @@ func SetLogLevel(logLevel string) { if logLevel != "" { lvl, err := logrus.ParseLevel(logLevel) if err != nil { - fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", logLevel) + _, _ = fmt.Fprintln(os.Stderr, "Unable to parse logging level:", logLevel) os.Exit(1) } logrus.SetLevel(lvl) diff --git a/vendor/github.com/docker/cli/cli/hints/hints.go b/vendor/github.com/docker/cli/cli/hints/hints.go index f99df8fda02d..aed3577893f6 100644 --- a/vendor/github.com/docker/cli/cli/hints/hints.go +++ b/vendor/github.com/docker/cli/cli/hints/hints.go @@ -5,7 +5,9 @@ import ( "strconv" ) -// Enabled returns whether cli hints are enabled or not +// Enabled returns whether cli hints are enabled or not. Hints are enabled by +// default, but can be disabled through the "DOCKER_CLI_HINTS" environment +// variable. func Enabled() bool { if v := os.Getenv("DOCKER_CLI_HINTS"); v != "" { enabled, err := strconv.ParseBool(v) diff --git a/vendor/github.com/docker/cli/cli/registry/client/endpoint.go b/vendor/github.com/docker/cli/cli/registry/client/endpoint.go index e06bfea50bc5..2446da85a044 100644 --- a/vendor/github.com/docker/cli/cli/registry/client/endpoint.go +++ b/vendor/github.com/docker/cli/cli/registry/client/endpoint.go @@ -22,12 +22,7 @@ type repositoryEndpoint struct { // Name returns the repository name func (r repositoryEndpoint) Name() string { - repoName := r.info.Name.Name() - // If endpoint does not support CanonicalName, use the RemoteName instead - if r.endpoint.TrimHostname { - repoName = reference.Path(r.info.Name) - } - return repoName + return reference.Path(r.info.Name) } // BaseURL returns the endpoint url diff --git a/vendor/github.com/docker/cli/cli/required.go b/vendor/github.com/docker/cli/cli/required.go index e8edcaafac2b..6455e8867e0e 100644 --- a/vendor/github.com/docker/cli/cli/required.go +++ b/vendor/github.com/docker/cli/cli/required.go @@ -1,8 +1,6 @@ package cli import ( - "strings" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -14,15 +12,20 @@ func NoArgs(cmd *cobra.Command, args []string) error { } if cmd.HasSubCommands() { - return errors.New("\n" + strings.TrimRight(cmd.UsageString(), "\n")) + return errors.Errorf( + "%[1]s: unknown command: %[2]s %[3]s\n\nUsage: %[4]s\n\nRun '%[2]s --help' for more information", + binName(cmd), + cmd.CommandPath(), + args[0], + cmd.UseLine(), + ) } return errors.Errorf( - "%q accepts no arguments.\nSee '%s --help'.\n\nUsage: %s\n\n%s", - cmd.CommandPath(), + "%[1]s: '%[2]s' accepts no arguments\n\nUsage: %[3]s\n\nRun '%[2]s --help' for more information", + binName(cmd), cmd.CommandPath(), cmd.UseLine(), - cmd.Short, ) } @@ -33,13 +36,12 @@ func RequiresMinArgs(minArgs int) cobra.PositionalArgs { return nil } return errors.Errorf( - "%q requires at least %d %s.\nSee '%s --help'.\n\nUsage: %s\n\n%s", + "%[1]s: '%[2]s' requires at least %[3]d %[4]s\n\nUsage: %[5]s\n\nSee '%[2]s --help' for more information", + binName(cmd), cmd.CommandPath(), minArgs, pluralize("argument", minArgs), - cmd.CommandPath(), cmd.UseLine(), - cmd.Short, ) } } @@ -51,13 +53,12 @@ func RequiresMaxArgs(maxArgs int) cobra.PositionalArgs { return nil } return errors.Errorf( - "%q requires at most %d %s.\nSee '%s --help'.\n\nUsage: %s\n\n%s", + "%[1]s: '%[2]s' requires at most %[3]d %[4]s\n\nUsage: %[5]s\n\nSRun '%[2]s --help' for more information", + binName(cmd), cmd.CommandPath(), maxArgs, pluralize("argument", maxArgs), - cmd.CommandPath(), cmd.UseLine(), - cmd.Short, ) } } @@ -69,14 +70,13 @@ func RequiresRangeArgs(minArgs int, maxArgs int) cobra.PositionalArgs { return nil } return errors.Errorf( - "%q requires at least %d and at most %d %s.\nSee '%s --help'.\n\nUsage: %s\n\n%s", + "%[1]s: '%[2]s' requires at least %[3]d and at most %[4]d %[5]s\n\nUsage: %[6]s\n\nRun '%[2]s --help' for more information", + binName(cmd), cmd.CommandPath(), minArgs, maxArgs, pluralize("argument", maxArgs), - cmd.CommandPath(), cmd.UseLine(), - cmd.Short, ) } } @@ -88,17 +88,21 @@ func ExactArgs(number int) cobra.PositionalArgs { return nil } return errors.Errorf( - "%q requires exactly %d %s.\nSee '%s --help'.\n\nUsage: %s\n\n%s", + "%[1]s: '%[2]s' requires %[3]d %[4]s\n\nUsage: %[5]s\n\nRun '%[2]s --help' for more information", + binName(cmd), cmd.CommandPath(), number, pluralize("argument", number), - cmd.CommandPath(), cmd.UseLine(), - cmd.Short, ) } } +// binName returns the name of the binary / root command (usually 'docker'). +func binName(cmd *cobra.Command) string { + return cmd.Root().Name() +} + //nolint:unparam func pluralize(word string, number int) string { if number == 1 { diff --git a/vendor/github.com/docker/cli/internal/tui/chip.go b/vendor/github.com/docker/cli/internal/tui/chip.go new file mode 100644 index 000000000000..bb3831094d9c --- /dev/null +++ b/vendor/github.com/docker/cli/internal/tui/chip.go @@ -0,0 +1,12 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.22 + +package tui + +import "strconv" + +func Chip(fg, bg int, content string) string { + fgAnsi := "\x1b[38;5;" + strconv.Itoa(fg) + "m" + bgAnsi := "\x1b[48;5;" + strconv.Itoa(bg) + "m" + return fgAnsi + bgAnsi + content + "\x1b[0m" +} diff --git a/vendor/github.com/docker/cli/internal/tui/colors.go b/vendor/github.com/docker/cli/internal/tui/colors.go new file mode 100644 index 000000000000..c36dfabc8545 --- /dev/null +++ b/vendor/github.com/docker/cli/internal/tui/colors.go @@ -0,0 +1,33 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.22 + +package tui + +import ( + "github.com/morikuni/aec" +) + +var ( + ColorTitle = aec.NewBuilder(aec.DefaultF, aec.Bold).ANSI + ColorPrimary = aec.NewBuilder(aec.DefaultF, aec.Bold).ANSI + ColorSecondary = aec.DefaultF + ColorTertiary = aec.NewBuilder(aec.DefaultF, aec.Faint).ANSI + ColorLink = aec.NewBuilder(aec.LightCyanF, aec.Underline).ANSI + ColorWarning = aec.LightYellowF + ColorFlag = aec.NewBuilder(aec.Bold).ANSI + ColorNone = aec.ANSI(noColor{}) +) + +type noColor struct{} + +func (a noColor) With(_ ...aec.ANSI) aec.ANSI { + return a +} + +func (a noColor) Apply(s string) string { + return s +} + +func (a noColor) String() string { + return "" +} diff --git a/vendor/github.com/docker/cli/internal/tui/count.go b/vendor/github.com/docker/cli/internal/tui/count.go new file mode 100644 index 000000000000..319776e1bfc6 --- /dev/null +++ b/vendor/github.com/docker/cli/internal/tui/count.go @@ -0,0 +1,70 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.22 + +package tui + +import ( + "strings" + + "github.com/mattn/go-runewidth" +) + +func cleanANSI(s string) string { + for { + start := strings.Index(s, "\x1b") + if start == -1 { + return s + } + end := strings.Index(s[start:], "m") + if end == -1 { + return s + } + s = s[:start] + s[start+end+1:] + } +} + +// Width returns the width of the string, ignoring ANSI escape codes. +// Not all ANSI escape codes are supported yet. +func Width(s string) int { + return runewidth.StringWidth(cleanANSI(s)) +} + +// Ellipsis truncates a string to a given number of runes with an ellipsis at the end. +// It tries to persist the ANSI escape sequences. +func Ellipsis(s string, length int) string { + out := make([]rune, 0, length) + ln := 0 + inEscape := false + tooLong := false + + for _, r := range s { + if r == '\x1b' { + out = append(out, r) + inEscape = true + continue + } + if inEscape { + out = append(out, r) + if r == 'm' { + inEscape = false + if tooLong { + break + } + } + continue + } + + ln += 1 + if ln == length { + tooLong = true + } + if !tooLong { + out = append(out, r) + } + } + + if tooLong { + return string(out) + "…" + } + return string(out) +} diff --git a/vendor/github.com/docker/cli/internal/tui/note.go b/vendor/github.com/docker/cli/internal/tui/note.go new file mode 100644 index 000000000000..c955b8cdb462 --- /dev/null +++ b/vendor/github.com/docker/cli/internal/tui/note.go @@ -0,0 +1,39 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.22 + +package tui + +import ( + "fmt" + "strings" + + "github.com/morikuni/aec" +) + +var InfoHeader = Str{ + Plain: " Info -> ", + Fancy: aec.Bold.Apply(aec.LightCyanB.Apply(aec.BlackF.Apply("i")) + " " + aec.LightCyanF.Apply("Info → ")), +} + +func (o Output) PrintNote(format string, args ...any) { + if o.isTerminal { + // TODO: Handle all flags + format = strings.ReplaceAll(format, "--platform", ColorFlag.Apply("--platform")) + } + + header := o.Sprint(InfoHeader) + + _, _ = fmt.Fprint(o, "\n", header) + s := fmt.Sprintf(format, args...) + for idx, line := range strings.Split(s, "\n") { + if idx > 0 { + _, _ = fmt.Fprint(o, strings.Repeat(" ", Width(header))) + } + + l := line + if o.isTerminal { + l = aec.Italic.Apply(l) + } + _, _ = fmt.Fprintln(o, l) + } +} diff --git a/vendor/github.com/docker/cli/internal/tui/output.go b/vendor/github.com/docker/cli/internal/tui/output.go new file mode 100644 index 000000000000..7fc194ac1e98 --- /dev/null +++ b/vendor/github.com/docker/cli/internal/tui/output.go @@ -0,0 +1,62 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.22 + +package tui + +import ( + "fmt" + + "github.com/docker/cli/cli/streams" + "github.com/morikuni/aec" +) + +type Output struct { + *streams.Out + isTerminal bool +} + +type terminalPrintable interface { + String(isTerminal bool) string +} + +func NewOutput(out *streams.Out) Output { + return Output{ + Out: out, + isTerminal: out.IsTerminal(), + } +} + +func (o Output) Color(clr aec.ANSI) aec.ANSI { + if o.isTerminal { + return clr + } + return ColorNone +} + +func (o Output) Sprint(all ...any) string { + var out []any + for _, p := range all { + if s, ok := p.(terminalPrintable); ok { + out = append(out, s.String(o.isTerminal)) + } else { + out = append(out, p) + } + } + return fmt.Sprint(out...) +} + +func (o Output) PrintlnWithColor(clr aec.ANSI, args ...any) { + msg := o.Sprint(args...) + if o.isTerminal { + msg = clr.Apply(msg) + } + _, _ = fmt.Fprintln(o.Out, msg) +} + +func (o Output) Println(p ...any) { + _, _ = fmt.Fprintln(o.Out, o.Sprint(p...)) +} + +func (o Output) Print(p ...any) { + _, _ = fmt.Print(o.Out, o.Sprint(p...)) +} diff --git a/vendor/github.com/docker/cli/internal/tui/str.go b/vendor/github.com/docker/cli/internal/tui/str.go new file mode 100644 index 000000000000..490e474f5efd --- /dev/null +++ b/vendor/github.com/docker/cli/internal/tui/str.go @@ -0,0 +1,19 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.22 + +package tui + +type Str struct { + // Fancy is the fancy string representation of the string. + Fancy string + + // Plain is the plain string representation of the string. + Plain string +} + +func (p Str) String(isTerminal bool) string { + if isTerminal { + return p.Fancy + } + return p.Plain +} diff --git a/vendor/github.com/docker/cli/opts/network.go b/vendor/github.com/docker/cli/opts/network.go index 413aec7b52e6..2ce5dff1f81b 100644 --- a/vendor/github.com/docker/cli/opts/network.go +++ b/vendor/github.com/docker/cli/opts/network.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "regexp" + "strconv" "strings" ) @@ -16,6 +17,7 @@ const ( networkOptMacAddress = "mac-address" networkOptLinkLocalIP = "link-local-ip" driverOpt = "driver-opt" + gwPriorityOpt = "gw-priority" ) // NetworkAttachmentOpts represents the network options for endpoint creation @@ -28,6 +30,7 @@ type NetworkAttachmentOpts struct { IPv6Address string LinkLocalIPs []string MacAddress string + GwPriority int } // NetworkOpt represents a network config in swarm mode. @@ -83,6 +86,11 @@ func (n *NetworkOpt) Set(value string) error { //nolint:gocyclo netOpt.DriverOpts = make(map[string]string) } netOpt.DriverOpts[key] = val + case gwPriorityOpt: + netOpt.GwPriority, err = strconv.Atoi(val) + if err != nil { + return fmt.Errorf("invalid gw-priority: %w", err) + } default: return errors.New("invalid field key " + key) } diff --git a/vendor/github.com/docker/docker/pkg/ioutils/fswriters_deprecated.go b/vendor/github.com/docker/docker/pkg/ioutils/fswriters_deprecated.go deleted file mode 100644 index c3cee16db232..000000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/fswriters_deprecated.go +++ /dev/null @@ -1,44 +0,0 @@ -package ioutils - -import ( - "io" - "os" - - "github.com/docker/docker/pkg/atomicwriter" -) - -// NewAtomicFileWriter returns WriteCloser so that writing to it writes to a -// temporary file and closing it atomically changes the temporary file to -// destination path. Writing and closing concurrently is not allowed. -// NOTE: umask is not considered for the file's permissions. -// -// Deprecated: use [atomicwriter.New] instead. -func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, error) { - return atomicwriter.New(filename, perm) -} - -// AtomicWriteFile atomically writes data to a file named by filename and with the specified permission bits. -// NOTE: umask is not considered for the file's permissions. -// -// Deprecated: use [atomicwriter.WriteFile] instead. -func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error { - return atomicwriter.WriteFile(filename, data, perm) -} - -// AtomicWriteSet is used to atomically write a set -// of files and ensure they are visible at the same time. -// Must be committed to a new directory. -// -// Deprecated: use [atomicwriter.WriteSet] instead. -type AtomicWriteSet = atomicwriter.WriteSet - -// NewAtomicWriteSet creates a new atomic write set to -// atomically create a set of files. The given directory -// is used as the base directory for storing files before -// commit. If no temporary directory is given the system -// default is used. -// -// Deprecated: use [atomicwriter.NewWriteSet] instead. -func NewAtomicWriteSet(tmpDir string) (*atomicwriter.WriteSet, error) { - return atomicwriter.NewWriteSet(tmpDir) -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/readers.go b/vendor/github.com/docker/docker/pkg/ioutils/readers.go deleted file mode 100644 index 9ddba2468d68..000000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/readers.go +++ /dev/null @@ -1,118 +0,0 @@ -package ioutils // import "github.com/docker/docker/pkg/ioutils" - -import ( - "context" - "io" - "runtime/debug" - "sync/atomic" - - "github.com/containerd/log" -) - -// readCloserWrapper wraps an io.Reader, and implements an io.ReadCloser -// It calls the given callback function when closed. It should be constructed -// with NewReadCloserWrapper -type readCloserWrapper struct { - io.Reader - closer func() error - closed atomic.Bool -} - -// Close calls back the passed closer function -func (r *readCloserWrapper) Close() error { - if !r.closed.CompareAndSwap(false, true) { - subsequentCloseWarn("ReadCloserWrapper") - return nil - } - return r.closer() -} - -// NewReadCloserWrapper wraps an io.Reader, and implements an io.ReadCloser. -// It calls the given callback function when closed. -func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser { - return &readCloserWrapper{ - Reader: r, - closer: closer, - } -} - -// cancelReadCloser wraps an io.ReadCloser with a context for cancelling read -// operations. -type cancelReadCloser struct { - cancel func() - pR *io.PipeReader // Stream to read from - pW *io.PipeWriter - closed atomic.Bool -} - -// NewCancelReadCloser creates a wrapper that closes the ReadCloser when the -// context is cancelled. The returned io.ReadCloser must be closed when it is -// no longer needed. -func NewCancelReadCloser(ctx context.Context, in io.ReadCloser) io.ReadCloser { - pR, pW := io.Pipe() - - // Create a context used to signal when the pipe is closed - doneCtx, cancel := context.WithCancel(context.Background()) - - p := &cancelReadCloser{ - cancel: cancel, - pR: pR, - pW: pW, - } - - go func() { - _, err := io.Copy(pW, in) - select { - case <-ctx.Done(): - // If the context was closed, p.closeWithError - // was already called. Calling it again would - // change the error that Read returns. - default: - p.closeWithError(err) - } - in.Close() - }() - go func() { - for { - select { - case <-ctx.Done(): - p.closeWithError(ctx.Err()) - case <-doneCtx.Done(): - return - } - } - }() - - return p -} - -// Read wraps the Read method of the pipe that provides data from the wrapped -// ReadCloser. -func (p *cancelReadCloser) Read(buf []byte) (n int, err error) { - return p.pR.Read(buf) -} - -// closeWithError closes the wrapper and its underlying reader. It will -// cause future calls to Read to return err. -func (p *cancelReadCloser) closeWithError(err error) { - p.pW.CloseWithError(err) - p.cancel() -} - -// Close closes the wrapper its underlying reader. It will cause -// future calls to Read to return io.EOF. -func (p *cancelReadCloser) Close() error { - if !p.closed.CompareAndSwap(false, true) { - subsequentCloseWarn("cancelReadCloser") - return nil - } - p.closeWithError(io.EOF) - return nil -} - -func subsequentCloseWarn(name string) { - log.G(context.TODO()).Error("subsequent attempt to close " + name) - if log.GetLevel() >= log.DebugLevel { - log.G(context.TODO()).Errorf("stack trace: %s", string(debug.Stack())) - } -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go b/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go deleted file mode 100644 index 010db59fe6c2..000000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go +++ /dev/null @@ -1,96 +0,0 @@ -package ioutils // import "github.com/docker/docker/pkg/ioutils" - -import ( - "io" - "sync" -) - -// WriteFlusher wraps the Write and Flush operation ensuring that every write -// is a flush. In addition, the Close method can be called to intercept -// Read/Write calls if the targets lifecycle has already ended. -type WriteFlusher struct { - w io.Writer - flusher flusher - flushed chan struct{} - flushedOnce sync.Once - closed chan struct{} - closeLock sync.Mutex -} - -type flusher interface { - Flush() -} - -func (wf *WriteFlusher) Write(b []byte) (n int, err error) { - select { - case <-wf.closed: - return 0, io.EOF - default: - } - - n, err = wf.w.Write(b) - wf.Flush() // every write is a flush. - return n, err -} - -// Flush the stream immediately. -func (wf *WriteFlusher) Flush() { - select { - case <-wf.closed: - return - default: - } - - wf.flushedOnce.Do(func() { - close(wf.flushed) - }) - wf.flusher.Flush() -} - -// Flushed returns the state of flushed. -// If it's flushed, return true, or else it return false. -func (wf *WriteFlusher) Flushed() bool { - // BUG(stevvooe): Remove this method. Its use is inherently racy. Seems to - // be used to detect whether or a response code has been issued or not. - // Another hook should be used instead. - var flushed bool - select { - case <-wf.flushed: - flushed = true - default: - } - return flushed -} - -// Close closes the write flusher, disallowing any further writes to the -// target. After the flusher is closed, all calls to write or flush will -// result in an error. -func (wf *WriteFlusher) Close() error { - wf.closeLock.Lock() - defer wf.closeLock.Unlock() - - select { - case <-wf.closed: - return io.EOF - default: - close(wf.closed) - } - return nil -} - -// nopFlusher represents a type which flush operation is nop. -type nopFlusher struct{} - -// Flush is a nop operation. -func (f *nopFlusher) Flush() {} - -// NewWriteFlusher returns a new WriteFlusher. -func NewWriteFlusher(w io.Writer) *WriteFlusher { - var fl flusher - if f, ok := w.(flusher); ok { - fl = f - } else { - fl = &nopFlusher{} - } - return &WriteFlusher{w: w, flusher: fl, closed: make(chan struct{}), flushed: make(chan struct{})} -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/writers.go b/vendor/github.com/docker/docker/pkg/ioutils/writers.go deleted file mode 100644 index 9c2d5d3b70d4..000000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/writers.go +++ /dev/null @@ -1,28 +0,0 @@ -package ioutils // import "github.com/docker/docker/pkg/ioutils" - -import ( - "io" - "sync/atomic" -) - -type writeCloserWrapper struct { - io.Writer - closer func() error - closed atomic.Bool -} - -func (r *writeCloserWrapper) Close() error { - if !r.closed.CompareAndSwap(false, true) { - subsequentCloseWarn("WriteCloserWrapper") - return nil - } - return r.closer() -} - -// NewWriteCloserWrapper returns a new io.WriteCloser. -func NewWriteCloserWrapper(r io.Writer, closer func() error) io.WriteCloser { - return &writeCloserWrapper{ - Writer: r, - closer: closer, - } -} diff --git a/vendor/modules.txt b/vendor/modules.txt index f07fc92f2391..d466852737b6 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -229,7 +229,7 @@ github.com/davecgh/go-spew/spew # github.com/distribution/reference v0.6.0 ## explicit; go 1.20 github.com/distribution/reference -# github.com/docker/cli v27.5.1+incompatible +# github.com/docker/cli v28.0.0-rc.1+incompatible ## explicit github.com/docker/cli/cli github.com/docker/cli/cli-plugins/hooks @@ -258,6 +258,7 @@ github.com/docker/cli/cli/registry/client github.com/docker/cli/cli/streams github.com/docker/cli/cli/trust github.com/docker/cli/cli/version +github.com/docker/cli/internal/tui github.com/docker/cli/opts github.com/docker/cli/pkg/kvfile github.com/docker/cli/templates @@ -311,7 +312,6 @@ github.com/docker/docker/pkg/archive github.com/docker/docker/pkg/atomicwriter github.com/docker/docker/pkg/homedir github.com/docker/docker/pkg/idtools -github.com/docker/docker/pkg/ioutils github.com/docker/docker/pkg/jsonmessage github.com/docker/docker/pkg/namesgenerator github.com/docker/docker/pkg/stdcopy