mirror of https://github.com/docker/cli.git
Compare commits
41 Commits
ef1405f869
...
19825fb5da
Author | SHA1 | Date |
---|---|---|
Sebastiaan van Stijn | 19825fb5da | |
Sebastiaan van Stijn | 6c76914532 | |
Sebastiaan van Stijn | 7b67057c32 | |
Sebastiaan van Stijn | 9ccc462005 | |
Sebastiaan van Stijn | 35bf069da2 | |
Sebastiaan van Stijn | 9b72a58d35 | |
Sebastiaan van Stijn | 6aeba15e55 | |
Sebastiaan van Stijn | a93fb1678a | |
Sebastiaan van Stijn | d41b80fafc | |
Sebastiaan van Stijn | 11fbc99939 | |
dependabot[bot] | b0c0cd5e32 | |
Sebastiaan van Stijn | 81401f37f2 | |
Sebastiaan van Stijn | f6599300ff | |
Sebastiaan van Stijn | 446d4138ed | |
Sebastiaan van Stijn | 07e5ddd054 | |
Sebastiaan van Stijn | 93a931920b | |
Giedrius Jonikas | cb2f95ceee | |
Sebastiaan van Stijn | 9861ce90fd | |
Sebastiaan van Stijn | d1d5353269 | |
Sebastiaan van Stijn | 4adbb18f1c | |
Sebastiaan van Stijn | e00ed82399 | |
Sebastiaan van Stijn | 3dd7621240 | |
Sebastiaan van Stijn | 4242cda826 | |
Sebastiaan van Stijn | a4228409d2 | |
Sebastiaan van Stijn | 7c80e4f938 | |
Harald Albers | 06260e68f3 | |
Harald Albers | 4525fe37b4 | |
Harald Albers | db0ed1e216 | |
Harald Albers | 2915749279 | |
Harald Albers | 3a2503fa43 | |
Harald Albers | 9a9ae231a9 | |
Harald Albers | 5f7c43e5e6 | |
Harald Albers | 3292afe6e6 | |
Harald Albers | 5d709a8d9f | |
Harald Albers | 2d89339b34 | |
Harald Albers | ac7bde6f64 | |
Harald Albers | e513454244 | |
Harald Albers | c555327f0b | |
Harald Albers | b598ec8cdb | |
Harald Albers | 761d76750c | |
Sebastiaan van Stijn | e2986f4467 |
|
@ -75,7 +75,7 @@ jobs:
|
||||||
TESTFLAGS: -coverprofile=/tmp/coverage/coverage.txt
|
TESTFLAGS: -coverprofile=/tmp/coverage/coverage.txt
|
||||||
-
|
-
|
||||||
name: Send to Codecov
|
name: Send to Codecov
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
file: ./build/coverage/coverage.txt
|
files: ./build/coverage/coverage.txt
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
|
@ -40,9 +40,9 @@ jobs:
|
||||||
targets: test-coverage
|
targets: test-coverage
|
||||||
-
|
-
|
||||||
name: Send to Codecov
|
name: Send to Codecov
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
file: ./build/coverage/coverage.txt
|
files: ./build/coverage/coverage.txt
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
host:
|
host:
|
||||||
|
@ -78,8 +78,8 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
-
|
-
|
||||||
name: Send to Codecov
|
name: Send to Codecov
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
file: /tmp/coverage.txt
|
files: /tmp/coverage.txt
|
||||||
working-directory: ${{ env.GOPATH }}/src/github.com/docker/cli
|
working-directory: ${{ env.GOPATH }}/src/github.com/docker/cli
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
|
@ -6,10 +6,10 @@ ARG BASE_DEBIAN_DISTRO=bookworm
|
||||||
|
|
||||||
ARG GO_VERSION=1.23.3
|
ARG GO_VERSION=1.23.3
|
||||||
ARG XX_VERSION=1.5.0
|
ARG XX_VERSION=1.5.0
|
||||||
ARG GOVERSIONINFO_VERSION=v1.3.0
|
ARG GOVERSIONINFO_VERSION=v1.4.1
|
||||||
ARG GOTESTSUM_VERSION=v1.10.0
|
ARG GOTESTSUM_VERSION=v1.10.0
|
||||||
ARG BUILDX_VERSION=0.17.1
|
ARG BUILDX_VERSION=0.18.0
|
||||||
ARG COMPOSE_VERSION=v2.29.7
|
ARG COMPOSE_VERSION=v2.30.3
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package manager
|
package manager
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// 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
|
||||||
|
// +build go1.22
|
||||||
|
|
||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -44,6 +48,65 @@ var allLinuxCapabilities = sync.OnceValue(func() []string {
|
||||||
return out
|
return out
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// logDriverOptions provides the options for each built-in logging driver.
|
||||||
|
var logDriverOptions = map[string][]string{
|
||||||
|
"awslogs": {
|
||||||
|
"max-buffer-size", "mode", "awslogs-create-group", "awslogs-credentials-endpoint", "awslogs-datetime-format",
|
||||||
|
"awslogs-group", "awslogs-multiline-pattern", "awslogs-region", "awslogs-stream", "tag",
|
||||||
|
},
|
||||||
|
"fluentd": {
|
||||||
|
"max-buffer-size", "mode", "env", "env-regex", "labels", "fluentd-address", "fluentd-async",
|
||||||
|
"fluentd-buffer-limit", "fluentd-request-ack", "fluentd-retry-wait", "fluentd-max-retries",
|
||||||
|
"fluentd-sub-second-precision", "tag",
|
||||||
|
},
|
||||||
|
"gcplogs": {
|
||||||
|
"max-buffer-size", "mode", "env", "env-regex", "labels", "gcp-log-cmd", "gcp-meta-id", "gcp-meta-name",
|
||||||
|
"gcp-meta-zone", "gcp-project",
|
||||||
|
},
|
||||||
|
"gelf": {
|
||||||
|
"max-buffer-size", "mode", "env", "env-regex", "labels", "gelf-address", "gelf-compression-level",
|
||||||
|
"gelf-compression-type", "gelf-tcp-max-reconnect", "gelf-tcp-reconnect-delay", "tag",
|
||||||
|
},
|
||||||
|
"journald": {"max-buffer-size", "mode", "env", "env-regex", "labels", "tag"},
|
||||||
|
"json-file": {"max-buffer-size", "mode", "env", "env-regex", "labels", "compress", "max-file", "max-size"},
|
||||||
|
"local": {"max-buffer-size", "mode", "compress", "max-file", "max-size"},
|
||||||
|
"none": {},
|
||||||
|
"splunk": {
|
||||||
|
"max-buffer-size", "mode", "env", "env-regex", "labels", "splunk-caname", "splunk-capath", "splunk-format",
|
||||||
|
"splunk-gzip", "splunk-gzip-level", "splunk-index", "splunk-insecureskipverify", "splunk-source",
|
||||||
|
"splunk-sourcetype", "splunk-token", "splunk-url", "splunk-verify-connection", "tag",
|
||||||
|
},
|
||||||
|
"syslog": {
|
||||||
|
"max-buffer-size", "mode", "env", "env-regex", "labels", "syslog-address", "syslog-facility", "syslog-format",
|
||||||
|
"syslog-tls-ca-cert", "syslog-tls-cert", "syslog-tls-key", "syslog-tls-skip-verify", "tag",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// builtInLogDrivers provides a list of the built-in logging drivers.
|
||||||
|
var builtInLogDrivers = sync.OnceValue(func() []string {
|
||||||
|
drivers := make([]string, 0, len(logDriverOptions))
|
||||||
|
for driver := range logDriverOptions {
|
||||||
|
drivers = append(drivers, driver)
|
||||||
|
}
|
||||||
|
return drivers
|
||||||
|
})
|
||||||
|
|
||||||
|
// allLogDriverOptions provides all options of the built-in logging drivers.
|
||||||
|
// The list does not contain duplicates.
|
||||||
|
var allLogDriverOptions = sync.OnceValue(func() []string {
|
||||||
|
var result []string
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
for driver := range logDriverOptions {
|
||||||
|
for _, opt := range logDriverOptions[driver] {
|
||||||
|
if !seen[opt] {
|
||||||
|
seen[opt] = true
|
||||||
|
result = append(result, opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
// restartPolicies is a list of all valid restart-policies..
|
// restartPolicies is a list of all valid restart-policies..
|
||||||
//
|
//
|
||||||
// TODO(thaJeztah): add descriptions, and enable descriptions for our completion scripts (cobra.CompletionOptions.DisableDescriptions is currently set to "true")
|
// TODO(thaJeztah): add descriptions, and enable descriptions for our completion scripts (cobra.CompletionOptions.DisableDescriptions is currently set to "true")
|
||||||
|
@ -54,6 +117,207 @@ var restartPolicies = []string{
|
||||||
string(container.RestartPolicyUnlessStopped),
|
string(container.RestartPolicyUnlessStopped),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addCompletions adds the completions that `run` and `create` have in common.
|
||||||
|
func addCompletions(cmd *cobra.Command, dockerCLI completion.APIClientProvider) {
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("attach", completion.FromList("stderr", "stdin", "stdout"))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("cap-add", completeLinuxCapabilityNames)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("cap-drop", completeLinuxCapabilityNames)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("cgroupns", completeCgroupns())
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("ipc", completeIpc(dockerCLI))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("link", completeLink(dockerCLI))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("log-driver", completeLogDriver(dockerCLI))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("log-opt", completeLogOpt)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("network", completion.NetworkNames(dockerCLI))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("pid", completePid(dockerCLI))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("pull", completion.FromList(PullImageAlways, PullImageMissing, PullImageNever))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("restart", completeRestartPolicies)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("security-opt", completeSecurityOpt)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("stop-signal", completeSignals)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("storage-opt", completeStorageOpt)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("ulimit", completeUlimit)
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("userns", completion.FromList("host"))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("uts", completion.FromList("host"))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("volume-driver", completeVolumeDriver(dockerCLI))
|
||||||
|
_ = cmd.RegisterFlagCompletionFunc("volumes-from", completion.ContainerNames(dockerCLI, true))
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeCgroupns implements shell completion for the `--cgroupns` option of `run` and `create`.
|
||||||
|
func completeCgroupns() completion.ValidArgsFn {
|
||||||
|
return completion.FromList(string(container.CgroupnsModeHost), string(container.CgroupnsModePrivate))
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeDetachKeys implements shell completion for the `--detach-keys` option of `run` and `create`.
|
||||||
|
func completeDetachKeys(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
return []string{"ctrl-"}, cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeIpc implements shell completion for the `--ipc` option of `run` and `create`.
|
||||||
|
// The completion is partly composite.
|
||||||
|
func completeIpc(dockerCLI completion.APIClientProvider) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
if len(toComplete) > 0 && strings.HasPrefix("container", toComplete) { //nolint:gocritic // not swapped, matches partly typed "container"
|
||||||
|
return []string{"container:"}, cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(toComplete, "container:") {
|
||||||
|
names, _ := completion.ContainerNames(dockerCLI, true)(cmd, args, toComplete)
|
||||||
|
return prefixWith("container:", names), cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
return []string{
|
||||||
|
string(container.IPCModeContainer + ":"),
|
||||||
|
string(container.IPCModeHost),
|
||||||
|
string(container.IPCModeNone),
|
||||||
|
string(container.IPCModePrivate),
|
||||||
|
string(container.IPCModeShareable),
|
||||||
|
}, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeLink implements shell completion for the `--link` option of `run` and `create`.
|
||||||
|
func completeLink(dockerCLI completion.APIClientProvider) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
return postfixWith(":", containerNames(dockerCLI, cmd, args, toComplete)), cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeLogDriver implements shell completion for the `--log-driver` option of `run` and `create`.
|
||||||
|
// The log drivers are collected from a call to the Info endpoint with a fallback to a hard-coded list
|
||||||
|
// of the build-in log drivers.
|
||||||
|
func completeLogDriver(dockerCLI completion.APIClientProvider) completion.ValidArgsFn {
|
||||||
|
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
info, err := dockerCLI.Client().Info(cmd.Context())
|
||||||
|
if err != nil {
|
||||||
|
return builtInLogDrivers(), cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
drivers := info.Plugins.Log
|
||||||
|
return drivers, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeLogOpt implements shell completion for the `--log-opt` option of `run` and `create`.
|
||||||
|
// If the user supplied a log-driver, only options for that driver are returned.
|
||||||
|
func completeLogOpt(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
driver, _ := cmd.Flags().GetString("log-driver")
|
||||||
|
if options, exists := logDriverOptions[driver]; exists {
|
||||||
|
return postfixWith("=", options), cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
return postfixWith("=", allLogDriverOptions()), cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
|
||||||
|
// completePid implements shell completion for the `--pid` option of `run` and `create`.
|
||||||
|
func completePid(dockerCLI completion.APIClientProvider) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
if len(toComplete) > 0 && strings.HasPrefix("container", toComplete) { //nolint:gocritic // not swapped, matches partly typed "container"
|
||||||
|
return []string{"container:"}, cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(toComplete, "container:") {
|
||||||
|
names, _ := completion.ContainerNames(dockerCLI, true)(cmd, args, toComplete)
|
||||||
|
return prefixWith("container:", names), cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
return []string{"container:", "host"}, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeSecurityOpt implements shell completion for the `--security-opt` option of `run` and `create`.
|
||||||
|
// The completion is partly composite.
|
||||||
|
func completeSecurityOpt(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
if len(toComplete) > 0 && strings.HasPrefix("apparmor=", toComplete) { //nolint:gocritic // not swapped, matches partly typed "apparmor="
|
||||||
|
return []string{"apparmor="}, cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
if len(toComplete) > 0 && strings.HasPrefix("label", toComplete) { //nolint:gocritic // not swapped, matches partly typed "label"
|
||||||
|
return []string{"label="}, cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(toComplete, "label=") {
|
||||||
|
if strings.HasPrefix(toComplete, "label=d") {
|
||||||
|
return []string{"label=disable"}, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
labels := []string{"disable", "level:", "role:", "type:", "user:"}
|
||||||
|
return prefixWith("label=", labels), cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
// length must be > 1 here so that completion of "s" falls through.
|
||||||
|
if len(toComplete) > 1 && strings.HasPrefix("seccomp", toComplete) { //nolint:gocritic // not swapped, matches partly typed "seccomp"
|
||||||
|
return []string{"seccomp="}, cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(toComplete, "seccomp=") {
|
||||||
|
return []string{"seccomp=unconfined"}, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
return []string{"apparmor=", "label=", "no-new-privileges", "seccomp=", "systempaths=unconfined"}, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeStorageOpt implements shell completion for the `--storage-opt` option of `run` and `create`.
|
||||||
|
func completeStorageOpt(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
return []string{"size="}, cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeUlimit implements shell completion for the `--ulimit` option of `run` and `create`.
|
||||||
|
func completeUlimit(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
limits := []string{
|
||||||
|
"as",
|
||||||
|
"chroot",
|
||||||
|
"core",
|
||||||
|
"cpu",
|
||||||
|
"data",
|
||||||
|
"fsize",
|
||||||
|
"locks",
|
||||||
|
"maxlogins",
|
||||||
|
"maxsyslogins",
|
||||||
|
"memlock",
|
||||||
|
"msgqueue",
|
||||||
|
"nice",
|
||||||
|
"nofile",
|
||||||
|
"nproc",
|
||||||
|
"priority",
|
||||||
|
"rss",
|
||||||
|
"rtprio",
|
||||||
|
"sigpending",
|
||||||
|
"stack",
|
||||||
|
}
|
||||||
|
return postfixWith("=", limits), cobra.ShellCompDirectiveNoSpace
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeVolumeDriver contacts the API to get the built-in and installed volume drivers.
|
||||||
|
func completeVolumeDriver(dockerCLI completion.APIClientProvider) completion.ValidArgsFn {
|
||||||
|
return func(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
info, err := dockerCLI.Client().Info(cmd.Context())
|
||||||
|
if err != nil {
|
||||||
|
// fallback: the built-in drivers
|
||||||
|
return []string{"local"}, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
drivers := info.Plugins.Volume
|
||||||
|
return drivers, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// containerNames contacts the API to get names and optionally IDs of containers.
|
||||||
|
// In case of an error, an empty list is returned.
|
||||||
|
func containerNames(dockerCLI completion.APIClientProvider, cmd *cobra.Command, args []string, toComplete string) []string {
|
||||||
|
names, _ := completion.ContainerNames(dockerCLI, true)(cmd, args, toComplete)
|
||||||
|
if names == nil {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefixWith prefixes every element in the slice with the given prefix.
|
||||||
|
func prefixWith(prefix string, values []string) []string {
|
||||||
|
result := make([]string, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
result[i] = prefix + v
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// postfixWith appends postfix to every element in the slice.
|
||||||
|
func postfixWith(postfix string, values []string) []string {
|
||||||
|
result := make([]string, len(values))
|
||||||
|
for i, v := range values {
|
||||||
|
result[i] = v + postfix
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func completeLinuxCapabilityNames(cmd *cobra.Command, args []string, toComplete string) (names []string, _ cobra.ShellCompDirective) {
|
func completeLinuxCapabilityNames(cmd *cobra.Command, args []string, toComplete string) (names []string, _ cobra.ShellCompDirective) {
|
||||||
return completion.FromList(allLinuxCapabilities()...)(cmd, args, toComplete)
|
return completion.FromList(allLinuxCapabilities()...)(cmd, args, toComplete)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/cli/internal/test"
|
||||||
|
"github.com/docker/cli/internal/test/builders"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/moby/sys/signal"
|
"github.com/moby/sys/signal"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
|
@ -21,6 +24,48 @@ func TestCompleteLinuxCapabilityNames(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompletePid(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
containerListFunc func(container.ListOptions) ([]container.Summary, error)
|
||||||
|
toComplete string
|
||||||
|
expectedCompletions []string
|
||||||
|
expectedDirective cobra.ShellCompDirective
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
toComplete: "",
|
||||||
|
expectedCompletions: []string{"container:", "host"},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoFileComp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toComplete: "c",
|
||||||
|
expectedCompletions: []string{"container:"},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoSpace,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
containerListFunc: func(container.ListOptions) ([]container.Summary, error) {
|
||||||
|
return []container.Summary{
|
||||||
|
*builders.Container("c1"),
|
||||||
|
*builders.Container("c2"),
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
toComplete: "container:",
|
||||||
|
expectedCompletions: []string{"container:c1", "container:c2"},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoFileComp,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.toComplete, func(t *testing.T) {
|
||||||
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
|
containerListFunc: tc.containerListFunc,
|
||||||
|
})
|
||||||
|
completions, directive := completePid(cli)(NewRunCommand(cli), nil, tc.toComplete)
|
||||||
|
assert.Check(t, is.DeepEqual(completions, tc.expectedCompletions))
|
||||||
|
assert.Check(t, is.Equal(directive, tc.expectedDirective))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCompleteRestartPolicies(t *testing.T) {
|
func TestCompleteRestartPolicies(t *testing.T) {
|
||||||
values, directives := completeRestartPolicies(nil, nil, "")
|
values, directives := completeRestartPolicies(nil, nil, "")
|
||||||
assert.Check(t, is.Equal(directives&cobra.ShellCompDirectiveNoFileComp, cobra.ShellCompDirectiveNoFileComp), "Should not perform file completion")
|
assert.Check(t, is.Equal(directives&cobra.ShellCompDirectiveNoFileComp, cobra.ShellCompDirectiveNoFileComp), "Should not perform file completion")
|
||||||
|
@ -28,6 +73,59 @@ func TestCompleteRestartPolicies(t *testing.T) {
|
||||||
assert.Check(t, is.DeepEqual(values, expected))
|
assert.Check(t, is.DeepEqual(values, expected))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompleteSecurityOpt(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
toComplete string
|
||||||
|
expectedCompletions []string
|
||||||
|
expectedDirective cobra.ShellCompDirective
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
toComplete: "",
|
||||||
|
expectedCompletions: []string{"apparmor=", "label=", "no-new-privileges", "seccomp=", "systempaths=unconfined"},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoFileComp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toComplete: "apparmor=",
|
||||||
|
expectedCompletions: []string{"apparmor="},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoSpace,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toComplete: "label=",
|
||||||
|
expectedCompletions: []string{"label=disable", "label=level:", "label=role:", "label=type:", "label=user:"},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toComplete: "s",
|
||||||
|
// We do not filter matching completions but delegate this task to the shell script.
|
||||||
|
expectedCompletions: []string{"apparmor=", "label=", "no-new-privileges", "seccomp=", "systempaths=unconfined"},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoFileComp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toComplete: "se",
|
||||||
|
expectedCompletions: []string{"seccomp="},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoSpace,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toComplete: "seccomp=",
|
||||||
|
expectedCompletions: []string{"seccomp=unconfined"},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoFileComp,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toComplete: "sy",
|
||||||
|
expectedCompletions: []string{"apparmor=", "label=", "no-new-privileges", "seccomp=", "systempaths=unconfined"},
|
||||||
|
expectedDirective: cobra.ShellCompDirectiveNoFileComp,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.toComplete, func(t *testing.T) {
|
||||||
|
completions, directive := completeSecurityOpt(nil, nil, tc.toComplete)
|
||||||
|
assert.Check(t, is.DeepEqual(completions, tc.expectedCompletions))
|
||||||
|
assert.Check(t, is.Equal(directive, tc.expectedDirective))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCompleteSignals(t *testing.T) {
|
func TestCompleteSignals(t *testing.T) {
|
||||||
values, directives := completeSignals(nil, nil, "")
|
values, directives := completeSignals(nil, nil, "")
|
||||||
assert.Check(t, is.Equal(directives&cobra.ShellCompDirectiveNoFileComp, cobra.ShellCompDirectiveNoFileComp), "Should not perform file completion")
|
assert.Check(t, is.Equal(directives&cobra.ShellCompDirectiveNoFileComp, cobra.ShellCompDirectiveNoFileComp), "Should not perform file completion")
|
||||||
|
|
|
@ -78,16 +78,15 @@ func NewCreateCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
command.AddTrustVerificationFlags(flags, &options.untrusted, dockerCli.ContentTrustEnabled())
|
command.AddTrustVerificationFlags(flags, &options.untrusted, dockerCli.ContentTrustEnabled())
|
||||||
copts = addFlags(flags)
|
copts = addFlags(flags)
|
||||||
|
|
||||||
_ = cmd.RegisterFlagCompletionFunc("cap-add", completeLinuxCapabilityNames)
|
addCompletions(cmd, dockerCli)
|
||||||
_ = cmd.RegisterFlagCompletionFunc("cap-drop", completeLinuxCapabilityNames)
|
|
||||||
_ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames)
|
flags.VisitAll(func(flag *pflag.Flag) {
|
||||||
_ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames)
|
// Set a default completion function if none was set. We don't look
|
||||||
_ = cmd.RegisterFlagCompletionFunc("network", completion.NetworkNames(dockerCli))
|
// up if it does already have one set, because Cobra does this for
|
||||||
_ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms)
|
// us, and returns an error (which we ignore for this reason).
|
||||||
_ = cmd.RegisterFlagCompletionFunc("pull", completion.FromList(PullImageAlways, PullImageMissing, PullImageNever))
|
_ = cmd.RegisterFlagCompletionFunc(flag.Name, completion.NoComplete)
|
||||||
_ = cmd.RegisterFlagCompletionFunc("restart", completeRestartPolicies)
|
})
|
||||||
_ = cmd.RegisterFlagCompletionFunc("stop-signal", completeSignals)
|
|
||||||
_ = cmd.RegisterFlagCompletionFunc("volumes-from", completion.ContainerNames(dockerCli, true))
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package container
|
package container
|
||||||
|
|
||||||
|
|
|
@ -69,16 +69,16 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
command.AddTrustVerificationFlags(flags, &options.untrusted, dockerCli.ContentTrustEnabled())
|
command.AddTrustVerificationFlags(flags, &options.untrusted, dockerCli.ContentTrustEnabled())
|
||||||
copts = addFlags(flags)
|
copts = addFlags(flags)
|
||||||
|
|
||||||
_ = cmd.RegisterFlagCompletionFunc("cap-add", completeLinuxCapabilityNames)
|
_ = cmd.RegisterFlagCompletionFunc("detach-keys", completeDetachKeys)
|
||||||
_ = cmd.RegisterFlagCompletionFunc("cap-drop", completeLinuxCapabilityNames)
|
addCompletions(cmd, dockerCli)
|
||||||
_ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames)
|
|
||||||
_ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames)
|
flags.VisitAll(func(flag *pflag.Flag) {
|
||||||
_ = cmd.RegisterFlagCompletionFunc("network", completion.NetworkNames(dockerCli))
|
// Set a default completion function if none was set. We don't look
|
||||||
_ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms)
|
// up if it does already have one set, because Cobra does this for
|
||||||
_ = cmd.RegisterFlagCompletionFunc("pull", completion.FromList(PullImageAlways, PullImageMissing, PullImageNever))
|
// us, and returns an error (which we ignore for this reason).
|
||||||
_ = cmd.RegisterFlagCompletionFunc("restart", completeRestartPolicies)
|
_ = cmd.RegisterFlagCompletionFunc(flag.Name, completion.NoComplete)
|
||||||
_ = cmd.RegisterFlagCompletionFunc("stop-signal", completeSignals)
|
})
|
||||||
_ = cmd.RegisterFlagCompletionFunc("volumes-from", completion.ContainerNames(dockerCli, true))
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -287,16 +287,26 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
|
||||||
cStats.mu.RUnlock()
|
cStats.mu.RUnlock()
|
||||||
|
|
||||||
if !options.NoStream {
|
if !options.NoStream {
|
||||||
// Start by clearing the screen and moving the cursor to the top-left
|
// Start by moving the cursor to the top-left
|
||||||
_, _ = fmt.Fprint(&statsTextBuffer, "\033[2J\033[H")
|
_, _ = fmt.Fprint(&statsTextBuffer, "\033[H")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = statsFormatWrite(statsCtx, ccStats, daemonOSType, !options.NoTrunc); err != nil {
|
if err = statsFormatWrite(statsCtx, ccStats, daemonOSType, !options.NoTrunc); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprint(dockerCLI.Out(), statsTextBuffer.String())
|
if !options.NoStream {
|
||||||
|
for _, line := range strings.Split(statsTextBuffer.String(), "\n") {
|
||||||
|
// In case the new text is shorter than the one we are writing over,
|
||||||
|
// we'll append the "erase line" escape sequence to clear the remaining text.
|
||||||
|
_, _ = fmt.Fprint(&statsTextBuffer, line, "\033[K\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We might have fewer containers than before, so let's clear the remaining text
|
||||||
|
_, _ = fmt.Fprint(&statsTextBuffer, "\033[J")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _ = fmt.Fprint(dockerCLI.Out(), statsTextBuffer.String())
|
||||||
statsTextBuffer.Reset()
|
statsTextBuffer.Reset()
|
||||||
|
|
||||||
if len(cStats.cs) == 0 && !showAll {
|
if len(cStats.cs) == 0 && !showAll {
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package context
|
package context
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package context
|
package context
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package context
|
package context
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package context
|
package context
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package idresolver
|
package idresolver
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package image
|
package image
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,8 @@ func runLoad(ctx context.Context, dockerCli command.Cli, opts loadOptions) error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "invalid platform")
|
return errors.Wrap(err, "invalid platform")
|
||||||
}
|
}
|
||||||
options.Platform = &p
|
// TODO(thaJeztah): change flag-type to support multiple platforms.
|
||||||
|
options.Platforms = append(options.Platforms, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := dockerCli.Client().ImageLoad(ctx, input, options)
|
response, err := dockerCli.Client().ImageLoad(ctx, input, options)
|
||||||
|
|
|
@ -109,7 +109,7 @@ func TestNewLoadCommandSuccess(t *testing.T) {
|
||||||
name: "with platform",
|
name: "with platform",
|
||||||
args: []string{"--platform", "linux/amd64"},
|
args: []string{"--platform", "linux/amd64"},
|
||||||
imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
|
imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
|
||||||
assert.Check(t, is.DeepEqual(ocispec.Platform{OS: "linux", Architecture: "amd64"}, *options.Platform))
|
assert.Check(t, is.DeepEqual([]ocispec.Platform{{OS: "linux", Architecture: "amd64"}}, options.Platforms))
|
||||||
return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package image
|
package image
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,8 @@ func RunSave(ctx context.Context, dockerCli command.Cli, opts saveOptions) error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "invalid platform")
|
return errors.Wrap(err, "invalid platform")
|
||||||
}
|
}
|
||||||
options.Platform = &p
|
// TODO(thaJeztah): change flag-type to support multiple platforms.
|
||||||
|
options.Platforms = append(options.Platforms, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
responseBody, err := dockerCli.Client().ImageSave(ctx, opts.images, options)
|
responseBody, err := dockerCli.Client().ImageSave(ctx, opts.images, options)
|
||||||
|
|
|
@ -106,7 +106,7 @@ func TestNewSaveCommandSuccess(t *testing.T) {
|
||||||
imageSaveFunc: func(images []string, options image.SaveOptions) (io.ReadCloser, error) {
|
imageSaveFunc: func(images []string, options image.SaveOptions) (io.ReadCloser, error) {
|
||||||
assert.Assert(t, is.Len(images, 1))
|
assert.Assert(t, is.Len(images, 1))
|
||||||
assert.Check(t, is.Equal("arg1", images[0]))
|
assert.Check(t, is.Equal("arg1", images[0]))
|
||||||
assert.Check(t, is.DeepEqual(ocispec.Platform{OS: "linux", Architecture: "amd64"}, *options.Platform))
|
assert.Check(t, is.DeepEqual([]ocispec.Platform{{OS: "linux", Architecture: "amd64"}}, options.Platforms))
|
||||||
return io.NopCloser(strings.NewReader("")), nil
|
return io.NopCloser(strings.NewReader("")), nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package inspect
|
package inspect
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package node
|
package node
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package node
|
package node
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package plugin
|
package plugin
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package plugin
|
package plugin
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package secret
|
package secret
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package service
|
package service
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package service
|
package service
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package service
|
package service
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package service
|
package service
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// FIXME(jsternberg): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package trust
|
package trust
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package command
|
package command
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package volume
|
package volume
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package interpolation
|
package interpolation
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package interpolation
|
package interpolation
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package template
|
package template
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package template
|
package template
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package store
|
package store
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package store
|
package store
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package store
|
package store
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package store
|
package store
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package store
|
package store
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package store
|
package store
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package api
|
package api
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
@ -572,7 +572,16 @@ func areFlagsSupported(cmd *cobra.Command, details versionDetails) error {
|
||||||
if _, ok := f.Annotations["experimental"]; ok && !details.ServerInfo().HasExperimental {
|
if _, ok := f.Annotations["experimental"]; ok && !details.ServerInfo().HasExperimental {
|
||||||
errs = append(errs, fmt.Sprintf(`"--%s" is only supported on a Docker daemon with experimental features enabled`, f.Name))
|
errs = append(errs, fmt.Sprintf(`"--%s" is only supported on a Docker daemon with experimental features enabled`, f.Name))
|
||||||
}
|
}
|
||||||
// buildkit-specific flags are noop when buildkit is not enabled, so we do not add an error in that case
|
if _, ok := f.Annotations["buildkit"]; ok {
|
||||||
|
if v, _ := command.BuildKitEnabled(details.ServerInfo()); !v {
|
||||||
|
errs = append(errs, fmt.Sprintf(`"--%s" is only supported with BuildKit enabled. Enable BuildKit with DOCKER_BUILDKIT=1`, f.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, ok := f.Annotations["no-buildkit"]; ok {
|
||||||
|
if v, _ := command.BuildKitEnabled(details.ServerInfo()); v {
|
||||||
|
errs = append(errs, fmt.Sprintf(`"--%s" is not supported with BuildKit enabled. Disable BuildKit with DOCKER_BUILDKIT=0`, f.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
return errors.New(strings.Join(errs, "\n"))
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
ARG GO_VERSION=1.23.3
|
ARG GO_VERSION=1.23.3
|
||||||
ARG ALPINE_VERSION=3.20
|
ARG ALPINE_VERSION=3.20
|
||||||
ARG GOLANGCI_LINT_VERSION=v1.61.0
|
ARG GOLANGCI_LINT_VERSION=v1.62.0
|
||||||
|
|
||||||
FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint
|
FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint
|
||||||
|
|
||||||
|
|
|
@ -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:
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||||
//go:build go1.21
|
//go:build go1.22
|
||||||
|
|
||||||
package templates
|
package templates
|
||||||
|
|
||||||
|
|
|
@ -13,20 +13,20 @@ require (
|
||||||
github.com/distribution/reference v0.6.0
|
github.com/distribution/reference v0.6.0
|
||||||
github.com/docker/cli-docs-tool v0.8.0
|
github.com/docker/cli-docs-tool v0.8.0
|
||||||
github.com/docker/distribution v2.8.3+incompatible
|
github.com/docker/distribution v2.8.3+incompatible
|
||||||
github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible // master (v-next)
|
github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible // master (v-next)
|
||||||
github.com/docker/docker-credential-helpers v0.8.2
|
github.com/docker/docker-credential-helpers v0.8.2
|
||||||
github.com/docker/go-connections v0.5.0
|
github.com/docker/go-connections v0.5.0
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
github.com/fvbommel/sortorder v1.1.0
|
github.com/fvbommel/sortorder v1.1.0
|
||||||
github.com/go-jose/go-jose/v4 v4.0.4
|
github.com/go-jose/go-jose/v4 v4.0.4
|
||||||
github.com/go-viper/mapstructure/v2 v2.0.0
|
github.com/go-viper/mapstructure/v2 v2.2.1
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
github.com/google/go-cmp v0.6.0
|
github.com/google/go-cmp v0.6.0
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
github.com/mattn/go-runewidth v0.0.15
|
github.com/mattn/go-runewidth v0.0.15
|
||||||
github.com/moby/patternmatcher v0.6.0
|
github.com/moby/patternmatcher v0.6.0
|
||||||
github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e
|
github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e
|
||||||
github.com/moby/sys/capability v0.3.0
|
github.com/moby/sys/capability v0.4.0
|
||||||
github.com/moby/sys/sequential v0.6.0
|
github.com/moby/sys/sequential v0.6.0
|
||||||
github.com/moby/sys/signal v0.7.1
|
github.com/moby/sys/signal v0.7.1
|
||||||
github.com/moby/term v0.5.0
|
github.com/moby/term v0.5.0
|
||||||
|
@ -39,7 +39,7 @@ require (
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a
|
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a
|
||||||
github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d
|
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
go.opentelemetry.io/otel v1.28.0
|
go.opentelemetry.io/otel v1.28.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0
|
||||||
|
|
16
vendor.sum
16
vendor.sum
|
@ -51,8 +51,8 @@ github.com/docker/cli-docs-tool v0.8.0/go.mod h1:8TQQ3E7mOXoYUs811LiPdUnAhXrcVsB
|
||||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible h1:kSQ4U+63JfFxIOrTo6wMW1mqkOkPpiTe/7ZfvUdNLVE=
|
github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible h1:ZWh4HhdUCagAd3S+gsFPOobHbc562obYFSrz3irGSsU=
|
||||||
github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||||
|
@ -89,8 +89,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
|
||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
|
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||||
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
@ -168,8 +168,8 @@ github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkV
|
||||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||||
github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e h1:1yC8fRqStY6NirU/swI74fsrHvZVMbtxsHcvl8YpzDg=
|
github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e h1:1yC8fRqStY6NirU/swI74fsrHvZVMbtxsHcvl8YpzDg=
|
||||||
github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e/go.mod h1:mTTGIAz/59OGZR5Qe+QByIe3Nxc+sSuJkrsStFhr6Lg=
|
github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e/go.mod h1:mTTGIAz/59OGZR5Qe+QByIe3Nxc+sSuJkrsStFhr6Lg=
|
||||||
github.com/moby/sys/capability v0.3.0 h1:kEP+y6te0gEXIaeQhIi0s7vKs/w0RPoH1qPa6jROcVg=
|
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
|
||||||
github.com/moby/sys/capability v0.3.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
|
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
|
||||||
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||||
github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
|
github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
|
||||||
|
@ -266,8 +266,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a h1:tlJ7tGUHvcvL1v3yR6NcCc9nOqh2L+CG6HWrYQtwzQ0=
|
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a h1:tlJ7tGUHvcvL1v3yR6NcCc9nOqh2L+CG6HWrYQtwzQ0=
|
||||||
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a/go.mod h1:Y94A6rPp2OwNfP/7vmf8O2xx2IykP8pPXQ1DLouGnEw=
|
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a/go.mod h1:Y94A6rPp2OwNfP/7vmf8O2xx2IykP8pPXQ1DLouGnEw=
|
||||||
github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d h1:wvQZpqy8p0D/FUia6ipKDhXrzPzBVJE4PZyPc5+5Ay0=
|
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 h1:TvtdmeYsYEij78hS4oxnwikoiLdIrgav3BA+CbhaDAI=
|
||||||
github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d/go.mod h1:xKQhd7snlzKFuUi1taTGWjpRE8iFTA06DeacYi3CVFQ=
|
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346/go.mod h1:xKQhd7snlzKFuUi1taTGWjpRE8iFTA06DeacYi3CVFQ=
|
||||||
github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b h1:FsyNrX12e5BkplJq7wKOLk0+C6LZ+KGXvuEcKUYm5ss=
|
github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b h1:FsyNrX12e5BkplJq7wKOLk0+C6LZ+KGXvuEcKUYm5ss=
|
||||||
github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE=
|
github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
|
|
@ -1991,6 +1991,18 @@ definitions:
|
||||||
type: "string"
|
type: "string"
|
||||||
x-nullable: false
|
x-nullable: false
|
||||||
example: "sha256:ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710"
|
example: "sha256:ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710"
|
||||||
|
Descriptor:
|
||||||
|
description: |
|
||||||
|
Descriptor is an OCI descriptor of the image target.
|
||||||
|
In case of a multi-platform image, this descriptor points to the OCI index
|
||||||
|
or a manifest list.
|
||||||
|
|
||||||
|
This field is only present if the daemon provides a multi-platform image store.
|
||||||
|
|
||||||
|
WARNING: This is experimental and may change at any time without any backward
|
||||||
|
compatibility.
|
||||||
|
x-nullable: true
|
||||||
|
$ref: "#/definitions/OCIDescriptor"
|
||||||
RepoTags:
|
RepoTags:
|
||||||
description: |
|
description: |
|
||||||
List of image names/tags in the local image cache that reference this
|
List of image names/tags in the local image cache that reference this
|
||||||
|
@ -2278,6 +2290,18 @@ definitions:
|
||||||
x-omitempty: true
|
x-omitempty: true
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/ImageManifestSummary"
|
$ref: "#/definitions/ImageManifestSummary"
|
||||||
|
Descriptor:
|
||||||
|
description: |
|
||||||
|
Descriptor is an OCI descriptor of the image target.
|
||||||
|
In case of a multi-platform image, this descriptor points to the OCI index
|
||||||
|
or a manifest list.
|
||||||
|
|
||||||
|
This field is only present if the daemon provides a multi-platform image store.
|
||||||
|
|
||||||
|
WARNING: This is experimental and may change at any time without any backward
|
||||||
|
compatibility.
|
||||||
|
x-nullable: true
|
||||||
|
$ref: "#/definitions/OCIDescriptor"
|
||||||
|
|
||||||
AuthConfig:
|
AuthConfig:
|
||||||
type: "object"
|
type: "object"
|
||||||
|
@ -7242,6 +7266,14 @@ paths:
|
||||||
type: "string"
|
type: "string"
|
||||||
Platform:
|
Platform:
|
||||||
type: "string"
|
type: "string"
|
||||||
|
ImageManifestDescriptor:
|
||||||
|
$ref: "#/definitions/OCIDescriptor"
|
||||||
|
description: |
|
||||||
|
OCI descriptor of the platform-specific manifest of the image
|
||||||
|
the container was created from.
|
||||||
|
|
||||||
|
Note: Only available if the daemon provides a multi-platform
|
||||||
|
image store.
|
||||||
MountLabel:
|
MountLabel:
|
||||||
type: "string"
|
type: "string"
|
||||||
ProcessLabel:
|
ProcessLabel:
|
||||||
|
@ -9210,9 +9242,14 @@ paths:
|
||||||
type: "string"
|
type: "string"
|
||||||
in: "query"
|
in: "query"
|
||||||
description: |
|
description: |
|
||||||
JSON encoded OCI platform describing platform to show the history for.
|
JSON-encoded OCI platform to select the platform-variant.
|
||||||
If not provided, the host platform will be used. If it's not
|
If omitted, it defaults to any locally available platform,
|
||||||
available, any present platform will be picked.
|
prioritizing the daemon's host platform.
|
||||||
|
|
||||||
|
If the daemon provides a multi-platform image store, this selects
|
||||||
|
the platform-variant to show the history for. If the image is
|
||||||
|
a single-platform image, or if the multi-platform image does not
|
||||||
|
provide a variant matching the given platform, an error is returned.
|
||||||
|
|
||||||
Example: `{"os": "linux", "architecture": "arm", "variant": "v5"}`
|
Example: `{"os": "linux", "architecture": "arm", "variant": "v5"}`
|
||||||
tags: ["Image"]
|
tags: ["Image"]
|
||||||
|
@ -9262,6 +9299,19 @@ paths:
|
||||||
all tags of the given image that are present in the local image store
|
all tags of the given image that are present in the local image store
|
||||||
are pushed.
|
are pushed.
|
||||||
type: "string"
|
type: "string"
|
||||||
|
- name: "platform"
|
||||||
|
type: "string"
|
||||||
|
in: "query"
|
||||||
|
description: |
|
||||||
|
JSON-encoded OCI platform to select the platform-variant to push.
|
||||||
|
If not provided, all available variants will attempt to be pushed.
|
||||||
|
|
||||||
|
If the daemon provides a multi-platform image store, this selects
|
||||||
|
the platform-variant to push to the registry. If the image is
|
||||||
|
a single-platform image, or if the multi-platform image does not
|
||||||
|
provide a variant matching the given platform, an error is returned.
|
||||||
|
|
||||||
|
Example: `{"os": "linux", "architecture": "arm", "variant": "v5"}`
|
||||||
- name: "X-Registry-Auth"
|
- name: "X-Registry-Auth"
|
||||||
in: "header"
|
in: "header"
|
||||||
description: |
|
description: |
|
||||||
|
@ -9271,11 +9321,6 @@ paths:
|
||||||
details.
|
details.
|
||||||
type: "string"
|
type: "string"
|
||||||
required: true
|
required: true
|
||||||
- name: "platform"
|
|
||||||
in: "query"
|
|
||||||
description: "Select a platform-specific manifest to be pushed. OCI platform (JSON encoded)"
|
|
||||||
type: "string"
|
|
||||||
x-nullable: true
|
|
||||||
tags: ["Image"]
|
tags: ["Image"]
|
||||||
/images/{name}/tag:
|
/images/{name}/tag:
|
||||||
post:
|
post:
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/mount"
|
"github.com/docker/docker/api/types/mount"
|
||||||
"github.com/docker/docker/api/types/storage"
|
"github.com/docker/docker/api/types/storage"
|
||||||
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PruneReport contains the response for Engine API:
|
// PruneReport contains the response for Engine API:
|
||||||
|
@ -171,4 +172,6 @@ type InspectResponse struct {
|
||||||
Mounts []MountPoint
|
Mounts []MountPoint
|
||||||
Config *Config
|
Config *Config
|
||||||
NetworkSettings *NetworkSettings
|
NetworkSettings *NetworkSettings
|
||||||
|
// ImageManifestDescriptor is the descriptor of a platform-specific manifest of the image used to create the container.
|
||||||
|
ImageManifestDescriptor *ocispec.Descriptor `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/api/types/strslice"
|
"github.com/docker/docker/api/types/strslice"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
units "github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CgroupnsMode represents the cgroup namespace mode of the container
|
// CgroupnsMode represents the cgroup namespace mode of the container
|
||||||
|
|
|
@ -3,6 +3,7 @@ package image
|
||||||
import (
|
import (
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/storage"
|
"github.com/docker/docker/api/types/storage"
|
||||||
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RootFS returns Image's RootFS description including the layer IDs.
|
// RootFS returns Image's RootFS description including the layer IDs.
|
||||||
|
@ -119,4 +120,11 @@ type InspectResponse struct {
|
||||||
//
|
//
|
||||||
// This information is local to the daemon, and not part of the image itself.
|
// This information is local to the daemon, and not part of the image itself.
|
||||||
Metadata Metadata
|
Metadata Metadata
|
||||||
|
|
||||||
|
// Descriptor is the OCI descriptor of the image target.
|
||||||
|
// It's only set if the daemon provides a multi-platform image store.
|
||||||
|
//
|
||||||
|
// WARNING: This is experimental and may change at any time without any backward
|
||||||
|
// compatibility.
|
||||||
|
Descriptor *ocispec.Descriptor `json:"Descriptor,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,12 +98,14 @@ type LoadOptions struct {
|
||||||
// Quiet suppresses progress output
|
// Quiet suppresses progress output
|
||||||
Quiet bool
|
Quiet bool
|
||||||
|
|
||||||
// Platform is a specific platform to load when the image is a multi-platform
|
// Platforms selects the platforms to load if the image is a
|
||||||
Platform *ocispec.Platform
|
// multi-platform image and has multiple variants.
|
||||||
|
Platforms []ocispec.Platform
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveOptions holds parameters to save images.
|
// SaveOptions holds parameters to save images.
|
||||||
type SaveOptions struct {
|
type SaveOptions struct {
|
||||||
// Platform is a specific platform to save if the image is a multi-platform image.
|
// Platforms selects the platforms to save if the image is a
|
||||||
Platform *ocispec.Platform
|
// multi-platform image and has multiple variants.
|
||||||
|
Platforms []ocispec.Platform
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package image
|
package image
|
||||||
|
|
||||||
|
import ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
|
||||||
type Summary struct {
|
type Summary struct {
|
||||||
|
|
||||||
// Number of containers using this image. Includes both stopped and running
|
// Number of containers using this image. Includes both stopped and running
|
||||||
|
@ -42,6 +44,13 @@ type Summary struct {
|
||||||
// Required: true
|
// Required: true
|
||||||
ParentID string `json:"ParentId"`
|
ParentID string `json:"ParentId"`
|
||||||
|
|
||||||
|
// Descriptor is the OCI descriptor of the image target.
|
||||||
|
// It's only set if the daemon provides a multi-platform image store.
|
||||||
|
//
|
||||||
|
// WARNING: This is experimental and may change at any time without any backward
|
||||||
|
// compatibility.
|
||||||
|
Descriptor *ocispec.Descriptor `json:"Descriptor,omitempty"`
|
||||||
|
|
||||||
// Manifests is a list of image manifests available in this image. It
|
// Manifests is a list of image manifests available in this image. It
|
||||||
// provides a more detailed view of the platform-specific image manifests or
|
// provides a more detailed view of the platform-specific image manifests or
|
||||||
// other image-attached data like build attestations.
|
// other image-attached data like build attestations.
|
||||||
|
|
|
@ -3,7 +3,6 @@ package client // import "github.com/docker/docker/client"
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
|
@ -11,26 +10,26 @@ import (
|
||||||
|
|
||||||
// ImageHistory returns the changes in an image in history format.
|
// ImageHistory returns the changes in an image in history format.
|
||||||
func (cli *Client) ImageHistory(ctx context.Context, imageID string, opts image.HistoryOptions) ([]image.HistoryResponseItem, error) {
|
func (cli *Client) ImageHistory(ctx context.Context, imageID string, opts image.HistoryOptions) ([]image.HistoryResponseItem, error) {
|
||||||
values := url.Values{}
|
query := url.Values{}
|
||||||
if opts.Platform != nil {
|
if opts.Platform != nil {
|
||||||
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := json.Marshal(*opts.Platform)
|
p, err := encodePlatform(opts.Platform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid platform: %v", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
values.Set("platform", string(p))
|
query.Set("platform", p)
|
||||||
|
}
|
||||||
|
|
||||||
|
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", query, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var history []image.HistoryResponseItem
|
var history []image.HistoryResponseItem
|
||||||
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", values, nil)
|
|
||||||
defer ensureReaderClosed(serverResp)
|
|
||||||
if err != nil {
|
|
||||||
return history, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.NewDecoder(serverResp.body).Decode(&history)
|
err = json.NewDecoder(serverResp.body).Decode(&history)
|
||||||
return history, err
|
return history, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,18 @@ func (cli *Client) ImageImport(ctx context.Context, source image.ImportSource, r
|
||||||
}
|
}
|
||||||
|
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
query.Set("fromSrc", source.SourceName)
|
if source.SourceName != "" {
|
||||||
query.Set("repo", ref)
|
query.Set("fromSrc", source.SourceName)
|
||||||
query.Set("tag", options.Tag)
|
}
|
||||||
query.Set("message", options.Message)
|
if ref != "" {
|
||||||
|
query.Set("repo", ref)
|
||||||
|
}
|
||||||
|
if options.Tag != "" {
|
||||||
|
query.Set("tag", options.Tag)
|
||||||
|
}
|
||||||
|
if options.Message != "" {
|
||||||
|
query.Set("message", options.Message)
|
||||||
|
}
|
||||||
if options.Platform != "" {
|
if options.Platform != "" {
|
||||||
query.Set("platform", strings.ToLower(options.Platform))
|
query.Set("platform", strings.ToLower(options.Platform))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -18,24 +17,24 @@ import (
|
||||||
// the provided multi-platform image. This is only has effect if the input image
|
// the provided multi-platform image. This is only has effect if the input image
|
||||||
// is a multi-platform image.
|
// is a multi-platform image.
|
||||||
func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, opts image.LoadOptions) (image.LoadResponse, error) {
|
func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, opts image.LoadOptions) (image.LoadResponse, error) {
|
||||||
v := url.Values{}
|
query := url.Values{}
|
||||||
v.Set("quiet", "0")
|
query.Set("quiet", "0")
|
||||||
if opts.Quiet {
|
if opts.Quiet {
|
||||||
v.Set("quiet", "1")
|
query.Set("quiet", "1")
|
||||||
}
|
}
|
||||||
if opts.Platform != nil {
|
if len(opts.Platforms) > 0 {
|
||||||
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
|
||||||
return image.LoadResponse{}, err
|
return image.LoadResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := json.Marshal(*opts.Platform)
|
p, err := encodePlatforms(opts.Platforms...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return image.LoadResponse{}, err
|
return image.LoadResponse{}, err
|
||||||
}
|
}
|
||||||
v.Set("platform", string(p))
|
query["platform"] = p
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.postRaw(ctx, "/images/load", v, input, http.Header{
|
resp, err := cli.postRaw(ctx, "/images/load", query, input, http.Header{
|
||||||
"Content-Type": {"application/x-tar"},
|
"Content-Type": {"application/x-tar"},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -2,8 +2,6 @@ package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
@ -17,16 +15,15 @@ func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, opts image.
|
||||||
"names": imageIDs,
|
"names": imageIDs,
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Platform != nil {
|
if len(opts.Platforms) > 0 {
|
||||||
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
|
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
p, err := encodePlatforms(opts.Platforms...)
|
||||||
p, err := json.Marshal(*opts.Platform)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid platform: %v", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
query.Set("platform", string(p))
|
query["platform"] = p
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.get(ctx, "/images/get", query, nil)
|
resp, err := cli.get(ctx, "/images/get", query, nil)
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`)
|
var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`)
|
||||||
|
@ -32,3 +36,43 @@ func getFiltersQuery(f filters.Args) (url.Values, error) {
|
||||||
}
|
}
|
||||||
return query, nil
|
return query, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encodePlatforms marshals the given platform(s) to JSON format, to
|
||||||
|
// be used for query-parameters for filtering / selecting platforms.
|
||||||
|
func encodePlatforms(platform ...ocispec.Platform) ([]string, error) {
|
||||||
|
if len(platform) == 0 {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
if len(platform) == 1 {
|
||||||
|
p, err := encodePlatform(&platform[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return []string{p}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
seen := make(map[string]struct{}, len(platform))
|
||||||
|
out := make([]string, 0, len(platform))
|
||||||
|
for i := range platform {
|
||||||
|
p, err := encodePlatform(&platform[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, ok := seen[p]; !ok {
|
||||||
|
out = append(out, p)
|
||||||
|
seen[p] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodePlatforms marshals the given platform to JSON format, to
|
||||||
|
// be used for query-parameters for filtering / selecting platforms. It
|
||||||
|
// is used as a helper for encodePlatforms,
|
||||||
|
func encodePlatform(platform *ocispec.Platform) (string, error) {
|
||||||
|
p, err := json.Marshal(platform)
|
||||||
|
if err != nil {
|
||||||
|
return "", errdefs.InvalidParameter(fmt.Errorf("invalid platform: %v", err))
|
||||||
|
}
|
||||||
|
return string(p), nil
|
||||||
|
}
|
||||||
|
|
|
@ -261,13 +261,13 @@ func readdirnames(dirname string) (names []nameIno, err error) {
|
||||||
func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno) {
|
func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno) {
|
||||||
origlen := len(buf)
|
origlen := len(buf)
|
||||||
for len(buf) > 0 {
|
for len(buf) > 0 {
|
||||||
dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0]))
|
dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited"
|
||||||
buf = buf[dirent.Reclen:]
|
buf = buf[dirent.Reclen:]
|
||||||
if dirent.Ino == 0 { // File absent in directory.
|
if dirent.Ino == 0 { // File absent in directory.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
|
b := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited"
|
||||||
name := string(bytes[0:clen(bytes[:])])
|
name := string(b[0:clen(b[:])])
|
||||||
if name == "." || name == ".." { // Useless names
|
if name == "." || name == ".." { // Useless names
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,11 @@ type subIDRange struct {
|
||||||
Length int
|
Length int
|
||||||
}
|
}
|
||||||
|
|
||||||
type ranges []subIDRange
|
type subIDRanges []subIDRange
|
||||||
|
|
||||||
func (e ranges) Len() int { return len(e) }
|
func (e subIDRanges) Len() int { return len(e) }
|
||||||
func (e ranges) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
|
func (e subIDRanges) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
|
||||||
func (e ranges) Less(i, j int) bool { return e[i].Start < e[j].Start }
|
func (e subIDRanges) Less(i, j int) bool { return e[i].Start < e[j].Start }
|
||||||
|
|
||||||
const (
|
const (
|
||||||
subuidFileName = "/etc/subuid"
|
subuidFileName = "/etc/subuid"
|
||||||
|
@ -162,7 +162,7 @@ func (i IdentityMapping) Empty() bool {
|
||||||
return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0
|
return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func createIDMap(subidRanges ranges) []IDMap {
|
func createIDMap(subidRanges subIDRanges) []IDMap {
|
||||||
idMap := []IDMap{}
|
idMap := []IDMap{}
|
||||||
|
|
||||||
containerID := 0
|
containerID := 0
|
||||||
|
@ -177,19 +177,19 @@ func createIDMap(subidRanges ranges) []IDMap {
|
||||||
return idMap
|
return idMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSubuid(username string) (ranges, error) {
|
func parseSubuid(username string) (subIDRanges, error) {
|
||||||
return parseSubidFile(subuidFileName, username)
|
return parseSubidFile(subuidFileName, username)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSubgid(username string) (ranges, error) {
|
func parseSubgid(username string) (subIDRanges, error) {
|
||||||
return parseSubidFile(subgidFileName, username)
|
return parseSubidFile(subgidFileName, username)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseSubidFile will read the appropriate file (/etc/subuid or /etc/subgid)
|
// parseSubidFile will read the appropriate file (/etc/subuid or /etc/subgid)
|
||||||
// and return all found ranges for a specified username. If the special value
|
// and return all found subIDRanges for a specified username. If the special value
|
||||||
// "ALL" is supplied for username, then all ranges in the file will be returned
|
// "ALL" is supplied for username, then all subIDRanges in the file will be returned
|
||||||
func parseSubidFile(path, username string) (ranges, error) {
|
func parseSubidFile(path, username string) (subIDRanges, error) {
|
||||||
var rangeList ranges
|
var rangeList subIDRanges
|
||||||
|
|
||||||
subidFile, err := os.Open(path)
|
subidFile, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -145,7 +145,7 @@ func findNextGIDRange() (int, error) {
|
||||||
return findNextRangeStart(ranges)
|
return findNextRangeStart(ranges)
|
||||||
}
|
}
|
||||||
|
|
||||||
func findNextRangeStart(rangeList ranges) (int, error) {
|
func findNextRangeStart(rangeList subIDRanges) (int, error) {
|
||||||
startID := defaultRangeStart
|
startID := defaultRangeStart
|
||||||
for _, arange := range rangeList {
|
for _, arange := range rangeList {
|
||||||
if wouldOverlap(arange, startID) {
|
if wouldOverlap(arange, startID) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
units "github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/moby/term"
|
"github.com/moby/term"
|
||||||
"github.com/morikuni/aec"
|
"github.com/morikuni/aec"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,8 +3,8 @@ package system // import "github.com/docker/docker/pkg/system"
|
||||||
// containerdRuntimeSupported determines if containerd should be the runtime.
|
// containerdRuntimeSupported determines if containerd should be the runtime.
|
||||||
var containerdRuntimeSupported = false
|
var containerdRuntimeSupported = false
|
||||||
|
|
||||||
// InitContainerdRuntime sets whether to use containerd for runtime on Windows.
|
// EnableContainerdRuntime sets whether to use containerd for runtime on Windows.
|
||||||
func InitContainerdRuntime(cdPath string) {
|
func EnableContainerdRuntime(cdPath string) {
|
||||||
if len(cdPath) > 0 {
|
if len(cdPath) > 0 {
|
||||||
containerdRuntimeSupported = true
|
containerdRuntimeSupported = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -36,6 +37,30 @@ func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cachedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
|
||||||
|
// it into a closure to be used directly
|
||||||
|
// if the type fails to convert we return a closure always erroring to keep the previous behaviour
|
||||||
|
func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (interface{}, error) {
|
||||||
|
switch f := typedDecodeHook(raw).(type) {
|
||||||
|
case DecodeHookFuncType:
|
||||||
|
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
|
||||||
|
return f(from.Type(), to.Type(), from.Interface())
|
||||||
|
}
|
||||||
|
case DecodeHookFuncKind:
|
||||||
|
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
|
||||||
|
return f(from.Kind(), to.Kind(), from.Interface())
|
||||||
|
}
|
||||||
|
case DecodeHookFuncValue:
|
||||||
|
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
|
||||||
|
return f(from, to)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
|
||||||
|
return nil, errors.New("invalid decode hook signature")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DecodeHookExec executes the given decode hook. This should be used
|
// DecodeHookExec executes the given decode hook. This should be used
|
||||||
// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
|
// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
|
||||||
// that took reflect.Kind instead of reflect.Type.
|
// that took reflect.Kind instead of reflect.Type.
|
||||||
|
@ -61,13 +86,17 @@ func DecodeHookExec(
|
||||||
// The composed funcs are called in order, with the result of the
|
// The composed funcs are called in order, with the result of the
|
||||||
// previous transformation.
|
// previous transformation.
|
||||||
func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
||||||
|
cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(fs))
|
||||||
|
for _, f := range fs {
|
||||||
|
cached = append(cached, cachedDecodeHook(f))
|
||||||
|
}
|
||||||
return func(f reflect.Value, t reflect.Value) (interface{}, error) {
|
return func(f reflect.Value, t reflect.Value) (interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
data := f.Interface()
|
data := f.Interface()
|
||||||
|
|
||||||
newFrom := f
|
newFrom := f
|
||||||
for _, f1 := range fs {
|
for _, c := range cached {
|
||||||
data, err = DecodeHookExec(f1, newFrom, t)
|
data, err = c(newFrom, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -81,13 +110,17 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
||||||
// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
|
// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
|
||||||
// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
|
// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
|
||||||
func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {
|
func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {
|
||||||
|
cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(ff))
|
||||||
|
for _, f := range ff {
|
||||||
|
cached = append(cached, cachedDecodeHook(f))
|
||||||
|
}
|
||||||
return func(a, b reflect.Value) (interface{}, error) {
|
return func(a, b reflect.Value) (interface{}, error) {
|
||||||
var allErrs string
|
var allErrs string
|
||||||
var out interface{}
|
var out interface{}
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
for _, f := range ff {
|
for _, c := range cached {
|
||||||
out, err = DecodeHookExec(f, a, b)
|
out, err = c(a, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
allErrs += err.Error() + "\n"
|
allErrs += err.Error() + "\n"
|
||||||
continue
|
continue
|
||||||
|
@ -144,6 +177,26 @@ func StringToTimeDurationHookFunc() DecodeHookFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StringToURLHookFunc returns a DecodeHookFunc that converts
|
||||||
|
// strings to *url.URL.
|
||||||
|
func StringToURLHookFunc() DecodeHookFunc {
|
||||||
|
return func(
|
||||||
|
f reflect.Type,
|
||||||
|
t reflect.Type,
|
||||||
|
data interface{},
|
||||||
|
) (interface{}, error) {
|
||||||
|
if f.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
if t != reflect.TypeOf(&url.URL{}) {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert it by parsing
|
||||||
|
return url.Parse(data.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// StringToIPHookFunc returns a DecodeHookFunc that converts
|
// StringToIPHookFunc returns a DecodeHookFunc that converts
|
||||||
// strings to net.IP
|
// strings to net.IP
|
||||||
func StringToIPHookFunc() DecodeHookFunc {
|
func StringToIPHookFunc() DecodeHookFunc {
|
||||||
|
|
|
@ -266,6 +266,10 @@ type DecoderConfig struct {
|
||||||
// defaults to "mapstructure"
|
// defaults to "mapstructure"
|
||||||
TagName string
|
TagName string
|
||||||
|
|
||||||
|
// The option of the value in the tag that indicates a field should
|
||||||
|
// be squashed. This defaults to "squash".
|
||||||
|
SquashTagOption string
|
||||||
|
|
||||||
// IgnoreUntaggedFields ignores all struct fields without explicit
|
// IgnoreUntaggedFields ignores all struct fields without explicit
|
||||||
// TagName, comparable to `mapstructure:"-"` as default behaviour.
|
// TagName, comparable to `mapstructure:"-"` as default behaviour.
|
||||||
IgnoreUntaggedFields bool
|
IgnoreUntaggedFields bool
|
||||||
|
@ -274,6 +278,10 @@ type DecoderConfig struct {
|
||||||
// field name or tag. Defaults to `strings.EqualFold`. This can be used
|
// field name or tag. Defaults to `strings.EqualFold`. This can be used
|
||||||
// to implement case-sensitive tag values, support snake casing, etc.
|
// to implement case-sensitive tag values, support snake casing, etc.
|
||||||
MatchName func(mapKey, fieldName string) bool
|
MatchName func(mapKey, fieldName string) bool
|
||||||
|
|
||||||
|
// DecodeNil, if set to true, will cause the DecodeHook (if present) to run
|
||||||
|
// even if the input is nil. This can be used to provide default values.
|
||||||
|
DecodeNil bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Decoder takes a raw interface value and turns it into structured
|
// A Decoder takes a raw interface value and turns it into structured
|
||||||
|
@ -283,7 +291,8 @@ type DecoderConfig struct {
|
||||||
// structure. The top-level Decode method is just a convenience that sets
|
// structure. The top-level Decode method is just a convenience that sets
|
||||||
// up the most basic Decoder.
|
// up the most basic Decoder.
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
config *DecoderConfig
|
config *DecoderConfig
|
||||||
|
cachedDecodeHook func(from reflect.Value, to reflect.Value) (interface{}, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata contains information about decoding a structure that
|
// Metadata contains information about decoding a structure that
|
||||||
|
@ -401,6 +410,10 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
|
||||||
config.TagName = "mapstructure"
|
config.TagName = "mapstructure"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.SquashTagOption == "" {
|
||||||
|
config.SquashTagOption = "squash"
|
||||||
|
}
|
||||||
|
|
||||||
if config.MatchName == nil {
|
if config.MatchName == nil {
|
||||||
config.MatchName = strings.EqualFold
|
config.MatchName = strings.EqualFold
|
||||||
}
|
}
|
||||||
|
@ -408,6 +421,9 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
|
||||||
result := &Decoder{
|
result := &Decoder{
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
if config.DecodeHook != nil {
|
||||||
|
result.cachedDecodeHook = cachedDecodeHook(config.DecodeHook)
|
||||||
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
@ -426,19 +442,26 @@ func (d *Decoder) Decode(input interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isNil returns true if the input is nil or a typed nil pointer.
|
||||||
|
func isNil(input interface{}) bool {
|
||||||
|
if input == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val := reflect.ValueOf(input)
|
||||||
|
return val.Kind() == reflect.Ptr && val.IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
// Decodes an unknown data type into a specific reflection value.
|
// Decodes an unknown data type into a specific reflection value.
|
||||||
func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error {
|
func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error {
|
||||||
var inputVal reflect.Value
|
var (
|
||||||
if input != nil {
|
inputVal = reflect.ValueOf(input)
|
||||||
inputVal = reflect.ValueOf(input)
|
outputKind = getKind(outVal)
|
||||||
|
decodeNil = d.config.DecodeNil && d.cachedDecodeHook != nil
|
||||||
// We need to check here if input is a typed nil. Typed nils won't
|
)
|
||||||
// match the "input == nil" below so we check that here.
|
if isNil(input) {
|
||||||
if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() {
|
// Typed nils won't match the "input == nil" below, so reset input.
|
||||||
input = nil
|
input = nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if input == nil {
|
if input == nil {
|
||||||
// If the data is nil, then we don't set anything, unless ZeroFields is set
|
// If the data is nil, then we don't set anything, unless ZeroFields is set
|
||||||
// to true.
|
// to true.
|
||||||
|
@ -449,30 +472,46 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
|
||||||
d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
|
d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
if !decodeNil {
|
||||||
}
|
return nil
|
||||||
|
}
|
||||||
if !inputVal.IsValid() {
|
}
|
||||||
// If the input value is invalid, then we just set the value
|
if !inputVal.IsValid() {
|
||||||
// to be the zero value.
|
if !decodeNil {
|
||||||
outVal.Set(reflect.Zero(outVal.Type()))
|
// If the input value is invalid, then we just set the value
|
||||||
if d.config.Metadata != nil && name != "" {
|
// to be the zero value.
|
||||||
d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
|
outVal.Set(reflect.Zero(outVal.Type()))
|
||||||
|
if d.config.Metadata != nil && name != "" {
|
||||||
|
d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Hooks need a valid inputVal, so reset it to zero value of outVal type.
|
||||||
|
switch outputKind {
|
||||||
|
case reflect.Struct, reflect.Map:
|
||||||
|
var mapVal map[string]interface{}
|
||||||
|
inputVal = reflect.ValueOf(mapVal) // create nil map pointer
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
var sliceVal []interface{}
|
||||||
|
inputVal = reflect.ValueOf(sliceVal) // create nil slice pointer
|
||||||
|
default:
|
||||||
|
inputVal = reflect.Zero(outVal.Type())
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.config.DecodeHook != nil {
|
if d.cachedDecodeHook != nil {
|
||||||
// We have a DecodeHook, so let's pre-process the input.
|
// We have a DecodeHook, so let's pre-process the input.
|
||||||
var err error
|
var err error
|
||||||
input, err = DecodeHookExec(d.config.DecodeHook, inputVal, outVal)
|
input, err = d.cachedDecodeHook(inputVal, outVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error decoding '%s': %w", name, err)
|
return fmt.Errorf("error decoding '%s': %w", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if isNil(input) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
outputKind := getKind(outVal)
|
|
||||||
addMetaKey := true
|
addMetaKey := true
|
||||||
switch outputKind {
|
switch outputKind {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
|
@ -753,8 +792,8 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"'%s' expected type '%s', got unconvertible type '%s', value: '%v'",
|
"'%s' expected type '%s', got unconvertible type '%#v', value: '%#v'",
|
||||||
name, val.Type(), dataVal.Type(), data)
|
name, val, dataVal, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -973,7 +1012,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
|
||||||
}
|
}
|
||||||
|
|
||||||
// If "squash" is specified in the tag, we squash the field down.
|
// If "squash" is specified in the tag, we squash the field down.
|
||||||
squash = squash || strings.Index(tagValue[index+1:], "squash") != -1
|
squash = squash || strings.Contains(tagValue[index+1:], d.config.SquashTagOption)
|
||||||
if squash {
|
if squash {
|
||||||
// When squashing, the embedded type can be a pointer to a struct.
|
// When squashing, the embedded type can be a pointer to a struct.
|
||||||
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
|
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
|
||||||
|
@ -1351,7 +1390,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||||
// We always parse the tags cause we're looking for other tags too
|
// We always parse the tags cause we're looking for other tags too
|
||||||
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
|
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
|
||||||
for _, tag := range tagParts[1:] {
|
for _, tag := range tagParts[1:] {
|
||||||
if tag == "squash" {
|
if tag == d.config.SquashTagOption {
|
||||||
squash = true
|
squash = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -1363,10 +1402,15 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||||
}
|
}
|
||||||
|
|
||||||
if squash {
|
if squash {
|
||||||
if fieldVal.Kind() != reflect.Struct {
|
switch fieldVal.Kind() {
|
||||||
errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind()))
|
case reflect.Struct:
|
||||||
} else {
|
|
||||||
structs = append(structs, fieldVal)
|
structs = append(structs, fieldVal)
|
||||||
|
case reflect.Interface:
|
||||||
|
if !fieldVal.IsNil() {
|
||||||
|
structs = append(structs, fieldVal.Elem().Elem())
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind()))
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[codespell]
|
|
||||||
skip = ./.git
|
|
||||||
ignore-words-list = nd
|
|
|
@ -1,6 +0,0 @@
|
||||||
linters:
|
|
||||||
enable:
|
|
||||||
- unconvert
|
|
||||||
- unparam
|
|
||||||
- gofumpt
|
|
||||||
- errorlint
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue