Merge pull request #6052 from thaJeztah/inspect_completion
inspect: add shell completion, improve flag-description for `--type` and improve validation
This commit is contained in:
commit
a2a13765f7
@ -11,6 +11,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/command/inspect"
|
||||
flagsHelper "github.com/docker/cli/cli/flags"
|
||||
"github.com/docker/docker/api/types"
|
||||
@ -20,13 +21,42 @@ import (
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
type objectType = string
|
||||
|
||||
const (
|
||||
typeConfig objectType = "config"
|
||||
typeContainer objectType = "container"
|
||||
typeImage objectType = "image"
|
||||
typeNetwork objectType = "network"
|
||||
typeNode objectType = "node"
|
||||
typePlugin objectType = "plugin"
|
||||
typeSecret objectType = "secret"
|
||||
typeService objectType = "service"
|
||||
typeTask objectType = "task"
|
||||
typeVolume objectType = "volume"
|
||||
)
|
||||
|
||||
var allTypes = []objectType{
|
||||
typeConfig,
|
||||
typeContainer,
|
||||
typeImage,
|
||||
typeNetwork,
|
||||
typeNode,
|
||||
typePlugin,
|
||||
typeSecret,
|
||||
typeService,
|
||||
typeTask,
|
||||
typeVolume,
|
||||
}
|
||||
|
||||
type inspectOptions struct {
|
||||
format string
|
||||
inspectType string
|
||||
size bool
|
||||
ids []string
|
||||
format string
|
||||
objectType objectType
|
||||
size bool
|
||||
ids []string
|
||||
}
|
||||
|
||||
// NewInspectCommand creates a new cobra.Command for `docker inspect`
|
||||
@ -39,25 +69,38 @@ func NewInspectCommand(dockerCli command.Cli) *cobra.Command {
|
||||
Args: cli.RequiresMinArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
opts.ids = args
|
||||
if cmd.Flags().Changed("type") && opts.objectType == "" {
|
||||
return fmt.Errorf(`type is empty: must be one of "%s"`, strings.Join(allTypes, `", "`))
|
||||
}
|
||||
return runInspect(cmd.Context(), dockerCli, opts)
|
||||
},
|
||||
// TODO(thaJeztah): should we consider adding completion for common object-types? (images, containers?)
|
||||
ValidArgsFunction: completion.NoComplete,
|
||||
}
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp)
|
||||
flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type")
|
||||
flags.StringVar(&opts.objectType, "type", "", "Only inspect objects of the given type")
|
||||
flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes if the type is container")
|
||||
|
||||
_ = cmd.RegisterFlagCompletionFunc("type", completion.FromList(allTypes...))
|
||||
flags.VisitAll(func(flag *pflag.Flag) {
|
||||
// Set a default completion function if none was set. We don't look
|
||||
// up if it does already have one set, because Cobra does this for
|
||||
// us, and returns an error (which we ignore for this reason).
|
||||
_ = cmd.RegisterFlagCompletionFunc(flag.Name, completion.NoComplete)
|
||||
})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error {
|
||||
var elementSearcher inspect.GetRefFunc
|
||||
switch opts.inspectType {
|
||||
case "", "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume":
|
||||
elementSearcher = inspectAll(ctx, dockerCli, opts.size, opts.inspectType)
|
||||
switch opts.objectType {
|
||||
case "", typeConfig, typeContainer, typeImage, typeNetwork, typeNode,
|
||||
typePlugin, typeSecret, typeService, typeTask, typeVolume:
|
||||
elementSearcher = inspectAll(ctx, dockerCli, opts.size, opts.objectType)
|
||||
default:
|
||||
return errors.Errorf("%q is not a valid value for --type", opts.inspectType)
|
||||
return errors.Errorf(`unknown type: %q: must be one of "%s"`, opts.objectType, strings.Join(allTypes, `", "`))
|
||||
}
|
||||
return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher)
|
||||
}
|
||||
@ -128,56 +171,56 @@ func inspectConfig(ctx context.Context, dockerCLI command.Cli) inspect.GetRefFun
|
||||
}
|
||||
}
|
||||
|
||||
func inspectAll(ctx context.Context, dockerCLI command.Cli, getSize bool, typeConstraint string) inspect.GetRefFunc {
|
||||
func inspectAll(ctx context.Context, dockerCLI command.Cli, getSize bool, typeConstraint objectType) inspect.GetRefFunc {
|
||||
inspectAutodetect := []struct {
|
||||
objectType string
|
||||
objectType objectType
|
||||
isSizeSupported bool
|
||||
isSwarmObject bool
|
||||
objectInspector func(string) (any, []byte, error)
|
||||
}{
|
||||
{
|
||||
objectType: "container",
|
||||
objectType: typeContainer,
|
||||
isSizeSupported: true,
|
||||
objectInspector: inspectContainers(ctx, dockerCLI, getSize),
|
||||
},
|
||||
{
|
||||
objectType: "image",
|
||||
objectType: typeImage,
|
||||
objectInspector: inspectImages(ctx, dockerCLI),
|
||||
},
|
||||
{
|
||||
objectType: "network",
|
||||
objectType: typeNetwork,
|
||||
objectInspector: inspectNetwork(ctx, dockerCLI),
|
||||
},
|
||||
{
|
||||
objectType: "volume",
|
||||
objectType: typeVolume,
|
||||
objectInspector: inspectVolume(ctx, dockerCLI),
|
||||
},
|
||||
{
|
||||
objectType: "service",
|
||||
objectType: typeService,
|
||||
isSwarmObject: true,
|
||||
objectInspector: inspectService(ctx, dockerCLI),
|
||||
},
|
||||
{
|
||||
objectType: "task",
|
||||
objectType: typeTask,
|
||||
isSwarmObject: true,
|
||||
objectInspector: inspectTasks(ctx, dockerCLI),
|
||||
},
|
||||
{
|
||||
objectType: "node",
|
||||
objectType: typeNode,
|
||||
isSwarmObject: true,
|
||||
objectInspector: inspectNode(ctx, dockerCLI),
|
||||
},
|
||||
{
|
||||
objectType: "plugin",
|
||||
objectType: typePlugin,
|
||||
objectInspector: inspectPlugin(ctx, dockerCLI),
|
||||
},
|
||||
{
|
||||
objectType: "secret",
|
||||
objectType: typeSecret,
|
||||
isSwarmObject: true,
|
||||
objectInspector: inspectSecret(ctx, dockerCLI),
|
||||
},
|
||||
{
|
||||
objectType: "config",
|
||||
objectType: typeConfig,
|
||||
isSwarmObject: true,
|
||||
objectInspector: inspectConfig(ctx, dockerCLI),
|
||||
},
|
||||
|
48
cli/command/system/inspect_test.go
Normal file
48
cli/command/system/inspect_test.go
Normal file
@ -0,0 +1,48 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestInspectValidateFlagsAndArgs(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "empty type",
|
||||
args: []string{"--type", "", "something"},
|
||||
expectedErr: `type is empty: must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume"`,
|
||||
},
|
||||
{
|
||||
name: "unknown type",
|
||||
args: []string{"--type", "unknown", "something"},
|
||||
expectedErr: `unknown type: "unknown": must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume"`,
|
||||
},
|
||||
{
|
||||
name: "no arg",
|
||||
args: []string{},
|
||||
expectedErr: `inspect: 'inspect' requires at least 1 argument`,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cmd := NewInspectCommand(test.NewFakeCli(&fakeClient{}))
|
||||
cmd.SetOut(io.Discard)
|
||||
cmd.SetErr(io.Discard)
|
||||
cmd.SetArgs(tc.args)
|
||||
|
||||
err := cmd.Execute()
|
||||
if tc.expectedErr != "" {
|
||||
assert.Check(t, is.ErrorContains(err, tc.expectedErr))
|
||||
} else {
|
||||
assert.Check(t, is.Nil(err))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ Return low-level information on Docker objects
|
||||
|:---------------------------------------|:---------|:--------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [`-f`](#format), [`--format`](#format) | `string` | | Format output using a custom template:<br>'json': Print in JSON format<br>'TEMPLATE': Print output using the given Go template.<br>Refer to https://docs.docker.com/go/formatting/ for more information about formatting output with templates |
|
||||
| [`-s`](#size), [`--size`](#size) | `bool` | | Display total file sizes if the type is container |
|
||||
| [`--type`](#type) | `string` | | Return JSON for specified type |
|
||||
| [`--type`](#type) | `string` | | Only inspect objects of the given type |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
Loading…
x
Reference in New Issue
Block a user