vendor: github.com/docker/cli/v28.0.0-rc.1

full diff: https://github.com/docker/cli/compare/v27.5.1..v28.0.0-rc.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-02-10 11:07:38 +01:00
parent b195b80ddf
commit 7216086b8c
33 changed files with 383 additions and 408 deletions
+1 -5
View File
@@ -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,
}
}
+4 -4
View File
@@ -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
}
+11 -9
View File
@@ -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
}
+19 -19
View File
@@ -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 {
+6 -2
View File
@@ -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
+1 -1
View File
@@ -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"
)
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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
}
+29 -7
View File
@@ -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
+2 -2
View File
@@ -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) {
+2 -2
View File
@@ -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) {
+16 -22
View File
@@ -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
}
+1 -1
View File
@@ -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)
+3 -1
View File
@@ -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)
+1 -6
View File
@@ -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
+22 -18
View File
@@ -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 {