diff --git a/cli/command/container/ps.go b/cli/command/container/ps.go index d7ae675f5b..3583ee1092 100644 --- a/cli/command/container/ps.go +++ b/cli/command/container/ps.go @@ -1,16 +1,15 @@ package container import ( + "io/ioutil" + "golang.org/x/net/context" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command/formatter" - - "io/ioutil" - + "github.com/docker/docker/opts" "github.com/docker/docker/utils/templates" "github.com/spf13/cobra" ) @@ -23,12 +22,12 @@ type psOptions struct { nLatest bool last int format string - filter []string + filter opts.FilterOpt } // NewPsCommand creates a new cobra.Command for `docker ps` func NewPsCommand(dockerCli *command.DockerCli) *cobra.Command { - var opts psOptions + opts := psOptions{filter: opts.NewFilterOpt()} cmd := &cobra.Command{ Use: "ps [OPTIONS]", @@ -48,7 +47,7 @@ func NewPsCommand(dockerCli *command.DockerCli) *cobra.Command { flags.BoolVarP(&opts.nLatest, "latest", "l", false, "Show the latest created container (includes all states)") flags.IntVarP(&opts.last, "last", "n", -1, "Show n last created containers (includes all states)") flags.StringVarP(&opts.format, "format", "", "", "Pretty-print containers using a Go template") - flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided") + flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided") return cmd } @@ -65,26 +64,17 @@ func (p *preProcessor) Size() bool { } func buildContainerListOptions(opts *psOptions) (*types.ContainerListOptions, error) { - options := &types.ContainerListOptions{ All: opts.all, Limit: opts.last, Size: opts.size, - Filter: filters.NewArgs(), + Filter: opts.filter.Value(), } if opts.nLatest && opts.last == -1 { options.Limit = 1 } - for _, f := range opts.filter { - var err error - options.Filter, err = filters.ParseFlag(f, options.Filter) - if err != nil { - return nil, err - } - } - // Currently only used with Size, so we can determine if the user // put {{.Size}} in their format. pre := &preProcessor{opts: options} diff --git a/cli/command/container/ps_test.go b/cli/command/container/ps_test.go index 2af183cce1..dafdcdf905 100644 --- a/cli/command/container/ps_test.go +++ b/cli/command/container/ps_test.go @@ -1,8 +1,16 @@ package container -import "testing" +import ( + "testing" + + "github.com/docker/docker/opts" + "github.com/docker/docker/pkg/testutil/assert" +) func TestBuildContainerListOptions(t *testing.T) { + filters := opts.NewFilterOpt() + assert.NilError(t, filters.Set("foo=bar")) + assert.NilError(t, filters.Set("baz=foo")) contexts := []struct { psOpts *psOptions @@ -16,7 +24,7 @@ func TestBuildContainerListOptions(t *testing.T) { all: true, size: true, last: 5, - filter: []string{"foo=bar", "baz=foo"}, + filter: filters, }, expectedAll: true, expectedSize: true, @@ -42,27 +50,12 @@ func TestBuildContainerListOptions(t *testing.T) { for _, c := range contexts { options, err := buildContainerListOptions(c.psOpts) - if err != nil { - t.Fatal(err) - } + assert.NilError(t, err) - if c.expectedAll != options.All { - t.Fatalf("Expected All to be %t but got %t", c.expectedAll, options.All) - } - - if c.expectedSize != options.Size { - t.Fatalf("Expected Size to be %t but got %t", c.expectedSize, options.Size) - } - - if c.expectedLimit != options.Limit { - t.Fatalf("Expected Limit to be %d but got %d", c.expectedLimit, options.Limit) - } - - f := options.Filter - - if f.Len() != len(c.expectedFilters) { - t.Fatalf("Expected %d filters but got %d", len(c.expectedFilters), f.Len()) - } + assert.Equal(t, c.expectedAll, options.All) + assert.Equal(t, c.expectedSize, options.Size) + assert.Equal(t, c.expectedLimit, options.Limit) + assert.Equal(t, options.Filter.Len(), len(c.expectedFilters)) for k, v := range c.expectedFilters { f := options.Filter diff --git a/cli/command/image/images.go b/cli/command/image/images.go index f00fecf672..648236dfe5 100644 --- a/cli/command/image/images.go +++ b/cli/command/image/images.go @@ -4,10 +4,10 @@ import ( "golang.org/x/net/context" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command/formatter" + "github.com/docker/docker/opts" "github.com/spf13/cobra" ) @@ -19,12 +19,12 @@ type imagesOptions struct { noTrunc bool showDigests bool format string - filter []string + filter opts.FilterOpt } // NewImagesCommand creates a new `docker images` command func NewImagesCommand(dockerCli *command.DockerCli) *cobra.Command { - var opts imagesOptions + opts := imagesOptions{filter: opts.NewFilterOpt()} cmd := &cobra.Command{ Use: "images [OPTIONS] [REPOSITORY[:TAG]]", @@ -45,7 +45,7 @@ func NewImagesCommand(dockerCli *command.DockerCli) *cobra.Command { flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Don't truncate output") flags.BoolVar(&opts.showDigests, "digests", false, "Show digests") flags.StringVar(&opts.format, "format", "", "Pretty-print images using a Go template") - flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided") + flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided") return cmd } @@ -53,23 +53,10 @@ func NewImagesCommand(dockerCli *command.DockerCli) *cobra.Command { func runImages(dockerCli *command.DockerCli, opts imagesOptions) error { ctx := context.Background() - // Consolidate all filter flags, and sanity check them early. - // They'll get process in the daemon/server. - imageFilterArgs := filters.NewArgs() - for _, f := range opts.filter { - var err error - imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs) - if err != nil { - return err - } - } - - matchName := opts.matchName - options := types.ImageListOptions{ - MatchName: matchName, + MatchName: opts.matchName, All: opts.all, - Filters: imageFilterArgs, + Filters: opts.filter.Value(), } images, err := dockerCli.Client().ImageList(ctx, options) diff --git a/cli/command/image/search.go b/cli/command/image/search.go index 6f8308af80..93db7006ac 100644 --- a/cli/command/image/search.go +++ b/cli/command/image/search.go @@ -9,10 +9,10 @@ import ( "golang.org/x/net/context" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" registrytypes "github.com/docker/docker/api/types/registry" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" + "github.com/docker/docker/opts" "github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/registry" "github.com/spf13/cobra" @@ -22,7 +22,7 @@ type searchOptions struct { term string noTrunc bool limit int - filter []string + filter opts.FilterOpt // Deprecated stars uint @@ -31,7 +31,7 @@ type searchOptions struct { // NewSearchCommand creates a new `docker search` command func NewSearchCommand(dockerCli *command.DockerCli) *cobra.Command { - var opts searchOptions + opts := searchOptions{filter: opts.NewFilterOpt()} cmd := &cobra.Command{ Use: "search [OPTIONS] TERM", @@ -46,7 +46,7 @@ func NewSearchCommand(dockerCli *command.DockerCli) *cobra.Command { flags := cmd.Flags() flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Don't truncate output") - flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided") + flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided") flags.IntVar(&opts.limit, "limit", registry.DefaultSearchLimit, "Max number of search results") flags.BoolVar(&opts.automated, "automated", false, "Only show automated builds") @@ -74,19 +74,10 @@ func runSearch(dockerCli *command.DockerCli, opts searchOptions) error { return err } - searchFilters := filters.NewArgs() - for _, f := range opts.filter { - var err error - searchFilters, err = filters.ParseFlag(f, searchFilters) - if err != nil { - return err - } - } - options := types.ImageSearchOptions{ RegistryAuth: encodedAuth, PrivilegeFunc: requestPrivilege, - Filters: searchFilters, + Filters: opts.filter.Value(), Limit: opts.limit, } diff --git a/cli/command/network/list.go b/cli/command/network/list.go index 19013a3b8e..a0f2e7f4f0 100644 --- a/cli/command/network/list.go +++ b/cli/command/network/list.go @@ -6,10 +6,10 @@ import ( "golang.org/x/net/context" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command/formatter" + "github.com/docker/docker/opts" "github.com/spf13/cobra" ) @@ -23,11 +23,11 @@ type listOptions struct { quiet bool noTrunc bool format string - filter []string + filter opts.FilterOpt } func newListCommand(dockerCli *command.DockerCli) *cobra.Command { - var opts listOptions + opts := listOptions{filter: opts.NewFilterOpt()} cmd := &cobra.Command{ Use: "ls [OPTIONS]", @@ -43,7 +43,7 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command { flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only display network IDs") flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Do not truncate the output") flags.StringVar(&opts.format, "format", "", "Pretty-print networks using a Go template") - flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Provide filter values (i.e. 'dangling=true')") + flags.VarP(&opts.filter, "filter", "f", "Provide filter values (i.e. 'dangling=true')") return cmd } @@ -51,19 +51,7 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command { func runList(dockerCli *command.DockerCli, opts listOptions) error { client := dockerCli.Client() - netFilterArgs := filters.NewArgs() - for _, f := range opts.filter { - var err error - netFilterArgs, err = filters.ParseFlag(f, netFilterArgs) - if err != nil { - return err - } - } - - options := types.NetworkListOptions{ - Filters: netFilterArgs, - } - + options := types.NetworkListOptions{Filters: opts.filter.Value()} networkResources, err := client.NetworkList(context.Background(), options) if err != nil { return err diff --git a/cli/command/system/events.go b/cli/command/system/events.go index 456e81b4ce..b9d740f356 100644 --- a/cli/command/system/events.go +++ b/cli/command/system/events.go @@ -11,9 +11,9 @@ import ( "github.com/docker/docker/api/types" eventtypes "github.com/docker/docker/api/types/events" - "github.com/docker/docker/api/types/filters" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" + "github.com/docker/docker/opts" "github.com/docker/docker/pkg/jsonlog" "github.com/spf13/cobra" ) @@ -21,12 +21,12 @@ import ( type eventsOptions struct { since string until string - filter []string + filter opts.FilterOpt } // NewEventsCommand creates a new cobra.Command for `docker events` func NewEventsCommand(dockerCli *command.DockerCli) *cobra.Command { - var opts eventsOptions + opts := eventsOptions{filter: opts.NewFilterOpt()} cmd := &cobra.Command{ Use: "events [OPTIONS]", @@ -40,28 +40,16 @@ func NewEventsCommand(dockerCli *command.DockerCli) *cobra.Command { flags := cmd.Flags() flags.StringVar(&opts.since, "since", "", "Show all events created since timestamp") flags.StringVar(&opts.until, "until", "", "Stream events until this timestamp") - flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided") + flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided") return cmd } func runEvents(dockerCli *command.DockerCli, opts *eventsOptions) error { - eventFilterArgs := filters.NewArgs() - - // Consolidate all filter flags, and sanity check them early. - // They'll get process in the daemon/server. - for _, f := range opts.filter { - var err error - eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs) - if err != nil { - return err - } - } - options := types.EventsOptions{ Since: opts.since, Until: opts.until, - Filters: eventFilterArgs, + Filters: opts.filter.Value(), } responseBody, err := dockerCli.Client().Events(context.Background(), options) diff --git a/cli/command/volume/list.go b/cli/command/volume/list.go index 75e77f828f..6d32d2cbfb 100644 --- a/cli/command/volume/list.go +++ b/cli/command/volume/list.go @@ -6,10 +6,10 @@ import ( "golang.org/x/net/context" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command/formatter" + "github.com/docker/docker/opts" "github.com/spf13/cobra" ) @@ -24,11 +24,11 @@ func (r byVolumeName) Less(i, j int) bool { type listOptions struct { quiet bool format string - filter []string + filter opts.FilterOpt } func newListCommand(dockerCli *command.DockerCli) *cobra.Command { - var opts listOptions + opts := listOptions{filter: opts.NewFilterOpt()} cmd := &cobra.Command{ Use: "ls [OPTIONS]", @@ -44,24 +44,14 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command { flags := cmd.Flags() flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only display volume names") flags.StringVar(&opts.format, "format", "", "Pretty-print volumes using a Go template") - flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Provide filter values (e.g. 'dangling=true')") + flags.VarP(&opts.filter, "filter", "f", "Provide filter values (e.g. 'dangling=true')") return cmd } func runList(dockerCli *command.DockerCli, opts listOptions) error { client := dockerCli.Client() - - volFilterArgs := filters.NewArgs() - for _, f := range opts.filter { - var err error - volFilterArgs, err = filters.ParseFlag(f, volFilterArgs) - if err != nil { - return err - } - } - - volumes, err := client.VolumeList(context.Background(), volFilterArgs) + volumes, err := client.VolumeList(context.Background(), opts.filter.Value()) if err != nil { return err } diff --git a/integration-cli/docker_cli_by_digest_test.go b/integration-cli/docker_cli_by_digest_test.go index 8cce0c8ec2..a04b04998d 100644 --- a/integration-cli/docker_cli_by_digest_test.go +++ b/integration-cli/docker_cli_by_digest_test.go @@ -344,7 +344,7 @@ func (s *DockerRegistrySuite) TestListDanglingImagesWithDigests(c *check.C) { dockerCmd(c, "pull", imageReference2) // list images - out, _ = dockerCmd(c, "images", "--digests", "--filter=\"dangling=true\"") + out, _ = dockerCmd(c, "images", "--digests", "--filter=dangling=true") // make sure repo shown, tag=, digest = $digest1 c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out)) @@ -357,7 +357,7 @@ func (s *DockerRegistrySuite) TestListDanglingImagesWithDigests(c *check.C) { dockerCmd(c, "pull", repoName+":dangle1") // list images - out, _ = dockerCmd(c, "images", "--digests", "--filter=\"dangling=true\"") + out, _ = dockerCmd(c, "images", "--digests", "--filter=dangling=true") // make sure image 1 has repo, tag, AND repo, , digest reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*dangle1\s*` + digest1.String() + `\s`) @@ -379,7 +379,7 @@ func (s *DockerRegistrySuite) TestListDanglingImagesWithDigests(c *check.C) { c.Assert(reWithDigest2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest2.String(), out)) // list images, no longer dangling, should not match - out, _ = dockerCmd(c, "images", "--digests", "--filter=\"dangling=true\"") + out, _ = dockerCmd(c, "images", "--digests", "--filter=dangling=true") // make sure image 1 has repo, tag, digest c.Assert(reWithDigest1.MatchString(out), checker.False, check.Commentf("unexpected %q: %s", reWithDigest1.String(), out))