Compare commits

...

461 Commits

Author SHA1 Message Date
980b856816 Merge pull request #6183 from thaJeztah/diff_simplify
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
cli/command/container: diff: remove redundant validation and cleanup
2025-07-16 12:32:48 +02:00
9c256146ac Merge pull request #6181 from thaJeztah/fork_readCloserWrapper
remove uses of github.com/docker/docker/pkg/ioutils ReadCloserWrapper
2025-07-16 12:19:14 +02:00
bc01f8489d Merge pull request #6182 from thaJeztah/fork_longpath
remove use of github.com/docker/docker/pkg/longpath
2025-07-16 12:18:06 +02:00
ea2a0c3b8a Merge pull request #6177 from thaJeztah/rm_aliases
cli/command: remove some redundant import-aliases
2025-07-16 12:17:23 +02:00
3d985799d4 cli/command: remove some redundant import-aliases
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-16 12:12:41 +02:00
f5f3b027e8 Merge pull request #6178 from thaJeztah/bump_dev_tools
Dockerfile: update Buildx v0.25.0, compose v2.38.2
2025-07-16 12:07:46 +02:00
143f36133a Merge pull request #6179 from thaJeztah/bump_gotestsum
Dockerfile: bump gotest.tools/gotestsum v1.12.3 (for go1.25)
2025-07-16 12:07:17 +02:00
d7181e47e2 Merge pull request #6185 from thaJeztah/alpine_doc
Dockerfile: document ALPINE_VERSION build-arg
2025-07-16 12:06:17 +02:00
8b6436ecee Dockerfile: document ALPINE_VERSION build-arg
docker build --call outline .

    TARGET: binary

    BUILD ARG               VALUE    DESCRIPTION
    BASE_VARIANT            alpine
    ALPINE_VERSION          3.21     sets the version of the alpine base image to use, including for the golang image.
    GO_VERSION              1.24.5
    XX_VERSION              1.6.1
    GOVERSIONINFO_VERSION   v1.4.1
    GO_LINKMODE             static   defines if static or dynamic binary should be produced
    GO_BUILDTAGS                     defines additional build tags
    GO_STRIP                         strips debugging symbols if set
    CGO_ENABLED                      manually sets if cgo is used
    VERSION                          sets the version for the produced binary
    PACKAGER_NAME                    sets the company that produced the windows binary

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-16 09:51:14 +02:00
7d574b816d Merge pull request #6180 from thaJeztah/truncate_id
remove uses of github.com/docker/docker/pkg/stringid
2025-07-15 14:03:18 +02:00
0f2b709c7c cli/command/container: diff: remove redundant validation and cleanup
client.ContainerDiff already validates the given container name/ID, and
produces an error when empty, so we don't have to check for this;
abba330bbf/client/container_diff.go (L13-L16)

While updating, also;

- remove the diffOptions type, as there were no other options, and make
  the container name/ID a string argument.
- fix camelCase nameing of dockerCLI

Before this patch:

    docker diff ""
    Container name cannot be empty

With this patch:

    docker diff ""
    invalid container name or ID: value is empty

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-15 01:08:29 +02:00
7668b683d2 Merge pull request #6176 from thaJeztah/rm_use_AllowOverwriteDirWithFile
cli/command/container: don't set CopyToContainerOptions.AllowOverwriteDirWithFile
2025-07-14 23:17:34 +02:00
53d02ece89 remove use of github.com/docker/docker/pkg/longpath
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-14 22:34:36 +02:00
3600ebca76 remove uses of github.com/docker/docker/pkg/ioutils ReadCloserWrapper
It was the only utility we consumed from the package, and it's trivial
to implement, so let's create local copies of it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-14 22:09:31 +02:00
9b047a501f remove uses of pkg/stringid.GenerateRandomID()
This utility was only used for testing, and to generate a random
suffix for Dockerfiles. As we don't need the same contract as
pkg/stringid.GenerateRandomID() (not allow all-numeric IDs as they
would not be usable for hostnames), we can use a local test-utility,
and local implementation for the random suffix instead.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-14 20:11:07 +02:00
e0f4bc699c cli/command/formatter: add TrunateID utility
We were depending on pkg/stringid to truncate IDs for presentation. While
traditionally, we used a fixed length for "truncated" IDs, this is not
a strict requirement (any ID-prefix should work, but conflicts may
happen on shorter IDs).

This patch adds a local `TruncateID()` utility in the formatter package;
it's currently using the same implementation and length as the
`stringid.TruncateID` function, but may diverge in future.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-14 20:10:56 +02:00
1264a59779 Dockerfile: bump gotest.tools/gotestsum v1.12.3 (for go1.25)
full diff: https://github.com/gotestyourself/gotestsum/compare/v1.12.0...v1.12.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-13 17:50:03 +02:00
e6b8cc1c7d Dockerfile: update buildx to v0.25.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-13 17:45:07 +02:00
50fa436c21 Dockerfile: update compose to v2.38.2
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-13 17:43:50 +02:00
0be687acc0 cli/command/container: don't set CopyToContainerOptions.AllowOverwriteDirWithFile
The `AllowOverwriteDirWithFile` option was added when reimplementing the
CLI using the API Client lib in [moby@1b2b91b]. Before that refactor, the
`noOverwriteDirNonDir` query argument [would be set unconditionally][1]
by the CLI, with no options to control the behavior.

It's unclear why the `noOverwriteDirNonDir` was implemented as opt-in (not
opt-out), as overwriting a file with a directory (or vice-versa) would
generally be unexpected behavior.

We're considering making `noOverwriteDirNonDir` unconditional on the daemon
side, and to deprecate the `AllowOverwriteDirWithFile` option. This patch
removes its use, as it was set to the default either way, and there's no
options to configure it from the CLI.

[1]: 8c9ad7b818/api/client/cp.go (L345-L346)
[moby@1b2b91b]: 1b2b91ba43

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-13 13:48:59 +02:00
c69d8bde4a Merge pull request #6173 from vvoland/fix-anchor-cdi
docs: fix CDI device configuration anchor
2025-07-11 15:27:46 +02:00
8eac03d5fa docs: fix CDI device configuration anchor
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-07-11 10:44:29 +02:00
578ccf607d Merge pull request #6170 from thaJeztah/e2e_newline_check
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
e2e/global: TestPromptExitCode: check for trailing newline
2025-07-09 14:04:02 +02:00
0c5e258f8a e2e/global: TestPromptExitCode: check for trailing newline
Make the test slightly more permissive; we're looking for a trailing
newline, not necessarily an empty line.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-09 13:35:17 +02:00
30cad385b6 Merge pull request #6167 from vvoland/update-go
Update to go1.24.5
2025-07-09 01:23:29 +02:00
9bcc88611f update to go1.24.5
- https://github.com/golang/go/issues?q=milestone%3AGo1.24.5+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.24.4...go1.24.5

This minor releases include 1 security fixes following the security policy:

- cmd/go: unexpected command execution in untrusted VCS repositories

    Various uses of the Go toolchain in untrusted VCS repositories can result in
    unexpected code execution. When using the Go toolchain in directories fetched
    using various VCS tools (such as directly cloning Git or Mercurial repositories)
    can cause the toolchain to execute unexpected commands, if said directory
    contains multiple VCS configuration metadata (such as a '.hg' directory in a Git
    repository). This is due to how the Go toolchain attempts to resolve which VCS
    is being used in order to embed build information in binaries and determine
    module versions.

    The toolchain will now abort attempting to resolve which VCS is being used if it
    detects multiple VCS configuration metadata in a module directory or nested VCS
    configuration metadata (such as a '.git' directoy in a parent directory and a
    '.hg' directory in a child directory). This will not prevent the toolchain from
    building modules, but will result in binaries omitting VCS related build
    information.

    If this behavior is expected by the user, the old behavior can be re-enabled by
    setting GODEBUG=allowmultiplevcs=1. This should only be done in trusted
    repositories.

    Thanks to RyotaK (https://ryotak.net) of GMO Flatt Security Inc for reporting
    this issue.

    This is CVE-2025-4674 and https://go.dev/issue/74380.

View the release notes for more information:
https://go.dev/doc/devel/release#go1.24.5

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-07-08 19:23:57 +02:00
3302212263 Merge pull request #6163 from Benehiko/env-credential-warn
registry: warn of `DOCKER_AUTH_CONFIG` usage in login and logout
2025-07-08 15:33:07 +02:00
ccd5bd8d57 registry: warn of DOCKER_AUTH_CONFIG usage in login and logout
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2025-07-08 14:07:32 +02:00
dec07e6fdf tui/note: add warning note type
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2025-07-08 14:07:22 +02:00
28f19a9d65 Merge pull request #6162 from ArthurFlag/ENGDOCS-2807-cdi-docs-update
docs: cdi isn't experimental
2025-07-07 17:53:48 +02:00
219e5ca4f2 Merge pull request #6165 from thaJeztah/bump_engine_28.3.1
vendor: github.com/docker/docker v28.3.1
2025-07-07 17:53:31 +02:00
7e040d91ef docs: cdi is not experimental anymore
Signed-off-by: ArthurFlag <arthur.flageul@docker.com>
2025-07-07 16:10:30 +02:00
76524e7d0e vendor: github.com/docker/docker v28.3.1
no changes in vendored code

full diff: https://github.com/docker/docker/compare/v28.3.0...v28.3.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-07 15:52:29 +02:00
3262107821 cli/config: export const dockerEnvConfig
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2025-07-04 14:04:38 +02:00
8403869122 Merge pull request #6158 from thaJeztah/reduce_strslice
cli/command/container: remove redundant uses of strslice.StrSlice
2025-07-02 17:42:43 +02:00
1fc7194554 Merge pull request #6159 from thaJeztah/hide_codecov
rename codecov.yml to .codecov.yml
2025-07-02 17:42:11 +02:00
fa2a7f1536 Merge pull request #6154 from thaJeztah/bump_engine
vendor: github.com/docker/docker v28.3.0
2025-07-02 17:41:49 +02:00
350b3a6e25 Merge pull request #6160 from thaJeztah/fix_otel_debug_logs
cli/debug: fix OTELErrorHandler logging messages if there's no error
2025-07-02 17:41:26 +02:00
4ea6fbf538 cli/debug: fix OTELErrorHandler logging messages if there's no error
I noticed this in a ticket in the compose issue tracker; with debug logging
enabled, the OTEL error-logger may be logging even if there's no error;

    DEBU[0000] Executing bake with args: [bake --file - --progress rawjson --metadata-file /tmp/compose-build-metadataFile-1203980021.json --allow fs.read=/home/user/dev/project --allow fs.read=/home/user/dev/project --allow fs.read=/home/user/dev/project/nginx --allow fs.read=/home/user/dev/project]
    TRAC[0000] Plugin server listening on @docker_cli_d8df486f78df3b7357995be71bf0cef6
    DEBU[0005] otel error                                    error="<nil>"
    ^CTRAC[0055] Closing plugin server
    TRAC[0055] Closing plugin server
    DEBU[0055] otel error                                    error="<nil>"
    DEBU[0055] otel error                                    error="<nil>"

Update the error-handler to not log if there's no error.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-02 11:59:05 +02:00
74a896f18c Merge pull request #6157 from ndeloof/use_api_socket
mount /var/run/docker.sock for --use-api-socket
2025-07-01 17:00:24 +02:00
94f097da28 rename codecov.yml to .codecov.yml
Make it a hidden file. From the [CodeCov docs][1]:

> Can I name the file .codecov.yml?
>
> Yes, you can name the file `codecov.yml` or `.codecov.yml`. However, the
> file must still be located in the repository root, `dev/`, or `.github/`
> directories

[1]: https://docs.codecov.com/docs/codecov-yaml#can-i-name-the-file-codecovyml

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-01 16:20:54 +02:00
e7e238eb4b cli/command/container: remove redundant uses of strslice.StrSlice
The strslice.StrSlice type is a string-slice with a custom JSON Unmarshal
function to provide backward-compatibility with older API requests (see
[moby@17d6f00] and [moby@ea4a067]).

Given that the type is assigned implicitly through the fields on HostConfig,
we can just use a regular []string instead.

[moby@17d6f00]: 17d6f00ec2
[moby@ea4a067]: ea4a06740b

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-01 10:09:54 +02:00
2ba7cb8b44 mount /var/run/docker.sock for --use-api-socket
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-06-30 12:38:15 +02:00
52e1e4fb21 vendor: github.com/docker/docker v28.3.0
no diff; same commit: https://github.com/docker/docker/compare/v28.3.0-rc.2...v28.3.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-30 09:35:21 +02:00
7cbee73f19 Merge pull request #6147 from thaJeztah/connhelper_quote
cli/connhelper: quote ssh arguments to prevent shell injection
2025-06-25 17:21:12 +02:00
ae6f8d0021 Merge pull request #6149 from vvoland/gha-tags
gha/bin-image: add major and minor version image tags
2025-06-25 14:35:11 +00:00
70867e7067 gha/bin-image: add major and minor version image tags
Adding image tags that follow the semver major and minor versions (e.g., `28`
and `28.3`) for the moby-bin images.

This makes it easier for users to reference the latest build within a
major or minor version series without having to know the exact
minor/patch version.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-06-24 23:35:10 +02:00
38b7060a21 Merge pull request #6148 from thaJeztah/vendor_rc2
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker v28.3.0-rc.2
2025-06-24 15:37:19 +00:00
2d46d162c1 vendor: github.com/docker/docker v28.3.0-rc.2
no diff; same commit, but tagged;
https://github.com/docker/docker/compare/265f70964794...v28.3.0-rc.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-24 16:35:29 +02:00
88d1133224 cli/connhelper: quote ssh arguments to prevent shell injection
When connecting to a remote daemon through an ssh:// connection,
the CLI connects with the remote host using ssh, executing the
`docker system dial-stdio` command on the remote host to connect
to the daemon API's unix socket.

By default, the `docker system dial-stdio` command connects with the
daemon using the default location (/var/run/docker.sock), or the
location as configured on the remote host.

Commit 25ebf0ec9c (included in docker
CLI v24.0.0-rc.2 and higher) introduced a feature to allow the location
of the socket to be specified through the host connection string, for
example:

     DOCKER_HOST='ssh://example.test/run/custom-docker.sock'

The custom path is included as part of the ssh command executed from
the client machine to connect with the remote host. THe example above
would execute the following command from the client machine;

    ssh -o ConnectTimeout=30 -T -- example.test docker --host unix:///run/custom-docker.sock system dial-stdio

ssh executes remote commands in a shell environment, and no quoting
was in place, which allowed for a connection string to include additional
content, which would be expanded / executed on the remote machine.

For example, the following example would execute `echo hello > /hello.txt`
on the remote machine;

    export DOCKER_HOST='ssh://example.test/var/run/docker.sock $(echo hello > /hello.txt)'
    docker info
    # (output of docker info from the remote machine)

While this doesn't allow the user to do anything they're not already
able to do so (by directly using the same SSH connection), the behavior
is not expected, so this patch adds quoting to prevent such URLs from
resulting in expansion.

This patch updates the cli/connhelper and cli/connhelper/ssh package to
quote parameters used in the ssh command to prevent code execution and
expansion of variables on the remote machine. Quoting is also applied to
other parameters that are obtained from the DOCKER_HOST url, such as username
and hostname.

- The existing `Spec.Args()` method inthe cli/connhelper/ssh package now
  quotes arguments, and returns a nil slice when failing to quote. Users
  of this package should therefore check the returned arguments before
  consuming. This  method did not provide an error-return, and adding
  one would be a breaking change.
- A new `Spec.Command` method is introduced, which (unlike the `Spec.Args()`
  method) provides an error return. Users are recommended to use this new
  method instead of the `Spec.Args()` method.

Some minor additional changes in behavior are included in this patch;

- Connection URLs with a trailing slash (e.g. `ssh://example.test/`)
  would previously result in `unix:///` being used as custom socket
  path. After this patch, the trailing slash is ignored, and no custom
  socket path is used.
- Specifying a remote command is now required. When passing an empty
  remote command, `Spec.Args()` now results in a `nil` value to be
  returned (or an `no remote command specified` error when using
  `Spec.Comnmand()`.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-24 16:26:17 +02:00
82eda48066 cli/connhelper/internal/syntax: fix linting issues
cli/connhelper/internal/syntax/parser.go:31:2: Duplicate words (the) found (dupword)
        // Note that it shares some features with Bash, due to the the shared
        ^
    cli/connhelper/internal/syntax/quote.go:48:1: cyclomatic complexity 35 of func `Quote` is high (> 16) (gocyclo)
    func Quote(s string, lang LangVariant) (string, error) {
    ^
    cli/connhelper/internal/syntax/quote.go:103:3: shadow: declaration of "offs" shadows declaration at line 56 (govet)
            offs := 0
            ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-24 16:24:34 +02:00
52d2a9b5ae cli/connhelper/internal/syntax: remove unused code from fork
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-24 16:24:29 +02:00
64a9a6d0c8 cli/connhelper: add fork of mvdan.cc/sh/v3/syntax v3.10.0
This adds a local fork of the mvdan.cc/sh/v3/syntax package to provide the
Quote function without having to introduce additional (indirect) dependencies
of the mvdan.cc/sh module.

This commit does not compile as it references code not forked.

The following files were included:

- https://raw.githubusercontent.com/mvdan/sh/refs/tags/v3.10.0/syntax/quote.go
- https://raw.githubusercontent.com/mvdan/sh/refs/tags/v3.10.0/syntax/parser.go
- https://raw.githubusercontent.com/mvdan/sh/refs/tags/v3.10.0/LICENSE

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-24 10:02:53 +02:00
f03fb6c40b Merge pull request #6146 from thaJeztah/bump_docker
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker 265f70964794 (v28.3.0-rc.2)
2025-06-20 18:33:20 +02:00
5bb0d7f70c vendor: github.com/docker/docker 265f70964794 (v28.3.0-rc.2)
full diff: https://github.com/docker/docker/compare/v28.3.0-rc.1...265f709647947fb5a1adf7e4f96f2113dcc377bd

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-20 18:25:22 +02:00
575d4af72f vendor: github.com/docker/docker v28.3.0-rc.1
no diff: just tagged; https://github.com/docker/docker/compare/6a1fb46d4805...v28.3.0-rc.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-20 17:43:37 +02:00
4b202b9e2b Merge pull request #6141 from thaJeztah/login_no_tty
prevent login prompt on registry operations with no TTY attached
2025-06-20 12:40:36 +02:00
80d1959ee3 Merge pull request #6144 from thaJeztah/rm_top_level_remove
remove undocumented top-level "docker remove" command
2025-06-20 06:14:15 +09:00
19a5c5c714 remove undocumented top-level "docker remove" command
This was introduced in 9b54d860cd,
which added `docker container remove` as alias for `docker container rm`.

However, due to the `NewRmCommand` being used both for adding the top-level
`docker rm` command and for adding the `docker container rm` command, it
also introduced a (hidden) top-level `docker remove` command;

    docker remove --help | head -n1
    Usage:  docker rm [OPTIONS] CONTAINER [CONTAINER...]

The command was not documented, and did not appear in `--help` output,
nor was auto-complete provided;

    docker --help | grep remove

    docker r<TAB>
    rename               (Rename a container)  rm  (Remove one or more containers)  run  (Create and run a new container from an image)
    restart  (Restart one or more containers)  rmi     (Remove one or more images)

This patch adds a dedicated, non-exported `newRemoveCommand` to add sub-
commands for `docker container`, taking a similar approach as was done in
[moby@b993609d5a] for `docker image rm`.

With this patch applied, the hidden command is no longer there, but
the `docker rm`, `docker container rm`, and `docker container remove`
commands stay functional as intended;

    docker remove foo
    docker: unknown command: docker remove

    Run 'docker --help' for more information

    docker rm --help | head -n1
    Usage:  docker rm [OPTIONS] CONTAINER [CONTAINER...]
    docker container rm --help | head -n1
    Usage:  docker container rm [OPTIONS] CONTAINER [CONTAINER...]
    docker container remove --help | head -n1
    Usage:  docker container rm [OPTIONS] CONTAINER [CONTAINER...]

[moby@b993609d5a]: b993609d5a

Reported-by: Lorenzo Buero <138243046+LorenzoBuero@users.noreply.github.com>
Co-authored-by: Lorenzo Buero <138243046+LorenzoBuero@users.noreply.github.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-19 15:42:54 +02:00
c88268681e prevent login prompt on registry operations with no TTY attached
When pulling or pushing images, the CLI could prompt for a password
if the push/pull failed and the registry returned a 401 (Unauthorized)

Ironically, this feature did not work when using Docker Hub (and possibly
other registries using basic auth), due to some custom error handling added
in [moby@19a93a6e3d42], which also discards the registry's status code,
changing it to a 404;

    curl -v -XPOST --unix-socket /var/run/docker.sock 'http://localhost/v1.50/images/create?fromImage=docker.io%2Fexample%2Fprivate&tag=latest'
    ...
    < HTTP/1.1 404 Not Found
    < Content-Type: application/json
    ...
    {"message":"pull access denied for example/private, repository does not exist or may require 'docker login'"}

And due to a bug, other registries (not using basic auth) returned a generic
error, which resulted in a 500 Internal Server Error. That bug was fixed in
docker 28.2, now returning the upstream status code and trigger an interactive
prompt;

    docker pull icr.io/my-ns/my-image:latest
    Please login prior to pull:
    Username:

This prompt would be triggered unconditionally, also if the CLI was run
non-interactively and no TTY attached;

    docker pull icr.io/my-ns/my-image:latest < /dev/null
    Please login prior to pull:
    Username:

With this PR, no prompt is shown ;

    # without STDIN attached
    docker pull icr.io/my-ns/my-image:latest < /dev/null
    Error response from daemon: error from registry: Authorization required. See https://cloud.ibm.com/docs/Registry?topic=Registry-troubleshoot-auth-req - Authorization required. See https://cloud.ibm.com/docs/Registry?topic=Registry-troubleshoot-auth-req

For now, the prompt is still shown otherwise;

    docker pull icr.io/my-ns/my-image:latest

    Login prior to pull:
    Username: ^C

[moby@19a93a6e3d42]: 19a93a6e3d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-19 10:25:27 +02:00
747cb4448f Merge pull request #6140 from vvoland/image-tree-used
image/tree: Fix top image chip detection
2025-06-18 20:13:03 +00:00
23fe9ec244 image/tree: Fix top image chip detection
Currently, image tree visualization doesn't properly detect chips for
parent images, only looking at child images. This patch fixes the issue
by checking both parent and child images when determining which chips to
display in the tree view.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-06-18 20:18:58 +02:00
51025e12e5 Merge pull request #6008 from Benehiko/env-credentials-store
Use `DOCKER_AUTH_CONFIG` env as credential store
2025-06-18 18:07:07 +00:00
9b83d5bbf9 Use DOCKER_AUTH_CONFIG env as credential store
This patch enables the CLI to natively pick up the `DOCKER_AUTH_CONFIG`
environment variable and use it as a credential store.

The `DOCKER_AUTH_CONFIG` value should be a JSON object and must store
the credentials in a base64 encoded string under the `auth` key.
Specifying additional fields will cause the parser to fail.

For example:
`printf "username:pat" | openssl base64 -A`

`export DOCKER_AUTH_CONFIG='{
  "auths": {
    "https://index.docker.io/v1/": {
      "auth": "aGk6KTpkY2tyX3BhdF9oZWxsbw=="
    }
  }
}'`

Credentials stored in `DOCKER_AUTH_CONFIG` would take precedence over any
credential stored in the file store (`~/.docker/config.json`) or native store
(credential helper).

Destructive actions, such as deleting a credential would result in a noop if
found in the environment credential. Credentials found in the file or
native store would get removed.

Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2025-06-18 18:55:42 +02:00
ab2d683f61 Merge pull request #6137 from thaJeztah/execconfig_detach
cli/command/container: remove use of ExecOptions.Detach as intermediate
2025-06-17 14:22:28 +02:00
3664c08b73 Merge pull request #6138 from thaJeztah/bump_swarmkit
vendor: github.com/moby/swarmkit/v2 v2.0.0
2025-06-17 14:21:47 +02:00
cccf6d8cc4 vendor: github.com/moby/swarmkit/v2 v2.0.0
full diff: https://github.com/moby/swarmkit/compare/8c1959736554...v2.0.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-17 13:26:30 +02:00
50da0ad9df cli/command/container: remove use of ExecOptions.Detach as intermediate
This field was added in [moby@5130fe5d38837302e], which
added it for use as intermediate struct when parsing CLI flags (through
`runconfig.ParseExec`) in [moby@c786a8ee5e9db8f5f].

Commit [moby@9d9dff3d0d9e92adf] rewrote the CLI to use
Cobra, and as part of this introduced a separate `execOptions` type in
`api/client/container`, however the ExecOptions.Detach field was still
used as intermediate field to store the flag's value.

Given that the client doesn't use this field, let's remove its use to
prevent giving the impression that it's used anywhere.

[moby@5130fe5d38837302e]: 5130fe5d38
[moby@c786a8ee5e9db8f5f]: c786a8ee5e
[moby@9d9dff3d0d9e92adf]: 9d9dff3d0d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-17 12:53:44 +02:00
dbb5872b69 Merge pull request #6135 from thaJeztah/fix_login_message
cli/command: RegistryAuthenticationPrivilegedFunc: fix hints for login
2025-06-16 14:35:56 +02:00
e2632c5c4f cli/command: RegistryAuthenticationPrivilegedFunc: fix hints for login
The RegistryAuthenticationPrivilegedFunc has some conditional logic to
add additional hints when logging in to the default (Docker Hub) registry.
Commit 9f4165ccb8 inadvertently passed the
wrong variable to PromptUserForCredentials, which caused it to show the
additional hints for Docker Hub.

Before this patch, hints were printed for the default (docker hub) registry;

    docker pull icr.io/my-ns/my-image:latest

    Login prior to pull:
    Log in with your Docker ID or email address to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com/ to create one.
    You can log in with your password or a Personal Access Token (PAT). Using a limited-scope PAT grants better security and is required for organizations using SSO. Learn more at https://docs.docker.com/go/access-tokens/

    Username:

With this patch, those hints are omitted;

    docker pull icr.io/my-ns/my-image:latest

    Login prior to pull:
    Username:

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-16 12:14:53 +02:00
f53bb8882f Merge pull request #6131 from vvoland/vendor-docker
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker v28.3.0-dev (6a1fb46d4805)
2025-06-13 16:29:11 +00:00
4cb0695b49 vendor: github.com/docker/docker v28.3.0-dev (6a1fb46d4805)
full diff: https://github.com/docker/docker/compare/v28.2.2...6a1fb46d4805

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-06-13 18:23:51 +02:00
3ce5130af6 Merge pull request #6132 from thaJeztah/replace_evt
cli/command/container: replace uses of deprecated event.Status field
2025-06-13 16:23:08 +00:00
99d4d1f386 cli/command/container: replace uses of deprecated event.Status field
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-13 18:18:28 +02:00
398fa5aa70 Merge pull request #6130 from thaJeztah/bump_version
bump version to v28.3.0-dev
2025-06-13 13:42:56 +00:00
e225d51919 bump version to v28.3.0-dev
This file is only used as default if no version is specified. We
should probably get rid of this, but let's update it to better
reflect the version that developer builds are building.

d48fb9f9f7/docker.Makefile (L22)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-13 14:11:56 +02:00
9cc2a2bf2d Merge pull request #6129 from vvoland/docs-deprecated
docs: deprecate empty Config fields in image inspect API
2025-06-13 14:10:48 +02:00
181563ee99 docs: deprecate empty Config fields in image inspect API
Image config fields like Cmd, Entrypoint, Env, etc. will be omitted from
/images/{name}/json response when empty, starting in v29.0.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-06-13 13:48:07 +02:00
082d23d12d Merge pull request #6127 from thaJeztah/bump_deps
vendor: update buildkit and containerd dependencies
2025-06-12 13:20:31 +00:00
59e34093bc vendor: otel v1.35.0, otel/contrib v0.60.0, grpc v1.72.2
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-12 14:16:23 +02:00
a76643bca3 vendor: github.com/prometheus/client_golang v1.22.0
full diff: https://github.com/prometheus/client_golang/compare/v1.20.5...v1.22.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-12 14:12:33 +02:00
f6985b7a27 vendor: google.golang.org/protobuf v1.36.6
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-12 14:11:07 +02:00
bab8478ef3 vendor: golang.org/x/sys v0.33.0
full diff: https://github.com/golang/sys/compare/v0.32.0...v0.33.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-12 14:09:24 +02:00
9f82d4a791 vendor: golang.org/x/sync v0.14.0
full diff: https://github.com/golang/sync/compare/v0.13.0...v0.14.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-12 13:54:57 +02:00
8b8f558b83 Merge pull request #6124 from vvoland/update-go
update to go1.24.4
2025-06-10 15:12:26 +02:00
5487986681 Merge pull request #6123 from ndeloof/pluginserver
only close plugin server if actually created
2025-06-10 15:12:06 +02:00
b9c563a581 only close plugin server if actually created
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2025-06-10 14:57:19 +02:00
fe7fc2ff7f update to go1.24.4
- https://github.com/golang/go/issues?q=milestone%3AGo1.24.4+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.24.3...go1.24.4

This release includes 3 security fixes following the security policy:

- net/http: sensitive headers not cleared on cross-origin redirect

    Proxy-Authorization and Proxy-Authenticate headers persisted on cross-origin redirects potentially leaking sensitive information.

    Thanks to Takeshi Kaneko (GMO Cybersecurity by Ierae, Inc.) for reporting this issue.

    This is CVE-2025-4673 and Go issue https://go.dev/issue/73816.

- os: inconsistent handling of O_CREATE|O_EXCL on Unix and Windows

    os.OpenFile(path, os.O_CREATE|O_EXCL) behaved differently on Unix and Windows systems when the target path was a dangling symlink. On Unix systems, OpenFile with O_CREATE and O_EXCL flags never follows symlinks. On Windows, when the target path was a symlink to a nonexistent location, OpenFile would create a file in that location.

    OpenFile now always returns an error when the O_CREATE and O_EXCL flags are both set and the target path is a symlink.

    Thanks to Junyoung Park and Dong-uk Kim of KAIST Hacking Lab for discovering this issue.

    This is CVE-2025-0913 and Go issue https://go.dev/issue/73702.

- crypto/x509: usage of ExtKeyUsageAny disables policy validation

    Calling Verify with a VerifyOptions.KeyUsages that contains ExtKeyUsageAny unintentionally disabledpolicy validation. This only affected certificate chains which contain policy graphs, which are rather uncommon.

    Thanks to Krzysztof Skrzętnicki (@Tener) of Teleport for reporting this issue.

    This is CVE-2025-22874 and Go issue https://go.dev/issue/73612.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-06-09 16:25:41 +02:00
9e506545fd Merge pull request #6120 from thaJeztah/fix_url
docs: fix link to live-restore
2025-06-02 13:02:40 +02:00
3c1bbfd82f docs: fix link to live-restore
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-06-02 12:56:04 +02:00
0bfd4c9f29 Merge pull request #6119 from thaJeztah/bump_engine
vendor: github.com/docker/docker v28.2.2
2025-06-02 10:15:52 +02:00
d8f09a1b75 Merge pull request #6117 from vvoland/binimage-nosha
gha/bin-image: Don't push sha tags
2025-05-30 17:42:22 +02:00
473b248260 vendor: github.com/docker/docker v28.2.2
no diff; same commit, but tagged:
https://github.com/docker/docker/compare/45873be4ae3f...v28.2.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-30 17:37:57 +02:00
b2d63d17af gha/bin-image: Don't push sha tags
This change eliminates the automatic creation of image tags in the
format `dockereng/cli-bin:sha-ad132f5` for every push.

They're not too useful, produce noise and use a lot of space.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-30 12:00:29 +02:00
e6534b4eb7 Merge pull request #6116 from vvoland/vendor-docker
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker v28.2.2-dev (45873be4ae3f)
2025-05-30 09:39:08 +00:00
5c3128e95e vendor: github.com/docker/docker v28.2.2-dev (45873be4ae3f)
full diff: 0e2cc22d36...45873be4ae

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-30 11:15:35 +02:00
879ac3f88f Merge pull request #6110 from thaJeztah/bump_engine
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker 0e2cc22d36ae (v28.2-dev)
2025-05-28 13:17:56 +00:00
92fa1e1fc9 vendor: github.com/docker/docker 0e2cc22d36ae (v28.2-dev)
no changes in vendored code

full diff: 26db31fdab...0e2cc22d36

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-28 15:05:58 +02:00
4bec3a6795 Merge pull request #6114 from thaJeztah/deprecate_non_compliant_registries
docs: deprecated: fallback for non-OCI-compliant registries is removed
2025-05-28 14:28:52 +02:00
a007d1ae24 Merge pull request #6113 from thaJeztah/config_suppress_err
cli/config/configfile: explicitly ignore error
2025-05-28 12:08:37 +00:00
bbfbd54f4d docs: deprecated: fallback for non-OCI-compliant registries is removed
GitHub deprecated the legacy registry, and it was [sunset on Feb 24th, 2025][1]
in favor of GitHub Container Registry (GHCR) (ghcr.io), so the fallback
was removed.

[1]: https://github.blog/changelog/2025-01-23-legacy-docker-registry-closing-down/

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-28 10:05:40 +02:00
2d21e1f7a5 cli/config/configfile: explicitly ignore error
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-28 09:55:33 +02:00
bc9be0bdea Merge pull request #6112 from thaJeztah/bump_tools
Dockerfile: bump buildx v0.24.0, compose v2.36.2
2025-05-28 09:09:24 +02:00
3fe7dc5cb4 Dockerfile: update compose to v2.36.2
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 22:50:20 +02:00
9eae2a8976 Dockerfile: update buildx to v0.24.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 22:49:34 +02:00
a29e53dab7 Merge pull request #6111 from thaJeztah/update_deprecations
docs: deprecated: update status for non-standard fields in image inspect
2025-05-27 16:57:52 +02:00
da0c976fb0 docs: deprecated: update status for non-standard fields in image inspect
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 16:14:00 +02:00
17dc2880fa Merge pull request #6109 from thaJeztah/image_rm_platform
image rm: add --platform option
2025-05-27 12:11:26 +02:00
bb0ca9f9ef image rm: add --platform option
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 10:58:11 +02:00
f567263802 Merge pull request #6099 from thaJeztah/bump_engine
vendor: github.com/docker/docker 26db31fdab62 (v28.2-dev)
2025-05-27 10:49:43 +02:00
7775f01caa vendor: github.com/docker/docker 26db31fdab62 (v28.2-dev)
full diff: https://github.com/docker/docker/compare/v28.2.0-rc.2...26db31fdab628a2345ed8f179e575099384166a9

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-27 09:20:06 +02:00
908ff04d6e Merge pull request #6108 from thaJeztah/bump_engine_28.2
vendor: github.com/docker/docker v28.2.0-rc.2
2025-05-26 13:17:15 +00:00
519bc2daa1 vendor: github.com/docker/docker v28.2.0-rc.2
no changes in vendored code

full diff: https://github.com/docker/docker/compare/f4ffeb8c38b3...v28.2.0-rc.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-26 14:06:52 +02:00
b2c4452acb Merge pull request #6101 from thaJeztah/deprecated_api_versions_removed
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
docs: deprecated: mark API < v1.24 as "removed"
2025-05-22 12:09:34 +00:00
3e287df661 Merge pull request #6100 from thaJeztah/fluentd_async_connect_removed
docs: deprecated: mark `fluentd-async-connect` as "removed"
2025-05-22 14:09:24 +02:00
f1fb3e3011 Merge pull request #5282 from willww64/fix-configfile-relative-symlink
correctly handle configuration file saving when it is a relative symlink
2025-05-22 12:08:40 +00:00
9c8666c106 docs: deprecated: mark API < v1.24 as "removed"
Support for API versions lower than v1.24 was removed in v26.0.
The DOCKER_MIN_API_VERSION environment-variable is still present
in the docker daemon, but can currently only be used to raise the
minimum version.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 13:37:44 +02:00
21d0466ff1 docs: deprecated: mark fluentd-async-connect as "removed"
The daemon still has migration code in place, but no longer accepts
the option for new containers, so marking it as "removed";
49ec488036

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 13:28:18 +02:00
1d3b933ac3 Merge pull request #6098 from thaJeztah/deprecated_inspect_fields
docs: deprecated: set Container and ContainerConfig fields to "removed"
2025-05-22 11:54:10 +02:00
649d088ddf Merge pull request #6096 from thaJeztah/graphdriver_plugin_deprecation
docs: update deprecation status of graphdriver-plugins to "removed"
2025-05-22 11:49:53 +02:00
e135563c1f Merge pull request #6097 from vvoland/28.x
vendor: github.com/docker/docker v28.2.0-dev (f4ffeb8c38b3)
2025-05-22 09:48:20 +00:00
026ae7a11f docs: deprecated: set Container and ContainerConfig fields to "removed"
These fields have been removed in v26.0 (API v1.45 and up), and are always
omitted when using the containerd image store;
03cddc62f4

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 11:45:57 +02:00
681c705be6 vendor: github.com/docker/docker v28.2.0-dev (f4ffeb8c38b3)
full diff: b590eff717...f4ffeb8c38

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-22 11:38:51 +02:00
bdd994b79a docs: update deprecation status of graphdriver-plugins to "removed"
This functionality, was removed and the DOCKERD_DEPRECATED_GRAPHDRIVER_PLUGINS
no longer can be used in v28.0;
42ca9154e9

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 11:29:37 +02:00
1015d15621 fix bug with config file being a relative symlink
- use filepath.EvalSymlink instead of check with filepath.IsAbs
- allow for dangling symlinks
- extract path from error when NotExist error occurs

Co-authored-by: Paweł Gronowski <me@woland.xyz>
Co-authored-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Will Wang <willww64@gmail.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 11:11:07 +02:00
ae922ec177 Merge pull request #6092 from thaJeztah/hijack_oncefunc
cli/command/container: hijackedIOStreamer.setupInput: use sync.OnceFunc
2025-05-22 10:02:11 +02:00
881c68f690 Merge pull request #4966 from Benehiko/relative-mount-path
feat: relative parent paths on bind mount src
2025-05-22 08:38:06 +02:00
761285bfee feat: relative parent paths on bind mount src
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2025-05-22 08:15:32 +02:00
f23ec25a12 Merge pull request #6095 from thaJeztah/update_schema1_deprecation
docs: move deprecation status of legacy schema1 images to "removed"
2025-05-22 08:06:45 +02:00
565b0a2822 Merge pull request #6094 from thaJeztah/fix_isautomated_status
docs: fix deprecation status for IsAutomated
2025-05-22 07:58:53 +02:00
4be9afb801 Merge pull request #6086 from thaJeztah/golangci_tweaks
golangci-lint: enable more linters, and some minor linting fixes
2025-05-22 07:57:53 +02:00
f05025caf9 docs: move deprecation status of legacy schema1 images to "removed"
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 01:10:13 +02:00
32a8f4c420 docs: fix deprecation status for IsAutomated
Follow-up to 6e4315f599, where
I forgot to update the status column.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-22 00:34:13 +02:00
68ef98d801 Merge pull request #6093 from vvoland/vendor-docker
vendor: github.com/docker/docker v28.2.0-dev (b590eff717b3)
2025-05-21 17:51:04 +00:00
63f2984336 vendor: github.com/docker/docker v28.2.0-dev (b590eff717b3)
full diff: 8601b22f5d...b590eff717

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-21 19:45:33 +02:00
0ee20b8543 Merge pull request #5995 from vvoland/swarm-init-cacert
swarm/init: Fix `--external-ca` ignoring `cacert` option
2025-05-21 18:31:14 +02:00
c07cd8aaad Merge pull request #6091 from thaJeztah/remove_deprecated_isautomated
search: remove deprecated "IsAutomated" placeholder
2025-05-21 15:43:36 +00:00
bf2eea31b5 cli/command/container: hijackedIOStreamer.setupInput: use sync.OnceFunc
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-21 17:34:51 +02:00
6e4315f599 search: remove deprecated "IsAutomated" placeholder
IsAutomated was deprecated in 4fc3f0e6f6
(docker v25.0), and marked for removal in docker 26.0 (which we missed).
This removes it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-21 17:13:59 +02:00
97e060e7b1 Merge pull request #6042 from thaJeztah/carry_5804_docker_ps_platform
docker ps: add "Platform" as formatting option
2025-05-21 12:28:57 +00:00
67c0be4b05 docker ps: allow formatting as JSON
With this patch:

    docker ps --format 'table {{.Names}}\t{{.Platform}}'
    NAMES                    PLATFORM
    optimistic_nightingale   linux/arm64
    mycontainer              linux/arm64/v8
    trusting_goldstine       linux/arm64

    docker ps --format '{{.Platform}}'
    linux/arm64
    linux/arm64/v8
    linux/arm64

    docker ps --format '{{json .Platform}}'
    {"architecture":"arm64","os":"linux"}
    {"architecture":"arm64","os":"linux","variant":"v8"}
    {"architecture":"arm64","os":"linux"}

    docker ps --format 'json'
    {"Command":"\"/bin/bash\"","CreatedAt":"2025-05-13 10:12:19 +0000 UTC","ID":"e8b3b2d604f1","Image":"docker-cli-dev","Labels":"desktop.docker.io/binds/0/Source=/Users/thajeztah/go/src/github.com/docker/cli,desktop.docker.io/binds/0/SourceKind=hostFile,desktop.docker.io/binds/0/Target=/go/src/github.com/docker/cli,desktop.docker.io/mounts/0/Source=/var/run/docker.sock,desktop.docker.io/mounts/0/SourceKind=dockerSocketProxied,desktop.docker.io/mounts/0/Target=/var/run/docker.sock,desktop.docker.io/ports.scheme=v2","LocalVolumes":"1","Mounts":"/host_mnt/User…,docker-cli-dev…,/run/host-serv…","Names":"optimistic_nightingale","Networks":"bridge","Platform":{"architecture":"arm64","os":"linux"},"Ports":"","RunningFor":"38 minutes ago","Size":"0B","State":"running","Status":"Up 38 minutes"}
    {"Command":"\"/docker-entrypoint.…\"","CreatedAt":"2025-05-13 09:58:01 +0000 UTC","ID":"c93b808dd54e","Image":"nginx:alpine","Labels":"desktop.docker.io/ports.scheme=v2,maintainer=NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e","LocalVolumes":"0","Mounts":"","Names":"mycontainer","Networks":"bridge","Platform":{"architecture":"arm64","os":"linux","variant":"v8"},"Ports":"80/tcp","RunningFor":"53 minutes ago","Size":"0B","State":"running","Status":"Up 53 minutes"}
    {"Command":"\"/usr/bin/gotty --ti…\"","CreatedAt":"2025-05-13 07:31:18 +0000 UTC","ID":"cbb981b06e46","Image":"thajeztah/dockershell:latest","Labels":"desktop.docker.io/ports.scheme=v2,com.thajeztah.docker-shell=1","LocalVolumes":"0","Mounts":"","Names":"trusting_goldstine","Networks":"bridge","Platform":{"architecture":"arm64","os":"linux"},"Ports":"0.0.0.0:55000-\u003e8080/tcp","RunningFor":"3 hours ago","Size":"0B","State":"running","Status":"Up 3 hours"}

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-21 12:44:38 +02:00
7aa6c79c0a docker ps: add "Platform" as formatting option
docker ps --format 'table {{.ID}}\t{{.Image}}{{.Command}}\t{{.RunningFor}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t{{.Platform}}'
    CONTAINER ID   IMAGECOMMAND                CREATED          STATUS          PORTS     NAMES              PLATFORM
    e422855eac55   docker-cli-dev"/bin/bash"   12 minutes ago   Up 12 minutes             strange_jennings   linux/arm64

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-21 12:43:01 +02:00
af090512a6 Merge pull request #6084 from thaJeztah/bump_engine
vendor: github.com/docker/docker 8601b22f5db5 (v28.2-dev)
2025-05-20 10:57:13 +02:00
067587bf15 Merge pull request #6085 from thaJeztah/bump_cli_docs_tool
vendor: github.com/docker/cli-docs-tool v0.10.0
2025-05-20 09:30:29 +02:00
ed5d9757c9 vendor: github.com/docker/docker 8601b22f5db5 (v28.2-dev)
full diff: https://github.com/docker/docker/compare/v28.2.0-rc.1...8601b22f5db511354d643a7722d11d33aa7ae13f

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 22:47:14 +02:00
89f38282fd vendor: github.com/docker/docker v28.2.0-rc.1
no diff: same commit, but tagged

full diff: https://github.com/docker/docker/compare/7937f0846c13...v28.2.0-rc.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 22:40:55 +02:00
9d027dff40 Dockerfile: update golangci-lint to v2.1.5
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:16:23 +02:00
d1e9946ab8 golangci-lint: enable more linters
Enables the asasalint, exptostd, fatcontext, gocheckcompilerdirectives,
iface, makezero, and spancheck linters.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:13 +02:00
615ffee13b golangci-lint: enable nosprintfhostport linter
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:12 +02:00
c1313a92a0 golangci-lint: enable makezero linter
cli/command/container/formatter_stats_test.go:339:11: append to slice `stats` with non-zero initialized length (makezero)
            stats = append(stats, entry)
                    ^

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:12 +02:00
18e911c958 cli/command/container: TestContainerStatsContextWriteTrunc: use subtests
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:12 +02:00
d65f0c9bbf golangci-lint: enable exhaustive linter
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:14:04 +02:00
b64d9b3b19 golangci-lint: replace nilerr for nilnesserr
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:07:15 +02:00
062ad57ce2 golangci-lint: enable mirror linter
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 20:07:05 +02:00
915b3fe992 vendor: github.com/docker/cli-docs-tool v0.10.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 17:44:21 +02:00
2ef9ab4494 golangci-lint: align comments
Format comments to be the same as in moby/moby for easier comparing.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 15:36:11 +02:00
d14b7e8d09 golangci-lint: remove exclusions for ST1020, ST1022
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 15:33:44 +02:00
0ffb72419a Merge pull request #6083 from thaJeztah/bump_engine
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker 7937f0846c13 (master, v28.x dev)
2025-05-19 14:27:28 +02:00
4665398a06 vendor: github.com/docker/docker 7937f0846c13 (master, v28.x dev)
full diff: 4b9f0707a0...7937f0846c

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-19 14:07:50 +02:00
d1857decba Merge pull request #6081 from thaJeztah/unify_cli_opts
cli/command, cli-plugins/plugin: some cleanups in WithInitializeClient, withPluginClientConn
2025-05-19 11:28:11 +02:00
240b06991b cli-plugins/plugin: rewrite withPluginClientConn w/ WithAPIClient
The WithInitializeClient looks redundant altogether, so let's
rewrite this function to not depend on it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 23:36:20 +02:00
7b1f889074 cli/command: make WithInitializeClient a wrapper for WithAPIClient
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 23:31:53 +02:00
0d82ff4ae1 cli/command: move WithInitializeClient to other options
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 23:29:52 +02:00
8e5fb5bd07 Merge pull request #6080 from vvoland/vendor-docker
vendor: github.com/docker/docker v28.2.0-dev (4b9f0707a039)
2025-05-16 19:22:18 +00:00
8c8a81eaea vendor: github.com/docker/docker v28.2.0-dev (4b9f0707a039)
full diff: b45aa469ca...4b9f0707a0

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-16 21:12:49 +02:00
0674a0085a Merge pull request #6079 from thaJeztah/less_errdefs
remove uses of github.com/docker/docker/errdefs
2025-05-16 21:06:21 +02:00
1058b22800 cli/command: remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:30:00 +02:00
eebf6824fc cli/command/plugin: remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:30:00 +02:00
214d2bfb6b cli/command/image: remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:30:00 +02:00
c4009463a7 cli/command/builder: remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:30:00 +02:00
3d68a39015 cli/command/system: remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:30:00 +02:00
251725676e cli/command/trust: remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:29:50 +02:00
1168edb259 cli/command/volume: use stdlib errors, remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:29:39 +02:00
981e75e0f4 cli/command/network: use stdlib errors, remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:28:59 +02:00
3382ee3e99 cli/command/context: use stdlib errors, remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:18:41 +02:00
b883976531 cli/context/store: use stdlib errors, remove errdefs uses
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:18:40 +02:00
bfc6aeca4a cli/command/container: define local errors instead of errdefs
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 20:18:40 +02:00
eee0cf9117 Merge pull request #6078 from vvoland/info-devices
system/info: Show discovered devices
2025-05-16 19:59:07 +02:00
f6a077a831 system/info: Show discovered devices
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-16 19:35:29 +02:00
be03dc9ce7 vendor: github.com/docker/docker v28.2.0-dev (b45aa469cac7)
full diff: c04dec1143...b45aa469ca

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-16 19:35:27 +02:00
628b2f1a81 Merge pull request #6074 from thaJeztah/c8d_errdefs_is
switch to github.com/containerd/errdefs for error-matching
2025-05-16 18:11:26 +02:00
d43b7daeb7 Merge pull request #6075 from thaJeztah/bump_engine
vendor: github.com/docker/docker c04dec11437f (master, v28.x dev)
2025-05-16 17:27:37 +02:00
7e609d491b vendor: github.com/docker/docker c04dec11437f (master, v28.x dev)
full diff: fd1a78e0a3...c04dec1143

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 17:01:28 +02:00
d956110288 Merge pull request #1581 from thaJeztah/dont_use_tls_for_sockets
Don't use TLS for socket connections
2025-05-16 15:45:13 +02:00
557cabb71e switch to github.com/containerd/errdefs for error-matching
replace uses of docker/errdefs.IsXXX utilities with their containerd/errdefs
equivalent.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 15:27:43 +02:00
c108da5d19 Merge pull request #6070 from thaJeztah/enable_importas_linter
golangci-lint: enable importas linter
2025-05-16 15:07:31 +02:00
12992f76e0 Merge pull request #6073 from thaJeztah/format_cleanups_and_fixes
cli/command/formatter: fix .Labels format being randomized
2025-05-16 15:01:38 +02:00
5ee17eefe6 cli/command/formatter: fix .Labels format being randomized
The labels are stored as a map, causing the output to be randomized.
This patch sorts the result to get a consistent output.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 14:11:56 +02:00
e6bf6dcd90 cli/command/formatter: minor cleanups
no need to initialize with an empty string

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 14:10:34 +02:00
43e496b396 cli/command/inspect: minor cleanup and improvements
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 14:10:31 +02:00
cacd86c3f3 Merge pull request #6072 from thaJeztah/bump_version
bump version to v28.2.0-dev
2025-05-16 11:44:29 +00:00
8752709427 Merge pull request #6071 from thaJeztah/update_authors2
update authors and mailmap
2025-05-16 11:44:12 +00:00
f03aeddfcc bump version to v28.2.0-dev
This file is only used as default if no version is specified. We
should probably get rid of this, but let's update it to better
reflect the version that developer builds are building.

d48fb9f9f7/docker.Makefile (L22)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 13:00:20 +02:00
49f2dd0761 update .mailmap and authors
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 12:58:03 +02:00
9f68bc0a2b golangci-lint: enable importas linter
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 12:36:30 +02:00
378e754c88 use consistent alias for gotest.tools/v3/assert/cmp
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 12:36:14 +02:00
7eaae97e37 cli/command/container: use consistent alias for oci-spec
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 12:34:28 +02:00
67f029ec02 Don't use TLS for socket connections
Before this patch:

    mkdir -p ./tempconfig && touch ./tempconfig/ca.pem ./tempconfig/cert.pem ./tempconfig/key.pem

    DOCKER_TLS_VERIFY=1 DOCKER_CONFIG=./tempconfig DOCKER_HOST=unix:///var/run/docker.sock docker info
    Failed to initialize: failed to retrieve context tls info: ca.pem seems invalid

With this patch:

    DOCKER_TLS_VERIFY=1 DOCKER_CONFIG=./tempconfig DOCKER_HOST=unix:///var/run/docker.sock docker info
    Client:
      Version:    28.1.1-25-g2dfe7b558.m
      Context:    default
    ...

Note that the above is just to illustrate; there's still parts in context-
related code that will check for, and load TLS-related files ahead of time.
We should make some of that code lazy-loading (i.e., don't load these until
we're actually gonna make an API connection). For example, if the TLS files
are missing;

    rm ./tempconfig/*.pem
    DOCKER_TLS_VERIFY=1 DOCKER_CONFIG=./tempconfig DOCKER_HOST=unix:///var/run/docker.sock docker info
    Failed to initialize: unable to resolve docker endpoint: open tempconfig/ca.pem: no such file or directory

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 12:10:50 +02:00
77fbbc38de Merge pull request #6063 from giautm/patch-1
cli/cli: use `len()` to check frontend ports in the `port` command
2025-05-16 12:03:15 +02:00
bca09c7ac4 Merge pull request #6019 from thaJeztah/docker_auth_config_socket
cli/command/container: --use-api-socket: support DOCKER_AUTH_CONFIG
2025-05-16 11:57:49 +02:00
267b5e7982 Merge pull request #6069 from thaJeztah/fluentd_completion
completion: add completion for "fluentd-write-timeout"
2025-05-16 11:46:34 +02:00
fe6241a5f7 Merge pull request #6066 from thaJeztah/bump_engine
vendor: github.com/docker/docker fd1a78e0a388 (master, v28.x dev)
2025-05-16 08:37:11 +00:00
535ac074d0 completion: add completion for "fluentd-write-timeout"
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 01:27:49 +02:00
678f7182e2 Merge pull request #6045 from robmry/allow_direct_routing
Docs: Add Linux daemon option --allow-direct-routing
2025-05-16 01:24:16 +02:00
218c7ad958 cli/command/formatter: use ContainerState consts
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 01:13:14 +02:00
6fd9c57744 cli/command/container: use ContainerState consts
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 01:13:14 +02:00
21e96eaaa7 cli/command/completion: use ContainerState consts in tests
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 01:13:14 +02:00
c9d04c770a cli/command/formatter: touch-up godoc for ContainerContext.State()
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 01:13:14 +02:00
d1c76198ba cli/command/formatter: TestContainerPsContext add test for State()
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 01:13:13 +02:00
54bf220a16 vendor: github.com/docker/docker fd1a78e0a388 (master, v28.x dev)
full diff: cb38cc0fdd...fd1a78e0a3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-16 01:12:36 +02:00
518ba2b4d8 Merge pull request #6061 from thaJeztah/bump_engine
vendor: github.com/docker/docker cb38cc0fdd55 (master, v28.x dev)
2025-05-13 07:51:58 +00:00
c409383dbc cli/cli/port: use len() to check frontends ports
This ensure the command won't print an empty output if the `frontends` port is nil

Signed-off-by: Giau. Tran Minh <hello@giautm.dev>
2025-05-13 03:48:15 +07:00
e07abcf433 vendor: github.com/docker/docker cb38cc0fdd55 (master, v28.x dev)
full diff: https://github.com/docker/docker/compare/v28.1.1...cb38cc0fdd555eae6c53be1c427c0a28d52965f6

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-12 17:28:34 +02:00
75a57131a8 Merge pull request #6060 from vvoland/update-go
update to go1.24.3
2025-05-12 17:15:18 +02:00
b0da72a318 update to go1.24.3
- https://go.dev/doc/go1.24
- https://go.dev/doc/devel/release#go1.24.3

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-05-12 13:25:14 +02:00
dd4536e4d0 Merge pull request #6058 from thaJeztah/restore_terminal
restore terminal when terminating after 3 signals
2025-05-12 10:35:20 +02:00
a09028c837 Merge pull request #6054 from thaJeztah/unify_internal
move cli/internal/ packages to top-level internal/
2025-05-12 10:32:41 +02:00
a17b9c542b restore terminal when terminating after 3 signals
When attaching to a container, hijack puts the terminal in raw mode,
and local echo is disabled. In normal cases, the terminal is restored
once the container detaches;
6f856263c2/cli/command/container/hijack.go (L40-L44)

However, when the CLI is forced to exit (after 3 signals), we `os.Exit(1)`,
which causes defers to not be executed, and because of this, the terminal
not being restored.

For example; start a container that's attached;

    docker run -it --rm --sig-proxy=false alpine sleep 20

In another terminal send a SIGINT 3 times to force terminate;

    kill -sINT $(pgrep -af docker\ run)
    kill -sINT $(pgrep -af docker\ run)
    kill -sINT $(pgrep -af docker\ run)

The first terminal shows that the docker cli was terminated;

    got 3 SIGTERM/SIGINTs, forcefully exiting

However, the terminal was not restored, so local echo is disabled, and
typing any command in the terminal does not show output (a manual `stty echo`
is needed to restore).

With this patch, the terminal is restored before we forcefully exit the
docker CLI. Restoring is a no-op if there's no previous state, so we
can unconditionally execute this.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-09 15:26:57 +02:00
6f856263c2 Merge pull request #6053 from thaJeztah/import_docs
docs: import: assorted fixes and touch-ups
2025-05-08 12:53:29 +02:00
a2a13765f7 Merge pull request #6052 from thaJeztah/inspect_completion
inspect: add shell completion, improve flag-description for `--type` and improve validation
2025-05-06 20:29:54 +02:00
12c0c13c3b Merge pull request #6051 from thaJeztah/inspect_fix_flags
docs: move flag examples to right section
2025-05-06 20:29:27 +02:00
479c7add4d cli/internal/oauth: move to top-level "internal"
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 20:09:28 +02:00
b6059af164 cli/internal/logdetails: move to top-level "internal"
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 20:04:25 +02:00
d0d8d1dc72 cli/internal/jsonstream: move to top-level "internal"
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 20:04:21 +02:00
4520a390d2 docs: import: add example for multiple --change flags
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 19:40:53 +02:00
763ae3e0fb docs: import: update documentation for --platform
The `--platform` flag originally was added for the experimental LCOW
feature and only accepted the target operating system. Current versions
of Docker allow passing both OS and Architecture, so updating the
documentation to reflect this.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 19:40:53 +02:00
2a67d601ad docs: import: update list of supported options for --change
Update the list of accepted "change" commands to match what's accepted
by the daemon. This list is the same for "docker commit" and "docker import",
which is defined by the [`validCommitCommands`] variable.

[`validCommitCommands`]: https://github.com/moby/moby/blob/v28.1.1/builder/dockerfile/builder.go#L30-L42

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 19:40:52 +02:00
79207281fb docs: import: fix anchor-links and minor touch-up
- Put the content related to `--changes` under a heading with the correct
  anchor, so that it will be linked from the "options" table.
- Move note about `sudo` to be under the right example.
- Update  some examples to directly read from a file instead of piping.
- Add heading for the `--message` flag.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 19:40:47 +02:00
52752f3aa2 inspect: improve (flag) validation
Produce an error if the `--type` flag was set, but an empty value
was passed.

Before this patch:

    docker inspect --type "" foo
    # json output

    docker inspect --type unknown foo
    "unknown" is not a valid value for --type

With this patch:

    docker inspect --type "" foo
    type is empty: must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume"

    docker inspect --type unknown foo
    unknown type: "unknown": must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume"

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 15:54:29 +02:00
8c5aaff57f inspect: update flag description of "--type" flag
Before this patch:

    docker inspect --help | grep '\-\-type'
          --type string     Return JSON for specified type

With this patch:

    docker inspect --help | grep '\-\-type'
          --type string     Only inspect objects of the given type

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 15:45:38 +02:00
7203340f53 inspect: add shell-completion for "--type" flag
With this patch:

    docker inspect --type <TAB>
    config     image    node    secret   task
    container  network  plugin  service  volume

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 15:43:55 +02:00
877ea1ce35 inspect: disable default (file) completion
Before this patch, flags and arguments would complete using filenames
from the current directory;

    docker inspect --type <TAB>
    AUTHORS       CONTRIBUTING.md             docs/             Makefile            SECURITY.md
    ...

    docker inspect <TAB>

With this patch, no completion is provided;

    docker inspect --type <TAB>
    # no results

    docker inspect <TAB>
    # no results

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 15:43:55 +02:00
f61e2bb6f1 inspect: add consts / enum for object-types
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 15:43:55 +02:00
25a168106a Merge pull request #6050 from brlin-tw/patch-1
docs: run: Drop unnecessary command options of the --workdir example
2025-05-06 15:22:33 +02:00
fc3ed90e3a docs: move flag examples to right section
When generating our docs, flag-descriptions are currently expected
to be under the "examples" section for them to be linked correctly.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-06 13:32:30 +02:00
75d54ac613 run: Drop unnecessary command options of the --workdir example
The `-i` and `-t` options are not needed, as the `pwd` command does not require a TTY nor an interactive session.  Drop them to simplify the example and avoid causing unnecessary confusion to the reader.

Signed-off-by: 林博仁(Buo-ren Lin) <buo.ren.lin@gmail.com>
2025-05-06 18:53:42 +08:00
f3a812f8f4 Add Linux daemon option --allow-direct-routing
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-05-01 10:46:21 +01:00
58d318b990 Merge pull request #6036 from thaJeztah/improve_username_handling
cli/command/registry: login: improve flag validation
2025-04-30 19:09:18 +02:00
3707d07381 Merge pull request #6041 from thaJeztah/bump_creds_helper_0.9.3
vendor: github.com/docker/docker-credential-helpers v0.9.3
2025-04-29 16:41:25 +02:00
1af8ae4be4 Merge pull request #6040 from thaJeztah/bump_md2man
vendor github.com/cpuguy83/go-md2man/v2 v2.0.7
2025-04-29 16:40:06 +02:00
fb261fdd0c Merge pull request #6037 from mmorel-35/staticcheck/quickfixes
fix(QF1003): Convert if/else-if chain to tagged switch
2025-04-28 21:20:22 +02:00
54efe295f0 fix(QF1003): Convert if/else-if chain to tagged switch
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-04-28 18:35:09 +02:00
09863a702c vendor: github.com/docker/docker-credential-helpers v0.9.3
no changes in vendored code

full diff: https://github.com/docker/docker-credential-helpers/compare/v0.9.2...v0.9.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-26 16:30:02 +02:00
4679278636 vendor github.com/cpuguy83/go-md2man/v2 v2.0.7
full diff: https://github.com/cpuguy83/go-md2man/compare/v2.0.6...v2.0.7

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-26 16:27:49 +02:00
e7af1812cf cli/command/registry: login: improve flag validation
Before this change, some errors could be ambiguous as they did not
distinguish a flag to be omitted, or set, but with an empty value.

For example, if a user would try to loging but with an empty username,
the error would suggest that the `--username` flag was not set (which
it was);

I don't have `MY_USERNAME` set in this shell;

    printenv MY_USERNAME || echo 'variable not set'
    variable not set

Now, attempting to do a non-interactive login would result in an
ambiguous error;

        echo "supersecret" | docker login --password-stdin --username "$MY_USERNAME"
        Must provide --username with --password-stdin

With this patch applied, the error indicates that the username was empty,
or not set;

        echo "supersecret" | docker login --password-stdin --username "$MY_USERNAME"
        username is empty
        echo "supersecret" | docker login --password-stdin
        the --password-stdin option requires --username to be set
        echo "supersecret" | docker login --password-stdin --password "supersecret"
        conflicting options: cannot specify both --password and --password-stdin

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-25 17:11:05 +02:00
8845ccd60f cli/command/registry: login: add unit test for flag validation
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-25 16:39:55 +02:00
c80675bfe1 Merge pull request #6028 from mmorel-35/golangci-lint@v2
chore: bump golangci-lint to v2
2025-04-24 18:37:34 +02:00
aadd7879c9 Merge pull request #6034 from thaJeztah/connhelper_cleanups_step2
cli/connhelper/ssh: add NewSpec utility to prevent parsing URL twice
2025-04-23 16:00:07 +02:00
8638ceff2c Merge pull request #6032 from thaJeztah/deprecate_ListOpts_GetAll
opts: deprecate ListOpts.GetAll in favor of ListOpts.GetSlice
2025-04-23 15:56:38 +02:00
ef0a5eb694 chore: bump golangci-lint to v2
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-04-23 13:11:58 +00:00
5215b1eca4 opts: deprecate ListOpts.GetAll in favor of ListOpts.GetSlice
The `GetSlice()` function is part of cobra's [cobra.SliceValue] interface,
and duplicates the older `GetAll()` method. This patch deprecates the
`GetAll()` method in favor of `GetSlice()`.

[cobra.SliceValue]: https://pkg.go.dev/github.com/spf13/cobra@v1.9.1#SliceValue

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-23 14:31:50 +02:00
ca199577a9 Merge pull request #6031 from thaJeztah/change_flag_uses
cli/command: change uses of ListOpts.GetAll for GetSlice
2025-04-23 14:31:28 +02:00
f105e964da cli/connhelper: don't parse URL twice
This function was parsing the same URL twice; first to detect the
scheme, then again (through ssh.ParseURL) to construct a ssh.Spec.

Change the function to use the URL that's parsed, and use ssh.NewSpec
instead.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-23 14:29:44 +02:00
11b53dabc6 cli/connhelper/ssh: add NewSpec utility
This allows creating a spec from an existing url.URL

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-23 14:29:42 +02:00
55073c404c cli/connhelper/ssh: tweak error-message (capitalize SSH)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-23 14:27:49 +02:00
22a573649d cli/command: change uses of ListOpts.GetAll for GetSlice
The `GetSlice()` function is part of cobra's [cobra.SliceValue] interface,
and duplicates the older `GetAll()` method. This patch changes our use
of the `GetAll()` method with the intent to deprecated it in future.

[cobra.SliceValue]: https://pkg.go.dev/github.com/spf13/cobra@v1.9.1#SliceValue

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-23 13:51:37 +02:00
81a5db6b82 Merge pull request #6030 from thaJeztah/flag_multiple_completion
opts: ListOpts: implement cobra.SliceValue to fix shell completion
2025-04-23 13:51:11 +02:00
11fea00142 Merge pull request #6022 from thaJeztah/connhelper_cleanups_step1
cli/connhelper: cleanups and test improvements
2025-04-23 13:37:27 +02:00
eeda0af3f4 Merge pull request #6029 from thaJeztah/stack_deploy_failearly
stack deploy: fail early on invalid image reference format
2025-04-23 11:32:35 +00:00
aa065b43c1 Merge pull request #6033 from thaJeztah/fix_import_heading
docs: image import: fix heading to be included in online docs
2025-04-23 13:27:47 +02:00
f36b28eae4 Merge pull request #6024 from thaJeztah/move_otel
move hack/otel to contrib
2025-04-23 13:26:47 +02:00
572e3f1c53 opts: ListOpts: implement cobra.SliceValue to fix shell completion
Cobra's shell completion has specific rules to decide whether a flag can
be accepted multiple times. If a flag does not meet that rule, it only
completes the flag name once; some of those rules depend on the "type"
of the option to end with "Array" or "Slice", which most of our options
don't.

Starting with Cobra 1.9, it also checks whether an option implements
the [cobra.SliceValue] interface (see [spf13/cobra 2210]).

This patch implements the [cobra.SliceValue] interface on ListOpts, so
that these options can be completed multiple times.

In a follow-up, we can update our code to replace our uses of `GetAll()`,
which is identical with the `GetSlice()` method, and potentially deprecate
the old method.

Before this patch, ListOpts would only be completed once when completing
flag names. For example, the following would show the `--label` flag the
first time, but omit it if a `--label` flag was already set;

    docker run--l<TAB>
    --label                  (Set meta data on a container)  --link-local-ip  (Container IPv4/IPv6 link-local addresses)
    --label-file  (Read in a line delimited file of labels)  --log-driver             (Logging driver for the container)
    --link                  (Add link to another container)  --log-opt                              (Log driver options)

    docker run --label hello --l<TAB>
    --label-file  (Read in a line delimited file of labels)  --link-local-ip  (Container IPv4/IPv6 link-local addresses)  --log-opt  (Log driver options)
    --link                  (Add link to another container)  --log-driver             (Logging driver for the container)

With this patch, the completion script correctly identifies the `--label`
flag to be accepted multiple times, and also completes it when already
set;

    docker run --label hello --l<TAB>
    --label                  (Set meta data on a container)  --link-local-ip  (Container IPv4/IPv6 link-local addresses)
    --label-file  (Read in a line delimited file of labels)  --log-driver             (Logging driver for the container)
    --link                  (Add link to another container)  --log-opt                              (Log driver options)

[cobra.SliceValue]: https://pkg.go.dev/github.com/spf13/cobra@v1.9.1#SliceValue
[spf13/cobra 2210]: https://github.com/spf13/cobra/pull/2210

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-23 12:22:42 +02:00
3c4bcce81e docs: image import: fix heading to be included in online docs
The online docs looks for level-3 headings under the "examples"
to be included.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-23 09:57:08 +02:00
bcb36e26cb stack deploy: fail early on invalid image reference format
Before this patch, `docker stack deploy` would not validate the image
reference on the client side, depending on the daemon to return an error,
which was not always easy to interpret;

    docker stack deploy -c docker-compose.yaml mystack
    Creating service mystack_myservice
    failed to create service mystack_myservice: Error response from daemon: rpc error: code = InvalidArgument desc = ContainerSpec: image reference must be provided

    IMAGE_NAME=FOOBAR  docker stack deploy -c docker-compose.yaml mystack
    Creating service mystack_myservice
    failed to create service mystack_myservice: Error response from daemon: rpc error: code = InvalidArgument desc = ContainerSpec: "FOOBAR" is not a valid repository/tag

With this patch, the CLI validates the image-reference for each service,
producing an error if the reference is empty or invalid.

    docker stack config -c docker-compose.yaml
    invalid service myservice: no image specified

    IMAGE_NAME=FOOBAR  ~/Projects/cli/build/docker stack deploy -c docker-compose.yaml mystack
    invalid image reference for service myservice: invalid reference format: repository name (library/FOOBAR) must be lowercase

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-22 16:23:41 +02:00
61c6818f0b Merge pull request #6026 from vvoland/vendor-docker
vendor: github.com/docker/docker v28.1.1
2025-04-18 21:46:44 +02:00
f3deb28111 vendor: github.com/docker/docker v28.1.1
full diff: https://github.com/docker/docker/compare/v28.1.0...v28.1.1

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-04-18 13:46:36 +02:00
4eba377327 Merge pull request #6025 from thaJeztah/bump_compose
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
Dockerfile: update compose to v2.35.1
2025-04-18 09:44:47 +00:00
9cd35577fc Dockerfile: update compose to v2.35.1
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-18 00:04:38 +02:00
1ca0a7d57a move hack/otel to contrib
Aligning with where we put this in moby, and contrib is a slightly
more suitable location for this.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 23:57:50 +02:00
c77159623b cli/connhelper: use stdlib errors
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 21:42:55 +02:00
2c24fb2bcd cli/connhelper/commandcon: use stdlib errors
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 21:42:55 +02:00
8c0c1db679 cli/connhelper/ssh: use stdlib errors and improve errors
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 21:38:52 +02:00
6ca9766897 cli/connhelper/ssh: improve GoDoc for ParseURL
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 21:34:18 +02:00
126713648e cli/connhelper/ssh: TestParseURL: various improvements
- use designated example domains as example value
- swap "expected" and "actual" values in assertions
- add doc / name for each test
- add test-cases for remote commands
- also test the Spec that's produced, not just the args
- merge two test-cases that could be combined

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 21:28:09 +02:00
cf87480ab5 Merge pull request #6020 from thaJeztah/bump_engine_28.1
vendor: github.com/docker/docker v28.1.0
2025-04-17 17:02:28 +02:00
adb0d29504 vendor: github.com/docker/docker v28.1.0
no diff; same commit, but tagged

full diff: https://github.com/docker/docker/compare/v28.1.0-rc.2...v28.1.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 16:12:40 +02:00
73be7342a6 cli/command/container: --use-api-socket: support DOCKER_AUTH_CONFIG
With this patch, the `--use-api-socket` flag can obtain credentials from
a validly formatted `DOCKER_AUTH_CONFIG` environment-variable. If the
env-var is not set, or doesn't contain credentials, it falls back to
attempting to read credentials from the CLI's configured credentials
store.

With this patch:

    # Make sure there's no auth on disk first
    mkdir -p tmpConfig
    export DOCKER_CONFIG=$PWD/tmpConfig
    rm -f $PWD/tmpConfig/config.json

    # no credentials
    docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    cat: can't open '/run/secrets/docker/config.json': No such file or directory

    # pass credentials through DOCKER_AUTH_CONFIG
    DOCKER_AUTH_CONFIG='{"auths": {"https://index.docker.io/v1/": {"auth": "am9lam9lOmhlbGxv"}}}' docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    {
        "auths": {
            "https://index.docker.io/v1/": {
                "auth": "am9lam9lOmhlbGxv"
            }
        }
    }

    # credentials from file if no DOCKER_AUTH_CONFIG is set
    echo '{"auths": {"https://index.docker.io/v1/": {"auth": "am9lam9lOmhlbGxv"}}}' > "${DOCKER_CONFIG}/config.json"
    docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    {
        "auths": {
            "https://index.docker.io/v1/": {
                "auth": "am9lam9lOmhlbGxv"
            }
        }
    }

    # same if DOCKER_AUTH_CONFIG is set, but doesn't contain credentials
    DOCKER_AUTH_CONFIG='{}' docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    {
        "auths": {
            "https://index.docker.io/v1/": {
                "auth": "am9lam9lOmhlbGxv"
            }
        }
    }

    DOCKER_AUTH_CONFIG='{"auths": {}}' docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    {
        "auths": {
            "https://index.docker.io/v1/": {
                "auth": "am9lam9lOmhlbGxv"
            }
        }
    }

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 12:15:57 +02:00
2002204ce9 cli/command/container: createContainer: move fn closer to where used
The "use-api-socket" code got in between, putting a lot of distance
between the declaration and use.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 12:15:57 +02:00
4d8c241ff0 Merge pull request #6018 from thaJeztah/use_api_socket_no_empty
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
cli/command/container: --use-api-socket: don't write empty credentials
2025-04-17 09:52:28 +00:00
711fcaeb25 cli/command/container: --use-api-socket: don't write empty credentials
Before this patch, a valid, but empty set of credentials would still
write a config-file to the container and set `DOCKER_CONFIG`:

    mkdir -p tmpConfig
    export DOCKER_CONFIG=$PWD/tmpConfig

    echo '{}' > "${DOCKER_CONFIG}/config.json"
    docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    {
        "auths": {}
    }

    echo '{"auths": {}}' > "${DOCKER_CONFIG}/config.json"
    docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    {
        "auths": {}
    }

    echo '{"auths": {"https://index.docker.io/v1/": {"auth": "am9lam9lOmhlbGxv"}}}' > "${DOCKER_CONFIG}/config.json"
    docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    {
        "auths": {
            "https://index.docker.io/v1/": {
                "auth": "am9lam9lOmhlbGxv"
            }
        }
    }

With this patch, the `DOCKER_CONFIG` env-var and config-file are only created
if we have credentials to set;

    mkdir -p tmpConfig
    export DOCKER_CONFIG=$PWD/tmpConfig

    echo '{}' > "${DOCKER_CONFIG}/config.json"
    docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    cat: can't open '/run/secrets/docker/config.json': No such file or directory

    echo '{"auths": {}}' > "${DOCKER_CONFIG}/config.json"
    docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    cat: can't open '/run/secrets/docker/config.json': No such file or directory

    echo '{"auths": {"https://index.docker.io/v1/": {"auth": "am9lam9lOmhlbGxv"}}}' > "${DOCKER_CONFIG}/config.json"
    docker run --rm --use-api-socket alpine cat /run/secrets/docker/config.json
    {
        "auths": {
            "https://index.docker.io/v1/": {
                "auth": "am9lam9lOmhlbGxv"
            }
        }
    }

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 11:36:06 +02:00
ed694dbbef Merge pull request #5868 from thaJeztah/bump_go_version
update minimum go version to go1.23
2025-04-17 09:20:56 +00:00
79ab3cb0e8 Merge pull request #6017 from thaJeztah/bump_engine_28.1
vendor: github.com/docker/docker v28.1.0-rc.2
2025-04-17 08:58:07 +00:00
1d768f8983 update go:build tags to go1.23 to align with vendor.mod
Go maintainers started to unconditionally update the minimum go version
for golang.org/x/ dependencies to go1.23, which means that we'll no longer
be able to support any version below that when updating those dependencies;

> all: upgrade go directive to at least 1.23.0 [generated]
>
> By now Go 1.24.0 has been released, and Go 1.22 is no longer supported
> per the Go Release Policy (https://go.dev/doc/devel/release#policy).
>
> For golang/go#69095.

This updates our minimum version to go1.23, as we won't be able to maintain
compatibility with older versions because of the above.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 10:43:47 +02:00
0e75283292 Merge pull request #6016 from thaJeztah/context_completion
context: add shell-completion for context-names
2025-04-17 08:41:48 +00:00
a5b6efa29d vendor: github.com/docker/docker v28.1.0-rc.2
no diff, same commit, but tagged:
https://github.com/docker/docker/compare/3f46cadf398a...v28.1.0-rc.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 10:34:50 +02:00
6fd72c6333 context: add shell-completion for context-names
For now, these are not exported and included in the cli/commands/contexts
package; a copy of this also lives in cmd/docker, but we need to find a
good place for these completions, as some of them bring in additional
dependencies.

Commands that accept multiple arguments provide completion, but removing
duplicates:

    docker context inspect<TAB>
    default  desktop-linux  (current)  production  tcd

    docker context inspec default<TAB>
    desktop-linux  (current)  production  tcd

    docker context inspect default tcd<TAB>
    desktop-linux  (current)  production

For "context export", we provide completion for the first argument, after
which file-completion is provided:

    # provides context names completion for the first argument
    docker context export production<TAB>
    default  desktop-linux  (current)  production  tcd

    # then provides completion for filenames
    docker context export desktop-linux<TAB>
    build/           man/                TESTING.md
    cli/             docker.Makefile     go.mod
    ...

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-17 10:32:18 +02:00
659b026b7f Merge pull request #6015 from Benehiko/fix-login-hints
Fix login hints should only show on hub registry
2025-04-16 18:15:47 +02:00
6c271162c5 Fix login hints should only show on hub registry
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2025-04-16 17:17:23 +02:00
b8857225a0 Merge pull request #6013 from thaJeztah/bump_engine
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker 3f46cadf398a (master, v28.0.0-rc.2)
2025-04-16 12:28:40 +00:00
fc04a49c35 vendor: github.com/docker/docker 3f46cadf398a (master, v28.0.0-rc.2)
full diff: https://github.com/docker/docker/compare/v28.1.0-rc.1...3f46cadf398abdf3196230fea41dac96b5d4016e

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-16 14:22:08 +02:00
129ab99109 Merge pull request #6011 from thaJeztah/bump_archive
vendor: github.com/moby/go-archive v0.1.0
2025-04-16 13:39:56 +02:00
59a723bda6 Merge pull request #6012 from thaJeztah/bump_dev_tools
Dockerfile: update buildx to v0.23.0, compose v2.33.1
2025-04-16 13:39:33 +02:00
6ca77b6529 Merge pull request #6009 from zhangwenlong8911/master
set CGO_ENABLED=1 on loong64
2025-04-16 13:28:57 +02:00
50900c0da7 Dockerfile: update compose to v2.33.1
Looks like later versions are currently missing on Docker Hub

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-16 13:24:28 +02:00
2dcc881d4d Dockerfile: update buildx to v0.23.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-16 13:19:14 +02:00
e7a091eceb vendor: github.com/moby/go-archive v0.1.0
full diff: https://github.com/moby/go-archive/compare/21f3f3385ab7...v0.1.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-16 13:08:08 +02:00
e04b67f51d Merge pull request #6010 from thaJeztah/tweak_platform_completion
completion: remove generic "os-only" for platforms
2025-04-16 09:44:31 +00:00
557d721299 completion: remove generic "os-only" for platforms
Using `--platform=linux` or `--platform=windows` is not commonly
used (or recommended). Let's remove these from the list of suggested
platforms.

We should tweak this completion further, and sort the list based
on the daemon's platform (putting linux first for a Linux daemon,
and windows first on a Windows daemon), possibly with the correct
architecture (and os-version) included, but we don't yet provide
that information in `/_ping`.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-16 11:30:26 +02:00
219d3fe25a Merge pull request #5858 from stevvooe/sjd/include-docker-socket
run: flag to include the docker socket
2025-04-16 10:49:27 +02:00
2b28bb649b set CGO_ENABLED=1 on loong64
Signed-off-by: Wenlong Zhang <zhangwenlong@loongson.cn>
2025-04-16 14:52:19 +08:00
1a502e91c9 run: flag to include the Docker API socket
Adds a flag to the create and run command, `--use-api-socket`, that can
be used to start a container with the correctly configured parameters to
ensure that accessing the docker socket will work with out managing bind
mounts and authentication injection.

The implementation in this PR resolves the tokens for the current
credential set in the client and then copies it into a container at the
well know location of /run/secrets/docker/config.json, setting
DOCKER_CONFIG to ensure it is resolved by existing tooling. We use a
compose-compatible secret location with the hope that the CLI and
compose can work together seamlessly.

The bind mount for the socket is resolved from the current context,
erroring out if the flag is set and the provided socket is not a unix
socket.

There are a few drawbacks to this approach but it resolves a long
standing pain point. We'll continue to develop this as we understand
more use cases but it is marked as experimental for now.

Signed-off-by: Stephen Day <stephen.day@docker.com>
2025-04-15 10:57:44 -07:00
1adc1583a7 Merge pull request #6006 from thaJeztah/bump_engine_28.1
vendor: github.com/docker/docker v28.1.0-rc.1
2025-04-15 17:01:40 +02:00
785a12eeef vendor: github.com/docker/docker v28.1.0-rc.1
no diff; same commit, but tagged;
https://github.com/docker/docker/compare/250792c1a540...v28.1.0-rc.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-12 08:15:26 +02:00
fc99fe2d08 Merge pull request #5994 from aevesdocker/oss-5
docs: replace sshfs with rclone
2025-04-11 17:00:42 +02:00
b501283743 docs: replace sshfs with rclone
Signed-off-by: aevesdocker <allie.sadler@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-11 16:54:46 +02:00
3372bcf821 Merge pull request #6001 from thaJeztah/tweak_prompt
Dockerfile: fix and clean up shell prompt
2025-04-11 16:53:28 +02:00
c528504434 Merge pull request #5947 from thaJeztah/docker_bake
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
add top-level "docker bake" command as alias for "docker buildx bake"
2025-04-11 14:44:08 +00:00
adb0abaec5 add top-level "docker bake" command as alias for "docker buildx bake"
The [`docker buildx bake`][1] command has reached GA; this patch adds
a top-level `docker bake` command as alias for `docker buildx bake` to
improve discoverability and make it more convenient to use.

With this patch:

    docker --help

    Usage:  docker [OPTIONS] COMMAND

    A self-sufficient runtime for containers

    Common Commands:
      run         Create and run a new container from an image
      exec        Execute a command in a running container
      ps          List containers
      build       Build an image from a Dockerfile
      bake        Build from a file
      pull        Download an image from a registry
      push        Upload an image to a registry
      images      List images
    ...

The command is hidden if buildx is not installed;

    docker --help
    Usage:  docker [OPTIONS] COMMAND

    A self-sufficient runtime for containers

    Common Commands:
      run         Create and run a new container from an image
      exec        Execute a command in a running container
      ps          List containers
      build       Build an image from a Dockerfile
      pull        Download an image from a registry
      push        Upload an image to a registry
      images      List images
    ...

We can do some tweaking after this; currently it show an error
in situations where buildx is missing. We don't account for
"DOCKER_BUILDKIT=0", because this is a new feature that requires
buildx, and cannot be "disabled";

buildx missing;

    docker bake
    ERROR: bake requires the buildx component but it is missing or broken.
           Install the buildx component to use bake:
           https://docs.docker.com/go/buildx/

BuildKit disabled:

    DOCKER_BUILDKIT=0 docker bake
    ERROR: bake requires the buildx component but it is missing or broken.
           Install the buildx component to use bake:
           https://docs.docker.com/go/buildx/

[1]: https://www.docker.com/blog/ga-launch-docker-bake/

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-11 16:28:47 +02:00
18178e079f Merge pull request #5981 from thaJeztah/remove_ContextType
context list: remove temporary ContextType from JSON output
2025-04-11 14:21:27 +00:00
e937b52210 Merge pull request #5953 from thaJeztah/opts_remove_deprecated
opts: remove deprecated PortOpt, ConfigOpt, SecretOpt aliases
2025-04-11 14:13:10 +00:00
6aa93d1f40 Merge pull request #5952 from thaJeztah/move_prompt_utils_step1
cli/command: move prompt utilities to separate package
2025-04-11 16:11:12 +02:00
a85062bcdc Merge pull request #5934 from vvoland/inspect-platform
image/inspect: Add --platform flag
2025-04-11 16:08:46 +02:00
0d9d187f31 image/inspect: Add --platform flag
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-04-11 15:53:41 +02:00
559c0121c8 Merge pull request #6002 from vvoland/vendor-docker
vendor: github.com/docker/docker v28.1.0-dev (250792c1a540)
2025-04-11 15:47:59 +02:00
ec9e729f76 vendor: github.com/docker/docker v28.1.0-dev (250792c1a540)
full diff: 511cd1c0a7...250792c1a5

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-04-11 15:23:24 +02:00
07b203e2f2 Merge pull request #5924 from thaJeztah/hide_untagged
docker images --tree: hide both untagged and dangling images by default
2025-04-11 13:14:59 +00:00
f18e239a53 docker images --tree: hide both untagged and dangling images by default
Before this patch, `docker image ls` / `docker image ls` would always
show untagged images, but hide "dangling" images (which effectively
only were produced by the legacy builder) unless `-a` / `--all` was
used. This often resulted in many `<none>:<none>` or `<untagged>` images
to be shown, which had little value to interact with, other than to
garbage collect (`docker system prune`).

In future, we want to take more advantage of containerd's garbage-collecting
features (removing unused images automatically), and this UX change is
a stepping stone toward that.

For now, this patch only changes the behavior for `docker image ls --tree`,
but we should make this the same for "non" --tree as well.

This patch:

- changes `docker image ls` to hide both "untagged" and "dangling" images
  by default.
- changes the behavior of `--all` on the client side to make them visible

The API response remains the same for now, but this is something we can
consider changing in future (possibly more granular than a single boolean).

Before this patch;

    docker image ls --tree
                                                                           i Info →   U  In Use

    IMAGE                                      ID             DISK USAGE   CONTENT SIZE   EXTRA
    docker:cli                                 28fb556c1ea1        276MB         69.8MB
    ├─ linux/amd64                             828f4f57525d           0B             0B
    ├─ linux/arm/v6                            563c0b58e54b           0B             0B
    ├─ linux/arm/v7                            6045d4846c59           0B             0B
    └─ linux/arm64/v8                          11e8dfd68841        276MB         69.8MB

    alpine:latest                              a8560b36e8b8       12.8MB         3.99MB    U
    ├─ linux/amd64                             1c4eef651f65           0B             0B
    ├─ linux/arm/v6                            903bfe2ae994           0B             0B
    ├─ linux/arm/v7                            9c2d245b3c01           0B             0B
    ├─ linux/arm64/v8                          757d680068d7       12.8MB         3.99MB    U
    ├─ linux/386                               2436f2b3b7d2           0B             0B
    ├─ linux/ppc64le                           9ed53fd3b831           0B             0B
    ├─ linux/riscv64                           1de5eb4a9a67           0B             0B
    └─ linux/s390x                             fe0dcdd1f783           0B             0B

    <untagged>                                 c6c1bcb0fd8d       12.8MB         3.99MB
    └─ linux/arm64                             cb171c618ae8       12.8MB         3.99MB

    <untagged>                                 7361ef970703       12.8MB         3.99MB
    └─ linux/arm64                             07033f43e44a       12.8MB         3.99MB

    <untagged>                                 0c62c63b81ec       12.8MB         3.99MB
    └─ linux/arm64                             94742272117f       12.8MB         3.99MB

    <untagged>                                 91dd947eebd0       12.8MB         3.99MB
    └─ linux/arm64                             ee55d203e26f       12.8MB         3.99MB

    <untagged>                                 382d9f57e8d8       12.8MB         3.99MB
    └─ linux/arm64                             5256d47804e3       12.8MB         3.99MB

    <untagged>                                 56fa17d2a7e7       12.8MB         3.99MB
    ├─ linux/amd64                             483f502c0e6a           0B             0B
    ├─ linux/arm/v6                            c79529000bdf           0B             0B
    ├─ linux/arm/v7                            cc455d4b2c47           0B             0B
    ├─ linux/arm64/v8                          508c1b94e1d2       12.8MB         3.99MB
    ├─ linux/386                               f32403957113           0B             0B
    ├─ linux/ppc64le                           23dbce23b88f           0B             0B
    ├─ linux/riscv64                           f9d2da150cee           0B             0B
    └─ linux/s390x                             6bb03952a007           0B             0B

After this patch

    docker image ls --tree
                                                                           i Info →   U  In Use

    IMAGE                                      ID             DISK USAGE   CONTENT SIZE   EXTRA
    docker:cli                                 28fb556c1ea1        276MB         69.8MB
    ├─ linux/amd64                             828f4f57525d           0B             0B
    ├─ linux/arm/v6                            563c0b58e54b           0B             0B
    ├─ linux/arm/v7                            6045d4846c59           0B             0B
    └─ linux/arm64/v8                          11e8dfd68841        276MB         69.8MB

    alpine:latest                              a8560b36e8b8       12.8MB         3.99MB    U
    ├─ linux/amd64                             1c4eef651f65           0B             0B
    ├─ linux/arm/v6                            903bfe2ae994           0B             0B
    ├─ linux/arm/v7                            9c2d245b3c01           0B             0B
    ├─ linux/arm64/v8                          757d680068d7       12.8MB         3.99MB    U
    ├─ linux/386                               2436f2b3b7d2           0B             0B
    ├─ linux/ppc64le                           9ed53fd3b831           0B             0B
    ├─ linux/riscv64                           1de5eb4a9a67           0B             0B
    └─ linux/s390x                             fe0dcdd1f783           0B             0B

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-11 14:58:23 +02:00
1f9a55de6a Dockerfile: fix and clean up shell prompt
The existing approach had some issues with how the control-chars
were escaped; also switching to use Dockerfile here-doc to make
it a bit more readable, and add some comments to the `.bashrc`.

Also make sure the MOTD isn't printed multiple times, and only
for interactive shells, and slightly tweak it with some colors.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-11 13:48:30 +02:00
c718d3f13c Merge pull request #6000 from vvoland/image-tree-totalcontent
cli/command/image: Fix total content size calculation in image tree
2025-04-11 13:45:35 +02:00
1a950db5ce cli/command/image: Fix total content size calculation in image tree
Before this patch, image total content size would only include
container images content size.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-04-11 13:30:20 +02:00
e2865628ae Merge pull request #5983 from thaJeztah/fix_context_non_default
cli/command: DockerCli.Initialize: make sure context-store config is set
2025-04-11 12:46:15 +02:00
e578f156c0 Merge pull request #5998 from thaJeztah/lazy_regexp
use lazyregexp to compile regexes on first use
2025-04-11 12:29:53 +02:00
b74b7b3c40 internal/prompt: TestConfirm: don't use un-keyed structs
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-11 12:23:24 +02:00
ecde8c38a5 internal/prompt: skip fmt.Printf and use writer directly
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-11 12:23:21 +02:00
b37d84fd10 cli/command: move prompt utilities to separate package
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-11 12:23:16 +02:00
af85e1e2f7 cli/command: implement ErrPromptTerminated without errdefs package
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-11 12:15:11 +02:00
8633197105 Merge pull request #5914 from thaJeztah/use_atomicwriter
cli/command: deprecate CopyToFile and reimplement with atomicwriter
2025-04-11 12:10:46 +02:00
94afbc1116 Merge pull request #5999 from thaJeztah/bump_engine
vendor: github.com/docker/docker 511cd1c0a736 (master, v28.x-dev)
2025-04-11 12:09:28 +02:00
4530417f6b vendor: github.com/docker/docker 511cd1c0a736 (master, v28.x-dev)
full diff: 185651d26b...511cd1c0a7

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 22:03:48 +02:00
23d7346f75 Merge pull request #5977 from thaJeztah/deprecate_config_experimental
cli/config/configfile: deprecate ConfigFile.Experimental field
2025-04-10 14:36:11 +02:00
4c820d3ac0 golangci-lint: add forbidigo rules to prevent regex.MustCompile
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:27 +02:00
ced66f22d6 cli/compose/template: use lazyregexp to compile regexes on first use
This package needed an (internal) interface to abstract the lazy-regexp.
For this, I split the implementation from the exported implementation; this
also revealed that some functions are not used (at least not in our code
base), and we could consider deprecating these.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:26 +02:00
0b0fc106dc cli/compose/template: rename vars that shadowed
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:26 +02:00
56c2fa6c0e e2e/cli-plugins: use regexp.Compile to prevent panic in tests
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:26 +02:00
1ed3859879 cli-plugins/manager: use lazyregexp to compile regexes on first use
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:26 +02:00
7fde1f799f cli/context/store: use lazyregexp to compile regexes on first use
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:25 +02:00
d5a8cd4093 cli/command/trust: use lazyregexp to compile regexes on first use
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:25 +02:00
01d8642c7e cli/command/system: use lazyregexp to compile regexes on first use
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:25 +02:00
a16c3a49c8 cli/command/image: use lazyregexp to compile regexes on first use
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:25 +02:00
d76057210a cli/command/container: use lazyregexp to compile regexes on first use
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:25 +02:00
9a849ba00c opts: use lazyregexp to compile regexes on first use
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:24 +02:00
481e6f1477 implement lazyregexp package
Based on the "lazyregexp" package in golang.org/x/mod;
https://cs.opensource.google/go/x/mod/+/refs/tags/v0.19.0:internal/lazyregexp/lazyre.go;l=66-78

This package allows defining regular expressions that should not be
compiled until used, but still providing validation to prevent
invalid regular expressions from producing a panic at runtime.

This is largely a copy of the package from golang.org/x/mod,
with FindAllStringSubmatch and ReplaceAllStringFunc added

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 12:22:24 +02:00
6c2d023d87 swarm/init: Fix --external-ca ignoring cacert option
31d6292458 mistakenly changed the `ToSpec`
function to set all certs passed via `external-ca` to empty strings.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-04-10 11:41:13 +02:00
bcd9c885e3 Merge pull request #5997 from thaJeztah/fastpath_needs_serverinfo
cli/command/system: needsServerInfo: add fast-paths
2025-04-10 09:24:06 +00:00
e587e8a269 Merge pull request #5996 from thaJeztah/bump_x_deps
vendor: update golang.org/x/.. dependencies
2025-04-10 09:23:17 +00:00
932574363f cli/command/system: needsServerInfo: add fast-paths
We can return early without executing the regular expression or evaluating
the template for `--format=json` or `--format='{{json .}}'`.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 10:50:04 +02:00
ac375caa87 Merge pull request #5918 from Benehiko/info-exit-code
system/info: failure to connect to docker socket should propagate error
2025-04-10 10:31:05 +02:00
7cc6b8ebf4 cli/command: deprecate CopyToFile and reimplement with atomicwriter
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 09:46:06 +02:00
b8bcf6f5ad container export: implement file-write with atomicwriter
Same functionality, but implemented with atomicwriter. There's a slight
difference in error-messages produced (but can be adjusted if we want).

Before:

    docker container export -o ./no/such/foo mycontainer
    failed to export container: invalid output path: directory "no/such" does not exist

    docker container export -o /no/permissions mycontainer
    failed to export container: stat /no/permissions: permission denied

After:

    docker container export -o ./no/such/foo mycontainer
    failed to export container: invalid file path: stat no/such: no such file or directory

    docker container export -o /no/permissions mycontainer
    failed to export container: failed to stat output path: lstat /no/permissions: permission denied

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 09:46:06 +02:00
d47d2338b7 image save: implement file-write with atomicwriter
Same functionality, but implemented with atomicwriter. There's a slight
difference in error-messages produced (but can be adjusted if we want).

Before:

    docker image save -o ./no/such/foo busybox:latest
    failed to save image: invalid output path: directory "no/such" does not exist

    docker image save -o /no/permissions busybox:latest
    failed to save image: stat /no/permissions: permission denied

After:

    docker image save -o ./no/such/foo busybox:latest
    failed to save image: invalid file path: stat no/such: no such file or directory

    docker image save -o /no/permissions busybox:latest
    failed to save image: failed to stat output path: lstat /no/permissions: permission denied

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 09:46:05 +02:00
410c0baadd Merge pull request #5992 from thaJeztah/migrate_archive
migrate to use github.com/moby/go-archive
2025-04-10 09:10:41 +02:00
d83a1b777c vendor: golang.org/x/net v0.39.0
full diff: https://github.com/golang/net/compare/v0.36.0...v0.39.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 00:01:30 +02:00
b515831508 vendor: golang.org/x/crypto v0.37.0
full diff: https://github.com/golang/crypto/compare/v0.35.0...v0.37.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-10 00:00:46 +02:00
2d3a81642a vendor: golang.org/x/text v0.24.0
no changes in vendored files

full diff: https://github.com/golang/text/compare/v0.22.0...v0.24.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-09 23:59:55 +02:00
69d903e706 vendor: golang.org/x/sync v0.13.0
full diff: https://github.com/golang/sync/compare/v0.11.0...v0.13.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-09 23:59:03 +02:00
e0fa0596a7 vendor: golang.org/x/time v0.11.0
full diff: https://github.com/golang/time/compare/v0.6.0...v0.11.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-09 23:58:09 +02:00
a91d194d7f vendor: golang.org/x/sys v0.32.0
full diff: https://github.com/golang/sys/compare/v0.31.0...v0.32.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-09 23:57:22 +02:00
a0385bf042 swarm/init: Test init --external-ca with custom cert
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-04-09 16:56:26 +02:00
342a01a9ff migrate to use github.com/moby/go-archive
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-09 13:18:58 +02:00
6714b50288 Merge pull request #5921 from thaJeztah/bump_engine
vendor: github.com/docker/docker 185651d26bc6 (master, v28.0-dev)
2025-04-09 13:12:32 +02:00
2bf317ad5f vendor: github.com/docker/docker 185651d26bc6 (master, v28.0-dev)
full diff: https://github.com/moby/moby/compare/v28.0.4...185651d26bc6281b199a5b7ff1942b53e4f17b96

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

vendor: moby with atomicwriter

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-07 19:20:39 +02:00
91cbde67c5 Merge pull request #5991 from thaJeztah/bump_x_sys
vendor: golang.org/x/sys v0.31.0
2025-04-07 16:02:14 +02:00
49a36daebe vendor: golang.org/x/sys v0.31.0
no changes in vendored code

full diff: https://github.com/golang/sys/compare/v0.30.0...v0.31.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-07 13:57:55 +02:00
90b48f8eb5 Merge pull request #5988 from thaJeztah/bump_sys_user_0.4.0
vendor: github.com/moby/sys/user v0.4.0
2025-04-07 09:37:14 +02:00
763be9b3f8 Merge pull request #5990 from thaJeztah/bump_compress
vendor: github.com/klauspost/compress v1.18.0
2025-04-07 09:36:52 +02:00
527998e6ee Merge pull request #5989 from thaJeztah/bump_go_cmp
vendor: github.com/google/go-cmp v0.7.0
2025-04-07 09:36:33 +02:00
77f40b8e99 vendor: github.com/klauspost/compress v1.18.0
full diff: https://github.com/klauspost/compress/compare/v1.17.11...v1.18.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-05 16:40:12 +02:00
205241bcc6 vendor: github.com/google/go-cmp v0.7.0
full diff: https://github.com/google/go-cmp/v0.6.0...v0.7.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-05 16:38:43 +02:00
edd2f7d9fb vendor: github.com/moby/sys/user v0.4.0
full diff: https://github.com/moby/sys/compare/user/v0.3.0...user/v0.4.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-04 22:01:29 +02:00
bd03f1154f opts: remove deprecated PortOpt, ConfigOpt, SecretOpt aliases
These options were moved to opts/swarmopts in ad21055bac
and have no known external consumers.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-04 21:45:59 +02:00
2631d5ba99 Merge pull request #5985 from thaJeztah/command_fix_tests
cli/command: minor test-fixes and cleanups
2025-04-04 18:21:24 +02:00
a2e179457e Merge pull request #5946 from thaJeztah/prunefilter_cleanup
cli/command: PruneFilters: slight cleanup
2025-04-04 18:19:45 +02:00
2c3cf8db0f Merge pull request #5984 from thaJeztah/fix_prune_cancel_errormessage
cli/command/network: fix error-message for cancelled prune
2025-04-04 18:18:46 +02:00
b65f52fd64 Merge pull request #5982 from thaJeztah/context_unexport_limitreader
cli/context/store: un-export LimitedReader
2025-04-04 18:14:52 +02:00
58fba25b09 Merge pull request #5986 from thaJeztah/bump_golang_1.23.8
update to go1.23.8 (fix CVE-2025-22871)
2025-04-03 11:24:41 +00:00
64413c20ef update to go1.23.8 (fix CVE-2025-22871)
full diff: https://github.com/golang/go/compare/go1.23.7...go1.23.8
release notes: https://go.dev/doc/devel/release#go1.24.2

go1.23.8 (released 2025-04-01) includes security fixes to the net/http package,
as well as bug fixes to the runtime and the go command. See the Go 1.23.8
milestone on our issue tracker for details;

https://github.com/golang/go/issues?q=milestone%3AGo1.23.8+label%3ACherryPickApproved

From the mailing list:

Hello gophers,

We have just released Go versions 1.24.2 and 1.23.8, minor point releases.
These minor releases include 1 security fixes following the security policy:

- net/http: request smuggling through invalid chunked data
  The net/http package accepted data in the chunked transfer encoding
  containing an invalid chunk-size line terminated by a bare LF.
  When used in conjunction with a server or proxy which incorrectly
  interprets a bare LF in a chunk extension as part of the extension,
  this could permit request smuggling.
  The net/http package now rejects chunk-size lines containing a bare LF.
  Thanks to Jeppe Bonde Weikop for reporting this issue.
  This is CVE-2025-22871 and Go issue https://go.dev/issue/71988.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-03 12:34:54 +02:00
db44e59be7 cli/command: use stdlib for temp-dirs
gotest.tools' fs package only provides very minimal benefits here;
use stdlib functions to make things slightly more transparent.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-02 16:45:05 +02:00
ce4b752274 cli/command: TestNewDockerCliAndOperators fix unhandled errors
Assert that the write succeeded; also changing `Fprintf` to `Fprint`,
because we were not using templating (we should check why no linter
complained about this).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-02 16:06:10 +02:00
f66c5a33d0 cli/command: TestHooksEnabled: fix test when config file is present
This test verifies the default behavior, but when running the test
in an environment that already has a ~/.docker/config.json present,
it may fail.

This patch updates the test to configure the config-directory to
point to an empty directory, making sure it's not affected by
state.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-02 16:06:07 +02:00
6523832c73 Merge pull request #5976 from thaJeztah/cli_move_TestExperimentalCLI
cli/command: move TestExperimentalCLI to cli/config
2025-04-02 12:47:32 +00:00
3122b8e7f5 cli/command/network: fix error-message for cancelled prune
This error-message was updated in 7c722c08d0,
but looks like the typo was overlooked in review.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 23:44:00 +02:00
ed0511251d cli/command: DockerCli.Initialize: make sure context-store config is set
In most situations, the CLI is created through the `NewDockerCli` constructor,
however, it's possible to construct a CLI manually (`&DockerCli{}`). We
should probably prevent this (and un-export the `DockerCli` implementation),
but currently have some code-paths that depend on the type being exported.

When constructing the CLI with this approach, the CLI would not be fully
initialized and not have the context-store configuration set up.

 Using the default context store without a config set will result in Endpoints
 from contexts not being type-mapped correctly, and used as a generic
 `map[string]any`, instead of a [docker.EndpointMeta].

When looking up the API endpoint (using [EndpointFromContext]), no endpoint
will be found, and a default, empty endpoint will be used instead which in
its turn, causes [newAPIClientFromEndpoint] to be initialized with the default
config instead of settings for the current context (which may mean; connecting
with the wrong endpoint and/or TLS Config to be missing).

I'm not sure if this situation could happen in practice, but it caused some
of our unit-tests ([TestInitializeFromClient] among others) to fail when
running outside of the dev-container on a host that used Docker Desktop's
"desktop-linux" context. In that situation, the test would produce the wrong
"Ping" results (using defaults, instead of the results produced in the test).

This patch:

- updates the contextStoreConfig field to be a pointer, so that we are
  able to detect if a config was already set.
- updates the `Initialize` function to set the default context-store config
  if no config was found (technically the field is mostly immutable, and
  can only set through `WithDefaultContextStoreConfig`, so this may be
  slightly redundant).

We should update this code to be less error-prone to use; the combination
of an exported type (`DockerCli`), a constructor `NewDockerCli` and a
`Initialize` function (as well as some internal contructors to allow
lazy initialization) make constructing the "CLI" hard to use, and there's
various codepaths where it can be in a partially initialized state. The
same applies to the default context store, which also requires too much
"domain" knowledge to use properly.

I'm leaving improvements around that for a follow-up.

[EndpointFromContext]: 33494921b8/cli/context/docker/load.go (L139-L149)
[docker.EndpointMeta]: 33494921b8/cli/context/docker/load.go (L19-L21)
[newAPIClientFromEndpoint]: 33494921b8/cli/command/cli.go (L295-L305)
[TestInitializeFromClient]: 33494921b8/cli/command/cli_test.go (L157-L205)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 23:24:29 +02:00
ce61ea015c cli/context/store: un-export LimitedReader
It was created for internal use, and is not part of the context-store
public API. It was introduced as part of the "zip import" functionality
added in 291e86289b. Initially it was
[non-exported][1], but during review, some suggestions were made to improve
the implementation, and the [suggested implementation][2] was based on
Go stdlib, but review overlooked that the implementation was now exported.

Let's un-export it, as this was (as outlined) never meant to be a public
type.

[1]: https://github.com/docker/cli/pull/1895#discussion_r287514522
[2]: https://github.com/docker/cli/pull/1895#discussion_r288688768

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 22:03:27 +02:00
cda7235c81 context list: remove temporary ContextType from JSON output
This reverts commit fed9fa0f72.

This removes the ContextType field, which was temporarily added to provide
compatibility with the "compose-cli" wrapper that shipped with Docker Desktop.
The compose-cli wrapper extended the context struct with an additional field
that was not part of the CLI itself, but was used by Visual Studio to detect
the type of context.

This temporary field shipped as part of Docker 27.0 June 2024), which should
be enough time for Visual Studio to have adjusted their integration.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 19:46:36 +02:00
c8f9187157 cli/config/configfile: deprecate ConfigFile.Experimental field
Configuration options for experimental CLI features were deprecated in
docker 19.03 (3172219932), and enabled by
default since docker 20.10 (977d3ae046).

This deprecates the corresponding field in the config-file.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 17:08:05 +02:00
0dabdd1a0d cli/command: move TestExperimentalCLI to cli/config
This test was only testing whether we could load a legacy config-file that
contained the "experimental" (experimental CLI) option. Experimental cli
options are disabled since 977d3ae046 (20.10),
and now enabled by default, but we should not fail to start the cli if the
config-file contains the option.

Move the test to the config package, as it doesn't need the cli for this.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 17:06:39 +02:00
33494921b8 Merge pull request #5980 from thaJeztah/container_use_subtests
cli/command/container: TestNewCreateCommandWithContentTrustErrors use subtests
2025-04-01 16:24:05 +02:00
c911ced1a4 Merge pull request #5979 from thaJeztah/fix_TestNewPortCommandOutput
cli/command/container: TestNewPortCommandOutput: remove DCT
2025-04-01 15:47:12 +02:00
d726a9b4cd Merge pull request #5978 from thaJeztah/cli_command_update_TestNewDockerCliAndOperators
cli/command: TestNewDockerCliAndOperators: update test without DCT
2025-04-01 15:46:32 +02:00
1c54b0ba66 Merge pull request #5975 from thaJeztah/internalize_image_runsave
cli/command/image: deprecate RunPull and make internal
2025-04-01 15:14:17 +02:00
4a3466eeb6 cli/command/container: TestNewCreateCommandWithContentTrustErrors use-subtests
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 14:53:51 +02:00
12d637c1b5 cli/command/container: TestNewPortCommandOutput: remove DCT
This looks like a copy/paste from other tests, because this test
does not test anything related to docker content trust.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 14:48:02 +02:00
8f9fec11ab cli/command: TestNewDockerCliAndOperators: update test without DCT
Use something more generic to verify the behavior.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 13:07:02 +02:00
2328745f92 cli/command/image: deprecate RunPull and make internal
This function was exported in 812f113685
for use in other parts of the CLI, but it's now only used locally.

Make it internal again, as it was never designed to be exported. There
are no known external consumers of this function, but deprecating it
first, in case there are.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 09:33:04 +02:00
b557e37a49 cli/command/image: un-export RunSave
This function was exported in e43c7920ea
for use of "docker app", which is now deprecated. The signature of this
function also depended on a non-exported type, so it could not be used
externally.

Make it internal again, as it was never designed to be exported. There
are no known external consumers of this function.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 09:32:58 +02:00
9b2479dca7 cli/command/image: un-export RunPush
This function was exported in e43c7920ea
for use of "docker app", which is now deprecated. The signature of this
function also depended on a non-exported type so it could not be used
externally.

Make it internal again, as it was never designed to be exported. There
are no known external consumers of this function.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-04-01 09:31:57 +02:00
2b84421520 Merge pull request #5974 from thaJeztah/bump_docker_28.0.4
vendor: github.com/docker/docker v28.0.4
2025-03-31 17:04:12 +00:00
207a1a0dd8 Merge pull request #5973 from thaJeztah/remove_deprecated_isautomated_docs
docs/reference: search: remove mention of deprecated "IsAutomated"
2025-03-31 19:02:58 +02:00
850fea8023 vendor: github.com/docker/docker v28.0.4
no changes in vendored files

full diff: https://github.com/docker/docker/compare/v28.0.3...v28.0.4

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-31 18:13:45 +02:00
8b222aedfa docs/reference: search: remove mention of deprecated "IsAutomated"
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-31 17:45:20 +02:00
0c4912b0ec Merge pull request #5958 from thaJeztah/login_message
cli/command/registry: loginClientSide: use locally defined message
2025-03-31 14:46:18 +02:00
8e6de54d18 Merge pull request #5961 from thaJeztah/trust_remove_intermediate_var
cli/trust: GetNotaryRepository: remove intermediate var
2025-03-31 11:40:13 +00:00
fc817a1367 Merge pull request #5970 from thaJeztah/swarm_completion_cleanup
cli/command/service: un-export CompletionFn
2025-03-31 11:39:37 +00:00
30c20d5c8c Merge pull request #5966 from thaJeztah/man_rewrite
man: rewrite to use cli-docs-tool manpage generator
2025-03-27 21:01:51 +01:00
99a6126cfe Merge pull request #5959 from thaJeztah/registry_client_skip_RepositoryInfo
cli/registry/client: skip RepositoryInfo as intermediate
2025-03-27 18:46:39 +01:00
491e8fdaf8 cli/registry/client: skip RepositoryInfo as intermediate
Remove RepositoryInfo as intermediate struct in some places; we want
to remove the use of this additional abstration. More changes are
needed to fully remove it, but chipping away its use in small bits.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-27 13:34:05 +01:00
930173a2ab Merge pull request #5969 from thaJeztah/simplify_auth_fixed
cli/command: Reapply "remove uses of GetAuthConfigKey, ParseRepositoryInfo" and add test
2025-03-27 13:24:10 +01:00
242422bbb3 cli/command/service: un-export CompletionFn
It's only used internally, and has no external consumers. Un-export
it, rename it to something more descriptive, and move it to a separate
file to align with other packages.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-27 09:59:29 +01:00
3fe40e5ea9 Merge pull request #5950 from thaJeztah/dockerfile_linting
Dockerfile: fix JSONArgsRecommended warning
2025-03-26 19:17:42 +01:00
f1385df2a7 Merge pull request #5968 from albers/completion-service-scale
Improve completion of `service scale` args
2025-03-26 17:41:50 +01:00
0e32baf115 cli/command: fix regression in resolving auth from config
This was introduced in 79141ce5eb, which
was reverted in f596202125, and re-applied
in the previous commit.

Before this patch, saving credentials worked correctly;

    docker login -u thajeztah
    Password:
    Login Succeeded

    cat ~/.docker/config.json
    {
        "auths": {
            "https://index.docker.io/v1/": {
                "auth": "REDACTED"
            }
        }
    }

But when resolving the credentials, the credentials stored would not be found;

    docker pull -q thajeztah/private-test-image
    Error response from daemon: pull access denied for thajeztah/private-test-image, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

With this patch applied:

    docker pull -q thajeztah/private-test-image
    docker.io/thajeztah/private-test-image:latest

Thanks to mtrmac (Miloslav Trmač) for spotting this mistake!

Suggested-by: Miloslav Trmač <mitr@redhat.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-26 14:43:57 +01:00
9f4165ccb8 Reapply "cli/command: remove uses of GetAuthConfigKey, ParseRepositoryInfo"
This reverts commit f596202125, and reapplies
79141ce5eb.

> cli/command: remove uses of GetAuthConfigKey, ParseRepositoryInfo
>
> Re-implement locally, based on the code in github.com/docker/docker/registry,
> but leaving out bits that are not used on the client-side, such as
> configuration of Mirrors, and configurable insecure-registry, which
> are not used on the client side.

This commit contains a regression due to a typo in `authConfigKey`;

    const authConfigKey = "https:/index.docker.io/v1/"

Which is missing a `/` after the scheme.

Which currently fails the TestRetrieveAuthTokenFromImage test.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-26 14:30:06 +01:00
15b95beac7 cli/command: add unit-test for RetrieveAuthTokenFromImage
It's currently slower because it calls registry.ParseRepositoryInfo,
which does a DNS lookup for hostnames to determine if they're a loopback
address (and marked "insecure");

    go test -v -run TestRetrieveAuthTokenFromImage
    === RUN   TestRetrieveAuthTokenFromImage
    === RUN   TestRetrieveAuthTokenFromImage/no-prefix
    === RUN   TestRetrieveAuthTokenFromImage/docker.io
    === RUN   TestRetrieveAuthTokenFromImage/index.docker.io
    === RUN   TestRetrieveAuthTokenFromImage/registry-1.docker.io
    === RUN   TestRetrieveAuthTokenFromImage/registry.hub.docker.com
    === RUN   TestRetrieveAuthTokenFromImage/[::1]
    === RUN   TestRetrieveAuthTokenFromImage/[::1]:5000
    === RUN   TestRetrieveAuthTokenFromImage/127.0.0.1
    === RUN   TestRetrieveAuthTokenFromImage/localhost
    === RUN   TestRetrieveAuthTokenFromImage/localhost:5000
    === RUN   TestRetrieveAuthTokenFromImage/no-auth.example.com
    --- PASS: TestRetrieveAuthTokenFromImage (0.35s)
        --- PASS: TestRetrieveAuthTokenFromImage/no-prefix (0.00s)
        --- PASS: TestRetrieveAuthTokenFromImage/docker.io (0.00s)
        --- PASS: TestRetrieveAuthTokenFromImage/index.docker.io (0.00s)
        --- PASS: TestRetrieveAuthTokenFromImage/registry-1.docker.io (0.08s)
        --- PASS: TestRetrieveAuthTokenFromImage/registry.hub.docker.com (0.12s)
        --- PASS: TestRetrieveAuthTokenFromImage/[::1] (0.13s)
        --- PASS: TestRetrieveAuthTokenFromImage/[::1]:5000 (0.00s)
        --- PASS: TestRetrieveAuthTokenFromImage/127.0.0.1 (0.00s)
        --- PASS: TestRetrieveAuthTokenFromImage/localhost (0.00s)
        --- PASS: TestRetrieveAuthTokenFromImage/localhost:5000 (0.00s)
        --- PASS: TestRetrieveAuthTokenFromImage/no-auth.example.com (0.01s)
    PASS
    ok  	github.com/docker/cli/cli/command	1.367s

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-26 14:25:50 +01:00
ee275d5733 Improve completion of service scale args
Signed-off-by: albers <github@albersweb.de>
2025-03-25 21:46:44 +00:00
80bca8eb1d man: rewrite to use cli-docs-tool manpage generator
It's a wrapper around Cobra's generator, but handles some special
cases. While rewriting, also rewrite the generator code to align
with the mddocs/yamldocs counterpart in docs/generate/

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-25 17:07:40 +01:00
1a14abb748 cli/command/registry: loginClientSide: use locally defined message
The "Service.Auth" pretended to return a message from the registry,
but the message returned is hard-coded in the registry package.

Remove its use to make this more transparent, and not to pretend
this is anything returned by the registry.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-25 16:07:48 +01:00
b8034c0ed7 Merge pull request #5962 from thaJeztah/bump_docker_28.0.3
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
vendor: github.com/docker/docker v28.0.3
2025-03-25 15:03:35 +00:00
3e699a351f Merge pull request #5964 from vvoland/fix-auth-regressionq
Revert "cli/command: remove uses of GetAuthConfigKey, ParseRepositoryInfo"
2025-03-25 15:52:46 +01:00
f596202125 Revert "cli/command: remove uses of GetAuthConfigKey, ParseRepositoryInfo"
This reverts commit 79141ce5eb.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-03-25 15:37:51 +01:00
ee2f787634 cli/config: update link to current version
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-25 14:37:59 +01:00
d8432cdf23 vendor: github.com/docker/docker v28.0.3
no diff; same commit, but tagged

full diff: https://github.com/docker/docker/compare/330857ad0ffb...v28.0.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-25 14:37:53 +01:00
60645d29f4 cli/trust: GetNotaryRepository: remove intermediate var
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-25 11:48:41 +01:00
2b0631f45e Merge pull request #5941 from thaJeztah/TestUserTerminatedError_handle_errs
Some checks failed
build / bin-image (push) Has been cancelled
build / prepare-plugins (push) Has been cancelled
build / plugins (push) Has been cancelled
codeql / codeql (push) Has been cancelled
e2e / tests (alpine, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 23, local) (push) Has been cancelled
e2e / tests (alpine, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 26, local) (push) Has been cancelled
e2e / tests (alpine, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 27, local) (push) Has been cancelled
e2e / tests (alpine, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (alpine, 28, local) (push) Has been cancelled
e2e / tests (debian, 23, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 23, local) (push) Has been cancelled
e2e / tests (debian, 26, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 26, local) (push) Has been cancelled
e2e / tests (debian, 27, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 27, local) (push) Has been cancelled
e2e / tests (debian, 28, connhelper-ssh) (push) Has been cancelled
e2e / tests (debian, 28, local) (push) Has been cancelled
test / ctn (push) Has been cancelled
test / host (macos-13) (push) Has been cancelled
test / host (macos-14) (push) Has been cancelled
validate / validate (lint) (push) Has been cancelled
validate / validate (shellcheck) (push) Has been cancelled
validate / validate (update-authors) (push) Has been cancelled
validate / validate (validate-vendor) (push) Has been cancelled
validate / validate-md (push) Has been cancelled
validate / validate-make (manpages) (push) Has been cancelled
validate / validate-make (yamldocs) (push) Has been cancelled
cmd/dockerd: TestUserTerminatedError: fix unhandled errors
2025-03-25 10:01:34 +00:00
84828b0eb8 Merge pull request #5960 from vvoland/vendor-docker
vendor: github.com/docker/docker v28.0.3-dev (330857ad0ffb)
2025-03-25 09:55:03 +00:00
b5ca7e8e6b vendor: github.com/docker/docker v28.0.3-dev (330857ad0ffb)
full diff: https://github.com/docker/docker/compare/v28.0.2...330857ad0ffb

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-03-25 10:30:54 +01:00
cfaaeb0982 Merge pull request #5957 from vvoland/stdout-trunc
container/run: Fix stdout/err truncation after container exit
2025-03-24 16:14:50 +00:00
5a8120c809 container/run: Fix TestRunAttachTermination
Restore part of the code removed by 966b44183f
that closed the stream. It's required now because the Run command won't
finish before the output stream was processed by the caller.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-03-24 17:09:35 +01:00
c27751fcfe container/run: Fix stdout/err truncation after container exit
Fix a regression introduced by 30c4637f03
which made the `docker run` command produce potentially truncated
stdout/stderr output.

Previous implementation stopped the content streaming as soon as the
container exited which would potentially truncate a long outputs.

This change fixes the issue by only canceling the IO stream immediately
if neither stdout nor stderr is attached.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-03-24 17:09:32 +01:00
7b348e4e94 Dockerfile: fix JSONArgsRecommended warning
1 warning found (use docker --debug to expand):
    - JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals (line 120)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-21 20:42:17 +01:00
ff5fdfae35 Merge pull request #5829 from thaJeztah/bump_cobra
vendor: github.com/spf13/cobra v1.9.1
2025-03-21 20:42:08 +01:00
9f19820f88 cli/command/completion: deprecate ValidArgsFn
Cobra now defines a CompletionFunc for the same, so we can alias
it to that, and stop using our own definition.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-21 20:30:58 +01:00
7607c3f945 vendor: github.com/spf13/cobra v1.9.1
full diff: https://github.com/spf13/cobra/compare/v1.8.1...v1.9.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-21 20:30:54 +01:00
61cd986723 Merge pull request #4903 from thaJeztah/carry_docs_no_internet
docs: include required tools in source tree
2025-03-21 18:49:27 +01:00
d97f65c4da cli/command: PruneFilters: slight cleanup
- remove pruneFilters.Contains for checks, as this is already
  handled by pruneFilters.ExactMatch.
- Update GoDoc to better describe the function's functionality
- Use a swtich instead of if/else.

This function should be moved to a separate package; possibly splitting
it out to a "Merge" function that accepts two filter.Args as argument.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-21 13:50:09 +01:00
30cac75693 Merge pull request #5945 from stevvooe/sjd/remove-flaky-test
e2e: skip flaky test
2025-03-21 13:49:19 +01:00
255a5f630e Merge pull request #5876 from thaJeztah/less_notary
cli/command, cil/command/image: remove deprecated methods and functions
2025-03-21 09:31:23 +01:00
535bb6c85c rewrite using "with-go-mod.sh" script and "go run"
Use the same script as is used in moby/moby, which more gracefully
handles an existing `go.mod` (which can be symlinked) into account.

- keep the scripts called generic, and update the Makefile to invoke
  them with the "with-go-mod.sh" script.
- use "go run" instead of building temporary binaries
- check if go-md2man exists before building a binary

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-21 00:36:47 +01:00
47775a8fa0 docs: include required tools in source tree
In order to be able to build the documentation without internet access
(as is required by some distribution build systems), all of the source
code needed for the build needs to be available in the source tarball.

This used to be possible with the docker-cli sources but was
accidentally broken with some CI changes that switched to downloading
the tools (by modifying go.mod as part of the docs build script).

This pattern also maked documentation builds less reproducible since the
tool version used was not based on the source code version.

Fixes: 7dc35c03fc ("validate manpages target")
Fixes: a650f4ddd0 ("switch to cli-docs-tool for yaml docs generation")
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-21 00:13:56 +01:00
4a80c6da83 e2e: skip flaky test
Signed-off-by: Stephen Day <stephen.day@docker.com>
2025-03-20 07:56:28 -07:00
b199ece92a Merge pull request #5939 from thaJeztah/cmd_dockerd_stdlib_errs
cmd/dockerd: use stdlib errors
2025-03-20 15:20:20 +01:00
48741f72ff Merge pull request #5944 from thaJeztah/vendor_docker_28.0.2
vendor: github.com/docker/docker v28.0.2
2025-03-20 11:58:58 +00:00
4541df21e5 cli/command/image: remove deprecated TagTrusted
This function was only used internally, and has no known external consumers.
It was deprecated in e37d814ce96b01393a400c081666ea1cca2eb8bd; this commit
removes it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-20 11:11:39 +01:00
eaf98b2202 cli/command/image: remove deprecated PushTrustedReference
This function was only used internally, and has no known external consumers.
It was deprecated in d80436021c21c26b492f0014511f13f41d8b42d9; this commit
removes it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-20 11:11:39 +01:00
98d0b0cc14 cli/command/image: remove deprecated TrustedPush
This function was only used by "docker trust sign", and has no known external
consumers. It was deprecated in c6f456bc90574f4180f3b990e8a4e216485e35b7;
this commit removes it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-20 11:11:39 +01:00
5ea072d936 cli/command: remove deprecated RegistryClient from CLI interface
This method was a shallow wrapper around registryclient.NewRegistryClient but
due to its signature resulted in various dependencies becoming a dependency
of the "command" package. Consequence of this was that cli-plugins, which
need the cli/command package, would also get those dependencies. It is no
longer used, and was deprecated in 8ad07217dc.

This patch removes the RegistryClient method from the interface

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-20 11:11:38 +01:00
08f86507b4 cli/command: remove deprecated ManifestStore from CLI interface
This method is a shallow wrapper around manifeststore.NewStore, but
due to its signature resulted in various dependencies becoming a dependency
of the "command" package. Consequence of this was that cli-plugins, which
need the cli/command package, would also get those dependencies. It is no
longer used, and was deprecated in e32d5d56f5.

This patch removes the ManifestStore method from the interface

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-20 11:11:38 +01:00
66eb27a487 cli/command: remove deprecated NotaryClient from CLI interface
This method is a shallow wrapper around trust.GetNotaryRepository, but
due to its signature resulted in the trust package, and notary dependencies
to become a dependency of the CLI. Consequence of this was that cli-plugins,
which need the cli/command package, would also get notary and its
dependencies as a dependency. It is no longer used, and was deprecated
in 9bc16bbde0.

This patch removes the NotaryClient method from the interface

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-20 11:11:35 +01:00
e002576821 Merge pull request #5942 from thaJeztah/simplify_auth_step1
cli/command: remove uses of GetAuthConfigKey, ParseRepositoryInfo
2025-03-20 11:10:47 +01:00
a9ac6fa376 vendor: github.com/docker/docker v28.0.2
no diff; same commit, but tagged:

full diff: https://github.com/docker/docker/compare/bea4de25004d...v28.0.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-19 18:27:29 +01:00
23eadcd950 Merge pull request #5936 from thaJeztah/plugin_manager_cleanups
cli-plugins/manager: minor cleanups and refactoring
2025-03-19 16:13:13 +01:00
3b45f3c09a Merge pull request #5926 from Benehiko/fix-attach-test-flake
test: fix flaky TestRunAttachTermination
2025-03-19 16:10:49 +01:00
79141ce5eb cli/command: remove uses of GetAuthConfigKey, ParseRepositoryInfo
Re-implement locally, based on the code in github.com/docker/docker/registry,
but leaving out bits that are not used on the client-side, such as
configuration of Mirrors, and configurable insecure-registry, which
are not used on the client side.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-19 15:34:57 +01:00
082dfb7360 cmd/dockerd: use stdlib errors
This package is not imported externally, and we don't need the added
functionality of pkg/errors here, so use stdlib errors.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-19 14:04:44 +01:00
f519a8648d cmd/dockerd: TestUserTerminatedError: fix unhandled errors
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-19 14:01:38 +01:00
353230d978 system/info: failure to connect to docker socket on docker info should propagate error
This patch propagates the error up the stack when running `docker info`
and a connection error to the server occurs.

Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2025-03-18 16:58:59 +01:00
966b44183f test: fix flaky TestRunAttachTermination
This patch fixes the `TestRunAttachTermination` flaky runs.
It seems like we weren't halting on the `waitFunc` so if the
process was fast enough to setup the signal handler and execute
`waitExitOrRemoved`. We now instead wait for the `killCh` channel
to close inside the mocked `waitFunc`.

Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2025-03-18 16:11:54 +01:00
091421f13f cli-plugins/manager: getPluginDirs: remove redundant error-return
This function returned an error (if any) from [config.Path]. However, the
only situation in which an error could be returned was if the given path
to append to `config.Dir` was outside of the config directory. This can
only happen if the path to append would try to traverse directories (e.g.,
passing `../../cli-plugins`).

Given that we're passing a hard-coded value, that would not be the case,
so we can simplify the code to join the path directly, and don't have to
handle errors.

[config.Path]: 2d74733942/cli/config/config.go (L100-L107)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-18 12:10:38 +01:00
d1a19d4476 cli-plugins/manager: ListPlugins: return early if no candidates
Skip the other logic, which includes listing all commands provided; if
there's no plugin-candidates, those steps won't be needed.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-18 12:10:38 +01:00
40725aea3c cli-plugins/manager: add test for empty / non-existing plugin dirs
Verify that listPluginCandidates returns an empty result if nothing was
found.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-18 12:10:38 +01:00
fdcfd229aa cli-plugins/manager: rename var that shadowed arg in test
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-18 12:10:38 +01:00
abd02b6a23 cli-plugins/manager: ListPlugins: pass context to error-group
This error-group was added in 89583b92b7, but
passed a context.TODO because the function didn't have a context as argument.

However, it does get the root-command passed, which holds the context, so
we can pass that.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-18 12:10:28 +01:00
1000 changed files with 36498 additions and 10001 deletions

View File

@ -121,7 +121,8 @@ jobs:
type=semver,pattern={{version}}
type=ref,event=branch
type=ref,event=pr
type=sha
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
-
name: Build and push image
uses: docker/bake-action@v6

View File

@ -63,7 +63,7 @@ jobs:
name: Update Go
uses: actions/setup-go@v5
with:
go-version: "1.23.7"
go-version: "1.24.5"
-
name: Initialize CodeQL
uses: github/codeql-action/init@v3

View File

@ -66,7 +66,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23.7"
go-version: "1.24.5"
-
name: Test
run: |

View File

@ -1,205 +1,226 @@
linters:
enable:
- bodyclose
- copyloopvar # Detects places where loop variables are copied.
- depguard
- dogsled
- dupword # Detects duplicate words.
- durationcheck
- errchkjson
- gocritic # Metalinter; detects bugs, performance, and styling issues.
- gocyclo
- gofumpt # Detects whether code was gofumpt-ed.
- goimports
- gosec # Detects security problems.
- gosimple
- govet
- ineffassign
- misspell # Detects commonly misspelled English words in comments.
- nakedret # Detects uses of naked returns.
- nilerr # Detects code that returns nil even if it checks that the error is not nil.
- nolintlint # Detects ill-formed or insufficient nolint directives.
- perfsprint # Detects fmt.Sprintf uses that can be replaced with a faster alternative.
- prealloc # Detects slice declarations that could potentially be pre-allocated.
- predeclared # Detects code that shadows one of Go's predeclared identifiers
- reassign
- revive # Metalinter; drop-in replacement for golint.
- staticcheck
- stylecheck # Replacement for golint
- thelper # Detects test helpers without t.Helper().
- tparallel # Detects inappropriate usage of t.Parallel().
- typecheck
- unconvert # Detects unnecessary type conversions.
- unparam
- unused
- usestdlibvars
- usetesting # Reports uses of functions with replacement inside the testing package.
- wastedassign
disable:
- errcheck
version: "2"
run:
# prevent golangci-lint from deducting the go version to lint for through go.mod,
# which causes it to fallback to go1.17 semantics.
#
# TODO(thaJeztah): update "usetesting" settings to enable go1.24 features once our minimum version is go1.24
go: "1.23.7"
go: "1.24.5"
timeout: 5m
linters-settings:
depguard:
rules:
main:
deny:
- pkg: "github.com/containerd/containerd/errdefs"
desc: The containerd errdefs package was migrated to a separate module. Use github.com/containerd/errdefs instead.
- pkg: "github.com/containerd/containerd/log"
desc: The containerd log package was migrated to a separate module. Use github.com/containerd/log instead.
- pkg: "github.com/containerd/containerd/pkg/userns"
desc: Use github.com/moby/sys/userns instead.
- pkg: "github.com/containerd/containerd/platforms"
desc: The containerd platforms package was migrated to a separate module. Use github.com/containerd/platforms instead.
- pkg: "github.com/docker/docker/pkg/system"
desc: This package should not be used unless strictly necessary.
- pkg: "github.com/docker/distribution/uuid"
desc: Use github.com/google/uuid instead.
- pkg: "io/ioutil"
desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil
gocyclo:
min-complexity: 16
gosec:
excludes:
- G104 # G104: Errors unhandled; (TODO: reduce unhandled errors, or explicitly ignore)
- G113 # G113: Potential uncontrolled memory consumption in Rat.SetString (CVE-2022-23772); (only affects go < 1.16.14. and go < 1.17.7)
- G115 # G115: integer overflow conversion; (TODO: verify these: https://github.com/docker/cli/issues/5584)
- G306 # G306: Expect WriteFile permissions to be 0600 or less (too restrictive; also flags "0o644" permissions)
- G307 # G307: Deferring unsafe method "*os.File" on type "Close" (also EXC0008); (TODO: evaluate these and fix where needed: G307: Deferring unsafe method "*os.File" on type "Close")
govet:
enable:
- shadow
settings:
shadow:
strict: true
lll:
line-length: 200
nakedret:
# Disallow naked returns if func has more lines of code than this setting.
# Default: 30
max-func-lines: 0
revive:
rules:
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-block
- name: empty-block
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-lines
- name: empty-lines
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-shadowing
- name: import-shadowing
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#line-length-limit
- name: line-length-limit
severity: warning
disabled: false
arguments: [200]
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-receiver
- name: unused-receiver
severity: warning
disabled: false
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#use-any
- name: use-any
severity: warning
disabled: false
usetesting:
# FIXME(thaJeztah): Disable `os.Chdir()` detections; should be automatically disabled on Go < 1.24; see https://github.com/docker/cli/pull/5835#issuecomment-2665302478
os-chdir: false
# FIXME(thaJeztah): Disable `context.Background()` detections; should be automatically disabled on Go < 1.24; see https://github.com/docker/cli/pull/5835#issuecomment-2665302478
context-background: false
# FIXME(thaJeztah): Disable `context.TODO()` detections; should be automatically disabled on Go < 1.24; see https://github.com/docker/cli/pull/5835#issuecomment-2665302478
context-todo: false
issues:
# The default exclusion rules are a bit too permissive, so copying the relevant ones below
exclude-use-default: false
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
max-issues-per-linter: 0
# This option has been defined when Go modules was not existed and when the
# golangci-lint core was different, this is not something we still recommend.
exclude-dirs-use-default: false
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
max-same-issues: 0
exclude:
- parameter .* always receives
formatters:
enable:
- gofumpt # Detects whether code was gofumpt-ed.
- goimports
exclude-files:
- cli/compose/schema/bindata.go
- .*generated.*
exclusions:
generated: strict
exclude-rules:
# We prefer to use an "exclude-list" so that new "default" exclusions are not
linters:
enable:
- asasalint # Detects "[]any" used as argument for variadic "func(...any)".
- bodyclose
- copyloopvar # Detects places where loop variables are copied.
- depguard
- dogsled # Detects assignments with too many blank identifiers.
- dupword # Detects duplicate words.
- durationcheck # Detect cases where two time.Duration values are being multiplied in possibly erroneous ways.
- errcheck
- errchkjson # Detects unsupported types passed to json encoding functions and reports if checks for the returned error can be omitted.
- exhaustive # Detects missing options in enum switch statements.
- exptostd # Detects functions from golang.org/x/exp/ that can be replaced by std functions.
- fatcontext # Detects nested contexts in loops and function literals.
- forbidigo
- gocheckcompilerdirectives # Detects invalid go compiler directive comments (//go:).
- gocritic # Metalinter; detects bugs, performance, and styling issues.
- gocyclo
- gosec # Detects security problems.
- govet
- iface # Detects incorrect use of interfaces. Currently only used for "identical" interfaces in the same package.
- importas # Enforces consistent import aliases.
- ineffassign
- makezero # Finds slice declarations with non-zero initial length.
- mirror # Detects wrong mirror patterns of bytes/strings usage.
- misspell # Detects commonly misspelled English words in comments.
- nakedret # Detects uses of naked returns.
- nilnesserr # Detects returning nil errors. It combines the features of nilness and nilerr,
- nosprintfhostport # Detects misuse of Sprintf to construct a host with port in a URL.
- nolintlint # Detects ill-formed or insufficient nolint directives.
- perfsprint # Detects fmt.Sprintf uses that can be replaced with a faster alternative.
- prealloc # Detects slice declarations that could potentially be pre-allocated.
- predeclared # Detects code that shadows one of Go's predeclared identifiers
- reassign # Detects reassigning a top-level variable in another package.
- revive # Metalinter; drop-in replacement for golint.
- spancheck # Detects mistakes with OpenTelemetry/Census spans.
- staticcheck
- thelper # Detects test helpers without t.Helper().
- tparallel # Detects inappropriate usage of t.Parallel().
- unconvert # Detects unnecessary type conversions.
- unparam
- unused
- usestdlibvars # Detects the possibility to use variables/constants from the Go standard library.
- usetesting # Reports uses of functions with replacement inside the testing package.
- wastedassign # Detects wasted assignment statements.
disable:
- errcheck
settings:
depguard:
rules:
main:
deny:
- pkg: "github.com/containerd/containerd/errdefs"
desc: The containerd errdefs package was migrated to a separate module. Use github.com/containerd/errdefs instead.
- pkg: "github.com/containerd/containerd/log"
desc: The containerd log package was migrated to a separate module. Use github.com/containerd/log instead.
- pkg: "github.com/containerd/containerd/pkg/userns"
desc: Use github.com/moby/sys/userns instead.
- pkg: "github.com/containerd/containerd/platforms"
desc: The containerd platforms package was migrated to a separate module. Use github.com/containerd/platforms instead.
- pkg: "github.com/docker/docker/pkg/system"
desc: This package should not be used unless strictly necessary.
- pkg: "github.com/docker/distribution/uuid"
desc: Use github.com/google/uuid instead.
- pkg: "io/ioutil"
desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil
forbidigo:
forbid:
- pkg: ^regexp$
pattern: ^regexp\.MustCompile
msg: Use internal/lazyregexp.New instead.
gocyclo:
min-complexity: 16
gosec:
excludes:
- G104 # G104: Errors unhandled; (TODO: reduce unhandled errors, or explicitly ignore)
- G115 # G115: integer overflow conversion; (TODO: verify these: https://github.com/docker/cli/issues/5584)
- G306 # G306: Expect WriteFile permissions to be 0600 or less (too restrictive; also flags "0o644" permissions)
- G307 # G307: Deferring unsafe method "*os.File" on type "Close" (also EXC0008); (TODO: evaluate these and fix where needed: G307: Deferring unsafe method "*os.File" on type "Close")
govet:
enable:
- shadow
settings:
shadow:
strict: true
lll:
line-length: 200
importas:
# Do not allow unaliased imports of aliased packages.
no-unaliased: true
alias:
# Enforce alias to prevent it accidentally being used instead of our
# own errdefs package (or vice-versa).
- pkg: github.com/containerd/errdefs
alias: cerrdefs
- pkg: github.com/opencontainers/image-spec/specs-go/v1
alias: ocispec
# Enforce that gotest.tools/v3/assert/cmp is always aliased as "is"
- pkg: gotest.tools/v3/assert/cmp
alias: is
nakedret:
# Disallow naked returns if func has more lines of code than this setting.
# Default: 30
max-func-lines: 0
staticcheck:
checks:
- all
- -QF1008 # Omit embedded fields from selector expression; https://staticcheck.dev/docs/checks/#QF1008
revive:
rules:
- name: empty-block # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-block
- name: empty-lines # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-lines
- name: import-shadowing # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#import-shadowing
- name: line-length-limit # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#line-length-limit
arguments: [200]
- name: unused-receiver # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-receiver
- name: use-any # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#use-any
usetesting:
os-chdir: false # FIXME(thaJeztah): Disable `os.Chdir()` detections; should be automatically disabled on Go < 1.24; see https://github.com/docker/cli/pull/5835#issuecomment-2665302478
context-background: false # FIXME(thaJeztah): Disable `context.Background()` detections; should be automatically disabled on Go < 1.24; see https://github.com/docker/cli/pull/5835#issuecomment-2665302478
context-todo: false # FIXME(thaJeztah): Disable `context.TODO()` detections; should be automatically disabled on Go < 1.24; see https://github.com/docker/cli/pull/5835#issuecomment-2665302478
exclusions:
# We prefer to use an "linters.exclusions.rules" so that new "default" exclusions are not
# automatically inherited. We can decide whether or not to follow upstream
# defaults when updating golang-ci-lint versions.
# Unfortunately, this means we have to copy the whole exclusion pattern, as
# (unlike the "include" option), the "exclude" option does not take exclusion
# ID's.
#
# These exclusion patterns are copied from the default excluses at:
# https://github.com/golangci/golangci-lint/blob/v1.44.0/pkg/config/issues.go#L10-L104
# These exclusion patterns are copied from the default excludes at:
# https://github.com/golangci/golangci-lint/blob/v1.61.0/pkg/config/issues.go#L11-L104
#
# The default list of exclusions can be found at:
# https://golangci-lint.run/usage/false-positives/#default-exclusions
generated: strict
# EXC0001
- text: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked"
linters:
- errcheck
# EXC0003
- text: "func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this"
linters:
- revive
# EXC0006
- text: "Use of unsafe calls should be audited"
linters:
- gosec
# EXC0007
- text: "Subprocess launch(ed with variable|ing should be audited)"
linters:
- gosec
# EXC0009
- text: "(Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)"
linters:
- gosec
# EXC0010
- text: "Potential file inclusion via variable"
linters:
- gosec
rules:
# EXC0003
- text: "func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this"
linters:
- revive
# TODO: make sure all packages have a description. Currently, there's 67 packages without.
- text: "package-comments: should have a package comment"
linters:
- revive
# EXC0007
- text: "Subprocess launch(ed with variable|ing should be audited)"
linters:
- gosec
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- errcheck
- gosec
- text: "ST1000: at least one file in a package should have a package comment"
linters:
- stylecheck
# EXC0009
- text: "(Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)"
linters:
- gosec
# Allow "err" and "ok" vars to shadow existing declarations, otherwise we get too many false positives.
- text: '^shadow: declaration of "(err|ok)" shadows declaration'
linters:
- govet
# EXC0010
- text: "Potential file inclusion via variable"
linters:
- gosec
# TODO: make sure all packages have a description. Currently, there's 67 packages without.
- text: "package-comments: should have a package comment"
linters:
- revive
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
max-issues-per-linter: 0
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- errcheck
- gosec
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
max-same-issues: 0
- text: "ST1000: at least one file in a package should have a package comment"
linters:
- staticcheck
# Allow "err" and "ok" vars to shadow existing declarations, otherwise we get too many false positives.
- text: '^shadow: declaration of "(err|ok)" shadows declaration'
linters:
- govet
# Ignore for cli/command/formatter/tabwriter, which is forked from go stdlib, so we want to align with it.
- text: '^(ST1020|ST1022): comment on exported'
path: "cli/command/formatter/tabwriter"
linters:
- staticcheck
# Log a warning if an exclusion rule is unused.
# Default: false
warn-unused: true

View File

@ -43,6 +43,7 @@ Alexis Couvreur <alexiscouvreur.pro@gmail.com>
Alicia Lauerman <alicia@eta.im> <allydevour@me.com>
Allen Sun <allensun.shl@alibaba-inc.com> <allen.sun@daocloud.io>
Allen Sun <allensun.shl@alibaba-inc.com> <shlallen1990@gmail.com>
Allie Sadler <allie.sadler@docker.com>
Andrew Weiss <andrew.weiss@docker.com> <andrew.weiss@microsoft.com>
Andrew Weiss <andrew.weiss@docker.com> <andrew.weiss@outlook.com>
André Martins <aanm90@gmail.com> <martins@noironetworks.com>
@ -65,6 +66,9 @@ Arnaud Porterie <icecrime@gmail.com>
Arnaud Porterie <icecrime@gmail.com> <arnaud.porterie@docker.com>
Arthur Gautier <baloo@gandi.net> <superbaloo+registrations.github@superbaloo.net>
Arthur Peka <arthur.peka@outlook.com> <arthrp@users.noreply.github.com>
Austin Vazquez <austin.vazquez.dev@gmail.com>
Austin Vazquez <austin.vazquez.dev@gmail.com> <55906459+austinvazquez@users.noreply.github.com>
Austin Vazquez <austin.vazquez.dev@gmail.com> <macedonv@amazon.com>
Avi Miller <avi.miller@oracle.com> <avi.miller@gmail.com>
Ben Bonnefoy <frenchben@docker.com>
Ben Golub <ben.golub@dotcloud.com>
@ -195,6 +199,8 @@ Gaetan de Villele <gdevillele@gmail.com>
Gang Qiao <qiaohai8866@gmail.com> <1373319223@qq.com>
George Kontridze <george@bugsnag.com>
Gerwim Feiken <g.feiken@tfe.nl> <gerwim@gmail.com>
Giau. Tran Minh <hello@giautm.dev>
Giau. Tran Minh <hello@giautm.dev> <12751435+giautm@users.noreply.github.com>
Giampaolo Mancini <giampaolo@trampolineup.com>
Gopikannan Venugopalsamy <gopikannan.venugopalsamy@gmail.com>
Gou Rao <gou@portworx.com> <gourao@users.noreply.github.com>
@ -214,6 +220,7 @@ Günther Jungbluth <gunther@gameslabs.net>
Hakan Özler <hakan.ozler@kodcu.com>
Hao Shu Wei <haosw@cn.ibm.com>
Hao Shu Wei <haosw@cn.ibm.com> <haoshuwei1989@163.com>
Harald Albers <github@albersweb.de>
Harald Albers <github@albersweb.de> <albers@users.noreply.github.com>
Harold Cooper <hrldcpr@gmail.com>
Harry Zhang <harryz@hyper.sh> <harryzhang@zju.edu.cn>
@ -330,6 +337,8 @@ Lajos Papp <lajos.papp@sequenceiq.com> <lalyos@yahoo.com>
Lei Jitang <leijitang@huawei.com>
Lei Jitang <leijitang@huawei.com> <leijitang@gmail.com>
Li Fu Bang <lifubang@acmcoder.com>
Li Yi <denverdino@gmail.com>
Li Yi <denverdino@gmail.com> <weiyuan.yl@alibaba-inc.com>
Liang Mingqiang <mqliang.zju@gmail.com>
Liang-Chi Hsieh <viirya@gmail.com>
Liao Qingwei <liaoqingwei@huawei.com>
@ -339,6 +348,7 @@ Lokesh Mandvekar <lsm5@fedoraproject.org> <lsm5@redhat.com>
Lorenzo Fontana <lo@linux.com> <fontanalorenzo@me.com>
Louis Opter <kalessin@kalessin.fr>
Louis Opter <kalessin@kalessin.fr> <louis@dotcloud.com>
Lovekesh Kumar <lovekesh.kumar@rtcamp.com>
Luca Favatella <luca.favatella@erlang-solutions.com> <lucafavatella@users.noreply.github.com>
Luke Marsden <me@lukemarsden.net> <luke@digital-crocus.com>
Lyn <energylyn@zju.edu.cn>
@ -396,6 +406,7 @@ Mike Dalton <mikedalton@github.com> <19153140+mikedalton@users.noreply.github.co
Mike Goelzer <mike.goelzer@docker.com> <mgoelzer@docker.com>
Milind Chawre <milindchawre@gmail.com>
Misty Stanley-Jones <misty@docker.com> <misty@apache.org>
Mohammad Hossein <mhm98035@gmail.com>
Mohit Soni <mosoni@ebay.com> <mohitsoni1989@gmail.com>
Moorthy RS <rsmoorthy@gmail.com> <rsmoorthy@users.noreply.github.com>
Morten Hekkvang <morten.hekkvang@sbab.se>
@ -419,6 +430,7 @@ O.S. Tezer <ostezer@gmail.com> <ostezer@users.noreply.github.com>
Oh Jinkyun <tintypemolly@gmail.com> <tintypemolly@Ohui-MacBook-Pro.local>
Oliver Pomeroy <oppomeroy@gmail.com>
Ouyang Liduo <oyld0210@163.com>
Patrick St. laurent <patrick@saint-laurent.us>
Patrick Stapleton <github@gdi2290.com>
Paul Liljenberg <liljenberg.paul@gmail.com> <letters@paulnotcom.se>
Pavel Tikhomirov <ptikhomirov@virtuozzo.com> <ptikhomirov@parallels.com>
@ -498,6 +510,7 @@ Stephen Day <stevvooe@gmail.com> <stephen.day@docker.com>
Stephen Day <stevvooe@gmail.com> <stevvooe@users.noreply.github.com>
Steve Desmond <steve@vtsv.ca> <stevedesmond-ca@users.noreply.github.com>
Steve Richards <steve.richards@docker.com> stevejr <>
Stuart Williams <pid@pidster.com>
Sun Gengze <690388648@qq.com>
Sun Jianbo <wonderflow.sun@gmail.com>
Sun Jianbo <wonderflow.sun@gmail.com> <wonderflow@zju.edu.cn>

31
AUTHORS
View File

@ -48,6 +48,7 @@ Alfred Landrum <alfred.landrum@docker.com>
Ali Rostami <rostami.ali@gmail.com>
Alicia Lauerman <alicia@eta.im>
Allen Sun <allensun.shl@alibaba-inc.com>
Allie Sadler <allie.sadler@docker.com>
Alvin Deng <alvin.q.deng@utexas.edu>
Amen Belayneh <amenbelayneh@gmail.com>
Amey Shrivastava <72866602+AmeyShrivastava@users.noreply.github.com>
@ -81,6 +82,7 @@ Antonis Kalipetis <akalipetis@gmail.com>
Anusha Ragunathan <anusha.ragunathan@docker.com>
Ao Li <la9249@163.com>
Arash Deshmeh <adeshmeh@ca.ibm.com>
Archimedes Trajano <developer@trajano.net>
Arko Dasgupta <arko@tetrate.io>
Arnaud Porterie <icecrime@gmail.com>
Arnaud Rebillout <elboulangero@gmail.com>
@ -88,6 +90,7 @@ Arthur Peka <arthur.peka@outlook.com>
Ashly Mathew <ashly.mathew@sap.com>
Ashwini Oruganti <ashwini.oruganti@gmail.com>
Aslam Ahemad <aslamahemad@gmail.com>
Austin Vazquez <austin.vazquez.dev@gmail.com>
Azat Khuyiyakhmetov <shadow_uz@mail.ru>
Bardia Keyoumarsi <bkeyouma@ucsc.edu>
Barnaby Gray <barnaby@pickle.me.uk>
@ -132,6 +135,7 @@ Cao Weiwei <cao.weiwei30@zte.com.cn>
Carlo Mion <mion00@gmail.com>
Carlos Alexandro Becker <caarlos0@gmail.com>
Carlos de Paula <me@carlosedp.com>
Carston Schilds <Carston.Schilds@visier.com>
Casey Korver <casey@korver.dev>
Ce Gao <ce.gao@outlook.com>
Cedric Davies <cedricda@microsoft.com>
@ -189,6 +193,7 @@ Daisuke Ito <itodaisuke00@gmail.com>
dalanlan <dalanlan925@gmail.com>
Damien Nadé <github@livna.org>
Dan Cotora <dan@bluevision.ro>
Dan Wallis <dan@wallis.nz>
Danial Gharib <danial.mail.gh@gmail.com>
Daniel Artine <daniel.artine@ufrj.br>
Daniel Cassidy <mail@danielcassidy.me.uk>
@ -237,6 +242,7 @@ Deshi Xiao <dxiao@redhat.com>
Dharmit Shah <shahdharmit@gmail.com>
Dhawal Yogesh Bhanushali <dbhanushali@vmware.com>
Dieter Reuter <dieter.reuter@me.com>
Dilep Dev <34891655+DilepDev@users.noreply.github.com>
Dima Stopel <dima@twistlock.com>
Dimitry Andric <d.andric@activevideo.com>
Ding Fei <dingfei@stars.org.cn>
@ -308,6 +314,8 @@ George MacRorie <gmacr31@gmail.com>
George Margaritis <gmargaritis@protonmail.com>
George Xie <georgexsh@gmail.com>
Gianluca Borello <g.borello@gmail.com>
Giau. Tran Minh <hello@giautm.dev>
Giedrius Jonikas <giedriusj1@gmail.com>
Gildas Cuisinier <gildas.cuisinier@gcuisinier.net>
Gio d'Amelio <giodamelio@gmail.com>
Gleb Stsenov <gleb.stsenov@gmail.com>
@ -344,6 +352,7 @@ Hugo Gabriel Eyherabide <hugogabriel.eyherabide@gmail.com>
huqun <huqun@zju.edu.cn>
Huu Nguyen <huu@prismskylabs.com>
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com>
Iain MacDonald <IJMacD@gmail.com>
Iain Samuel McLean Elder <iain@isme.es>
Ian Campbell <ian.campbell@docker.com>
Ian Philpot <ian.philpot@microsoft.com>
@ -393,6 +402,7 @@ Jesse Adametz <jesseadametz@gmail.com>
Jessica Frazelle <jess@oxide.computer>
Jezeniel Zapanta <jpzapanta22@gmail.com>
Jian Zhang <zhangjian.fnst@cn.fujitsu.com>
Jianyong Wu <wujianyong@hygon.cn>
Jie Luo <luo612@zju.edu.cn>
Jilles Oldenbeuving <ojilles@gmail.com>
Jim Chen <njucjc@gmail.com>
@ -446,6 +456,7 @@ Julian <gitea+julian@ic.thejulian.uk>
Julien Barbier <write0@gmail.com>
Julien Kassar <github@kassisol.com>
Julien Maitrehenry <julien.maitrehenry@me.com>
Julio Cesar Garcia <juliogarciamelgarejo@gmail.com>
Justas Brazauskas <brazauskasjustas@gmail.com>
Justin Chadwell <me@jedevc.com>
Justin Cormack <justin.cormack@docker.com>
@ -490,19 +501,22 @@ Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
Kyle Mitofsky <Kylemit@gmail.com>
Lachlan Cooper <lachlancooper@gmail.com>
Lai Jiangshan <jiangshanlai@gmail.com>
Lajos Papp <lajos.papp@sequenceiq.com>
Lars Kellogg-Stedman <lars@redhat.com>
Laura Brehm <laurabrehm@hey.com>
Laura Frank <ljfrank@gmail.com>
Laurent Erignoux <lerignoux@gmail.com>
Laurent Goderre <laurent.goderre@docker.com>
Lee Gaines <eightlimbed@gmail.com>
Lei Jitang <leijitang@huawei.com>
Lennie <github@consolejunkie.net>
lentil32 <lentil32@icloud.com>
Leo Gallucci <elgalu3@gmail.com>
Leonid Skorospelov <leosko94@gmail.com>
Lewis Daly <lewisdaly@me.com>
Li Fu Bang <lifubang@acmcoder.com>
Li Yi <denverdino@gmail.com>
Li Yi <weiyuan.yl@alibaba-inc.com>
Li Zeghong <zeghong@hotmail.com>
Liang-Chi Hsieh <viirya@gmail.com>
Lihua Tang <lhtang@alauda.io>
Lily Guo <lily.guo@docker.com>
@ -515,6 +529,7 @@ lixiaobing10051267 <li.xiaobing1@zte.com.cn>
Lloyd Dewolf <foolswisdom@gmail.com>
Lorenzo Fontana <lo@linux.com>
Louis Opter <kalessin@kalessin.fr>
Lovekesh Kumar <lovekesh.kumar@rtcamp.com>
Luca Favatella <luca.favatella@erlang-solutions.com>
Luca Marturana <lucamarturana@gmail.com>
Lucas Chan <lucas-github@lucaschan.com>
@ -559,6 +574,7 @@ Matt Robenolt <matt@ydekproductions.com>
Matteo Orefice <matteo.orefice@bites4bits.software>
Matthew Heon <mheon@redhat.com>
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
Matthieu MOREL <matthieu.morel35@gmail.com>
Mauro Porras P <mauroporrasp@gmail.com>
Max Shytikov <mshytikov@gmail.com>
Max-Julian Pogner <max-julian@pogner.at>
@ -566,6 +582,7 @@ Maxime Petazzoni <max@signalfuse.com>
Maximillian Fan Xavier <maximillianfx@gmail.com>
Mei ChunTao <mei.chuntao@zte.com.cn>
Melroy van den Berg <melroy@melroy.org>
Mert Şişmanoğlu <mert190737fb@gmail.com>
Metal <2466052+tedhexaflow@users.noreply.github.com>
Micah Zoltu <micah@newrelic.com>
Michael A. Smith <michael@smith-li.com>
@ -598,7 +615,9 @@ Mindaugas Rukas <momomg@gmail.com>
Miroslav Gula <miroslav.gula@naytrolabs.com>
Misty Stanley-Jones <misty@docker.com>
Mohammad Banikazemi <mb@us.ibm.com>
Mohammad Hossein <mhm98035@gmail.com>
Mohammed Aaqib Ansari <maaquib@gmail.com>
Mohammed Aminu Futa <mohammedfuta2000@gmail.com>
Mohini Anne Dsouza <mohini3917@gmail.com>
Moorthy RS <rsmoorthy@gmail.com>
Morgan Bauer <mbauer@us.ibm.com>
@ -633,9 +652,11 @@ Nicolas De Loof <nicolas.deloof@gmail.com>
Nikhil Chawla <chawlanikhil24@gmail.com>
Nikolas Garofil <nikolas.garofil@uantwerpen.be>
Nikolay Milovanov <nmil@itransformers.net>
NinaLua <iturf@sina.cn>
Nir Soffer <nsoffer@redhat.com>
Nishant Totla <nishanttotla@gmail.com>
NIWA Hideyuki <niwa.niwa@nifty.ne.jp>
Noah Silas <noah@hustle.com>
Noah Treuhaft <noah.treuhaft@docker.com>
O.S. Tezer <ostezer@gmail.com>
Oded Arbel <oded@geek.co.il>
@ -653,10 +674,12 @@ Patrick Böänziger <patrick.baenziger@bsi-software.com>
Patrick Daigle <114765035+pdaig@users.noreply.github.com>
Patrick Hemmer <patrick.hemmer@gmail.com>
Patrick Lang <plang@microsoft.com>
Patrick St. laurent <patrick@saint-laurent.us>
Paul <paul9869@gmail.com>
Paul Kehrer <paul.l.kehrer@gmail.com>
Paul Lietar <paul@lietar.net>
Paul Mulders <justinkb@gmail.com>
Paul Rogalski <mail@paul-rogalski.de>
Paul Seyfert <pseyfert.mathphys@gmail.com>
Paul Weaver <pauweave@cisco.com>
Pavel Pospisil <pospispa@gmail.com>
@ -678,7 +701,6 @@ Philip Alexander Etling <paetling@gmail.com>
Philipp Gillé <philipp.gille@gmail.com>
Philipp Schmied <pschmied@schutzwerk.com>
Phong Tran <tran.pho@northeastern.edu>
pidster <pid@pidster.com>
Pieter E Smit <diepes@github.com>
pixelistik <pixelistik@users.noreply.github.com>
Pratik Karki <prertik@outlook.com>
@ -738,6 +760,7 @@ Samuel Cochran <sj26@sj26.com>
Samuel Karp <skarp@amazon.com>
Sandro Jäckel <sandro.jaeckel@gmail.com>
Santhosh Manohar <santhosh@docker.com>
Sarah Sanders <sarah.sanders@docker.com>
Sargun Dhillon <sargun@netflix.com>
Saswat Bhattacharya <sas.saswat@gmail.com>
Saurabh Kumar <saurabhkumar0184@gmail.com>
@ -770,6 +793,7 @@ Spencer Brown <spencer@spencerbrown.org>
Spring Lee <xi.shuai@outlook.com>
squeegels <lmscrewy@gmail.com>
Srini Brahmaroutu <srbrahma@us.ibm.com>
Stavros Panakakis <stavrospanakakis@gmail.com>
Stefan S. <tronicum@user.github.com>
Stefan Scherer <stefan.scherer@docker.com>
Stefan Weil <sw@weilnetz.de>
@ -780,6 +804,7 @@ Steve Durrheimer <s.durrheimer@gmail.com>
Steve Richards <steve.richards@docker.com>
Steven Burgess <steven.a.burgess@hotmail.com>
Stoica-Marcu Floris-Andrei <floris.sm@gmail.com>
Stuart Williams <pid@pidster.com>
Subhajit Ghosh <isubuz.g@gmail.com>
Sun Jianbo <wonderflow.sun@gmail.com>
Sune Keller <absukl@almbrand.dk>
@ -867,6 +892,7 @@ Wang Yumu <37442693@qq.com>
Wataru Ishida <ishida.wataru@lab.ntt.co.jp>
Wayne Song <wsong@docker.com>
Wen Cheng Ma <wenchma@cn.ibm.com>
Wenlong Zhang <zhangwenlong@loongson.cn>
Wenzhi Liang <wenzhi.liang@gmail.com>
Wes Morgan <cap10morgan@gmail.com>
Wewang Xiaorenfine <wang.xiaoren@zte.com.cn>
@ -908,3 +934,4 @@ Zhuo Zhi <h.dwwwwww@gmail.com>
Átila Camurça Alves <camurca.home@gmail.com>
Александр Менщиков <__Singleton__@hackerdom.ru>
徐俊杰 <paco.xu@daocloud.io>
林博仁 Buo-ren Lin <Buo.Ren.Lin@gmail.com>

View File

@ -1,19 +1,30 @@
# syntax=docker/dockerfile:1
ARG BASE_VARIANT=alpine
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
# It must be a supported tag in the docker.io/library/alpine image repository
# that's also available as alpine image variant for the Golang version used.
ARG ALPINE_VERSION=3.21
ARG BASE_DEBIAN_DISTRO=bookworm
ARG GO_VERSION=1.23.7
ARG GO_VERSION=1.24.5
ARG XX_VERSION=1.6.1
ARG GOVERSIONINFO_VERSION=v1.4.1
ARG GOTESTSUM_VERSION=v1.12.0
# GOTESTSUM_VERSION sets the version of gotestsum to install in the dev container.
# It must be a valid tag in the https://github.com/gotestyourself/gotestsum repository.
ARG GOTESTSUM_VERSION=v1.12.3
# BUILDX_VERSION sets the version of buildx to use for the e2e tests.
# It must be a tag in the docker.io/docker/buildx-bin image repository
# on Docker Hub.
ARG BUILDX_VERSION=0.20.1
ARG COMPOSE_VERSION=v2.32.4
ARG BUILDX_VERSION=0.25.0
# COMPOSE_VERSION is the version of compose to install in the dev container.
# It must be a tag in the docker.io/docker/compose-bin image repository
# on Docker Hub.
ARG COMPOSE_VERSION=v2.38.2
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
@ -117,7 +128,7 @@ COPY --link --from=compose /docker-compose /usr/libexec/docker/cli-plugins/docke
COPY --link . .
ENV DOCKER_BUILDKIT=1
ENV PATH=/go/src/github.com/docker/cli/build:$PATH
CMD ./scripts/test/e2e/entry
CMD ["./scripts/test/e2e/entry"]
FROM build-base-${BASE_VARIANT} AS dev
COPY --link . .

View File

@ -67,20 +67,20 @@ dynbinary: ## build dynamically linked binary
.PHONY: plugins
plugins: ## build example CLI plugins
./scripts/build/plugins
scripts/build/plugins
.PHONY: vendor
vendor: ## update vendor with go modules
rm -rf vendor
./scripts/vendor update
scripts/with-go-mod.sh scripts/vendor update
.PHONY: validate-vendor
validate-vendor: ## validate vendor
./scripts/vendor validate
scripts/with-go-mod.sh scripts/vendor validate
.PHONY: mod-outdated
mod-outdated: ## check outdated dependencies
./scripts/vendor outdated
scripts/with-go-mod.sh scripts/vendor outdated
.PHONY: authors
authors: ## generate AUTHORS file from git history
@ -115,15 +115,15 @@ shell-completion: ## generate shell-completion scripts
.PHONY: manpages
manpages: ## generate man pages from go source and markdown
scripts/docs/generate-man.sh
scripts/with-go-mod.sh scripts/docs/generate-man.sh
.PHONY: mddocs
mddocs: ## generate markdown files from go source
scripts/docs/generate-md.sh
scripts/with-go-mod.sh scripts/docs/generate-md.sh
.PHONY: yamldocs
yamldocs: ## generate documentation YAML files consumed by docs repo
scripts/docs/generate-yaml.sh
scripts/with-go-mod.sh scripts/docs/generate-yaml.sh
.PHONY: help
help: ## print this help

View File

@ -1 +1 @@
28.0.0-dev
28.3.0-dev

View File

@ -9,7 +9,7 @@ import (
"github.com/docker/cli/cli-plugins/metadata"
"github.com/spf13/cobra"
"gotest.tools/v3/assert"
"gotest.tools/v3/assert/cmp"
is "gotest.tools/v3/assert/cmp"
)
type fakeCandidate struct {
@ -81,7 +81,7 @@ func TestValidateCandidate(t *testing.T) {
assert.ErrorContains(t, err, tc.err)
case tc.invalid != "":
assert.NilError(t, err)
assert.Assert(t, cmp.ErrorType(p.Err, reflect.TypeOf(&pluginError{})))
assert.Assert(t, is.ErrorType(p.Err, reflect.TypeOf(&pluginError{})))
assert.ErrorContains(t, p.Err, tc.invalid)
default:
assert.NilError(t, err)

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package manager

View File

@ -64,13 +64,10 @@ func invokeAndCollectHooks(ctx context.Context, cfg *configfile.ConfigFile, root
return nil
}
pluginDirs, err := getPluginDirs(cfg)
if err != nil {
return nil
}
pluginDirs := getPluginDirs(cfg)
nextSteps := make([]string, 0, len(pluginsCfg))
for pluginName, cfg := range pluginsCfg {
match, ok := pluginMatch(cfg, subCmdStr)
for pluginName, pluginCfg := range pluginsCfg {
match, ok := pluginMatch(pluginCfg, subCmdStr)
if !ok {
continue
}

View File

@ -61,20 +61,16 @@ func IsNotFound(err error) bool {
// 3. Platform-specific defaultSystemPluginDirs.
//
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
func getPluginDirs(cfg *configfile.ConfigFile) ([]string, error) {
func getPluginDirs(cfg *configfile.ConfigFile) []string {
var pluginDirs []string
if cfg != nil {
pluginDirs = append(pluginDirs, cfg.CLIPluginsExtraDirs...)
}
pluginDir, err := config.Path("cli-plugins")
if err != nil {
return nil, err
}
pluginDir := filepath.Join(config.Dir(), "cli-plugins")
pluginDirs = append(pluginDirs, pluginDir)
pluginDirs = append(pluginDirs, defaultSystemPluginDirs...)
return pluginDirs, nil
return pluginDirs
}
func addPluginCandidatesFromDir(res map[string][]string, d string) {
@ -85,7 +81,7 @@ func addPluginCandidatesFromDir(res map[string][]string, d string) {
return
}
for _, dentry := range dentries {
switch dentry.Type() & os.ModeType {
switch dentry.Type() & os.ModeType { //nolint:exhaustive,nolintlint // no need to include all possible file-modes in this list
case 0, os.ModeSymlink:
// Regular file or symlink, keep going
default:
@ -116,10 +112,7 @@ func listPluginCandidates(dirs []string) map[string][]string {
// GetPlugin returns a plugin on the system by its name
func GetPlugin(name string, dockerCLI config.Provider, rootcmd *cobra.Command) (*Plugin, error) {
pluginDirs, err := getPluginDirs(dockerCLI.ConfigFile())
if err != nil {
return nil, err
}
pluginDirs := getPluginDirs(dockerCLI.ConfigFile())
return getPlugin(name, pluginDirs, rootcmd)
}
@ -145,16 +138,20 @@ func getPlugin(name string, pluginDirs []string, rootcmd *cobra.Command) (*Plugi
// ListPlugins produces a list of the plugins available on the system
func ListPlugins(dockerCli config.Provider, rootcmd *cobra.Command) ([]Plugin, error) {
pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
if err != nil {
return nil, err
}
pluginDirs := getPluginDirs(dockerCli.ConfigFile())
candidates := listPluginCandidates(pluginDirs)
if len(candidates) == 0 {
return nil, nil
}
var plugins []Plugin
var mu sync.Mutex
eg, _ := errgroup.WithContext(context.TODO())
ctx := rootcmd.Context()
if ctx == nil {
// Fallback, mostly for tests that pass a bare cobra.command
ctx = context.Background()
}
eg, _ := errgroup.WithContext(ctx)
cmds := rootcmd.Commands()
for _, paths := range candidates {
func(paths []string) {
@ -202,10 +199,7 @@ func PluginRunCommand(dockerCli config.Provider, name string, rootcmd *cobra.Com
return nil, errPluginNotFound(name)
}
exename := addExeSuffix(metadata.NamePrefix + name)
pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
if err != nil {
return nil, err
}
pluginDirs := getPluginDirs(dockerCli.ConfigFile())
for _, d := range pluginDirs {
path := filepath.Join(d, exename)

View File

@ -1,6 +1,7 @@
package manager
import (
"path/filepath"
"strings"
"testing"
@ -81,6 +82,12 @@ func TestListPluginCandidates(t *testing.T) {
assert.DeepEqual(t, candidates, exp)
}
func TestListPluginCandidatesEmpty(t *testing.T) {
tmpDir := t.TempDir()
candidates := listPluginCandidates([]string{tmpDir, filepath.Join(tmpDir, "no-such-dir")})
assert.Assert(t, len(candidates) == 0)
}
// Regression test for https://github.com/docker/cli/issues/5643.
// Check that inaccessible directories that come before accessible ones are ignored
// and do not prevent the latter from being processed.
@ -166,14 +173,11 @@ func TestErrPluginNotFound(t *testing.T) {
func TestGetPluginDirs(t *testing.T) {
cli := test.NewFakeCli(nil)
pluginDir, err := config.Path("cli-plugins")
assert.NilError(t, err)
pluginDir := filepath.Join(config.Dir(), "cli-plugins")
expected := append([]string{pluginDir}, defaultSystemPluginDirs...)
var pluginDirs []string
pluginDirs, err = getPluginDirs(cli.ConfigFile())
pluginDirs := getPluginDirs(cli.ConfigFile())
assert.Equal(t, strings.Join(expected, ":"), strings.Join(pluginDirs, ":"))
assert.NilError(t, err)
extras := []string{
"foo", "bar", "baz",
@ -182,7 +186,6 @@ func TestGetPluginDirs(t *testing.T) {
cli.SetConfigFile(&configfile.ConfigFile{
CLIPluginsExtraDirs: extras,
})
pluginDirs, err = getPluginDirs(cli.ConfigFile())
pluginDirs = getPluginDirs(cli.ConfigFile())
assert.DeepEqual(t, expected, pluginDirs)
assert.NilError(t, err)
}

View File

@ -8,14 +8,14 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"github.com/docker/cli/cli-plugins/metadata"
"github.com/docker/cli/internal/lazyregexp"
"github.com/spf13/cobra"
)
var pluginNameRe = regexp.MustCompile("^[a-z][a-z0-9]*$")
var pluginNameRe = lazyregexp.New("^[a-z][a-z0-9]*$")
// Plugin represents a potential plugin with all it's metadata.
type Plugin struct {

View File

@ -109,7 +109,7 @@ func Run(makeCmd func(command.Cli) *cobra.Command, meta metadata.Metadata) {
}
func withPluginClientConn(name string) command.CLIOption {
return command.WithInitializeClient(func(dockerCli *command.DockerCli) (client.APIClient, error) {
return func(cli *command.DockerCli) error {
cmd := "docker"
if x := os.Getenv(metadata.ReexecEnvvar); x != "" {
cmd = x
@ -133,11 +133,14 @@ func withPluginClientConn(name string) command.CLIOption {
helper, err := connhelper.GetCommandConnectionHelper(cmd, flags...)
if err != nil {
return nil, err
return err
}
return client.NewClientWithOpts(client.WithDialContext(helper.Dialer))
})
apiClient, err := client.NewClientWithOpts(client.WithDialContext(helper.Dialer))
if err != nil {
return err
}
return command.WithAPIClient(apiClient)(cli)
}
}
func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta metadata.Metadata) *cli.TopLevelCommand {

View File

@ -3,16 +3,16 @@ package builder
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/client"
)
type fakeClient struct {
client.Client
builderPruneFunc func(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
builderPruneFunc func(ctx context.Context, opts build.CachePruneOptions) (*build.CachePruneReport, error)
}
func (c *fakeClient) BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
func (c *fakeClient) BuildCachePrune(ctx context.Context, opts build.CachePruneOptions) (*build.CachePruneReport, error) {
if c.builderPruneFunc != nil {
return c.builderPruneFunc(ctx, opts)
}

View File

@ -23,3 +23,22 @@ func NewBuilderCommand(dockerCli command.Cli) *cobra.Command {
)
return cmd
}
// NewBakeStubCommand returns a cobra command "stub" for the "bake" subcommand.
// This command is a placeholder / stub that is dynamically replaced by an
// alias for "docker buildx bake" if BuildKit is enabled (and the buildx plugin
// installed).
func NewBakeStubCommand(dockerCLI command.Streams) *cobra.Command {
return &cobra.Command{
Use: "bake [OPTIONS] [TARGET...]",
Short: "Build from a file",
RunE: command.ShowHelp(dockerCLI.Err()),
Annotations: map[string]string{
// We want to show this command in the "top" category in --help
// output, and not to be grouped under "management commands".
"category-top": "5",
"aliases": "docker buildx bake",
"version": "1.31",
},
}
}

View File

@ -9,10 +9,10 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/internal/prompt"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/errdefs"
units "github.com/docker/go-units"
"github.com/docker/docker/api/types/build"
"github.com/docker/go-units"
"github.com/spf13/cobra"
)
@ -69,18 +69,18 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
warning = allCacheWarning
}
if !options.force {
r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning)
r, err := prompt.Confirm(ctx, dockerCli.In(), dockerCli.Out(), warning)
if err != nil {
return 0, "", err
}
if !r {
return 0, "", errdefs.Cancelled(errors.New("builder prune has been cancelled"))
return 0, "", cancelledErr{errors.New("builder prune has been cancelled")}
}
}
report, err := dockerCli.Client().BuildCachePrune(ctx, types.BuildCachePruneOptions{
report, err := dockerCli.Client().BuildCachePrune(ctx, build.CachePruneOptions{
All: options.all,
KeepStorage: options.keepStorage.Value(),
KeepStorage: options.keepStorage.Value(), // FIXME(thaJeztah): rewrite to use new options; see https://github.com/moby/moby/pull/48720
Filters: pruneFilters,
})
if err != nil {
@ -100,6 +100,10 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
return report.SpaceReclaimed, output, nil
}
type cancelledErr struct{ error }
func (cancelledErr) Cancelled() {}
// CachePrune executes a prune command for build cache
func CachePrune(ctx context.Context, dockerCli command.Cli, all bool, filter opts.FilterOpt) (uint64, string, error) {
return runPrune(ctx, dockerCli, pruneOptions{force: true, all: all, filter: filter})

View File

@ -7,7 +7,7 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/build"
)
func TestBuilderPromptTermination(t *testing.T) {
@ -15,7 +15,7 @@ func TestBuilderPromptTermination(t *testing.T) {
t.Cleanup(cancel)
cli := test.NewFakeCli(&fakeClient{
builderPruneFunc: func(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
builderPruneFunc: func(ctx context.Context, opts build.CachePruneOptions) (*build.CachePruneReport, error) {
return nil, errors.New("fakeClient builderPruneFunc should not be called")
},
})

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package command
@ -24,7 +24,7 @@ import (
"github.com/docker/cli/cli/version"
dopts "github.com/docker/cli/opts"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
"github.com/pkg/errors"
@ -56,12 +56,12 @@ type Cli interface {
CurrentContext() string
DockerEndpoint() docker.Endpoint
TelemetryClient
DeprecatedNotaryClient
DeprecatedManifestClient
}
// DockerCli is an instance the docker command line client.
// Instances of the client can be returned from NewDockerCli.
// Instances of the client should be created using the [NewDockerCli]
// constructor to make sure they are properly initialized with defaults
// set.
type DockerCli struct {
configFile *configfile.ConfigFile
options *cliflags.ClientOptions
@ -76,7 +76,7 @@ type DockerCli struct {
init sync.Once
initErr error
dockerEndpoint docker.Endpoint
contextStoreConfig store.Config
contextStoreConfig *store.Config
initTimeout time.Duration
res telemetryResource
@ -180,7 +180,7 @@ func (cli *DockerCli) BuildKitEnabled() (bool, error) {
}
si := cli.ServerInfo()
if si.BuildkitVersion == types.BuilderBuildKit {
if si.BuildkitVersion == build.BuilderBuildKit {
// The daemon advertised BuildKit as the preferred builder; this may
// be either a Linux daemon or a Windows daemon with experimental
// BuildKit support enabled.
@ -222,15 +222,6 @@ func (cli *DockerCli) HooksEnabled() bool {
return false
}
// WithInitializeClient is passed to DockerCli.Initialize by callers who wish to set a particular API Client for use by the CLI.
func WithInitializeClient(makeClient func(dockerCli *DockerCli) (client.APIClient, error)) CLIOption {
return func(dockerCli *DockerCli) error {
var err error
dockerCli.client, err = makeClient(dockerCli)
return err
}
}
// Initialize the dockerCli runs initialization that must happen after command
// line flags are parsed.
func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption) error {
@ -252,13 +243,33 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption)
return errors.New("conflicting options: cannot specify both --host and --context")
}
if cli.contextStoreConfig == nil {
// This path can be hit when calling Initialize on a DockerCli that's
// not constructed through [NewDockerCli]. Using the default context
// store without a config set will result in Endpoints from contexts
// not being type-mapped correctly, and used as a generic "map[string]any",
// instead of a [docker.EndpointMeta].
//
// When looking up the API endpoint (using [EndpointFromContext]), no
// endpoint will be found, and a default, empty endpoint will be used
// instead which in its turn, causes newAPIClientFromEndpoint to
// be initialized with the default config instead of settings for
// the current context (which may mean; connecting with the wrong
// endpoint and/or TLS Config to be missing).
//
// [EndpointFromContext]: https://github.com/docker/cli/blob/33494921b80fd0b5a06acc3a34fa288de4bb2e6b/cli/context/docker/load.go#L139-L149
if err := WithDefaultContextStoreConfig()(cli); err != nil {
return err
}
}
cli.options = opts
cli.configFile = config.LoadDefaultConfigFile(cli.err)
cli.currentContext = resolveContextName(cli.options, cli.configFile)
cli.contextStore = &ContextStoreWithDefault{
Store: store.New(config.ContextStoreDir(), cli.contextStoreConfig),
Store: store.New(config.ContextStoreDir(), *cli.contextStoreConfig),
Resolver: func() (*DefaultContext, error) {
return ResolveDefaultContext(cli.options, cli.contextStoreConfig)
return ResolveDefaultContext(cli.options, *cli.contextStoreConfig)
},
}
@ -499,7 +510,7 @@ func (cli *DockerCli) Apply(ops ...CLIOption) error {
type ServerInfo struct {
HasExperimental bool
OSType string
BuildkitVersion types.BuilderVersion
BuildkitVersion build.BuilderVersion
// SwarmStatus provides information about the current swarm status of the
// engine, obtained from the "Swarm" header in the API response.

View File

@ -1,56 +0,0 @@
package command
import (
"context"
"path/filepath"
"github.com/docker/cli/cli/config"
manifeststore "github.com/docker/cli/cli/manifest/store"
registryclient "github.com/docker/cli/cli/registry/client"
"github.com/docker/cli/cli/trust"
"github.com/docker/docker/api/types/registry"
notaryclient "github.com/theupdateframework/notary/client"
)
type DeprecatedNotaryClient interface {
// NotaryClient provides a Notary Repository to interact with signed metadata for an image
//
// Deprecated: use [trust.GetNotaryRepository] instead. This method is no longer used and will be removed in the next release.
NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error)
}
type DeprecatedManifestClient interface {
// ManifestStore returns a store for local manifests
//
// Deprecated: use [manifeststore.NewStore] instead. This method is no longer used and will be removed in the next release.
ManifestStore() manifeststore.Store
// RegistryClient returns a client for communicating with a Docker distribution
// registry.
//
// Deprecated: use [registryclient.NewRegistryClient]. This method is no longer used and will be removed in the next release.
RegistryClient(bool) registryclient.RegistryClient
}
// NotaryClient provides a Notary Repository to interact with signed metadata for an image
func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) {
return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...)
}
// ManifestStore returns a store for local manifests
//
// Deprecated: use [manifeststore.NewStore] instead. This method is no longer used and will be removed in the next release.
func (*DockerCli) ManifestStore() manifeststore.Store {
return manifeststore.NewStore(filepath.Join(config.Dir(), "manifests"))
}
// RegistryClient returns a client for communicating with a Docker distribution
// registry
//
// Deprecated: use [registryclient.NewRegistryClient]. This method is no longer used and will be removed in the next release.
func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient {
resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig {
return ResolveAuthConfig(cli.ConfigFile(), index)
}
return registryclient.NewRegistryClient(resolver, UserAgent(), allowInsecure)
}

View File

@ -11,7 +11,6 @@ import (
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/client"
"github.com/docker/docker/errdefs"
"github.com/moby/term"
"github.com/pkg/errors"
)
@ -101,7 +100,8 @@ func WithContentTrust(enabled bool) CLIOption {
// WithDefaultContextStoreConfig configures the cli to use the default context store configuration.
func WithDefaultContextStoreConfig() CLIOption {
return func(cli *DockerCli) error {
cli.contextStoreConfig = DefaultContextStoreConfig()
cfg := DefaultContextStoreConfig()
cli.contextStoreConfig = &cfg
return nil
}
}
@ -114,6 +114,18 @@ func WithAPIClient(c client.APIClient) CLIOption {
}
}
// WithInitializeClient is passed to [DockerCli.Initialize] to initialize
// an API Client for use by the CLI.
func WithInitializeClient(makeClient func(*DockerCli) (client.APIClient, error)) CLIOption {
return func(cli *DockerCli) error {
c, err := makeClient(cli)
if err != nil {
return err
}
return WithAPIClient(c)(cli)
}
}
// envOverrideHTTPHeaders is the name of the environment-variable that can be
// used to set custom HTTP headers to be sent by the client. This environment
// variable is the equivalent to the HttpHeaders field in the configuration
@ -177,7 +189,7 @@ func withCustomHeadersFromEnv() client.Opt {
csvReader := csv.NewReader(strings.NewReader(value))
fields, err := csvReader.Read()
if err != nil {
return errdefs.InvalidParameter(errors.Errorf(
return invalidParameter(errors.Errorf(
"failed to parse custom headers from %s environment variable: value must be formatted as comma-separated key=value pairs",
envOverrideHTTPHeaders,
))
@ -194,7 +206,7 @@ func withCustomHeadersFromEnv() client.Opt {
k = strings.TrimSpace(k)
if k == "" {
return errdefs.InvalidParameter(errors.Errorf(
return invalidParameter(errors.Errorf(
`failed to set custom headers from %s environment variable: value contains a key=value pair with an empty key: '%s'`,
envOverrideHTTPHeaders, kv,
))
@ -205,7 +217,7 @@ func withCustomHeadersFromEnv() client.Opt {
// from an environment variable with the same name). In the meantime,
// produce an error to prevent users from depending on this.
if !hasValue {
return errdefs.InvalidParameter(errors.Errorf(
return invalidParameter(errors.Errorf(
`failed to set custom headers from %s environment variable: missing "=" in key=value pair: '%s'`,
envOverrideHTTPHeaders, kv,
))

View File

@ -19,12 +19,10 @@ import (
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/flags"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"gotest.tools/v3/assert"
"gotest.tools/v3/fs"
)
func TestNewAPIClientFromFlags(t *testing.T) {
@ -207,8 +205,8 @@ func TestInitializeFromClient(t *testing.T) {
// Makes sure we don't hang forever on the initial connection.
// https://github.com/docker/cli/issues/3652
func TestInitializeFromClientHangs(t *testing.T) {
dir := t.TempDir()
socket := filepath.Join(dir, "my.sock")
tmpDir := t.TempDir()
socket := filepath.Join(tmpDir, "my.sock")
l, err := net.Listen("unix", socket)
assert.NilError(t, err)
@ -256,79 +254,40 @@ func TestInitializeFromClientHangs(t *testing.T) {
}
}
// The CLI no longer disables/hides experimental CLI features, however, we need
// to verify that existing configuration files do not break
func TestExperimentalCLI(t *testing.T) {
defaultVersion := "v1.55"
testcases := []struct {
doc string
configfile string
}{
{
doc: "default",
configfile: `{}`,
},
{
doc: "experimental",
configfile: `{
"experimental": "enabled"
}`,
},
}
for _, tc := range testcases {
t.Run(tc.doc, func(t *testing.T) {
dir := fs.NewDir(t, tc.doc, fs.WithFile("config.json", tc.configfile))
defer dir.Remove()
apiclient := &fakeClient{
version: defaultVersion,
pingFunc: func() (types.Ping, error) {
return types.Ping{Experimental: true, OSType: "linux", APIVersion: defaultVersion}, nil
},
}
cli := &DockerCli{client: apiclient, err: streams.NewOut(os.Stderr)}
config.SetDir(dir.Path())
err := cli.Initialize(flags.NewClientOptions())
assert.NilError(t, err)
})
}
}
func TestNewDockerCliAndOperators(t *testing.T) {
// Test default operations and also overriding default ones
cli, err := NewDockerCli(
WithContentTrust(true),
)
cli, err := NewDockerCli(WithInputStream(io.NopCloser(strings.NewReader("some input"))))
assert.NilError(t, err)
// Check streams are initialized
assert.Check(t, cli.In() != nil)
assert.Check(t, cli.Out() != nil)
assert.Check(t, cli.Err() != nil)
assert.Equal(t, cli.ContentTrustEnabled(), true)
inputStream, err := io.ReadAll(cli.In())
assert.NilError(t, err)
assert.Equal(t, string(inputStream), "some input")
// Apply can modify a dockerCli after construction
inbuf := bytes.NewBuffer([]byte("input"))
outbuf := bytes.NewBuffer(nil)
errbuf := bytes.NewBuffer(nil)
err = cli.Apply(
WithInputStream(io.NopCloser(inbuf)),
WithInputStream(io.NopCloser(strings.NewReader("input"))),
WithOutputStream(outbuf),
WithErrorStream(errbuf),
)
assert.NilError(t, err)
// Check input stream
inputStream, err := io.ReadAll(cli.In())
inputStream, err = io.ReadAll(cli.In())
assert.NilError(t, err)
assert.Equal(t, string(inputStream), "input")
// Check output stream
fmt.Fprintf(cli.Out(), "output")
_, err = fmt.Fprint(cli.Out(), "output")
assert.NilError(t, err)
outputStream, err := io.ReadAll(outbuf)
assert.NilError(t, err)
assert.Equal(t, string(outputStream), "output")
// Check error stream
fmt.Fprintf(cli.Err(), "error")
_, err = fmt.Fprint(cli.Err(), "error")
assert.NilError(t, err)
errStream, err := io.ReadAll(errbuf)
assert.NilError(t, err)
assert.Equal(t, string(errStream), "error")
@ -345,6 +304,8 @@ func TestInitializeShouldAlwaysCreateTheContextStore(t *testing.T) {
func TestHooksEnabled(t *testing.T) {
t.Run("disabled by default", func(t *testing.T) {
// Make sure we don't depend on any existing ~/.docker/config.json
config.SetDir(t.TempDir())
cli, err := NewDockerCli()
assert.NilError(t, err)
@ -356,12 +317,11 @@ func TestHooksEnabled(t *testing.T) {
"features": {
"hooks": "true"
}}`
dir := fs.NewDir(t, "", fs.WithFile("config.json", configFile))
defer dir.Remove()
config.SetDir(t.TempDir())
err := os.WriteFile(filepath.Join(config.Dir(), "config.json"), []byte(configFile), 0o600)
assert.NilError(t, err)
cli, err := NewDockerCli()
assert.NilError(t, err)
config.SetDir(dir.Path())
assert.Check(t, cli.HooksEnabled())
})
@ -371,12 +331,11 @@ func TestHooksEnabled(t *testing.T) {
"hooks": "true"
}}`
t.Setenv("DOCKER_CLI_HOOKS", "false")
dir := fs.NewDir(t, "", fs.WithFile("config.json", configFile))
defer dir.Remove()
config.SetDir(t.TempDir())
err := os.WriteFile(filepath.Join(config.Dir(), "config.json"), []byte(configFile), 0o600)
assert.NilError(t, err)
cli, err := NewDockerCli()
assert.NilError(t, err)
config.SetDir(dir.Path())
assert.Check(t, !cli.HooksEnabled())
})
@ -386,12 +345,11 @@ func TestHooksEnabled(t *testing.T) {
"hooks": "true"
}}`
t.Setenv("DOCKER_CLI_HINTS", "false")
dir := fs.NewDir(t, "", fs.WithFile("config.json", configFile))
defer dir.Remove()
config.SetDir(t.TempDir())
err := os.WriteFile(filepath.Join(config.Dir(), "config.json"), []byte(configFile), 0o600)
assert.NilError(t, err)
cli, err := NewDockerCli()
assert.NilError(t, err)
config.SetDir(dir.Path())
assert.Check(t, !cli.HooksEnabled())
})
}

View File

@ -43,6 +43,7 @@ func AddCommands(cmd *cobra.Command, dockerCli command.Cli) {
system.NewInfoCommand(dockerCli),
// management commands
builder.NewBakeStubCommand(dockerCli),
builder.NewBuilderCommand(dockerCli),
checkpoint.NewCheckpointCommand(dockerCli),
container.NewContainerCommand(dockerCli),

View File

@ -13,8 +13,10 @@ import (
"github.com/spf13/cobra"
)
// ValidArgsFn a function to be used by cobra command as `ValidArgsFunction` to offer command line completion
type ValidArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)
// ValidArgsFn a function to be used by cobra command as `ValidArgsFunction` to offer command line completion.
//
// Deprecated: use [cobra.CompletionFunc].
type ValidArgsFn = cobra.CompletionFunc
// APIClientProvider provides a method to get an [client.APIClient], initializing
// it if needed.
@ -27,7 +29,7 @@ type APIClientProvider interface {
}
// ImageNames offers completion for images present within the local store
func ImageNames(dockerCLI APIClientProvider, limit int) ValidArgsFn {
func ImageNames(dockerCLI APIClientProvider, limit int) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if limit > 0 && len(args) >= limit {
return nil, cobra.ShellCompDirectiveNoFileComp
@ -47,7 +49,7 @@ func ImageNames(dockerCLI APIClientProvider, limit int) ValidArgsFn {
// ContainerNames offers completion for container names and IDs
// By default, only names are returned.
// Set DOCKER_COMPLETION_SHOW_CONTAINER_IDS=yes to also complete IDs.
func ContainerNames(dockerCLI APIClientProvider, all bool, filters ...func(container.Summary) bool) ValidArgsFn {
func ContainerNames(dockerCLI APIClientProvider, all bool, filters ...func(container.Summary) bool) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCLI.Client().ContainerList(cmd.Context(), container.ListOptions{
All: all,
@ -80,7 +82,7 @@ func ContainerNames(dockerCLI APIClientProvider, all bool, filters ...func(conta
}
// VolumeNames offers completion for volumes
func VolumeNames(dockerCLI APIClientProvider) ValidArgsFn {
func VolumeNames(dockerCLI APIClientProvider) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCLI.Client().VolumeList(cmd.Context(), volume.ListOptions{})
if err != nil {
@ -95,7 +97,7 @@ func VolumeNames(dockerCLI APIClientProvider) ValidArgsFn {
}
// NetworkNames offers completion for networks
func NetworkNames(dockerCLI APIClientProvider) ValidArgsFn {
func NetworkNames(dockerCLI APIClientProvider) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCLI.Client().NetworkList(cmd.Context(), network.ListOptions{})
if err != nil {
@ -133,7 +135,7 @@ func EnvVarNames(_ *cobra.Command, _ []string, _ string) (names []string, _ cobr
}
// FromList offers completion for the given list of options.
func FromList(options ...string) ValidArgsFn {
func FromList(options ...string) cobra.CompletionFunc {
return cobra.FixedCompletions(options, cobra.ShellCompDirectiveNoFileComp)
}
@ -150,7 +152,6 @@ func NoComplete(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCo
}
var commonPlatforms = []string{
"linux",
"linux/386",
"linux/amd64",
"linux/arm",
@ -167,10 +168,8 @@ var commonPlatforms = []string{
// Not yet supported
"linux/riscv64",
"windows",
"windows/amd64",
"wasip1",
"wasip1/wasm",
}

View File

@ -82,9 +82,9 @@ func TestCompleteContainerNames(t *testing.T) {
doc: "all containers",
showAll: true,
containers: []container.Summary{
{ID: "id-c", State: "running", Names: []string{"/container-c", "/container-c/link-b"}},
{ID: "id-b", State: "created", Names: []string{"/container-b"}},
{ID: "id-a", State: "exited", Names: []string{"/container-a"}},
{ID: "id-c", State: container.StateRunning, Names: []string{"/container-c", "/container-c/link-b"}},
{ID: "id-b", State: container.StateCreated, Names: []string{"/container-b"}},
{ID: "id-a", State: container.StateExited, Names: []string{"/container-a"}},
},
expOut: []string{"container-c", "container-c/link-b", "container-b", "container-a"},
expOpts: container.ListOptions{All: true},
@ -95,9 +95,9 @@ func TestCompleteContainerNames(t *testing.T) {
showAll: true,
showIDs: true,
containers: []container.Summary{
{ID: "id-c", State: "running", Names: []string{"/container-c", "/container-c/link-b"}},
{ID: "id-b", State: "created", Names: []string{"/container-b"}},
{ID: "id-a", State: "exited", Names: []string{"/container-a"}},
{ID: "id-c", State: container.StateRunning, Names: []string{"/container-c", "/container-c/link-b"}},
{ID: "id-b", State: container.StateCreated, Names: []string{"/container-b"}},
{ID: "id-a", State: container.StateExited, Names: []string{"/container-a"}},
},
expOut: []string{"id-c", "container-c", "container-c/link-b", "id-b", "container-b", "id-a", "container-a"},
expOpts: container.ListOptions{All: true},
@ -107,7 +107,7 @@ func TestCompleteContainerNames(t *testing.T) {
doc: "only running containers",
showAll: false,
containers: []container.Summary{
{ID: "id-c", State: "running", Names: []string{"/container-c", "/container-c/link-b"}},
{ID: "id-c", State: container.StateRunning, Names: []string{"/container-c", "/container-c/link-b"}},
},
expOut: []string{"container-c", "container-c/link-b"},
expDirective: cobra.ShellCompDirectiveNoFileComp,
@ -116,12 +116,12 @@ func TestCompleteContainerNames(t *testing.T) {
doc: "with filter",
showAll: true,
filters: []func(container.Summary) bool{
func(container container.Summary) bool { return container.State == "created" },
func(ctr container.Summary) bool { return ctr.State == container.StateCreated },
},
containers: []container.Summary{
{ID: "id-c", State: "running", Names: []string{"/container-c", "/container-c/link-b"}},
{ID: "id-b", State: "created", Names: []string{"/container-b"}},
{ID: "id-a", State: "exited", Names: []string{"/container-a"}},
{ID: "id-c", State: container.StateRunning, Names: []string{"/container-c", "/container-c/link-b"}},
{ID: "id-b", State: container.StateCreated, Names: []string{"/container-b"}},
{ID: "id-a", State: container.StateExited, Names: []string{"/container-a"}},
},
expOut: []string{"container-b"},
expOpts: container.ListOptions{All: true},
@ -131,13 +131,13 @@ func TestCompleteContainerNames(t *testing.T) {
doc: "multiple filters",
showAll: true,
filters: []func(container.Summary) bool{
func(container container.Summary) bool { return container.ID == "id-a" },
func(container container.Summary) bool { return container.State == "created" },
func(ctr container.Summary) bool { return ctr.ID == "id-a" },
func(ctr container.Summary) bool { return ctr.State == container.StateCreated },
},
containers: []container.Summary{
{ID: "id-c", State: "running", Names: []string{"/container-c", "/container-c/link-b"}},
{ID: "id-b", State: "created", Names: []string{"/container-b"}},
{ID: "id-a", State: "created", Names: []string{"/container-a"}},
{ID: "id-c", State: container.StateRunning, Names: []string{"/container-c", "/container-c/link-b"}},
{ID: "id-b", State: container.StateCreated, Names: []string{"/container-b"}},
{ID: "id-a", State: container.StateCreated, Names: []string{"/container-a"}},
},
expOut: []string{"container-a"},
expOpts: container.ListOptions{All: true},

View File

@ -3,24 +3,23 @@ package config
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"
)
type fakeClient struct {
client.Client
configCreateFunc func(context.Context, swarm.ConfigSpec) (types.ConfigCreateResponse, error)
configCreateFunc func(context.Context, swarm.ConfigSpec) (swarm.ConfigCreateResponse, error)
configInspectFunc func(context.Context, string) (swarm.Config, []byte, error)
configListFunc func(context.Context, types.ConfigListOptions) ([]swarm.Config, error)
configListFunc func(context.Context, swarm.ConfigListOptions) ([]swarm.Config, error)
configRemoveFunc func(string) error
}
func (c *fakeClient) ConfigCreate(ctx context.Context, spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
func (c *fakeClient) ConfigCreate(ctx context.Context, spec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
if c.configCreateFunc != nil {
return c.configCreateFunc(ctx, spec)
}
return types.ConfigCreateResponse{}, nil
return swarm.ConfigCreateResponse{}, nil
}
func (c *fakeClient) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.Config, []byte, error) {
@ -30,7 +29,7 @@ func (c *fakeClient) ConfigInspectWithRaw(ctx context.Context, id string) (swarm
return swarm.Config{}, nil, nil
}
func (c *fakeClient) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
func (c *fakeClient) ConfigList(ctx context.Context, options swarm.ConfigListOptions) ([]swarm.Config, error) {
if c.configListFunc != nil {
return c.configListFunc(ctx, options)
}

View File

@ -4,7 +4,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/spf13/cobra"
)
@ -30,9 +30,9 @@ func NewConfigCommand(dockerCli command.Cli) *cobra.Command {
}
// completeNames offers completion for swarm configs
func completeNames(dockerCLI completion.APIClientProvider) completion.ValidArgsFn {
func completeNames(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := dockerCLI.Client().ConfigList(cmd.Context(), types.ConfigListOptions{})
list, err := dockerCLI.Client().ConfigList(cmd.Context(), swarm.ConfigListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

View File

@ -59,7 +59,7 @@ func RunConfigCreate(ctx context.Context, dockerCLI command.Cli, options CreateO
spec := swarm.ConfigSpec{
Annotations: swarm.Annotations{
Name: options.Name,
Labels: opts.ConvertKVStringsToMap(options.Labels.GetAll()),
Labels: opts.ConvertKVStringsToMap(options.Labels.GetSlice()),
},
Data: configData,
}

View File

@ -12,7 +12,6 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -24,7 +23,7 @@ const configDataFile = "config-create-with-name.golden"
func TestConfigCreateErrors(t *testing.T) {
testCases := []struct {
args []string
configCreateFunc func(context.Context, swarm.ConfigSpec) (types.ConfigCreateResponse, error)
configCreateFunc func(context.Context, swarm.ConfigSpec) (swarm.ConfigCreateResponse, error)
expectedError string
}{
{
@ -37,8 +36,8 @@ func TestConfigCreateErrors(t *testing.T) {
},
{
args: []string{"name", filepath.Join("testdata", configDataFile)},
configCreateFunc: func(_ context.Context, configSpec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
return types.ConfigCreateResponse{}, errors.New("error creating config")
configCreateFunc: func(_ context.Context, configSpec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
return swarm.ConfigCreateResponse{}, errors.New("error creating config")
},
expectedError: "error creating config",
},
@ -62,14 +61,14 @@ func TestConfigCreateWithName(t *testing.T) {
const name = "config-with-name"
var actual []byte
cli := test.NewFakeCli(&fakeClient{
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
if spec.Name != name {
return types.ConfigCreateResponse{}, fmt.Errorf("expected name %q, got %q", name, spec.Name)
return swarm.ConfigCreateResponse{}, fmt.Errorf("expected name %q, got %q", name, spec.Name)
}
actual = spec.Data
return types.ConfigCreateResponse{
return swarm.ConfigCreateResponse{
ID: "ID-" + spec.Name,
}, nil
},
@ -101,12 +100,12 @@ func TestConfigCreateWithLabels(t *testing.T) {
}
cli := test.NewFakeCli(&fakeClient{
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
if !reflect.DeepEqual(spec, expected) {
return types.ConfigCreateResponse{}, fmt.Errorf("expected %+v, got %+v", expected, spec)
return swarm.ConfigCreateResponse{}, fmt.Errorf("expected %+v, got %+v", expected, spec)
}
return types.ConfigCreateResponse{
return swarm.ConfigCreateResponse{
ID: "ID-" + spec.Name,
}, nil
},
@ -127,16 +126,16 @@ func TestConfigCreateWithTemplatingDriver(t *testing.T) {
const name = "config-with-template-driver"
cli := test.NewFakeCli(&fakeClient{
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
configCreateFunc: func(_ context.Context, spec swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
if spec.Name != name {
return types.ConfigCreateResponse{}, fmt.Errorf("expected name %q, got %q", name, spec.Name)
return swarm.ConfigCreateResponse{}, fmt.Errorf("expected name %q, got %q", name, spec.Name)
}
if spec.Templating.Name != expectedDriver.Name {
return types.ConfigCreateResponse{}, fmt.Errorf("expected driver %v, got %v", expectedDriver, spec.Labels)
return swarm.ConfigCreateResponse{}, fmt.Errorf("expected driver %v, got %v", expectedDriver, spec.Labels)
}
return types.ConfigCreateResponse{
return swarm.ConfigCreateResponse{
ID: "ID-" + spec.Name,
}, nil
},

View File

@ -8,7 +8,7 @@ import (
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/command/inspect"
"github.com/docker/docker/api/types/swarm"
units "github.com/docker/go-units"
"github.com/docker/go-units"
)
const (

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package config

View File

@ -10,7 +10,7 @@ import (
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/fvbommel/sortorder"
"github.com/spf13/cobra"
)
@ -48,7 +48,7 @@ func newConfigListCommand(dockerCli command.Cli) *cobra.Command {
func RunConfigList(ctx context.Context, dockerCLI command.Cli, options ListOptions) error {
apiClient := dockerCLI.Client()
configs, err := apiClient.ConfigList(ctx, types.ConfigListOptions{Filters: options.Filter.Value()})
configs, err := apiClient.ConfigList(ctx, swarm.ConfigListOptions{Filters: options.Filter.Value()})
if err != nil {
return err
}

View File

@ -10,7 +10,6 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/builders"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -20,7 +19,7 @@ import (
func TestConfigListErrors(t *testing.T) {
testCases := []struct {
args []string
configListFunc func(context.Context, types.ConfigListOptions) ([]swarm.Config, error)
configListFunc func(context.Context, swarm.ConfigListOptions) ([]swarm.Config, error)
expectedError string
}{
{
@ -28,7 +27,7 @@ func TestConfigListErrors(t *testing.T) {
expectedError: "accepts no argument",
},
{
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
configListFunc: func(_ context.Context, options swarm.ConfigListOptions) ([]swarm.Config, error) {
return []swarm.Config{}, errors.New("error listing configs")
},
expectedError: "error listing configs",
@ -49,7 +48,7 @@ func TestConfigListErrors(t *testing.T) {
func TestConfigList(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
configListFunc: func(_ context.Context, options swarm.ConfigListOptions) ([]swarm.Config, error) {
return []swarm.Config{
*builders.Config(builders.ConfigID("ID-1-foo"),
builders.ConfigName("1-foo"),
@ -79,7 +78,7 @@ func TestConfigList(t *testing.T) {
func TestConfigListWithQuietOption(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
configListFunc: func(_ context.Context, options swarm.ConfigListOptions) ([]swarm.Config, error) {
return []swarm.Config{
*builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")),
*builders.Config(builders.ConfigID("ID-bar"), builders.ConfigName("bar"), builders.ConfigLabels(map[string]string{
@ -96,7 +95,7 @@ func TestConfigListWithQuietOption(t *testing.T) {
func TestConfigListWithConfigFormat(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
configListFunc: func(_ context.Context, options swarm.ConfigListOptions) ([]swarm.Config, error) {
return []swarm.Config{
*builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")),
*builders.Config(builders.ConfigID("ID-bar"), builders.ConfigName("bar"), builders.ConfigLabels(map[string]string{
@ -115,7 +114,7 @@ func TestConfigListWithConfigFormat(t *testing.T) {
func TestConfigListWithFormat(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
configListFunc: func(_ context.Context, options swarm.ConfigListOptions) ([]swarm.Config, error) {
return []swarm.Config{
*builders.Config(builders.ConfigID("ID-foo"), builders.ConfigName("foo")),
*builders.Config(builders.ConfigID("ID-bar"), builders.ConfigName("bar"), builders.ConfigLabels(map[string]string{
@ -132,7 +131,7 @@ func TestConfigListWithFormat(t *testing.T) {
func TestConfigListWithFilter(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
configListFunc: func(_ context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
configListFunc: func(_ context.Context, options swarm.ConfigListOptions) ([]swarm.Config, error) {
assert.Check(t, is.Equal("foo", options.Filters.Get("name")[0]))
assert.Check(t, is.Equal("lbl1=Label-bar", options.Filters.Get("label")[0]))
return []swarm.Config{

View File

@ -56,7 +56,7 @@ func NewAttachCommand(dockerCLI command.Cli) *cobra.Command {
"aliases": "docker container attach, docker attach",
},
ValidArgsFunction: completion.ContainerNames(dockerCLI, false, func(ctr container.Summary) bool {
return ctr.State != "paused"
return ctr.State != container.StatePaused
}),
}

View File

@ -0,0 +1,46 @@
package container
import (
"fmt"
"os"
"strings"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/types"
)
// readCredentials resolves auth-config from the current environment to be
// applied to the container if the `--use-api-socket` flag is set.
//
// - If a valid "DOCKER_AUTH_CONFIG" env-var is found, and it contains
// credentials, it's value is used.
// - If no "DOCKER_AUTH_CONFIG" env-var is found, or it does not contain
// credentials, it attempts to read from the CLI's credentials store.
//
// It returns an error if either the "DOCKER_AUTH_CONFIG" is incorrectly
// formatted, or when failing to read from the credentials store.
//
// A nil value is returned if neither option contained any credentials.
func readCredentials(dockerCLI config.Provider) (creds map[string]types.AuthConfig, _ error) {
if v, ok := os.LookupEnv("DOCKER_AUTH_CONFIG"); ok && v != "" {
// The results are expected to have been unmarshaled the same as
// when reading from a config-file, which includes decoding the
// base64-encoded "username:password" into the "UserName" and
// "Password" fields.
ac := &configfile.ConfigFile{}
if err := ac.LoadFromReader(strings.NewReader(v)); err != nil {
return nil, fmt.Errorf("failed to read credentials from DOCKER_AUTH_CONFIG: %w", err)
}
if len(ac.AuthConfigs) > 0 {
return ac.AuthConfigs, nil
}
}
// Resolve this here for later, ensuring we error our before we create the container.
creds, err := dockerCLI.ConfigFile().GetAllCredentials()
if err != nil {
return nil, fmt.Errorf("resolving credentials failed: %w", err)
}
return creds, nil
}

View File

@ -11,7 +11,7 @@ import (
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/system"
"github.com/docker/docker/client"
specs "github.com/opencontainers/image-spec/specs-go/v1"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
type fakeClient struct {
@ -22,7 +22,7 @@ type fakeClient struct {
createContainerFunc func(config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
platform *specs.Platform,
platform *ocispec.Platform,
containerName string) (container.CreateResponse, error)
containerStartFunc func(containerID string, options container.StartOptions) error
imageCreateFunc func(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error)
@ -84,7 +84,7 @@ func (f *fakeClient) ContainerCreate(
config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
platform *specs.Platform,
platform *ocispec.Platform,
containerName string,
) (container.CreateResponse, error) {
if f.createContainerFunc != nil {

View File

@ -28,7 +28,7 @@ func NewContainerCommand(dockerCli command.Cli) *cobra.Command {
NewPortCommand(dockerCli),
NewRenameCommand(dockerCli),
NewRestartCommand(dockerCli),
NewRmCommand(dockerCli),
newRemoveCommand(dockerCli),
NewRunCommand(dockerCli),
NewStartCommand(dockerCli),
NewStatsCommand(dockerCli),

View File

@ -61,7 +61,7 @@ func runCommit(ctx context.Context, dockerCli command.Cli, options *commitOption
Reference: options.reference,
Comment: options.comment,
Author: options.author,
Changes: options.changes.GetAll(),
Changes: options.changes.GetSlice(),
Pause: options.pause,
})
if err != nil {

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package container
@ -56,7 +56,7 @@ var logDriverOptions = map[string][]string{
"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",
"fluentd-sub-second-precision", "fluentd-write-timeout", "tag",
},
"gcplogs": {
"max-buffer-size", "mode", "env", "env-regex", "labels", "gcp-log-cmd", "gcp-meta-id", "gcp-meta-name",
@ -144,7 +144,7 @@ func addCompletions(cmd *cobra.Command, dockerCLI completion.APIClientProvider)
}
// completeCgroupns implements shell completion for the `--cgroupns` option of `run` and `create`.
func completeCgroupns() completion.ValidArgsFn {
func completeCgroupns() cobra.CompletionFunc {
return completion.FromList(string(container.CgroupnsModeHost), string(container.CgroupnsModePrivate))
}
@ -155,7 +155,7 @@ func completeDetachKeys(_ *cobra.Command, _ []string, _ string) ([]string, cobra
// 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) {
func completeIpc(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
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
@ -175,7 +175,7 @@ func completeIpc(dockerCLI completion.APIClientProvider) func(cmd *cobra.Command
}
// 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) {
func completeLink(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return postfixWith(":", containerNames(dockerCLI, cmd, args, toComplete)), cobra.ShellCompDirectiveNoSpace
}
@ -184,7 +184,7 @@ func completeLink(dockerCLI completion.APIClientProvider) func(cmd *cobra.Comman
// 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 {
func completeLogDriver(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
info, err := dockerCLI.Client().Info(cmd.Context())
if err != nil {
@ -206,7 +206,7 @@ func completeLogOpt(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.S
}
// 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) {
func completePid(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
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
@ -277,7 +277,7 @@ func completeUlimit(_ *cobra.Command, _ []string, _ string) ([]string, cobra.She
}
// completeVolumeDriver contacts the API to get the built-in and installed volume drivers.
func completeVolumeDriver(dockerCLI completion.APIClientProvider) completion.ValidArgsFn {
func completeVolumeDriver(dockerCLI completion.APIClientProvider) cobra.CompletionFunc {
return func(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
info, err := dockerCLI.Client().Info(cmd.Context())
if err != nil {

View File

@ -16,8 +16,8 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/archive"
units "github.com/docker/go-units"
"github.com/docker/go-units"
"github.com/moby/go-archive"
"github.com/morikuni/aec"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -398,8 +398,7 @@ func copyToContainer(ctx context.Context, dockerCLI command.Cli, copyConfig cpCo
}
options := container.CopyToContainerOptions{
AllowOverwriteDirWithFile: false,
CopyUIDGID: copyConfig.copyUIDGID,
CopyUIDGID: copyConfig.copyUIDGID,
}
if copyConfig.quiet {

View File

@ -10,7 +10,8 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/archive"
"github.com/moby/go-archive"
"github.com/moby/go-archive/compression"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/fs"
@ -74,7 +75,7 @@ func TestRunCopyFromContainerToFilesystem(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
containerCopyFromFunc: func(ctr, srcPath string) (io.ReadCloser, container.PathStat, error) {
assert.Check(t, is.Equal("container", ctr))
readCloser, err := archive.Tar(srcDir.Path(), archive.Uncompressed)
readCloser, err := archive.Tar(srcDir.Path(), compression.None)
return readCloser, container.PathStat{}, err
},
})

View File

@ -1,27 +1,35 @@
package container
import (
"archive/tar"
"bytes"
"context"
"fmt"
"io"
"net/netip"
"os"
"path"
"strings"
cerrdefs "github.com/containerd/errdefs"
"github.com/containerd/platforms"
"github.com/distribution/reference"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/internal/jsonstream"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/types"
"github.com/docker/cli/cli/streams"
"github.com/docker/cli/cli/trust"
"github.com/docker/cli/internal/jsonstream"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types/container"
imagetypes "github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/errdefs"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/docker/docker/client"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@ -35,11 +43,12 @@ const (
)
type createOptions struct {
name string
platform string
untrusted bool
pull string // always, missing, never
quiet bool
name string
platform string
untrusted bool
pull string // always, missing, never
quiet bool
useAPISocket bool
}
// NewCreateCommand creates a new cobra.Command for `docker create`
@ -70,6 +79,8 @@ func NewCreateCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVar(&options.name, "name", "", "Assign a name to the container")
flags.StringVar(&options.pull, "pull", PullImageMissing, `Pull image before creating ("`+PullImageAlways+`", "|`+PullImageMissing+`", "`+PullImageNever+`")`)
flags.BoolVarP(&options.quiet, "quiet", "q", false, "Suppress the pull output")
flags.BoolVarP(&options.useAPISocket, "use-api-socket", "", false, "Bind mount Docker API socket and required auth")
flags.SetAnnotation("use-api-socket", "experimentalCLI", nil) // Marks flag as experimental for now.
// Add an explicit help that doesn't have a `-h` to prevent the conflict
// with hostname
@ -98,7 +109,7 @@ func runCreate(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet,
StatusCode: 125,
}
}
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetSlice()))
newEnv := []string{}
for k, v := range proxyConfig {
if v == nil {
@ -179,20 +190,20 @@ func (cid *cidFile) Write(id string) error {
return nil
}
func newCIDFile(path string) (*cidFile, error) {
if path == "" {
func newCIDFile(cidPath string) (*cidFile, error) {
if cidPath == "" {
return &cidFile{}, nil
}
if _, err := os.Stat(path); err == nil {
return nil, errors.Errorf("container ID file found, make sure the other container isn't running or delete %s", path)
if _, err := os.Stat(cidPath); err == nil {
return nil, errors.Errorf("container ID file found, make sure the other container isn't running or delete %s", cidPath)
}
f, err := os.Create(path)
f, err := os.Create(cidPath)
if err != nil {
return nil, errors.Wrap(err, "failed to create the container ID file")
}
return &cidFile{path: path, file: f}, nil
return &cidFile{path: cidPath, file: f}, nil
}
//nolint:gocyclo
@ -229,6 +240,86 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
}
}
const dockerConfigPathInContainer = "/run/secrets/docker/config.json"
var apiSocketCreds map[string]types.AuthConfig
if options.useAPISocket {
// We'll create two new mounts to handle this flag:
// 1. Mount the actual docker socket.
// 2. A synthezised ~/.docker/config.json with resolved tokens.
if dockerCli.ServerInfo().OSType == "windows" {
return "", errors.New("flag --use-api-socket can't be used with a Windows Docker Engine")
}
// hard-code engine socket path until https://github.com/moby/moby/pull/43459 gives us a discovery mechanism
containerCfg.HostConfig.Mounts = append(containerCfg.HostConfig.Mounts, mount.Mount{
Type: mount.TypeBind,
Source: "/var/run/docker.sock",
Target: "/var/run/docker.sock",
BindOptions: &mount.BindOptions{},
})
/*
Ideally, we'd like to copy the config into a tmpfs but unfortunately,
the mounts won't be in place until we start the container. This can
leave around the config if the container doesn't get deleted.
We are using the most compose-secret-compatible approach,
which is implemented at
https://github.com/docker/compose/blob/main/pkg/compose/convergence.go#L737
// Prepare a tmpfs mount for our credentials so they go away after the
// container exits. We'll copy into this mount after the container is
// created.
containerCfg.HostConfig.Mounts = append(containerCfg.HostConfig.Mounts, mount.Mount{
Type: mount.TypeTmpfs,
Target: "/docker/",
TmpfsOptions: &mount.TmpfsOptions{
SizeBytes: 1 << 20, // only need a small partition
Mode: 0o600,
},
})
*/
var envvarPresent bool
for _, envvar := range containerCfg.Config.Env {
if strings.HasPrefix(envvar, "DOCKER_CONFIG=") {
envvarPresent = true
}
}
// If the DOCKER_CONFIG env var is already present, we assume the client knows
// what they're doing and don't inject the creds.
if !envvarPresent {
// Resolve this here for later, ensuring we error our before we create the container.
creds, err := readCredentials(dockerCli)
if err != nil {
return "", fmt.Errorf("resolving credentials failed: %w", err)
}
if len(creds) > 0 {
// Set our special little location for the config file.
containerCfg.Config.Env = append(containerCfg.Config.Env, "DOCKER_CONFIG="+path.Dir(dockerConfigPathInContainer))
apiSocketCreds = creds // inject these after container creation.
}
}
}
var platform *ocispec.Platform
// Engine API version 1.41 first introduced the option to specify platform on
// create. It will produce an error if you try to set a platform on older API
// versions, so check the API version here to maintain backwards
// compatibility for CLI users.
if options.platform != "" && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.41") {
p, err := platforms.Parse(options.platform)
if err != nil {
return "", errors.Wrap(invalidParameter(err), "error parsing specified platform")
}
platform = &p
}
pullAndTagImage := func() error {
if err := pullImage(ctx, dockerCli, config.Image, options); err != nil {
return err
@ -239,19 +330,6 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
return nil
}
var platform *specs.Platform
// Engine API version 1.41 first introduced the option to specify platform on
// create. It will produce an error if you try to set a platform on older API
// versions, so check the API version here to maintain backwards
// compatibility for CLI users.
if options.platform != "" && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.41") {
p, err := platforms.Parse(options.platform)
if err != nil {
return "", errors.Wrap(errdefs.InvalidParameter(err), "error parsing specified platform")
}
platform = &p
}
if options.pull == PullImageAlways {
if err := pullAndTagImage(); err != nil {
return "", err
@ -263,7 +341,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, platform, options.name)
if err != nil {
// Pull image if it does not exist locally and we have the PullImageMissing option. Default behavior.
if errdefs.IsNotFound(err) && namedRef != nil && options.pull == PullImageMissing {
if cerrdefs.IsNotFound(err) && namedRef != nil && options.pull == PullImageMissing {
if !options.quiet {
// we don't want to write to stdout anything apart from container.ID
_, _ = fmt.Fprintf(dockerCli.Err(), "Unable to find image '%s' locally\n", reference.FamiliarString(namedRef))
@ -286,11 +364,25 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
if warn := localhostDNSWarning(*hostConfig); warn != "" {
response.Warnings = append(response.Warnings, warn)
}
containerID = response.ID
for _, w := range response.Warnings {
_, _ = fmt.Fprintln(dockerCli.Err(), "WARNING:", w)
}
err = containerIDFile.Write(response.ID)
return response.ID, err
err = containerIDFile.Write(containerID)
if options.useAPISocket && len(apiSocketCreds) > 0 {
// Create a new config file with just the auth.
newConfig := &configfile.ConfigFile{
AuthConfigs: apiSocketCreds,
}
if err := copyDockerConfigIntoContainer(ctx, dockerCli.Client(), containerID, dockerConfigPathInContainer, newConfig); err != nil {
return "", fmt.Errorf("injecting docker config.json into container failed: %w", err)
}
}
return containerID, err
}
// check the DNS settings passed via --dns against localhost regexp to warn if
@ -321,3 +413,39 @@ func validatePullOpt(val string) error {
)
}
}
// copyDockerConfigIntoContainer takes the client configuration and copies it
// into the container.
//
// The path should be an absolute path in the container, commonly
// /root/.docker/config.json.
func copyDockerConfigIntoContainer(ctx context.Context, dockerAPI client.APIClient, containerID string, configPath string, config *configfile.ConfigFile) error {
var configBuf bytes.Buffer
if err := config.SaveToWriter(&configBuf); err != nil {
return fmt.Errorf("saving creds: %w", err)
}
// We don't need to get super fancy with the tar creation.
var tarBuf bytes.Buffer
tarWriter := tar.NewWriter(&tarBuf)
tarWriter.WriteHeader(&tar.Header{
Name: configPath,
Size: int64(configBuf.Len()),
Mode: 0o600,
})
if _, err := io.Copy(tarWriter, &configBuf); err != nil {
return fmt.Errorf("writing config to tar file for config copy: %w", err)
}
if err := tarWriter.Close(); err != nil {
return fmt.Errorf("closing tar for config copy failed: %w", err)
}
if err := dockerAPI.CopyToContainer(ctx, containerID, "/",
&tarBuf, container.CopyToContainerOptions{}); err != nil {
return fmt.Errorf("copying config.json into container failed: %w", err)
}
return nil
}

View File

@ -19,7 +19,7 @@ import (
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/system"
"github.com/google/go-cmp/cmp"
specs "github.com/opencontainers/image-spec/specs-go/v1"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/spf13/pflag"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -121,7 +121,7 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
platform *specs.Platform,
platform *ocispec.Platform,
containerName string,
) (container.CreateResponse, error) {
defer func() { tc.ResponseCounter++ }()
@ -248,23 +248,25 @@ func TestNewCreateCommandWithContentTrustErrors(t *testing.T) {
},
}
for _, tc := range testCases {
fakeCLI := test.NewFakeCli(&fakeClient{
createContainerFunc: func(config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
platform *specs.Platform,
containerName string,
) (container.CreateResponse, error) {
return container.CreateResponse{}, errors.New("shouldn't try to pull image")
},
}, test.EnableContentTrust)
fakeCLI.SetNotaryClient(tc.notaryFunc)
cmd := NewCreateCommand(fakeCLI)
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.ErrorContains(t, err, tc.expectedError)
t.Run(tc.name, func(t *testing.T) {
fakeCLI := test.NewFakeCli(&fakeClient{
createContainerFunc: func(config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
platform *ocispec.Platform,
containerName string,
) (container.CreateResponse, error) {
return container.CreateResponse{}, errors.New("shouldn't try to pull image")
},
}, test.EnableContentTrust)
fakeCLI.SetNotaryClient(tc.notaryFunc)
cmd := NewCreateCommand(fakeCLI)
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.ErrorContains(t, err, tc.expectedError)
})
}
}
@ -306,7 +308,7 @@ func TestNewCreateCommandWithWarnings(t *testing.T) {
createContainerFunc: func(config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
platform *specs.Platform,
platform *ocispec.Platform,
containerName string,
) (container.CreateResponse, error) {
return container.CreateResponse{Warnings: tc.warnings}, nil
@ -345,7 +347,7 @@ func TestCreateContainerWithProxyConfig(t *testing.T) {
createContainerFunc: func(config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
platform *specs.Platform,
platform *ocispec.Platform,
containerName string,
) (container.CreateResponse, error) {
sort.Strings(config.Env)

View File

@ -7,25 +7,17 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
type diffOptions struct {
container string
}
// NewDiffCommand creates a new cobra.Command for `docker diff`
func NewDiffCommand(dockerCli command.Cli) *cobra.Command {
var opts diffOptions
return &cobra.Command{
Use: "diff CONTAINER",
Short: "Inspect changes to files or directories on a container's filesystem",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.container = args[0]
return runDiff(cmd.Context(), dockerCli, &opts)
return runDiff(cmd.Context(), dockerCli, args[0])
},
Annotations: map[string]string{
"aliases": "docker container diff, docker diff",
@ -34,16 +26,13 @@ func NewDiffCommand(dockerCli command.Cli) *cobra.Command {
}
}
func runDiff(ctx context.Context, dockerCli command.Cli, opts *diffOptions) error {
if opts.container == "" {
return errors.New("Container name cannot be empty")
}
changes, err := dockerCli.Client().ContainerDiff(ctx, opts.container)
func runDiff(ctx context.Context, dockerCLI command.Cli, containerID string) error {
changes, err := dockerCLI.Client().ContainerDiff(ctx, containerID)
if err != nil {
return err
}
diffCtx := formatter.Context{
Output: dockerCli.Out(),
Output: dockerCLI.Out(),
Format: NewDiffFormat("{{.Type}} {{.Path}}"),
}
return DiffFormatWrite(diffCtx, changes)

View File

@ -77,17 +77,3 @@ func TestRunDiffClientError(t *testing.T) {
err := cmd.Execute()
assert.ErrorIs(t, err, clientError)
}
func TestRunDiffEmptyContainerError(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{})
cmd := NewDiffCommand(cli)
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
containerID := ""
cmd.SetArgs([]string{containerID})
err := cmd.Execute()
assert.Error(t, err, "Container name cannot be empty")
}

View File

@ -0,0 +1,31 @@
package container
import cerrdefs "github.com/containerd/errdefs"
func invalidParameter(err error) error {
if err == nil || cerrdefs.IsInvalidArgument(err) {
return err
}
return invalidParameterErr{err}
}
type invalidParameterErr struct{ error }
func (invalidParameterErr) InvalidParameter() {}
func (e invalidParameterErr) Unwrap() error {
return e.error
}
func notFound(err error) error {
if err == nil || cerrdefs.IsNotFound(err) {
return err
}
return notFoundErr{err}
}
type notFoundErr struct{ error }
func (notFoundErr) NotFound() {}
func (e notFoundErr) Unwrap() error {
return e.error
}

View File

@ -53,7 +53,7 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
return RunExec(cmd.Context(), dockerCli, containerIDorName, options)
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(ctr container.Summary) bool {
return ctr.State != "paused"
return ctr.State != container.StatePaused
}),
Annotations: map[string]string{
"category-top": "2",
@ -99,7 +99,7 @@ func RunExec(ctx context.Context, dockerCLI command.Cli, containerIDorName strin
if _, err := apiClient.ContainerInspect(ctx, containerIDorName); err != nil {
return err
}
if !execOptions.Detach {
if !options.Detach {
if err := dockerCLI.In().CheckTty(execOptions.AttachStdin, execOptions.Tty); err != nil {
return err
}
@ -117,9 +117,9 @@ func RunExec(ctx context.Context, dockerCLI command.Cli, containerIDorName strin
return errors.New("exec ID empty")
}
if execOptions.Detach {
if options.Detach {
return apiClient.ContainerExecStart(ctx, execID, container.ExecStartOptions{
Detach: execOptions.Detach,
Detach: options.Detach,
Tty: execOptions.Tty,
ConsoleSize: execOptions.ConsoleSize,
})
@ -223,13 +223,12 @@ func parseExec(execOpts ExecOptions, configFile *configfile.ConfigFile) (*contai
Privileged: execOpts.Privileged,
Tty: execOpts.TTY,
Cmd: execOpts.Command,
Detach: execOpts.Detach,
WorkingDir: execOpts.Workdir,
}
// collect all the environment variables for the container
var err error
if execOptions.Env, err = opts.ReadKVEnvStrings(execOpts.EnvFile.GetAll(), execOpts.Env.GetAll()); err != nil {
if execOptions.Env, err = opts.ReadKVEnvStrings(execOpts.EnvFile.GetSlice(), execOpts.Env.GetSlice()); err != nil {
return nil, err
}

View File

@ -5,6 +5,7 @@ import (
"errors"
"io"
"os"
"strconv"
"testing"
"github.com/docker/cli/cli"
@ -75,8 +76,7 @@ TWO=2
{
options: withDefaultOpts(ExecOptions{Detach: true}),
expected: container.ExecOptions{
Detach: true,
Cmd: []string{"command"},
Cmd: []string{"command"},
},
},
{
@ -86,9 +86,8 @@ TWO=2
Detach: true,
}),
expected: container.ExecOptions{
Detach: true,
Tty: true,
Cmd: []string{"command"},
Tty: true,
Cmd: []string{"command"},
},
},
{
@ -97,7 +96,6 @@ TWO=2
expected: container.ExecOptions{
Cmd: []string{"command"},
DetachKeys: "de",
Detach: true,
},
},
{
@ -109,7 +107,6 @@ TWO=2
expected: container.ExecOptions{
Cmd: []string{"command"},
DetachKeys: "ab",
Detach: true,
},
},
{
@ -141,10 +138,12 @@ TWO=2
},
}
for _, testcase := range testcases {
execConfig, err := parseExec(testcase.options, &testcase.configFile)
assert.NilError(t, err)
assert.Check(t, is.DeepEqual(testcase.expected, *execConfig))
for i, testcase := range testcases {
t.Run("test "+strconv.Itoa(i+1), func(t *testing.T) {
execConfig, err := parseExec(testcase.options, &testcase.configFile)
assert.NilError(t, err)
assert.Check(t, is.DeepEqual(testcase.expected, *execConfig))
})
}
}

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/moby/sys/atomicwriter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -41,27 +42,28 @@ func NewExportCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
func runExport(ctx context.Context, dockerCli command.Cli, opts exportOptions) error {
if opts.output == "" && dockerCli.Out().IsTerminal() {
return errors.New("cowardly refusing to save to a terminal. Use the -o flag or redirect")
func runExport(ctx context.Context, dockerCLI command.Cli, opts exportOptions) error {
var output io.Writer
if opts.output == "" {
if dockerCLI.Out().IsTerminal() {
return errors.New("cowardly refusing to save to a terminal. Use the -o flag or redirect")
}
output = dockerCLI.Out()
} else {
writer, err := atomicwriter.New(opts.output, 0o600)
if err != nil {
return errors.Wrap(err, "failed to export container")
}
defer writer.Close()
output = writer
}
if err := command.ValidateOutputPath(opts.output); err != nil {
return errors.Wrap(err, "failed to export container")
}
clnt := dockerCli.Client()
responseBody, err := clnt.ContainerExport(ctx, opts.container)
responseBody, err := dockerCLI.Client().ContainerExport(ctx, opts.container)
if err != nil {
return err
}
defer responseBody.Close()
if opts.output == "" {
_, err := io.Copy(dockerCli.Out(), responseBody)
return err
}
return command.CopyToFile(opts.output, responseBody)
_, err = io.Copy(output, responseBody)
return err
}

View File

@ -42,8 +42,6 @@ func TestContainerExportOutputToIrregularFile(t *testing.T) {
cmd.SetErr(io.Discard)
cmd.SetArgs([]string{"-o", "/dev/random", "container"})
err := cmd.Execute()
assert.Assert(t, err != nil)
expected := `"/dev/random" must be a directory or a regular file`
assert.ErrorContains(t, err, expected)
const expected = `failed to export container: cannot write to a character device file`
assert.Error(t, cmd.Execute(), expected)
}

View File

@ -5,8 +5,7 @@ import (
"sync"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/pkg/stringid"
units "github.com/docker/go-units"
"github.com/docker/go-units"
)
const (
@ -176,7 +175,7 @@ func (c *statsContext) Name() string {
func (c *statsContext) ID() string {
if c.trunc {
return stringid.TruncateID(c.s.ID)
return formatter.TruncateID(c.s.ID)
}
return c.s.ID
}

View File

@ -5,13 +5,13 @@ import (
"testing"
"github.com/docker/cli/cli/command/formatter"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/cli/internal/test"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestContainerStatsContext(t *testing.T) {
containerID := stringid.GenerateRandomID()
containerID := test.RandomID()
var ctx statsContext
tt := []struct {
@ -148,7 +148,7 @@ container2 -- --
`,
},
}
stats := []StatsEntry{
entries := []StatsEntry{
{
Container: "container1",
CPUPercentage: 20,
@ -181,7 +181,7 @@ container2 -- --
t.Run(string(tc.context.Format), func(t *testing.T) {
var out bytes.Buffer
tc.context.Output = &out
err := statsFormatWrite(tc.context, stats, "windows", false)
err := statsFormatWrite(tc.context, entries, "windows", false)
if err != nil {
assert.Error(t, err, tc.expected)
} else {
@ -273,45 +273,46 @@ func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) {
}
func TestContainerStatsContextWriteTrunc(t *testing.T) {
var out bytes.Buffer
contexts := []struct {
tests := []struct {
doc string
context formatter.Context
trunc bool
expected string
}{
{
formatter.Context{
doc: "non-truncated",
context: formatter.Context{
Format: "{{.ID}}",
Output: &out,
},
false,
"b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc\n",
expected: "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc\n",
},
{
formatter.Context{
doc: "truncated",
context: formatter.Context{
Format: "{{.ID}}",
Output: &out,
},
true,
"b95a83497c91\n",
trunc: true,
expected: "b95a83497c91\n",
},
}
for _, context := range contexts {
statsFormatWrite(context.context, []StatsEntry{{ID: "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc"}}, "linux", context.trunc)
assert.Check(t, is.Equal(context.expected, out.String()))
// Clean buffer
out.Reset()
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
var out bytes.Buffer
tc.context.Output = &out
err := statsFormatWrite(tc.context, []StatsEntry{{ID: "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc"}}, "linux", tc.trunc)
assert.NilError(t, err)
assert.Check(t, is.Equal(tc.expected, out.String()))
})
}
}
func BenchmarkStatsFormat(b *testing.B) {
b.ReportAllocs()
stats := genStats()
entries := genStats()
for i := 0; i < b.N; i++ {
for _, s := range stats {
for _, s := range entries {
_ = s.CPUPerc()
_ = s.MemUsage()
_ = s.MemPerc()
@ -334,9 +335,9 @@ func genStats() []statsContext {
NetworkTx: 987.654321,
PidsCurrent: 123456789,
}}
stats := make([]statsContext, 100)
for i := 0; i < 100; i++ {
stats = append(stats, entry)
entries := make([]statsContext, 0, 100)
for range 100 {
entries = append(entries, entry)
}
return stats
return entries
}

View File

@ -9,7 +9,6 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/stdcopy"
"github.com/moby/term"
"github.com/sirupsen/logrus"
@ -19,6 +18,18 @@ import (
// TODO: This could be moved to `pkg/term`.
var defaultEscapeKeys = []byte{16, 17}
// readCloserWrapper wraps an io.Reader, and implements an io.ReadCloser
// It calls the given callback function when closed.
type readCloserWrapper struct {
io.Reader
closer func() error
}
// Close calls back the passed closer function
func (r *readCloserWrapper) Close() error {
return r.closer()
}
// A hijackedIOStreamer handles copying input to and output from streams to the
// connection.
type hijackedIOStreamer struct {
@ -84,12 +95,9 @@ func (h *hijackedIOStreamer) setupInput() (restore func(), err error) {
// Use sync.Once so we may call restore multiple times but ensure we
// only restore the terminal once.
var restoreOnce sync.Once
restore = func() {
restoreOnce.Do(func() {
_ = restoreTerminal(h.streams, h.inputStream)
})
}
restore = sync.OnceFunc(func() {
_ = restoreTerminal(h.streams, h.inputStream)
})
// Wrap the input to detect detach escape sequence.
// Use default escape keys if an invalid sequence is given.
@ -103,7 +111,10 @@ func (h *hijackedIOStreamer) setupInput() (restore func(), err error) {
}
}
h.inputStream = ioutils.NewReadCloserWrapper(term.NewEscapeProxy(h.inputStream, escapeKeys), h.inputStream.Close)
h.inputStream = &readCloserWrapper{
Reader: term.NewEscapeProxy(h.inputStream, escapeKeys),
closer: h.inputStream.Close,
}
return restore, nil
}

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package container

View File

@ -8,18 +8,16 @@ import (
"path"
"path/filepath"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"github.com/docker/cli/cli/compose/loader"
"github.com/docker/cli/internal/lazyregexp"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types/container"
mounttypes "github.com/docker/docker/api/types/mount"
networktypes "github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/errdefs"
"github.com/docker/go-connections/nat"
"github.com/pkg/errors"
"github.com/spf13/pflag"
@ -40,7 +38,7 @@ const (
seccompProfileUnconfined = "unconfined"
)
var deviceCgroupRuleRegexp = regexp.MustCompile(`^[acb] ([0-9]+|\*):([0-9]+|\*) [rwm]{1,3}$`)
var deviceCgroupRuleRegexp = lazyregexp.New(`^[acb] ([0-9]+|\*):([0-9]+|\*) [rwm]{1,3}$`)
// containerOptions is a data object with all the options for creating a container
type containerOptions struct {
@ -376,7 +374,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
if parsed.Type == string(mounttypes.TypeBind) {
if hostPart, targetPath, ok := strings.Cut(bind, ":"); ok {
if strings.HasPrefix(hostPart, "."+string(filepath.Separator)) || hostPart == "." {
if !filepath.IsAbs(hostPart) && strings.HasPrefix(hostPart, ".") {
if absHostPart, err := filepath.Abs(hostPart); err == nil {
hostPart = absHostPart
}
@ -396,28 +394,25 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
// Can't evaluate options passed into --tmpfs until we actually mount
tmpfs := make(map[string]string)
for _, t := range copts.tmpfs.GetAll() {
for _, t := range copts.tmpfs.GetSlice() {
k, v, _ := strings.Cut(t, ":")
tmpfs[k] = v
}
var (
runCmd strslice.StrSlice
entrypoint strslice.StrSlice
)
var runCmd, entrypoint []string
if len(copts.Args) > 0 {
runCmd = copts.Args
}
if copts.entrypoint != "" {
entrypoint = strslice.StrSlice{copts.entrypoint}
entrypoint = []string{copts.entrypoint}
} else if flags.Changed("entrypoint") {
// if `--entrypoint=` is parsed then Entrypoint is reset
entrypoint = []string{""}
}
publishOpts := copts.publish.GetAll()
publishOpts := copts.publish.GetSlice()
var (
ports map[nat.Port]struct{}
portBindings map[nat.Port][]nat.PortBinding
@ -435,7 +430,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
}
// Merge in exposed ports to the map of published ports
for _, e := range copts.expose.GetAll() {
for _, e := range copts.expose.GetSlice() {
if strings.Contains(e, ":") {
return nil, errors.Errorf("invalid port format for --expose: %s", e)
}
@ -465,7 +460,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
// what operating system it is.
deviceMappings := []container.DeviceMapping{}
var cdiDeviceNames []string
for _, device := range copts.devices.GetAll() {
for _, device := range copts.devices.GetSlice() {
var (
validated string
deviceMapping container.DeviceMapping
@ -487,13 +482,13 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
}
// collect all the environment variables for the container
envVariables, err := opts.ReadKVEnvStrings(copts.envFile.GetAll(), copts.env.GetAll())
envVariables, err := opts.ReadKVEnvStrings(copts.envFile.GetSlice(), copts.env.GetSlice())
if err != nil {
return nil, err
}
// collect all the labels for the container
labels, err := opts.ReadKVStrings(copts.labelsFile.GetAll(), copts.labels.GetAll())
labels, err := opts.ReadKVStrings(copts.labelsFile.GetSlice(), copts.labels.GetSlice())
if err != nil {
return nil, err
}
@ -523,19 +518,19 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
return nil, err
}
loggingOpts, err := parseLoggingOpts(copts.loggingDriver, copts.loggingOpts.GetAll())
loggingOpts, err := parseLoggingOpts(copts.loggingDriver, copts.loggingOpts.GetSlice())
if err != nil {
return nil, err
}
securityOpts, err := parseSecurityOpts(copts.securityOpt.GetAll())
securityOpts, err := parseSecurityOpts(copts.securityOpt.GetSlice())
if err != nil {
return nil, err
}
securityOpts, maskedPaths, readonlyPaths := parseSystemPaths(securityOpts)
storageOpts, err := parseStorageOpts(copts.storageOpt.GetAll())
storageOpts, err := parseStorageOpts(copts.storageOpt.GetSlice())
if err != nil {
return nil, err
}
@ -552,9 +547,9 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
if haveHealthSettings {
return nil, errors.Errorf("--no-healthcheck conflicts with --health-* options")
}
healthConfig = &container.HealthConfig{Test: strslice.StrSlice{"NONE"}}
healthConfig = &container.HealthConfig{Test: []string{"NONE"}}
} else if haveHealthSettings {
var probe strslice.StrSlice
var probe []string
if copts.healthCmd != "" {
probe = []string{"CMD-SHELL", copts.healthCmd}
}
@ -621,7 +616,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
IOMaximumIOps: copts.ioMaxIOps,
IOMaximumBandwidth: uint64(copts.ioMaxBandwidth),
Ulimits: copts.ulimits.GetList(),
DeviceCgroupRules: copts.deviceCgroupRules.GetAll(),
DeviceCgroupRules: copts.deviceCgroupRules.GetSlice(),
Devices: deviceMappings,
DeviceRequests: deviceRequests,
}
@ -658,7 +653,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
AutoRemove: copts.autoRemove,
Privileged: copts.privileged,
PortBindings: portBindings,
Links: copts.links.GetAll(),
Links: copts.links.GetSlice(),
PublishAllPorts: copts.publishAll,
// Make sure the dns fields are never nil.
// New containers don't ever have those fields nil,
@ -668,17 +663,17 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
DNS: copts.dns.GetAllOrEmpty(),
DNSSearch: copts.dnsSearch.GetAllOrEmpty(),
DNSOptions: copts.dnsOptions.GetAllOrEmpty(),
ExtraHosts: copts.extraHosts.GetAll(),
VolumesFrom: copts.volumesFrom.GetAll(),
ExtraHosts: copts.extraHosts.GetSlice(),
VolumesFrom: copts.volumesFrom.GetSlice(),
IpcMode: container.IpcMode(copts.ipcMode),
NetworkMode: container.NetworkMode(copts.netMode.NetworkMode()),
PidMode: pidMode,
UTSMode: utsMode,
UsernsMode: usernsMode,
CgroupnsMode: cgroupnsMode,
CapAdd: strslice.StrSlice(copts.capAdd.GetAll()),
CapDrop: strslice.StrSlice(copts.capDrop.GetAll()),
GroupAdd: copts.groupAdd.GetAll(),
CapAdd: copts.capAdd.GetSlice(),
CapDrop: copts.capDrop.GetSlice(),
GroupAdd: copts.groupAdd.GetSlice(),
RestartPolicy: restartPolicy,
SecurityOpt: securityOpts,
StorageOpt: storageOpts,
@ -781,7 +776,7 @@ func parseNetworkOpts(copts *containerOptions) (map[string]*networktypes.Endpoin
return nil, err
}
if _, ok := endpoints[n.Target]; ok {
return nil, errdefs.InvalidParameter(errors.Errorf("network %q is specified multiple times", n.Target))
return nil, invalidParameter(errors.Errorf("network %q is specified multiple times", n.Target))
}
// For backward compatibility: if no custom options are provided for the network,
@ -795,7 +790,7 @@ func parseNetworkOpts(copts *containerOptions) (map[string]*networktypes.Endpoin
endpoints[n.Target] = ep
}
if hasUserDefined && hasNonUserDefined {
return nil, errdefs.InvalidParameter(errors.New("conflicting options: cannot attach both user-defined and non-user-defined network-modes"))
return nil, invalidParameter(errors.New("conflicting options: cannot attach both user-defined and non-user-defined network-modes"))
}
return endpoints, nil
}
@ -803,32 +798,32 @@ func parseNetworkOpts(copts *containerOptions) (map[string]*networktypes.Endpoin
func applyContainerOptions(n *opts.NetworkAttachmentOpts, copts *containerOptions) error { //nolint:gocyclo
// TODO should we error if _any_ advanced option is used? (i.e. forbid to combine advanced notation with the "old" flags (`--network-alias`, `--link`, `--ip`, `--ip6`)?
if len(n.Aliases) > 0 && copts.aliases.Len() > 0 {
return errdefs.InvalidParameter(errors.New("conflicting options: cannot specify both --network-alias and per-network alias"))
return invalidParameter(errors.New("conflicting options: cannot specify both --network-alias and per-network alias"))
}
if len(n.Links) > 0 && copts.links.Len() > 0 {
return errdefs.InvalidParameter(errors.New("conflicting options: cannot specify both --link and per-network links"))
return invalidParameter(errors.New("conflicting options: cannot specify both --link and per-network links"))
}
if n.IPv4Address != "" && copts.ipv4Address != "" {
return errdefs.InvalidParameter(errors.New("conflicting options: cannot specify both --ip and per-network IPv4 address"))
return invalidParameter(errors.New("conflicting options: cannot specify both --ip and per-network IPv4 address"))
}
if n.IPv6Address != "" && copts.ipv6Address != "" {
return errdefs.InvalidParameter(errors.New("conflicting options: cannot specify both --ip6 and per-network IPv6 address"))
return invalidParameter(errors.New("conflicting options: cannot specify both --ip6 and per-network IPv6 address"))
}
if n.MacAddress != "" && copts.macAddress != "" {
return errdefs.InvalidParameter(errors.New("conflicting options: cannot specify both --mac-address and per-network MAC address"))
return invalidParameter(errors.New("conflicting options: cannot specify both --mac-address and per-network MAC address"))
}
if len(n.LinkLocalIPs) > 0 && copts.linkLocalIPs.Len() > 0 {
return errdefs.InvalidParameter(errors.New("conflicting options: cannot specify both --link-local-ip and per-network link-local IP addresses"))
return invalidParameter(errors.New("conflicting options: cannot specify both --link-local-ip and per-network link-local IP addresses"))
}
if copts.aliases.Len() > 0 {
n.Aliases = make([]string, copts.aliases.Len())
copy(n.Aliases, copts.aliases.GetAll())
copy(n.Aliases, copts.aliases.GetSlice())
}
// For a user-defined network, "--link" is an endpoint option, it creates an alias. But,
// for the default bridge it defines a legacy-link.
if container.NetworkMode(n.Target).IsUserDefined() && copts.links.Len() > 0 {
n.Links = make([]string, copts.links.Len())
copy(n.Links, copts.links.GetAll())
copy(n.Links, copts.links.GetSlice())
}
if copts.ipv4Address != "" {
n.IPv4Address = copts.ipv4Address
@ -841,7 +836,7 @@ func applyContainerOptions(n *opts.NetworkAttachmentOpts, copts *containerOption
}
if copts.linkLocalIPs.Len() > 0 {
n.LinkLocalIPs = make([]string, copts.linkLocalIPs.Len())
copy(n.LinkLocalIPs, copts.linkLocalIPs.GetAll())
copy(n.LinkLocalIPs, copts.linkLocalIPs.GetSlice())
}
return nil
}

View File

@ -32,7 +32,7 @@ func NewPauseCommand(dockerCli command.Cli) *cobra.Command {
"aliases": "docker container pause, docker pause",
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(ctr container.Summary) bool {
return ctr.State != "paused"
return ctr.State != container.StatePaused
}),
}
}

View File

@ -68,7 +68,7 @@ func runPort(ctx context.Context, dockerCli command.Cli, opts *portOptions) erro
return errors.Wrapf(err, "Error: invalid port (%s)", port)
}
frontends, exists := c.NetworkSettings.Ports[nat.Port(port+"/"+proto)]
if !exists || frontends == nil {
if !exists || len(frontends) == 0 {
return errors.Errorf("Error: No public port '%s' published for %s", opts.port, opts.container)
}
for _, frontend := range frontends {

View File

@ -65,7 +65,7 @@ func TestNewPortCommandOutput(t *testing.T) {
}
return ci, nil
},
}, test.EnableContentTrust)
})
cmd := NewPortCommand(cli)
cmd.SetErr(io.Discard)
cmd.SetArgs([]string{"some_container", tc.port})

View File

@ -7,9 +7,9 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/internal/prompt"
"github.com/docker/cli/opts"
"github.com/docker/docker/errdefs"
units "github.com/docker/go-units"
"github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -56,12 +56,12 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
pruneFilters := command.PruneFilters(dockerCli, options.filter.Value())
if !options.force {
r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning)
r, err := prompt.Confirm(ctx, dockerCli.In(), dockerCli.Out(), warning)
if err != nil {
return 0, "", err
}
if !r {
return 0, "", errdefs.Cancelled(errors.New("container prune has been cancelled"))
return 0, "", cancelledErr{errors.New("container prune has been cancelled")}
}
}
@ -81,6 +81,10 @@ func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions)
return spaceReclaimed, output, nil
}
type cancelledErr struct{ error }
func (cancelledErr) Cancelled() {}
// RunPrune calls the Container Prune API
// This returns the amount of space reclaimed and a detailed output string
func RunPrune(ctx context.Context, dockerCli command.Cli, _ bool, filter opts.FilterOpt) (uint64, string, error) {

View File

@ -10,7 +10,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@ -66,7 +65,7 @@ func TestRestart(t *testing.T) {
containerRestartFunc: func(ctx context.Context, containerID string, options container.StopOptions) error {
assert.Check(t, is.DeepEqual(options, tc.expectedOpts))
if containerID == "nosuchcontainer" {
return errdefs.NotFound(errors.New("Error: no such container: " + containerID))
return notFound(errors.New("Error: no such container: " + containerID))
}
// TODO(thaJeztah): consider using parallelOperation for restart, similar to "stop" and "remove"

View File

@ -6,11 +6,11 @@ import (
"fmt"
"strings"
cerrdefs "github.com/containerd/errdefs"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/errdefs"
"github.com/spf13/cobra"
)
@ -27,10 +27,9 @@ func NewRmCommand(dockerCli command.Cli) *cobra.Command {
var opts rmOptions
cmd := &cobra.Command{
Use: "rm [OPTIONS] CONTAINER [CONTAINER...]",
Aliases: []string{"remove"},
Short: "Remove one or more containers",
Args: cli.RequiresMinArgs(1),
Use: "rm [OPTIONS] CONTAINER [CONTAINER...]",
Short: "Remove one or more containers",
Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.containers = args
return runRm(cmd.Context(), dockerCli, &opts)
@ -39,7 +38,7 @@ func NewRmCommand(dockerCli command.Cli) *cobra.Command {
"aliases": "docker container rm, docker container remove, docker rm",
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true, func(ctr container.Summary) bool {
return opts.force || ctr.State == "exited" || ctr.State == "created"
return opts.force || ctr.State == container.StateExited || ctr.State == container.StateCreated
}),
}
@ -50,6 +49,15 @@ func NewRmCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
// newRemoveCommand adds subcommands for "docker container"; unlike the
// top-level "docker rm", it also adds a "remove" alias to support
// "docker container remove" in addition to "docker container rm".
func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
cmd := *NewRmCommand(dockerCli)
cmd.Aliases = []string{"rm", "remove"}
return &cmd
}
func runRm(ctx context.Context, dockerCLI command.Cli, opts *rmOptions) error {
apiClient := dockerCLI.Client()
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, ctrID string) error {
@ -67,7 +75,7 @@ func runRm(ctx context.Context, dockerCLI command.Cli, opts *rmOptions) error {
var errs []error
for _, name := range opts.containers {
if err := <-errChan; err != nil {
if opts.force && errdefs.IsNotFound(err) {
if opts.force && cerrdefs.IsNotFound(err) {
_, _ = fmt.Fprintln(dockerCLI.Err(), err)
continue
}

View File

@ -10,7 +10,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
)
@ -36,7 +35,7 @@ func TestRemoveForce(t *testing.T) {
mutex.Unlock()
if container == "nosuchcontainer" {
return errdefs.NotFound(errors.New("Error: no such container: " + container))
return notFound(errors.New("Error: no such container: " + container))
}
return nil
},

View File

@ -60,6 +60,7 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVar(&options.detachKeys, "detach-keys", "", "Override the key sequence for detaching a container")
flags.StringVar(&options.pull, "pull", PullImageMissing, `Pull image before running ("`+PullImageAlways+`", "`+PullImageMissing+`", "`+PullImageNever+`")`)
flags.BoolVarP(&options.quiet, "quiet", "q", false, "Suppress the pull output")
flags.BoolVarP(&options.createOptions.useAPISocket, "use-api-socket", "", false, "Bind mount Docker API socket and required auth")
// Add an explicit help that doesn't have a `-h` to prevent the conflict
// with hostname
@ -89,7 +90,7 @@ func runRun(ctx context.Context, dockerCli command.Cli, flags *pflag.FlagSet, ro
StatusCode: 125,
}
}
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetAll()))
proxyConfig := dockerCli.ConfigFile().ParseProxyConfig(dockerCli.Client().DaemonHost(), opts.ConvertKVStringsToMapWithNil(copts.env.GetSlice()))
newEnv := []string{}
for k, v := range proxyConfig {
if v == nil {
@ -238,10 +239,16 @@ func runContainer(ctx context.Context, dockerCli command.Cli, runOpts *runOption
return cli.StatusError{StatusCode: status}
}
case status := <-statusChan:
// notify hijackedIOStreamer that we're exiting and wait
// so that the terminal can be restored.
cancelFun()
<-errCh
// If container exits, output stream processing may not be finished yet,
// we need to keep the streamer running until all output is read.
// However, if stdout or stderr is not attached, we can just exit.
if !config.AttachStdout && !config.AttachStderr {
// Notify hijackedIOStreamer that we're exiting and wait
// so that the terminal can be restored.
cancelFun()
}
<-errCh // Drain channel but don't care about result
if status != 0 {
return cli.StatusError{StatusCode: status}
}

View File

@ -21,7 +21,7 @@ import (
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/pkg/jsonmessage"
specs "github.com/opencontainers/image-spec/specs-go/v1"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/spf13/pflag"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -57,7 +57,7 @@ func TestRunValidateFlags(t *testing.T) {
func TestRunLabel(t *testing.T) {
fakeCLI := test.NewFakeCli(&fakeClient{
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *specs.Platform, _ string) (container.CreateResponse, error) {
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *ocispec.Platform, _ string) (container.CreateResponse, error) {
return container.CreateResponse{
ID: "id",
}, nil
@ -80,7 +80,7 @@ func TestRunAttach(t *testing.T) {
var conn net.Conn
attachCh := make(chan struct{})
fakeCLI := test.NewFakeCli(&fakeClient{
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *specs.Platform, _ string) (container.CreateResponse, error) {
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *ocispec.Platform, _ string) (container.CreateResponse, error) {
return container.CreateResponse{
ID: "id",
}, nil
@ -151,13 +151,15 @@ func TestRunAttachTermination(t *testing.T) {
killCh := make(chan struct{})
attachCh := make(chan struct{})
fakeCLI := test.NewFakeCli(&fakeClient{
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *specs.Platform, _ string) (container.CreateResponse, error) {
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ *ocispec.Platform, _ string) (container.CreateResponse, error) {
return container.CreateResponse{
ID: "id",
}, nil
},
containerKillFunc: func(ctx context.Context, containerID, signal string) error {
killCh <- struct{}{}
containerKillFunc: func(ctx context.Context, containerID, sig string) error {
if sig == "TERM" {
close(killCh)
}
return nil
},
containerAttachFunc: func(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error) {
@ -172,7 +174,7 @@ func TestRunAttachTermination(t *testing.T) {
waitFunc: func(_ string) (<-chan container.WaitResponse, <-chan error) {
responseChan := make(chan container.WaitResponse, 1)
errChan := make(chan error)
<-killCh
responseChan <- container.WaitResponse{
StatusCode: 130,
}
@ -201,8 +203,7 @@ func TestRunAttachTermination(t *testing.T) {
case <-attachCh:
}
assert.NilError(t, syscall.Kill(syscall.Getpid(), syscall.SIGINT))
// end stream from "container" so that we'll detach
assert.NilError(t, syscall.Kill(syscall.Getpid(), syscall.SIGTERM))
conn.Close()
select {
@ -228,7 +229,7 @@ func TestRunPullTermination(t *testing.T) {
attachCh := make(chan struct{})
fakeCLI := test.NewFakeCli(&fakeClient{
createContainerFunc: func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig,
platform *specs.Platform, containerName string,
platform *ocispec.Platform, containerName string,
) (container.CreateResponse, error) {
return container.CreateResponse{}, errors.New("shouldn't try to create a container")
},
@ -331,7 +332,7 @@ func TestRunCommandWithContentTrustErrors(t *testing.T) {
createContainerFunc: func(config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
platform *specs.Platform,
platform *ocispec.Platform,
containerName string,
) (container.CreateResponse, error) {
return container.CreateResponse{}, errors.New("shouldn't try to pull image")

View File

@ -43,7 +43,7 @@ func NewStartCommand(dockerCli command.Cli) *cobra.Command {
"aliases": "docker container start, docker start",
},
ValidArgsFunction: completion.ContainerNames(dockerCli, true, func(ctr container.Summary) bool {
return ctr.State == "exited" || ctr.State == "created"
return ctr.State == container.StateExited || ctr.State == container.StateCreated
}),
}

View File

@ -10,7 +10,6 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@ -66,7 +65,7 @@ func TestStop(t *testing.T) {
containerStopFunc: func(ctx context.Context, containerID string, options container.StopOptions) error {
assert.Check(t, is.DeepEqual(options, tc.expectedOpts))
if containerID == "nosuchcontainer" {
return errdefs.NotFound(errors.New("Error: no such container: " + containerID))
return notFound(errors.New("Error: no such container: " + containerID))
}
// containerStopFunc is called in parallel for each container

View File

@ -32,7 +32,7 @@ func NewUnpauseCommand(dockerCli command.Cli) *cobra.Command {
"aliases": "docker container unpause, docker unpause",
},
ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(ctr container.Summary) bool {
return ctr.State == "paused"
return ctr.State == container.StatePaused
}),
}
return cmd

View File

@ -75,8 +75,8 @@ func legacyWaitExitOrRemoved(ctx context.Context, apiClient client.APIClient, co
eventProcessor := func(e events.Message) bool {
stopProcessing := false
switch e.Status {
case "die":
switch e.Action { //nolint:exhaustive // TODO(thaJeztah): make exhaustive
case events.ActionDie:
if v, ok := e.Actor.Attributes["exitCode"]; ok {
code, cerr := strconv.Atoi(v)
if cerr != nil {
@ -98,10 +98,10 @@ func legacyWaitExitOrRemoved(ctx context.Context, apiClient client.APIClient, co
}
}()
}
case "detach":
case events.ActionDetach:
exitCode = 0
stopProcessing = true
case "destroy":
case events.ActionDestroy:
stopProcessing = true
}
return stopProcessing

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package command

View File

@ -0,0 +1,46 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.23
package context
import (
"slices"
"github.com/docker/cli/cli/context/store"
"github.com/spf13/cobra"
)
type contextProvider interface {
ContextStore() store.Store
CurrentContext() string
}
// completeContextNames implements shell completion for context-names.
//
// FIXME(thaJeztah): export, and remove duplicate of this function in cmd/docker.
func completeContextNames(dockerCLI contextProvider, limit int, withFileComp bool) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
return func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if limit > 0 && len(args) >= limit {
if withFileComp {
// Provide file/path completion after context name (for "docker context export")
return nil, cobra.ShellCompDirectiveDefault
}
return nil, cobra.ShellCompDirectiveNoFileComp
}
// TODO(thaJeztah): implement function similar to [store.Names] to (also) include descriptions.
names, _ := store.Names(dockerCLI.ContextStore())
out := make([]string, 0, len(names))
for _, name := range names {
if slices.Contains(args, name) {
// Already completed
continue
}
if name == dockerCLI.CurrentContext() {
name += "\tcurrent"
}
out = append(out, name)
}
return out, cobra.ShellCompDirectiveNoFileComp
}
}

View File

@ -0,0 +1,80 @@
package context
import (
"testing"
"github.com/docker/cli/cli/context/store"
"github.com/spf13/cobra"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
type fakeContextProvider struct {
contextStore store.Store
}
func (c *fakeContextProvider) ContextStore() store.Store {
return c.contextStore
}
func (*fakeContextProvider) CurrentContext() string {
return "default"
}
type fakeContextStore struct {
store.Store
names []string
}
func (f fakeContextStore) List() (c []store.Metadata, _ error) {
for _, name := range f.names {
c = append(c, store.Metadata{Name: name})
}
return c, nil
}
func TestCompleteContextNames(t *testing.T) {
allNames := []string{"context-b", "context-c", "context-a"}
cli := &fakeContextProvider{
contextStore: fakeContextStore{
names: allNames,
},
}
t.Run("with limit", func(t *testing.T) {
compFunc := completeContextNames(cli, 1, false)
values, directives := compFunc(nil, nil, "")
assert.Check(t, is.Equal(directives, cobra.ShellCompDirectiveNoFileComp))
assert.Check(t, is.DeepEqual(values, allNames))
values, directives = compFunc(nil, []string{"context-c"}, "")
assert.Check(t, is.Equal(directives, cobra.ShellCompDirectiveNoFileComp))
assert.Check(t, is.Len(values, 0))
})
t.Run("with limit and file completion", func(t *testing.T) {
compFunc := completeContextNames(cli, 1, true)
values, directives := compFunc(nil, nil, "")
assert.Check(t, is.Equal(directives, cobra.ShellCompDirectiveNoFileComp))
assert.Check(t, is.DeepEqual(values, allNames))
values, directives = compFunc(nil, []string{"context-c"}, "")
assert.Check(t, is.Equal(directives, cobra.ShellCompDirectiveDefault), "should provide filenames completion after limit")
assert.Check(t, is.Len(values, 0))
})
t.Run("without limits", func(t *testing.T) {
compFunc := completeContextNames(cli, -1, false)
values, directives := compFunc(nil, []string{"context-c"}, "")
assert.Check(t, is.Equal(directives, cobra.ShellCompDirectiveNoFileComp))
assert.Check(t, is.DeepEqual(values, []string{"context-b", "context-a"}), "should not contain already completed")
values, directives = compFunc(nil, []string{"context-c", "context-a"}, "")
assert.Check(t, is.Equal(directives, cobra.ShellCompDirectiveNoFileComp))
assert.Check(t, is.DeepEqual(values, []string{"context-b"}), "should not contain already completed")
values, directives = compFunc(nil, []string{"context-c", "context-a", "context-b"}, "")
assert.Check(t, is.Equal(directives, cobra.ShellCompDirectiveNoFileComp), "should provide filenames completion after limit")
assert.Check(t, is.Len(values, 0))
})
}

View File

@ -1,20 +1,20 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package context
import (
"bytes"
"errors"
"fmt"
cerrdefs "github.com/containerd/errdefs"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/command/formatter/tabwriter"
"github.com/docker/cli/cli/context/docker"
"github.com/docker/cli/cli/context/store"
"github.com/docker/docker/errdefs"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -91,7 +91,7 @@ func createNewContext(contextStore store.ReaderWriter, o *CreateOptions) error {
}
dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(contextStore, o.Docker)
if err != nil {
return errors.Wrap(err, "unable to create docker endpoint config")
return fmt.Errorf("unable to create docker endpoint config: %w", err)
}
contextMetadata := store.Metadata{
Endpoints: map[string]any{
@ -122,11 +122,11 @@ func checkContextNameForCreation(s store.Reader, name string) error {
if err := store.ValidateContextName(name); err != nil {
return err
}
if _, err := s.GetMetadata(name); !errdefs.IsNotFound(err) {
if _, err := s.GetMetadata(name); !cerrdefs.IsNotFound(err) {
if err != nil {
return errors.Wrap(err, "error while getting existing contexts")
return fmt.Errorf("error while getting existing contexts: %w", err)
}
return errors.Errorf("context %q already exists", name)
return fmt.Errorf("context %q already exists", name)
}
return nil
}

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package context

View File

@ -18,7 +18,7 @@ type ExportOptions struct {
Dest string
}
func newExportCommand(dockerCli command.Cli) *cobra.Command {
func newExportCommand(dockerCLI command.Cli) *cobra.Command {
return &cobra.Command{
Use: "export [OPTIONS] CONTEXT [FILE|-]",
Short: "Export a context to a tar archive FILE or a tar stream on STDOUT.",
@ -32,8 +32,9 @@ func newExportCommand(dockerCli command.Cli) *cobra.Command {
} else {
opts.Dest = opts.ContextName + ".dockercontext"
}
return RunExport(dockerCli, opts)
return RunExport(dockerCLI, opts)
},
ValidArgsFunction: completeContextNames(dockerCLI, 1, true),
}
}

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/docker/cli/cli/context/store"
"github.com/spf13/cobra"
)
@ -19,6 +20,8 @@ func newImportCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return RunImport(dockerCli, args[0], args[1])
},
// TODO(thaJeztah): this should also include "-"
ValidArgsFunction: completion.FileNames,
}
return cmd
}

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package context
@ -19,7 +19,7 @@ type inspectOptions struct {
}
// newInspectCommand creates a new cobra.Command for `docker context inspect`
func newInspectCommand(dockerCli command.Cli) *cobra.Command {
func newInspectCommand(dockerCLI command.Cli) *cobra.Command {
var opts inspectOptions
cmd := &cobra.Command{
@ -28,13 +28,14 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
opts.refs = args
if len(opts.refs) == 0 {
if dockerCli.CurrentContext() == "" {
if dockerCLI.CurrentContext() == "" {
return errors.New("no context specified")
}
opts.refs = []string{dockerCli.CurrentContext()}
opts.refs = []string{dockerCLI.CurrentContext()}
}
return runInspect(dockerCli, opts)
return runInspect(dockerCLI, opts)
},
ValidArgsFunction: completeContextNames(dockerCLI, -1, false),
}
flags := cmd.Flags()

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package context
@ -69,8 +69,6 @@ func runList(dockerCli command.Cli, opts *listOptions) error {
Name: rawMeta.Name,
Current: isCurrent,
Error: err.Error(),
ContextType: getContextType(nil, opts.format),
})
continue
}
@ -85,8 +83,6 @@ func runList(dockerCli command.Cli, opts *listOptions) error {
Description: meta.Description,
DockerEndpoint: dockerEndpoint.Host,
Error: errMsg,
ContextType: getContextType(meta.AdditionalFields, opts.format),
}
contexts = append(contexts, &desc)
}
@ -103,8 +99,6 @@ func runList(dockerCli command.Cli, opts *listOptions) error {
Name: curContext,
Current: true,
Error: errMsg,
ContextType: getContextType(nil, opts.format),
})
}
sort.Slice(contexts, func(i, j int) bool {
@ -120,30 +114,6 @@ func runList(dockerCli command.Cli, opts *listOptions) error {
return nil
}
// getContextType sets the LegacyContextType field for compatibility with
// Visual Studio, which depends on this field from the "cloud integration"
// wrapper.
//
// https://github.com/docker/compose-cli/blob/c156ce6da4c2b317174d42daf1b019efa87e9f92/api/context/store/contextmetadata.go#L28-L34
// https://github.com/docker/compose-cli/blob/c156ce6da4c2b317174d42daf1b019efa87e9f92/api/context/store/store.go#L34-L51
//
// TODO(thaJeztah): remove this and [ClientContext.ContextType] once Visual Studio is updated to no longer depend on this.
func getContextType(meta map[string]any, format string) string {
if format != formatter.JSONFormat && format != formatter.JSONFormatKey {
// We only need the ContextType field when formatting as JSON,
// which is the format-string used by Visual Studio to detect the
// context-type.
return ""
}
if ct, ok := meta["Type"]; ok {
// If the context on-disk has a context-type (ecs, aci), return it.
return ct.(string)
}
// Use the default context-type.
return "moby"
}
func format(dockerCli command.Cli, opts *listOptions, contexts []*formatter.ClientContext) error {
contextCtx := formatter.Context{
Output: dockerCli.Out(),

View File

@ -7,7 +7,6 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/errdefs"
"github.com/spf13/cobra"
)
@ -16,7 +15,7 @@ type RemoveOptions struct {
Force bool
}
func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
func newRemoveCommand(dockerCLI command.Cli) *cobra.Command {
var opts RemoveOptions
cmd := &cobra.Command{
Use: "rm CONTEXT [CONTEXT...]",
@ -24,8 +23,9 @@ func newRemoveCommand(dockerCli command.Cli) *cobra.Command {
Short: "Remove one or more contexts",
Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return RunRemove(dockerCli, opts, args)
return RunRemove(dockerCLI, opts, args)
},
ValidArgsFunction: completeContextNames(dockerCLI, -1, false),
}
cmd.Flags().BoolVarP(&opts.Force, "force", "f", false, "Force the removal of a context in use")
return cmd
@ -74,9 +74,13 @@ func checkContextExists(dockerCli command.Cli, name string) error {
contextDir := dockerCli.ContextStore().GetStorageInfo(name).MetadataPath
_, err := os.Stat(contextDir)
if os.IsNotExist(err) {
return errdefs.NotFound(fmt.Errorf("context %q does not exist", name))
return notFoundErr{fmt.Errorf("context %q does not exist", name)}
}
// Ignore other errors; if relevant, they will produce an error when
// performing the actual delete.
return nil
}
type notFoundErr struct{ error }
func (notFoundErr) NotFound() {}

View File

@ -4,9 +4,9 @@ import (
"path/filepath"
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@ -18,7 +18,7 @@ func TestRemove(t *testing.T) {
_, err := cli.ContextStore().GetMetadata("current")
assert.NilError(t, err)
_, err = cli.ContextStore().GetMetadata("other")
assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
}
func TestRemoveNotAContext(t *testing.T) {

View File

@ -1,5 +1,5 @@
{"Name":"context1","Description":"description of context1","DockerEndpoint":"https://someswarmserver.example.com","Current":false,"Error":"","ContextType":"aci"}
{"Name":"context2","Description":"description of context2","DockerEndpoint":"https://someswarmserver.example.com","Current":false,"Error":"","ContextType":"ecs"}
{"Name":"context3","Description":"description of context3","DockerEndpoint":"https://someswarmserver.example.com","Current":false,"Error":"","ContextType":"moby"}
{"Name":"current","Description":"description of current","DockerEndpoint":"https://someswarmserver.example.com","Current":true,"Error":"","ContextType":"moby"}
{"Name":"default","Description":"Current DOCKER_HOST based configuration","DockerEndpoint":"unix:///var/run/docker.sock","Current":false,"Error":"","ContextType":"moby"}
{"Current":false,"Description":"description of context1","DockerEndpoint":"https://someswarmserver.example.com","Error":"","Name":"context1"}
{"Current":false,"Description":"description of context2","DockerEndpoint":"https://someswarmserver.example.com","Error":"","Name":"context2"}
{"Current":false,"Description":"description of context3","DockerEndpoint":"https://someswarmserver.example.com","Error":"","Name":"context3"}
{"Current":true,"Description":"description of current","DockerEndpoint":"https://someswarmserver.example.com","Error":"","Name":"current"}
{"Current":false,"Description":"Current DOCKER_HOST based configuration","DockerEndpoint":"unix:///var/run/docker.sock","Error":"","Name":"default"}

View File

@ -9,7 +9,6 @@ import (
"github.com/docker/cli/cli/command/formatter/tabwriter"
"github.com/docker/cli/cli/context/docker"
"github.com/docker/cli/cli/context/store"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -33,7 +32,7 @@ func longUpdateDescription() string {
return buf.String()
}
func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
func newUpdateCommand(dockerCLI command.Cli) *cobra.Command {
opts := &UpdateOptions{}
cmd := &cobra.Command{
Use: "update [OPTIONS] CONTEXT",
@ -41,9 +40,10 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.Name = args[0]
return RunUpdate(dockerCli, opts)
return RunUpdate(dockerCLI, opts)
},
Long: longUpdateDescription(),
Long: longUpdateDescription(),
ValidArgsFunction: completeContextNames(dockerCLI, 1, false),
}
flags := cmd.Flags()
flags.StringVar(&opts.Description, "description", "", "Description of the context")
@ -76,7 +76,7 @@ func RunUpdate(dockerCLI command.Cli, o *UpdateOptions) error {
if o.Docker != nil {
dockerEP, dockerTLS, err := getDockerEndpointMetadataAndTLS(s, o.Docker)
if err != nil {
return errors.Wrap(err, "unable to create docker endpoint config")
return fmt.Errorf("unable to create docker endpoint config: %w", err)
}
c.Endpoints[docker.DockerEndpoint] = dockerEP
tlsDataToReset[docker.DockerEndpoint] = dockerTLS

View File

@ -10,15 +10,16 @@ import (
"github.com/spf13/cobra"
)
func newUseCommand(dockerCli command.Cli) *cobra.Command {
func newUseCommand(dockerCLI command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "use CONTEXT",
Short: "Set the current docker context",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
return RunUse(dockerCli, name)
return RunUse(dockerCLI, name)
},
ValidArgsFunction: completeContextNames(dockerCLI, 1, false),
}
return cmd
}

View File

@ -9,11 +9,11 @@ import (
"runtime"
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/flags"
"github.com/docker/docker/errdefs"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@ -47,7 +47,7 @@ func TestUse(t *testing.T) {
func TestUseNoExist(t *testing.T) {
cli := makeFakeCli(t)
err := newUseCommand(cli).RunE(nil, []string{"test"})
assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
}
// TestUseDefaultWithoutConfigFile verifies that the CLI does not create

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package command

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package command
@ -7,7 +7,6 @@ import (
"github.com/docker/cli/cli/context/docker"
"github.com/docker/cli/cli/context/store"
cliflags "github.com/docker/cli/cli/flags"
"github.com/docker/docker/errdefs"
"github.com/pkg/errors"
)
@ -117,7 +116,7 @@ func (s *ContextStoreWithDefault) List() ([]store.Metadata, error) {
// CreateOrUpdate is not allowed for the default context and fails
func (s *ContextStoreWithDefault) CreateOrUpdate(meta store.Metadata) error {
if meta.Name == DefaultContextName {
return errdefs.InvalidParameter(errors.New("default context cannot be created nor updated"))
return invalidParameter(errors.New("default context cannot be created nor updated"))
}
return s.Store.CreateOrUpdate(meta)
}
@ -125,7 +124,7 @@ func (s *ContextStoreWithDefault) CreateOrUpdate(meta store.Metadata) error {
// Remove is not allowed for the default context and fails
func (s *ContextStoreWithDefault) Remove(name string) error {
if name == DefaultContextName {
return errdefs.InvalidParameter(errors.New("default context cannot be removed"))
return invalidParameter(errors.New("default context cannot be removed"))
}
return s.Store.Remove(name)
}
@ -145,7 +144,7 @@ func (s *ContextStoreWithDefault) GetMetadata(name string) (store.Metadata, erro
// ResetTLSMaterial is not implemented for default context and fails
func (s *ContextStoreWithDefault) ResetTLSMaterial(name string, data *store.ContextTLSData) error {
if name == DefaultContextName {
return errdefs.InvalidParameter(errors.New("default context cannot be edited"))
return invalidParameter(errors.New("default context cannot be edited"))
}
return s.Store.ResetTLSMaterial(name, data)
}
@ -153,7 +152,7 @@ func (s *ContextStoreWithDefault) ResetTLSMaterial(name string, data *store.Cont
// ResetEndpointTLSMaterial is not implemented for default context and fails
func (s *ContextStoreWithDefault) ResetEndpointTLSMaterial(contextName string, endpointName string, data *store.EndpointTLSData) error {
if contextName == DefaultContextName {
return errdefs.InvalidParameter(errors.New("default context cannot be edited"))
return invalidParameter(errors.New("default context cannot be edited"))
}
return s.Store.ResetEndpointTLSMaterial(contextName, endpointName, data)
}
@ -186,7 +185,7 @@ func (s *ContextStoreWithDefault) GetTLSData(contextName, endpointName, fileName
return nil, err
}
if defaultContext.TLS.Endpoints[endpointName].Files[fileName] == nil {
return nil, errdefs.NotFound(errors.Errorf("TLS data for %s/%s/%s does not exist", DefaultContextName, endpointName, fileName))
return nil, notFound(errors.Errorf("TLS data for %s/%s/%s does not exist", DefaultContextName, endpointName, fileName))
}
return defaultContext.TLS.Endpoints[endpointName].Files[fileName], nil
}

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package command
@ -7,11 +7,11 @@ import (
"crypto/rand"
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/context/docker"
"github.com/docker/cli/cli/context/store"
cliflags "github.com/docker/cli/cli/flags"
"github.com/docker/docker/errdefs"
"github.com/docker/go-connections/tlsconfig"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@ -158,7 +158,7 @@ func TestErrCreateDefault(t *testing.T) {
Metadata: testContext{Bar: "baz"},
Name: "default",
})
assert.Check(t, is.ErrorType(err, errdefs.IsInvalidParameter))
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
assert.Error(t, err, "default context cannot be created nor updated")
}
@ -166,7 +166,7 @@ func TestErrRemoveDefault(t *testing.T) {
meta := testDefaultMetadata()
s := testStore(t, meta, store.ContextTLSData{})
err := s.Remove("default")
assert.Check(t, is.ErrorType(err, errdefs.IsInvalidParameter))
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
assert.Error(t, err, "default context cannot be removed")
}
@ -174,5 +174,5 @@ func TestErrTLSDataError(t *testing.T) {
meta := testDefaultMetadata()
s := testStore(t, meta, store.ContextTLSData{})
_, err := s.GetTLSData("default", "noop", "noop")
assert.Check(t, is.ErrorType(err, errdefs.IsNotFound))
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
}

View File

@ -6,8 +6,7 @@ import (
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/api/types/build"
"github.com/docker/go-units"
)
@ -52,7 +51,7 @@ shared: {{.Shared}}
return Format(source)
}
func buildCacheSort(buildCache []*types.BuildCache) {
func buildCacheSort(buildCache []*build.CacheRecord) {
sort.Slice(buildCache, func(i, j int) bool {
lui, luj := buildCache[i].LastUsedAt, buildCache[j].LastUsedAt
switch {
@ -71,7 +70,7 @@ func buildCacheSort(buildCache []*types.BuildCache) {
}
// BuildCacheWrite renders the context for a list of containers
func BuildCacheWrite(ctx Context, buildCaches []*types.BuildCache) error {
func BuildCacheWrite(ctx Context, buildCaches []*build.CacheRecord) error {
render := func(format func(subContext SubContext) error) error {
buildCacheSort(buildCaches)
for _, bc := range buildCaches {
@ -88,7 +87,7 @@ func BuildCacheWrite(ctx Context, buildCaches []*types.BuildCache) error {
type buildCacheContext struct {
HeaderContext
trunc bool
v *types.BuildCache
v *build.CacheRecord
}
func newBuildCacheContext() *buildCacheContext {
@ -115,7 +114,7 @@ func (c *buildCacheContext) MarshalJSON() ([]byte, error) {
func (c *buildCacheContext) ID() string {
id := c.v.ID
if c.trunc {
id = stringid.TruncateID(c.v.ID)
id = TruncateID(c.v.ID)
}
if c.v.InUse {
return id + "*"
@ -131,7 +130,7 @@ func (c *buildCacheContext) Parent() string {
parent = c.v.Parent //nolint:staticcheck // Ignore SA1019: Field was deprecated in API v1.42, but kept for backward compatibility
}
if c.trunc {
return stringid.TruncateID(parent)
return TruncateID(parent)
}
return parent
}

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package formatter
@ -11,10 +11,11 @@ import (
"strings"
"time"
"github.com/containerd/platforms"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/go-units"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
const (
@ -26,8 +27,18 @@ const (
mountsHeader = "MOUNTS"
localVolumes = "LOCAL VOLUMES"
networksHeader = "NETWORKS"
platformHeader = "PLATFORM"
)
// Platform wraps a [ocispec.Platform] to implement the stringer interface.
type Platform struct {
ocispec.Platform
}
func (p Platform) String() string {
return platforms.FormatAll(p.Platform)
}
// NewContainerFormat returns a Format for rendering using a Context
func NewContainerFormat(source string, quiet bool, size bool) Format {
switch source {
@ -68,16 +79,14 @@ ports: {{- pad .Ports 1 0}}
// ContainerWrite renders the context for a list of containers
func ContainerWrite(ctx Context, containers []container.Summary) error {
render := func(format func(subContext SubContext) error) error {
return ctx.Write(NewContainerContext(), func(format func(subContext SubContext) error) error {
for _, ctr := range containers {
err := format(&ContainerContext{trunc: ctx.Trunc, c: ctr})
if err != nil {
if err := format(&ContainerContext{trunc: ctx.Trunc, c: ctr}); err != nil {
return err
}
}
return nil
}
return ctx.Write(NewContainerContext(), render)
})
}
// ContainerContext is a struct used for rendering a list of containers in a Go template.
@ -111,6 +120,7 @@ func NewContainerContext() *ContainerContext {
"Mounts": mountsHeader,
"LocalVolumes": localVolumes,
"Networks": networksHeader,
"Platform": platformHeader,
}
return &containerCtx
}
@ -124,7 +134,7 @@ func (c *ContainerContext) MarshalJSON() ([]byte, error) {
// option being set, the full or truncated ID is returned.
func (c *ContainerContext) ID() string {
if c.trunc {
return stringid.TruncateID(c.c.ID)
return TruncateID(c.c.ID)
}
return c.c.ID
}
@ -161,7 +171,7 @@ func (c *ContainerContext) Image() string {
return "<no image>"
}
if c.trunc {
if trunc := stringid.TruncateID(c.c.ImageID); trunc == stringid.TruncateID(c.c.Image) {
if trunc := TruncateID(c.c.ImageID); trunc == TruncateID(c.c.Image) {
return trunc
}
// truncate digest if no-trunc option was not selected
@ -210,6 +220,16 @@ func (c *ContainerContext) RunningFor() string {
return units.HumanDuration(time.Now().UTC().Sub(createdAt)) + " ago"
}
// Platform returns a human-readable representation of the container's
// platform if it is available.
func (c *ContainerContext) Platform() *Platform {
p := c.c.ImageManifestDescriptor
if p == nil || p.Platform == nil {
return nil
}
return &Platform{*p.Platform}
}
// Ports returns a comma-separated string representing open ports of the container
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
// it's used by command 'docker ps'
@ -218,7 +238,8 @@ func (c *ContainerContext) Ports() string {
return DisplayablePorts(c.c.Ports)
}
// State returns the container's current state (e.g. "running" or "paused")
// State returns the container's current state (e.g. "running" or "paused").
// Refer to [container.ContainerState] for possible states.
func (c *ContainerContext) State() string {
return c.c.State
}
@ -255,6 +276,7 @@ func (c *ContainerContext) Labels() string {
for k, v := range c.c.Labels {
joinLabels = append(joinLabels, k+"="+v)
}
sort.Strings(joinLabels)
return strings.Join(joinLabels, ",")
}

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package formatter
@ -13,14 +13,14 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stringid"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/golden"
)
func TestContainerPsContext(t *testing.T) {
containerID := stringid.GenerateRandomID()
containerID := test.RandomID()
unix := time.Now().Add(-65 * time.Second).Unix()
var ctx ContainerContext
@ -33,7 +33,7 @@ func TestContainerPsContext(t *testing.T) {
{
container: container.Summary{ID: containerID},
trunc: true,
expValue: stringid.TruncateID(containerID),
expValue: TruncateID(containerID),
call: ctx.ID,
},
{
@ -106,11 +106,17 @@ func TestContainerPsContext(t *testing.T) {
call: ctx.Ports,
},
{
container: container.Summary{Status: "RUNNING"},
container: container.Summary{Status: "Up 123 seconds"},
trunc: true,
expValue: "RUNNING",
expValue: "Up 123 seconds",
call: ctx.Status,
},
{
container: container.Summary{State: container.StateRunning},
trunc: true,
expValue: container.StateRunning,
call: ctx.State,
},
{
container: container.Summary{SizeRw: 10},
trunc: true,
@ -346,8 +352,8 @@ size: 0B
}
containers := []container.Summary{
{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unixTime, State: "running"},
{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unixTime, State: "running"},
{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unixTime, State: container.StateRunning},
{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unixTime, State: container.StateRunning},
}
for _, tc := range cases {
@ -365,9 +371,6 @@ size: 0B
}
func TestContainerContextWriteWithNoContainers(t *testing.T) {
out := bytes.NewBufferString("")
containers := []container.Summary{}
cases := []struct {
context Context
expected string
@ -375,40 +378,34 @@ func TestContainerContextWriteWithNoContainers(t *testing.T) {
{
context: Context{
Format: "{{.Image}}",
Output: out,
},
},
{
context: Context{
Format: "table {{.Image}}",
Output: out,
},
expected: "IMAGE\n",
},
{
context: Context{
Format: NewContainerFormat("{{.Image}}", false, true),
Output: out,
},
},
{
context: Context{
Format: NewContainerFormat("table {{.Image}}", false, true),
Output: out,
},
expected: "IMAGE\n",
},
{
context: Context{
Format: "table {{.Image}}\t{{.Size}}",
Output: out,
},
expected: "IMAGE SIZE\n",
},
{
context: Context{
Format: NewContainerFormat("table {{.Image}}\t{{.Size}}", false, true),
Output: out,
},
expected: "IMAGE SIZE\n",
},
@ -416,11 +413,11 @@ func TestContainerContextWriteWithNoContainers(t *testing.T) {
for _, tc := range cases {
t.Run(string(tc.context.Format), func(t *testing.T) {
err := ContainerWrite(tc.context, containers)
out := new(bytes.Buffer)
tc.context.Output = out
err := ContainerWrite(tc.context, nil)
assert.NilError(t, err)
assert.Equal(t, out.String(), tc.expected)
// Clean buffer
out.Reset()
})
}
}
@ -428,13 +425,36 @@ func TestContainerContextWriteWithNoContainers(t *testing.T) {
func TestContainerContextWriteJSON(t *testing.T) {
unix := time.Now().Add(-65 * time.Second).Unix()
containers := []container.Summary{
{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unix, State: "running"},
{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unix, State: "running"},
{
ID: "containerID1",
Names: []string{"/foobar_baz"},
Image: "ubuntu",
Created: unix,
State: container.StateRunning,
},
{
ID: "containerID2",
Names: []string{"/foobar_bar"},
Image: "ubuntu",
Created: unix,
State: container.StateRunning,
ImageManifestDescriptor: &ocispec.Descriptor{Platform: &ocispec.Platform{Architecture: "amd64", OS: "linux"}},
},
{
ID: "containerID3",
Names: []string{"/foobar_bar"},
Image: "ubuntu",
Created: unix,
State: container.StateRunning,
ImageManifestDescriptor: &ocispec.Descriptor{Platform: &ocispec.Platform{}},
},
}
expectedCreated := time.Unix(unix, 0).String()
expectedJSONs := []map[string]any{
{
"Command": "\"\"",
"Command": `""`,
"CreatedAt": expectedCreated,
"ID": "containerID1",
"Image": "ubuntu",
@ -443,6 +463,7 @@ func TestContainerContextWriteJSON(t *testing.T) {
"Mounts": "",
"Names": "foobar_baz",
"Networks": "",
"Platform": nil,
"Ports": "",
"RunningFor": "About a minute ago",
"Size": "0B",
@ -450,7 +471,7 @@ func TestContainerContextWriteJSON(t *testing.T) {
"Status": "",
},
{
"Command": "\"\"",
"Command": `""`,
"CreatedAt": expectedCreated,
"ID": "containerID2",
"Image": "ubuntu",
@ -459,6 +480,24 @@ func TestContainerContextWriteJSON(t *testing.T) {
"Mounts": "",
"Names": "foobar_bar",
"Networks": "",
"Platform": map[string]any{"architecture": "amd64", "os": "linux"},
"Ports": "",
"RunningFor": "About a minute ago",
"Size": "0B",
"State": "running",
"Status": "",
},
{
"Command": `""`,
"CreatedAt": expectedCreated,
"ID": "containerID3",
"Image": "ubuntu",
"Labels": "",
"LocalVolumes": "0",
"Mounts": "",
"Names": "foobar_bar",
"Networks": "",
"Platform": map[string]any{"architecture": "", "os": ""},
"Ports": "",
"RunningFor": "About a minute ago",
"Size": "0B",
@ -500,28 +539,59 @@ func TestContainerContextWriteJSONField(t *testing.T) {
}
func TestContainerBackCompat(t *testing.T) {
containers := []container.Summary{{ID: "brewhaha"}}
cases := []string{
"ID",
"Names",
"Image",
"Command",
"CreatedAt",
"RunningFor",
"Ports",
"Status",
"Size",
"Labels",
"Mounts",
createdAtTime := time.Now().AddDate(-1, 0, 0) // 1 year ago
ctrContext := container.Summary{
ID: "aabbccddeeff",
Names: []string{"/foobar_baz"},
Image: "docker.io/library/ubuntu", // should this have canonical format or not?
ImageID: "sha256:a5a665ff33eced1e0803148700880edab4269067ed77e27737a708d0d293fbf5", // should this have algo-prefix or not?
ImageManifestDescriptor: nil,
Command: "/bin/sh",
Created: createdAtTime.UTC().Unix(),
Ports: []container.Port{{PrivatePort: 8080, PublicPort: 8080, Type: "tcp"}},
SizeRw: 123,
SizeRootFs: 12345,
Labels: map[string]string{"label1": "value1", "label2": "value2"},
State: "running",
Status: "running",
HostConfig: struct {
NetworkMode string `json:",omitempty"`
Annotations map[string]string `json:",omitempty"`
}{
NetworkMode: "bridge",
Annotations: map[string]string{
"com.example.annotation": "hello",
},
},
NetworkSettings: nil,
Mounts: nil,
}
buf := bytes.NewBuffer(nil)
for _, c := range cases {
ctx := Context{Format: Format(fmt.Sprintf("{{ .%s }}", c)), Output: buf}
if err := ContainerWrite(ctx, containers); err != nil {
t.Logf("could not render template for field '%s': %v", c, err)
t.Fail()
}
buf.Reset()
tests := []struct {
field string
expected string
}{
{field: "ID", expected: "aabbccddeeff"},
{field: "Names", expected: "foobar_baz"},
{field: "Image", expected: "docker.io/library/ubuntu"},
{field: "Command", expected: `"/bin/sh"`},
{field: "CreatedAt", expected: time.Unix(createdAtTime.Unix(), 0).String()},
{field: "RunningFor", expected: "12 months ago"},
{field: "Ports", expected: "8080/tcp"},
{field: "Status", expected: "running"},
{field: "Size", expected: "123B (virtual 12.3kB)"},
{field: "Labels", expected: "label1=value1,label2=value2"},
{field: "Mounts", expected: ""},
}
for _, tc := range tests {
t.Run(tc.field, func(t *testing.T) {
buf := new(bytes.Buffer)
ctx := Context{Format: Format(fmt.Sprintf("{{ .%s }}", tc.field)), Output: buf}
assert.NilError(t, ContainerWrite(ctx, []container.Summary{ctrContext}))
assert.Check(t, is.Equal(strings.TrimSpace(buf.String()), tc.expected))
})
}
}

View File

@ -1,7 +1,5 @@
package formatter
import "encoding/json"
const (
// ClientContextTableFormat is the default client context format.
ClientContextTableFormat = "table {{.Name}}{{if .Current}} *{{end}}\t{{.Description}}\t{{.DockerEndpoint}}\t{{.Error}}"
@ -30,13 +28,6 @@ type ClientContext struct {
DockerEndpoint string
Current bool
Error string
// ContextType is a temporary field for compatibility with
// Visual Studio, which depends on this from the "cloud integration"
// wrapper.
//
// Deprecated: this type is only for backward-compatibility. Do not use.
ContextType string `json:"ContextType,omitempty"`
}
// ClientContextWrite writes formatted contexts using the Context
@ -69,13 +60,6 @@ func newClientContextContext() *clientContextContext {
}
func (c *clientContextContext) MarshalJSON() ([]byte, error) {
if c.c.ContextType != "" {
// We only have ContextType set for plain "json" or "{{json .}}" formatting,
// so we should be able to just use the default json.Marshal with no
// special handling.
return json.Marshal(c.c)
}
// FIXME(thaJeztah): why do we need a special marshal function here?
return MarshalJSON(c)
}

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package formatter

View File

@ -4,15 +4,14 @@ import (
"bytes"
"fmt"
"strconv"
"strings"
"text/template"
"github.com/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/volume"
units "github.com/docker/go-units"
"github.com/docker/go-units"
)
const (
@ -39,12 +38,12 @@ type DiskUsageContext struct {
Images []*image.Summary
Containers []*container.Summary
Volumes []*volume.Volume
BuildCache []*types.BuildCache
BuildCache []*build.CacheRecord
BuilderSize int64
}
func (ctx *DiskUsageContext) startSubsection(format string) (*template.Template, error) {
ctx.buffer = bytes.NewBufferString("")
ctx.buffer = &bytes.Buffer{}
ctx.header = ""
ctx.Format = Format(format)
ctx.preFormat()
@ -88,7 +87,7 @@ func (ctx *DiskUsageContext) Write() (err error) {
if ctx.Verbose {
return ctx.verboseWrite()
}
ctx.buffer = bytes.NewBufferString("")
ctx.buffer = &bytes.Buffer{}
ctx.preFormat()
tmpl, err := ctx.parseFormat()
@ -330,9 +329,15 @@ func (c *diskUsageContainersContext) TotalCount() string {
}
func (*diskUsageContainersContext) isActive(ctr container.Summary) bool {
return strings.Contains(ctr.State, "running") ||
strings.Contains(ctr.State, "paused") ||
strings.Contains(ctr.State, "restarting")
switch ctr.State {
case container.StateRunning, container.StatePaused, container.StateRestarting:
return true
case container.StateCreated, container.StateRemoving, container.StateExited, container.StateDead:
return false
default:
// Unknown state (should never happen).
return false
}
}
func (c *diskUsageContainersContext) Active() string {
@ -436,7 +441,7 @@ func (c *diskUsageVolumesContext) Reclaimable() string {
type diskUsageBuilderContext struct {
HeaderContext
builderSize int64
buildCache []*types.BuildCache
buildCache []*build.CacheRecord
}
func (c *diskUsageBuilderContext) MarshalJSON() ([]byte, error) {

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package formatter
@ -20,11 +20,32 @@ func charWidth(r rune) int {
switch width.LookupRune(r).Kind() {
case width.EastAsianWide, width.EastAsianFullwidth:
return 2
case width.Neutral, width.EastAsianAmbiguous, width.EastAsianNarrow, width.EastAsianHalfwidth:
return 1
default:
return 1
}
}
const shortLen = 12
// TruncateID returns a shorthand version of a string identifier for presentation,
// after trimming digest algorithm prefix (if any).
//
// This function is a copy of [stringid.TruncateID] for presentation / formatting
// purposes.
//
// [stringid.TruncateID]: https://github.com/moby/moby/blob/v28.3.2/pkg/stringid/stringid.go#L19
func TruncateID(id string) string {
if i := strings.IndexRune(id, ':'); i >= 0 {
id = id[i+1:]
}
if len(id) > shortLen {
id = id[:shortLen]
}
return id
}
// Ellipsis truncates a string to fit within maxDisplayWidth, and appends ellipsis (…).
// For maxDisplayWidth of 1 and lower, no ellipsis is appended.
// For maxDisplayWidth of 1, first char of string will return even if its width > 1.

View File

@ -7,6 +7,49 @@ import (
is "gotest.tools/v3/assert/cmp"
)
func TestTruncateID(t *testing.T) {
tests := []struct {
doc, id, expected string
}{
{
doc: "empty ID",
id: "",
expected: "",
},
{
// IDs are expected to be 12 (short) or 64 characters, and not be numeric only,
// but TruncateID should handle these gracefully.
doc: "invalid ID",
id: "1234",
expected: "1234",
},
{
doc: "full ID",
id: "90435eec5c4e124e741ef731e118be2fc799a68aba0466ec17717f24ce2ae6a2",
expected: "90435eec5c4e",
},
{
doc: "digest",
id: "sha256:90435eec5c4e124e741ef731e118be2fc799a68aba0466ec17717f24ce2ae6a2",
expected: "90435eec5c4e",
},
{
doc: "very long ID",
id: "90435eec5c4e124e741ef731e118be2fc799a68aba0466ec17717f24ce2ae6a290435eec5c4e124e741ef731e118be2fc799a68aba0466ec17717f24ce2ae6a2",
expected: "90435eec5c4e",
},
}
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
actual := TruncateID(tc.id)
if actual != tc.expected {
t.Errorf("expected: %q, got: %q", tc.expected, actual)
}
})
}
}
func TestEllipsis(t *testing.T) {
testcases := []struct {
source string

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package formatter
@ -82,6 +82,9 @@ func (c *Context) parseFormat() (*template.Template, error) {
}
func (c *Context) postFormat(tmpl *template.Template, subContext SubContext) {
if c.Output == nil {
c.Output = io.Discard
}
if c.Format.IsTable() {
t := tabwriter.NewWriter(c.Output, 10, 1, 3, ' ', 0)
buffer := bytes.NewBufferString("")
@ -111,7 +114,7 @@ type SubFormat func(func(SubContext) error) error
// Write the template to the buffer using this Context
func (c *Context) Write(sub SubContext, f SubFormat) error {
c.buffer = bytes.NewBufferString("")
c.buffer = &bytes.Buffer{}
c.preFormat()
tmpl, err := c.parseFormat()

View File

@ -1,5 +1,5 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.22
//go:build go1.23
package formatter

View File

@ -6,8 +6,7 @@ import (
"github.com/distribution/reference"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/pkg/stringid"
units "github.com/docker/go-units"
"github.com/docker/go-units"
)
const (
@ -216,7 +215,7 @@ func (c *imageContext) MarshalJSON() ([]byte, error) {
func (c *imageContext) ID() string {
if c.trunc {
return stringid.TruncateID(c.i.ID)
return TruncateID(c.i.ID)
}
return c.i.ID
}

Some files were not shown because too many files have changed in this diff Show More