Skip to content

Commit 7091e8b

Browse files
committed
cli/flags: add "hostVar" to handle --host / -H as a single string
hostVar is used for the '--host' / '-H' flag to set [ClientOptions.Hosts]. The [ClientOptions.Hosts] field is a slice because it was originally shared with the daemon config. However, the CLI only allows for a single host to be specified. hostVar presents itself as a "string", but stores the value in a string slice. It produces an error when trying to set multiple values, matching the check in [getServerHost]. [getServerHost]: https://github.com/docker/cli/blob/7eab668982645def1cd46fe1b60894cba6fd17a4/cli/command/cli.go#L542-L551 Signed-off-by: Sebastiaan van Stijn <[email protected]> (cherry picked from commit f14eeeb) Signed-off-by: Sebastiaan van Stijn <[email protected]>
1 parent ff42ff9 commit 7091e8b

File tree

3 files changed

+50
-15
lines changed

3 files changed

+50
-15
lines changed

cli/flags/options.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package flags
22

33
import (
4+
"errors"
45
"fmt"
56
"os"
67
"path/filepath"
@@ -53,6 +54,39 @@ var (
5354
dockerTLS = os.Getenv(EnvEnableTLS) != ""
5455
)
5556

57+
// hostVar is used for the '--host' / '-H' flag to set [ClientOptions.Hosts].
58+
// The [ClientOptions.Hosts] field is a slice because it was originally shared
59+
// with the daemon config. However, the CLI only allows for a single host to
60+
// be specified.
61+
//
62+
// hostVar presents itself as a "string", but stores the value in a string
63+
// slice. It produces an error when trying to set multiple values, matching
64+
// the check in [getServerHost].
65+
//
66+
// [getServerHost]: https://github.com/docker/cli/blob/7eab668982645def1cd46fe1b60894cba6fd17a4/cli/command/cli.go#L542-L551
67+
type hostVar struct {
68+
dst *[]string
69+
set bool
70+
}
71+
72+
func (h *hostVar) String() string {
73+
if h.dst == nil || len(*h.dst) == 0 {
74+
return ""
75+
}
76+
return (*h.dst)[0]
77+
}
78+
79+
func (h *hostVar) Set(s string) error {
80+
if h.set {
81+
return errors.New("specify only one -H")
82+
}
83+
*h.dst = []string{s}
84+
h.set = true
85+
return nil
86+
}
87+
88+
func (*hostVar) Type() string { return "string" }
89+
5690
// ClientOptions are the options used to configure the client cli.
5791
type ClientOptions struct {
5892
Debug bool
@@ -95,7 +129,7 @@ func (o *ClientOptions) InstallFlags(flags *pflag.FlagSet) {
95129

96130
// TODO(thaJeztah): show the default host.
97131
// TODO(thaJeztah): this should be a string, not an "array" as we only allow a single host.
98-
flags.StringArrayVarP(&o.Hosts, "host", "H", nil, "Daemon socket to connect to")
132+
flags.VarP(&hostVar{dst: &o.Hosts}, "host", "H", "Daemon socket to connect to")
99133
flags.StringVarP(&o.Context, "context", "c", "",
100134
`Name of the context to use to connect to the daemon (overrides `+client.EnvOverrideHost+` env var and default context set with "docker context use")`)
101135
}

docs/reference/commandline/docker.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,18 @@ The base command for the Docker CLI.
6969

7070
### Options
7171

72-
| Name | Type | Default | Description |
73-
|:---------------------------------|:--------------|:-------------------------|:--------------------------------------------------------------------------------------------------------------------------------------|
74-
| `--config` | `string` | `/root/.docker` | Location of client config files |
75-
| `-c`, `--context` | `string` | | Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with `docker context use`) |
76-
| `-D`, `--debug` | `bool` | | Enable debug mode |
77-
| [`-H`](#host), [`--host`](#host) | `stringArray` | | Daemon socket to connect to |
78-
| `-l`, `--log-level` | `string` | `info` | Set the logging level (`debug`, `info`, `warn`, `error`, `fatal`) |
79-
| `--tls` | `bool` | | Use TLS; implied by --tlsverify |
80-
| `--tlscacert` | `string` | `/root/.docker/ca.pem` | Trust certs signed only by this CA |
81-
| `--tlscert` | `string` | `/root/.docker/cert.pem` | Path to TLS certificate file |
82-
| `--tlskey` | `string` | `/root/.docker/key.pem` | Path to TLS key file |
83-
| `--tlsverify` | `bool` | | Use TLS and verify the remote |
72+
| Name | Type | Default | Description |
73+
|:---------------------------------|:---------|:-------------------------|:--------------------------------------------------------------------------------------------------------------------------------------|
74+
| `--config` | `string` | `/root/.docker` | Location of client config files |
75+
| `-c`, `--context` | `string` | | Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with `docker context use`) |
76+
| `-D`, `--debug` | `bool` | | Enable debug mode |
77+
| [`-H`](#host), [`--host`](#host) | `string` | | Daemon socket to connect to |
78+
| `-l`, `--log-level` | `string` | `info` | Set the logging level (`debug`, `info`, `warn`, `error`, `fatal`) |
79+
| `--tls` | `bool` | | Use TLS; implied by --tlsverify |
80+
| `--tlscacert` | `string` | `/root/.docker/ca.pem` | Trust certs signed only by this CA |
81+
| `--tlscert` | `string` | `/root/.docker/cert.pem` | Path to TLS certificate file |
82+
| `--tlskey` | `string` | `/root/.docker/key.pem` | Path to TLS key file |
83+
| `--tlsverify` | `bool` | | Use TLS and verify the remote |
8484

8585

8686
<!---MARKER_GEN_END-->

e2e/cli-plugins/flags_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cliplugins
22

33
import (
4+
"fmt"
45
"os"
56
"testing"
67

@@ -91,9 +92,9 @@ func TestGlobalArgsOnlyParsedOnce(t *testing.T) {
9192
// This is checking the precondition wrt -H mentioned in the function comment
9293
name: "fails-if-H-used-twice",
9394
args: []string{"-H", dh, "-H", dh, "version", "-f", "{{.Client.Version}}"},
94-
expectedExitCode: 1,
95+
expectedExitCode: 125,
9596
expectedOut: icmd.None,
96-
expectedErr: "Specify only one -H",
97+
expectedErr: fmt.Sprintf(`invalid argument %q for "-H, --host" flag: specify only one -H`, dh),
9798
},
9899
{
99100
name: "builtin",

0 commit comments

Comments
 (0)