Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions cli-plugins/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,25 @@ func (e errPluginNotFound) Error() string {
//
// Plugin-discovery is performed in the following order of preference:
//
// 1. The "cli-plugins" directory inside the CLIs [config.Path] (usually "~/.docker/cli-plugins").
// 1. Additional plugin directories from the DOCKER_CLI_PLUGINS_EXTRA_DIRS environment variable.
// 2. Additional plugin directories as configured through [ConfigFile.CLIPluginsExtraDirs].
// 3. Platform-specific defaultSystemPluginDirs.
// 3. The "cli-plugins" directory inside the CLIs [config.Path] (usually "~/.docker/cli-plugins").
// 4. Platform-specific defaultSystemPluginDirs.
//
// The environment variable uses the platform's path-list separator. Empty entries
// are ignored so that appending to an unset variable preserves the search order.
//
// [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 {
var pluginDirs []string

for _, dir := range filepath.SplitList(os.Getenv("DOCKER_CLI_PLUGINS_EXTRA_DIRS")) {
if dir == "" {
continue
}
pluginDirs = append(pluginDirs, dir)
}

if cfg != nil {
pluginDirs = append(pluginDirs, cfg.CLIPluginsExtraDirs...)
}
Expand Down
47 changes: 47 additions & 0 deletions cli-plugins/manager/manager_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package manager

import (
"os"
"path/filepath"
"strings"
"testing"
Expand Down Expand Up @@ -171,6 +172,8 @@ func TestErrPluginNotFound(t *testing.T) {
func TestGetPluginDirs(t *testing.T) {
cli := test.NewFakeCli(nil)

t.Setenv("DOCKER_CLI_PLUGINS_EXTRA_DIRS", "")

pluginDir := filepath.Join(config.Dir(), "cli-plugins")
expected := append([]string{pluginDir}, defaultSystemPluginDirs...)

Expand All @@ -186,3 +189,47 @@ func TestGetPluginDirs(t *testing.T) {
pluginDirs = getPluginDirs(cli.ConfigFile())
assert.DeepEqual(t, expected, pluginDirs)
}

func TestGetPluginDirsFromEnv(t *testing.T) {
dir := t.TempDir()
envFirst := filepath.Join(dir, "env-first")
envSecond := filepath.Join(dir, "env-second")
configExtra := filepath.Join(dir, "config-extra")

cfg := &configfile.ConfigFile{
CLIPluginsExtraDirs: []string{configExtra},
}

testCases := []struct {
name string
paths []string
expected []string
}{
{
name: "multiple paths",
paths: []string{envFirst, envSecond},
expected: []string{envFirst, envSecond},
},
{
name: "empty entries",
paths: []string{"", envFirst, "", envSecond, ""},
expected: []string{envFirst, envSecond},
},
{
name: "empty value",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Setenv("DOCKER_CLI_PLUGINS_EXTRA_DIRS",
strings.Join(tc.paths, string(os.PathListSeparator)))

expected := append([]string{}, tc.expected...)
expected = append(expected, configExtra, filepath.Join(config.Dir(), "cli-plugins"))
expected = append(expected, defaultSystemPluginDirs...)

assert.DeepEqual(t, getPluginDirs(cfg), expected)
})
}
}
10 changes: 3 additions & 7 deletions cli-plugins/manager/manager_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ package manager
// defaultSystemPluginDirs are the platform-specific locations to search
// for plugins in order of preference.
//
// Plugin-discovery is performed in the following order of preference:
//
// 1. The "cli-plugins" directory inside the CLIs config-directory (usually "~/.docker/cli-plugins").
// 2. Additional plugin directories as configured through [ConfigFile.CLIPluginsExtraDirs].
// 3. Platform-specific defaultSystemPluginDirs (as defined below).
//
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
// These directories are searched after the directories from the environment
// variable, the configuration file, and the CLI's config-directory.
// See [getPluginDirs] for the complete search order.
var defaultSystemPluginDirs = []string{
"/usr/local/lib/docker/cli-plugins",
"/usr/local/libexec/docker/cli-plugins",
Expand Down
10 changes: 3 additions & 7 deletions cli-plugins/manager/manager_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ import (
// defaultSystemPluginDirs are the platform-specific locations to search
// for plugins in order of preference.
//
// Plugin-discovery is performed in the following order of preference:
//
// 1. The "cli-plugins" directory inside the CLIs config-directory (usually "~/.docker/cli-plugins").
// 2. Additional plugin directories as configured through [ConfigFile.CLIPluginsExtraDirs].
// 3. Platform-specific defaultSystemPluginDirs (as defined below).
//
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
// These directories are searched after the directories from the environment
// variable, the configuration file, and the CLI's config-directory.
// See [getPluginDirs] for the complete search order.
var defaultSystemPluginDirs = []string{
filepath.Join(os.Getenv("ProgramFiles"), "Docker", "cli-plugins"),
}
28 changes: 26 additions & 2 deletions docs/reference/commandline/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ The following environment variables control the behavior of the `docker` command
| :---------------------------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `DOCKER_API_VERSION` | Override the negotiated API version to use for debugging (e.g. `1.19`) |
| `DOCKER_CERT_PATH` | Location of your authentication keys. This variable is used both by the `docker` CLI and the [`dockerd` daemon](https://docs.docker.com/reference/cli/dockerd/) |
| `DOCKER_CLI_PLUGINS_EXTRA_DIRS` | Additional directories to search for CLI plugins, separated by `:` on Linux and macOS or `;` on Windows. See [CLI plugin directories](#cli-plugin-directories). |
| `DOCKER_CONFIG` | The location of your client configuration files. |
| `DOCKER_CONTEXT` | Name of the `docker context` to use (overrides `DOCKER_HOST` env var and default context set with `docker context use`) |
| `DOCKER_CUSTOM_HEADERS` | (Experimental) Configure [custom HTTP headers](#custom-http-headers) to be sent by the client. Headers must be provided as a comma-separated list of `name=value` pairs. This is the equivalent to the `HttpHeaders` field in the configuration file. |
Expand All @@ -129,8 +130,7 @@ The following environment variables control the behavior of the `docker` command
| `DOCKER_TLS` | Enable TLS for connections made by the `docker` CLI (equivalent of the `--tls` command-line option). Set to a non-empty value to enable TLS. Note that TLS is enabled automatically if any of the other TLS options are set. |
| `DOCKER_TLS_VERIFY` | When set Docker uses TLS and verifies the remote. This variable is used both by the `docker` CLI and the [`dockerd` daemon](https://docs.docker.com/reference/cli/dockerd/) |
| `BUILDKIT_PROGRESS` | Set type of progress output (`auto`, `plain`, `tty`, `rawjson`) when [building](https://docs.docker.com/reference/cli/docker/image/build/) with [BuildKit backend](https://docs.docker.com/build/buildkit/). Use plain to show container output (default `auto`). |
| `NO_COLOR` | Disable any ANSI escape codes in the output in accordance with https://no-color.org/
|
| `NO_COLOR` | Disable any ANSI escape codes in the output in accordance with https://no-color.org/ |

Because Docker is developed using Go, you can also use any environment
variables used by the Go runtime. In particular, you may find these useful:
Expand All @@ -144,6 +144,30 @@ variables used by the Go runtime. In particular, you may find these useful:
See the [Go specification](https://pkg.go.dev/golang.org/x/net/http/httpproxy#Config)
for details on these variables.

#### CLI plugin directories

Use `DOCKER_CLI_PLUGINS_EXTRA_DIRS` to add CLI plugin directories without editing
`config.json`. Separate paths with `:` on Linux and macOS, or `;` on Windows.
Empty entries are ignored. If the variable is unset or empty, the search paths
remain unchanged.

The CLI searches for plugins in the following order:

1. Directories from `DOCKER_CLI_PLUGINS_EXTRA_DIRS`, in the order listed.
2. Directories from `cliPluginsExtraDirs` in `config.json`, in the order listed.
3. The `cli-plugins` directory inside the CLI configuration directory
(`~/.docker/cli-plugins` by default).
4. Platform-specific system plugin directories.

If multiple directories contain a plugin with the same name, the first candidate
takes precedence.

For example, append a directory to the environment variable on Linux or macOS:

```console
$ export DOCKER_CLI_PLUGINS_EXTRA_DIRS="$DOCKER_CLI_PLUGINS_EXTRA_DIRS:/home/username/my/plugins"
```

### Option types

Single character command line options can be combined, so rather than
Expand Down