vendor: github.com/docker/cli v28.1.0
full diff: https://github.com/docker/cli/compare/v28.0.4...v28.1.0 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
+27
-5
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package command
|
||||
|
||||
@@ -59,7 +59,9 @@ type Cli interface {
|
||||
}
|
||||
|
||||
// DockerCli is an instance the docker command line client.
|
||||
// Instances of the client can be returned from NewDockerCli.
|
||||
// Instances of the client should be created using the [NewDockerCli]
|
||||
// constructor to make sure they are properly initialized with defaults
|
||||
// set.
|
||||
type DockerCli struct {
|
||||
configFile *configfile.ConfigFile
|
||||
options *cliflags.ClientOptions
|
||||
@@ -74,7 +76,7 @@ type DockerCli struct {
|
||||
init sync.Once
|
||||
initErr error
|
||||
dockerEndpoint docker.Endpoint
|
||||
contextStoreConfig store.Config
|
||||
contextStoreConfig *store.Config
|
||||
initTimeout time.Duration
|
||||
res telemetryResource
|
||||
|
||||
@@ -250,13 +252,33 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption)
|
||||
return errors.New("conflicting options: cannot specify both --host and --context")
|
||||
}
|
||||
|
||||
if cli.contextStoreConfig == nil {
|
||||
// This path can be hit when calling Initialize on a DockerCli that's
|
||||
// not constructed through [NewDockerCli]. Using the default context
|
||||
// store without a config set will result in Endpoints from contexts
|
||||
// not being type-mapped correctly, and used as a generic "map[string]any",
|
||||
// instead of a [docker.EndpointMeta].
|
||||
//
|
||||
// When looking up the API endpoint (using [EndpointFromContext]), no
|
||||
// endpoint will be found, and a default, empty endpoint will be used
|
||||
// instead which in its turn, causes newAPIClientFromEndpoint to
|
||||
// be initialized with the default config instead of settings for
|
||||
// the current context (which may mean; connecting with the wrong
|
||||
// endpoint and/or TLS Config to be missing).
|
||||
//
|
||||
// [EndpointFromContext]: https://github.com/docker/cli/blob/33494921b80fd0b5a06acc3a34fa288de4bb2e6b/cli/context/docker/load.go#L139-L149
|
||||
if err := WithDefaultContextStoreConfig()(cli); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cli.options = opts
|
||||
cli.configFile = config.LoadDefaultConfigFile(cli.err)
|
||||
cli.currentContext = resolveContextName(cli.options, cli.configFile)
|
||||
cli.contextStore = &ContextStoreWithDefault{
|
||||
Store: store.New(config.ContextStoreDir(), cli.contextStoreConfig),
|
||||
Store: store.New(config.ContextStoreDir(), *cli.contextStoreConfig),
|
||||
Resolver: func() (*DefaultContext, error) {
|
||||
return ResolveDefaultContext(cli.options, cli.contextStoreConfig)
|
||||
return ResolveDefaultContext(cli.options, *cli.contextStoreConfig)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -101,7 +101,8 @@ func WithContentTrust(enabled bool) CLIOption {
|
||||
// WithDefaultContextStoreConfig configures the cli to use the default context store configuration.
|
||||
func WithDefaultContextStoreConfig() CLIOption {
|
||||
return func(cli *DockerCli) error {
|
||||
cli.contextStoreConfig = DefaultContextStoreConfig()
|
||||
cfg := DefaultContextStoreConfig()
|
||||
cli.contextStoreConfig = &cfg
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package command
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package command
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package formatter
|
||||
|
||||
|
||||
-16
@@ -1,7 +1,5 @@
|
||||
package formatter
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
const (
|
||||
// ClientContextTableFormat is the default client context format.
|
||||
ClientContextTableFormat = "table {{.Name}}{{if .Current}} *{{end}}\t{{.Description}}\t{{.DockerEndpoint}}\t{{.Error}}"
|
||||
@@ -30,13 +28,6 @@ type ClientContext struct {
|
||||
DockerEndpoint string
|
||||
Current bool
|
||||
Error string
|
||||
|
||||
// ContextType is a temporary field for compatibility with
|
||||
// Visual Studio, which depends on this from the "cloud integration"
|
||||
// wrapper.
|
||||
//
|
||||
// Deprecated: this type is only for backward-compatibility. Do not use.
|
||||
ContextType string `json:"ContextType,omitempty"`
|
||||
}
|
||||
|
||||
// ClientContextWrite writes formatted contexts using the Context
|
||||
@@ -69,13 +60,6 @@ func newClientContextContext() *clientContextContext {
|
||||
}
|
||||
|
||||
func (c *clientContextContext) MarshalJSON() ([]byte, error) {
|
||||
if c.c.ContextType != "" {
|
||||
// We only have ContextType set for plain "json" or "{{json .}}" formatting,
|
||||
// so we should be able to just use the default json.Marshal with no
|
||||
// special handling.
|
||||
return json.Marshal(c.c)
|
||||
}
|
||||
// FIXME(thaJeztah): why do we need a special marshal function here?
|
||||
return MarshalJSON(c)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package formatter
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package formatter
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package formatter
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package formatter
|
||||
|
||||
|
||||
+44
-19
@@ -13,9 +13,9 @@ import (
|
||||
configtypes "github.com/docker/cli/cli/config/types"
|
||||
"github.com/docker/cli/cli/hints"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/cli/internal/prompt"
|
||||
"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"
|
||||
)
|
||||
@@ -28,16 +28,22 @@ const (
|
||||
"for organizations using SSO. Learn more at https://docs.docker.com/go/access-tokens/"
|
||||
)
|
||||
|
||||
// authConfigKey is the key used to store credentials for Docker Hub. It is
|
||||
// a copy of [registry.IndexServer].
|
||||
//
|
||||
// [registry.IndexServer]: https://pkg.go.dev/github.com/docker/docker/registry#IndexServer
|
||||
const authConfigKey = "https://index.docker.io/v1/"
|
||||
|
||||
// RegistryAuthenticationPrivilegedFunc returns a RequestPrivilegeFunc from the specified registry index info
|
||||
// for the given command.
|
||||
func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInfo, cmdName string) registrytypes.RequestAuthConfig {
|
||||
configKey := getAuthConfigKey(index.Name)
|
||||
isDefaultRegistry := configKey == authConfigKey || index.Official
|
||||
return func(ctx context.Context) (string, error) {
|
||||
_, _ = fmt.Fprintf(cli.Out(), "\nLogin prior to %s:\n", cmdName)
|
||||
indexServer := registry.GetAuthConfigKey(index)
|
||||
isDefaultRegistry := indexServer == registry.IndexServer
|
||||
authConfig, err := GetDefaultAuthConfig(cli.ConfigFile(), true, indexServer, isDefaultRegistry)
|
||||
authConfig, err := GetDefaultAuthConfig(cli.ConfigFile(), true, configKey, isDefaultRegistry)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", indexServer, err)
|
||||
_, _ = fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", authConfigKey, err)
|
||||
}
|
||||
|
||||
select {
|
||||
@@ -46,7 +52,7 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
|
||||
default:
|
||||
}
|
||||
|
||||
authConfig, err = PromptUserForCredentials(ctx, cli, "", "", authConfig.Username, indexServer)
|
||||
authConfig, err = PromptUserForCredentials(ctx, cli, "", "", authConfig.Username, authConfigKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -63,7 +69,7 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
|
||||
func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInfo) registrytypes.AuthConfig {
|
||||
configKey := index.Name
|
||||
if index.Official {
|
||||
configKey = registry.IndexServer
|
||||
configKey = authConfigKey
|
||||
}
|
||||
|
||||
a, _ := cfg.GetAuthConfig(configKey)
|
||||
@@ -132,7 +138,7 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
|
||||
|
||||
argUser = strings.TrimSpace(argUser)
|
||||
if argUser == "" {
|
||||
if serverAddress == registry.IndexServer {
|
||||
if serverAddress == authConfigKey {
|
||||
// When signing in to the default (Docker Hub) registry, we display
|
||||
// hints for creating an account, and (if hints are enabled), using
|
||||
// a token instead of a password.
|
||||
@@ -143,16 +149,16 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
|
||||
}
|
||||
}
|
||||
|
||||
var prompt string
|
||||
var msg string
|
||||
defaultUsername = strings.TrimSpace(defaultUsername)
|
||||
if defaultUsername == "" {
|
||||
prompt = "Username: "
|
||||
msg = "Username: "
|
||||
} else {
|
||||
prompt = fmt.Sprintf("Username (%s): ", defaultUsername)
|
||||
msg = fmt.Sprintf("Username (%s): ", defaultUsername)
|
||||
}
|
||||
|
||||
var err error
|
||||
argUser, err = PromptForInput(ctx, cli.In(), cli.Out(), prompt)
|
||||
argUser, err = prompt.ReadInput(ctx, cli.In(), cli.Out(), msg)
|
||||
if err != nil {
|
||||
return registrytypes.AuthConfig{}, err
|
||||
}
|
||||
@@ -166,7 +172,7 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
|
||||
|
||||
argPassword = strings.TrimSpace(argPassword)
|
||||
if argPassword == "" {
|
||||
restoreInput, err := DisableInputEcho(cli.In())
|
||||
restoreInput, err := prompt.DisableInputEcho(cli.In())
|
||||
if err != nil {
|
||||
return registrytypes.AuthConfig{}, err
|
||||
}
|
||||
@@ -180,10 +186,13 @@ 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 serverAddress == authConfigKey {
|
||||
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 = prompt.ReadInput(ctx, cli.In(), cli.Out(), "Password: ")
|
||||
if err != nil {
|
||||
return registrytypes.AuthConfig{}, err
|
||||
}
|
||||
@@ -225,9 +234,25 @@ func resolveAuthConfigFromImage(cfg *configfile.ConfigFile, image string) (regis
|
||||
if err != nil {
|
||||
return registrytypes.AuthConfig{}, err
|
||||
}
|
||||
repoInfo, err := registry.ParseRepositoryInfo(registryRef)
|
||||
configKey := getAuthConfigKey(reference.Domain(registryRef))
|
||||
a, err := cfg.GetAuthConfig(configKey)
|
||||
if err != nil {
|
||||
return registrytypes.AuthConfig{}, err
|
||||
}
|
||||
return ResolveAuthConfig(cfg, repoInfo.Index), nil
|
||||
return registrytypes.AuthConfig(a), nil
|
||||
}
|
||||
|
||||
// getAuthConfigKey special-cases using the full index address of the official
|
||||
// index as the AuthConfig key, and uses the (host)name[:port] for private indexes.
|
||||
//
|
||||
// It is similar to [registry.GetAuthConfigKey], but does not require on
|
||||
// [registrytypes.IndexInfo] as intermediate.
|
||||
//
|
||||
// [registry.GetAuthConfigKey]: https://pkg.go.dev/github.com/docker/docker/registry#GetAuthConfigKey
|
||||
// [registrytypes.IndexInfo]:https://pkg.go.dev/github.com/docker/docker/api/types/registry#IndexInfo
|
||||
func getAuthConfigKey(domainName string) string {
|
||||
if domainName == "docker.io" || domainName == "index.docker.io" {
|
||||
return authConfigKey
|
||||
}
|
||||
return domainName
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package command
|
||||
|
||||
|
||||
+37
-101
@@ -1,70 +1,45 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/config"
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/cli/internal/prompt"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/moby/sys/sequential"
|
||||
"github.com/moby/term"
|
||||
"github.com/moby/sys/atomicwriter"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// CopyToFile writes the content of the reader to the specified file
|
||||
//
|
||||
// Deprecated: use [atomicwriter.New].
|
||||
func CopyToFile(outfile string, r io.Reader) error {
|
||||
// We use sequential file access here to avoid depleting the standby list
|
||||
// on Windows. On Linux, this is a call directly to os.CreateTemp
|
||||
tmpFile, err := sequential.CreateTemp(filepath.Dir(outfile), ".docker_temp_")
|
||||
writer, err := atomicwriter.New(outfile, 0o600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpPath := tmpFile.Name()
|
||||
|
||||
_, err = io.Copy(tmpFile, r)
|
||||
tmpFile.Close()
|
||||
|
||||
if err != nil {
|
||||
os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.Rename(tmpPath, outfile); err != nil {
|
||||
os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
defer writer.Close()
|
||||
_, err = io.Copy(writer, r)
|
||||
return err
|
||||
}
|
||||
|
||||
var ErrPromptTerminated = errdefs.Cancelled(errors.New("prompt terminated"))
|
||||
const ErrPromptTerminated = prompt.ErrTerminated
|
||||
|
||||
// DisableInputEcho disables input echo on the provided streams.In.
|
||||
// This is useful when the user provides sensitive information like passwords.
|
||||
// The function returns a restore function that should be called to restore the
|
||||
// terminal state.
|
||||
func DisableInputEcho(ins *streams.In) (restore func() error, err error) {
|
||||
oldState, err := term.SaveState(ins.FD())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
restore = func() error {
|
||||
return term.RestoreTerminal(ins.FD(), oldState)
|
||||
}
|
||||
return restore, term.DisableEcho(ins.FD(), oldState)
|
||||
return prompt.DisableInputEcho(ins)
|
||||
}
|
||||
|
||||
// PromptForInput requests input from the user.
|
||||
@@ -75,23 +50,7 @@ func DisableInputEcho(ins *streams.In) (restore func() error, err error) {
|
||||
// the stack and close the io.Reader used for the prompt which will prevent the
|
||||
// background goroutine from blocking indefinitely.
|
||||
func PromptForInput(ctx context.Context, in io.Reader, out io.Writer, message string) (string, error) {
|
||||
_, _ = fmt.Fprint(out, message)
|
||||
|
||||
result := make(chan string)
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(in)
|
||||
if scanner.Scan() {
|
||||
result <- strings.TrimSpace(scanner.Text())
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_, _ = fmt.Fprintln(out, "")
|
||||
return "", ErrPromptTerminated
|
||||
case r := <-result:
|
||||
return r, nil
|
||||
}
|
||||
return prompt.ReadInput(ctx, in, out, message)
|
||||
}
|
||||
|
||||
// PromptForConfirmation requests and checks confirmation from the user.
|
||||
@@ -105,68 +64,45 @@ func PromptForInput(ctx context.Context, in io.Reader, out io.Writer, message st
|
||||
// the stack and close the io.Reader used for the prompt which will prevent the
|
||||
// background goroutine from blocking indefinitely.
|
||||
func PromptForConfirmation(ctx context.Context, ins io.Reader, outs io.Writer, message string) (bool, error) {
|
||||
if message == "" {
|
||||
message = "Are you sure you want to proceed?"
|
||||
}
|
||||
message += " [y/N] "
|
||||
|
||||
_, _ = fmt.Fprint(outs, message)
|
||||
|
||||
// On Windows, force the use of the regular OS stdin stream.
|
||||
if runtime.GOOS == "windows" {
|
||||
ins = streams.NewIn(os.Stdin)
|
||||
}
|
||||
|
||||
result := make(chan bool)
|
||||
|
||||
go func() {
|
||||
var res bool
|
||||
scanner := bufio.NewScanner(ins)
|
||||
if scanner.Scan() {
|
||||
answer := strings.TrimSpace(scanner.Text())
|
||||
if strings.EqualFold(answer, "y") {
|
||||
res = true
|
||||
}
|
||||
}
|
||||
result <- res
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
_, _ = fmt.Fprintln(outs, "")
|
||||
return false, ErrPromptTerminated
|
||||
case r := <-result:
|
||||
return r, nil
|
||||
}
|
||||
return prompt.Confirm(ctx, ins, outs, message)
|
||||
}
|
||||
|
||||
// PruneFilters returns consolidated prune filters obtained from config.json and cli
|
||||
// PruneFilters merges prune filters specified in config.json with those specified
|
||||
// as command-line flags.
|
||||
//
|
||||
// CLI label filters have precedence over those specified in config.json. If a
|
||||
// label filter specified as flag conflicts with a label defined in config.json
|
||||
// (i.e., "label=some-value" conflicts with "label!=some-value", and vice versa),
|
||||
// then the filter defined in config.json is omitted.
|
||||
func PruneFilters(dockerCLI config.Provider, pruneFilters filters.Args) filters.Args {
|
||||
cfg := dockerCLI.ConfigFile()
|
||||
if cfg == nil {
|
||||
return pruneFilters
|
||||
}
|
||||
|
||||
// Merge filters provided through the CLI with default filters defined
|
||||
// in the CLI-configfile.
|
||||
for _, f := range cfg.PruneFilters {
|
||||
k, v, ok := strings.Cut(f, "=")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if k == "label" {
|
||||
// CLI label filter supersede config.json.
|
||||
// If CLI label filter conflict with config.json,
|
||||
// skip adding label! filter in config.json.
|
||||
if pruneFilters.Contains("label!") && pruneFilters.ExactMatch("label!", v) {
|
||||
switch k {
|
||||
case "label":
|
||||
// "label != some-value" conflicts with "label = some-value"
|
||||
if pruneFilters.ExactMatch("label!", v) {
|
||||
continue
|
||||
}
|
||||
} else if k == "label!" {
|
||||
// CLI label! filter supersede config.json.
|
||||
// If CLI label! filter conflict with config.json,
|
||||
// skip adding label filter in config.json.
|
||||
if pruneFilters.Contains("label") && pruneFilters.ExactMatch("label", v) {
|
||||
pruneFilters.Add(k, v)
|
||||
case "label!":
|
||||
// "label != some-value" conflicts with "label = some-value"
|
||||
if pruneFilters.ExactMatch("label", v) {
|
||||
continue
|
||||
}
|
||||
pruneFilters.Add(k, v)
|
||||
default:
|
||||
pruneFilters.Add(k, v)
|
||||
}
|
||||
pruneFilters.Add(k, v)
|
||||
}
|
||||
|
||||
return pruneFilters
|
||||
@@ -178,7 +114,7 @@ func AddPlatformFlag(flags *pflag.FlagSet, target *string) {
|
||||
_ = flags.SetAnnotation("platform", "version", []string{"1.32"})
|
||||
}
|
||||
|
||||
// ValidateOutputPath validates the output paths of the `export` and `save` commands.
|
||||
// ValidateOutputPath validates the output paths of the "docker cp" command.
|
||||
func ValidateOutputPath(path string) error {
|
||||
dir := filepath.Dir(filepath.Clean(path))
|
||||
if dir != "" && dir != "." {
|
||||
@@ -204,8 +140,8 @@ func ValidateOutputPath(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateOutputPathFileMode validates the output paths of the `cp` command and serves as a
|
||||
// helper to `ValidateOutputPath`
|
||||
// ValidateOutputPathFileMode validates the output paths of the "docker cp" command
|
||||
// and serves as a helper to [ValidateOutputPath]
|
||||
func ValidateOutputPathFileMode(fileMode os.FileMode) error {
|
||||
switch {
|
||||
case fileMode&os.ModeDevice != 0:
|
||||
|
||||
+3
-1
@@ -36,12 +36,14 @@ type ConfigFile struct {
|
||||
NodesFormat string `json:"nodesFormat,omitempty"`
|
||||
PruneFilters []string `json:"pruneFilters,omitempty"`
|
||||
Proxies map[string]ProxyConfig `json:"proxies,omitempty"`
|
||||
Experimental string `json:"experimental,omitempty"`
|
||||
CurrentContext string `json:"currentContext,omitempty"`
|
||||
CLIPluginsExtraDirs []string `json:"cliPluginsExtraDirs,omitempty"`
|
||||
Plugins map[string]map[string]string `json:"plugins,omitempty"`
|
||||
Aliases map[string]string `json:"aliases,omitempty"`
|
||||
Features map[string]string `json:"features,omitempty"`
|
||||
|
||||
// Deprecated: experimental CLI features are always enabled and this field is no longer used. Use [Features] instead for optional features. This field will be removed in a future release.
|
||||
Experimental string `json:"experimental,omitempty"`
|
||||
}
|
||||
|
||||
// ProxyConfig contains proxy configuration settings
|
||||
|
||||
+4
-4
@@ -5,14 +5,14 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// LimitedReader is a fork of io.LimitedReader to override Read.
|
||||
type LimitedReader struct {
|
||||
// limitedReader is a fork of [io.LimitedReader] to override Read.
|
||||
type limitedReader struct {
|
||||
R io.Reader
|
||||
N int64 // max bytes remaining
|
||||
}
|
||||
|
||||
// Read is a fork of io.LimitedReader.Read that returns an error when limit exceeded.
|
||||
func (l *LimitedReader) Read(p []byte) (n int, err error) {
|
||||
// Read is a fork of [io.LimitedReader.Read] that returns an error when limit exceeded.
|
||||
func (l *limitedReader) Read(p []byte) (n int, err error) {
|
||||
if l.N < 0 {
|
||||
return 0, errors.New("read exceeds the defined limit")
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package store
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/atomicwriter"
|
||||
"github.com/fvbommel/sortorder"
|
||||
"github.com/moby/sys/atomicwriter"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package store
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/internal/lazyregexp"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
const restrictedNamePattern = "^[a-zA-Z0-9][a-zA-Z0-9_.+-]+$"
|
||||
|
||||
var restrictedNameRegEx = regexp.MustCompile(restrictedNamePattern)
|
||||
var restrictedNameRegEx = lazyregexp.New(restrictedNamePattern)
|
||||
|
||||
// Store provides a context store for easily remembering endpoints configuration
|
||||
type Store interface {
|
||||
@@ -356,7 +356,7 @@ func isValidFilePath(p string) error {
|
||||
}
|
||||
|
||||
func importTar(name string, s Writer, reader io.Reader) error {
|
||||
tr := tar.NewReader(&LimitedReader{R: reader, N: maxAllowedFileSizeToImport})
|
||||
tr := tar.NewReader(&limitedReader{R: reader, N: maxAllowedFileSizeToImport})
|
||||
tlsData := ContextTLSData{
|
||||
Endpoints: map[string]EndpointTLSData{},
|
||||
}
|
||||
@@ -406,7 +406,7 @@ func importTar(name string, s Writer, reader io.Reader) error {
|
||||
}
|
||||
|
||||
func importZip(name string, s Writer, reader io.Reader) error {
|
||||
body, err := io.ReadAll(&LimitedReader{R: reader, N: maxAllowedFileSizeToImport})
|
||||
body, err := io.ReadAll(&limitedReader{R: reader, N: maxAllowedFileSizeToImport})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -434,7 +434,7 @@ func importZip(name string, s Writer, reader io.Reader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(&LimitedReader{R: f, N: maxAllowedFileSizeToImport})
|
||||
data, err := io.ReadAll(&limitedReader{R: f, N: maxAllowedFileSizeToImport})
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
//go:build go1.23
|
||||
|
||||
package store
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/atomicwriter"
|
||||
"github.com/moby/sys/atomicwriter"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user