Browse code

Use opts.FilterOpt for filter flags.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2016/09/14 03:53:11
Showing 8 changed files
... ...
@@ -1,16 +1,15 @@
1 1
 package container
2 2
 
3 3
 import (
4
+	"io/ioutil"
5
+
4 6
 	"golang.org/x/net/context"
5 7
 
6 8
 	"github.com/docker/docker/api/types"
7
-	"github.com/docker/docker/api/types/filters"
8 9
 	"github.com/docker/docker/cli"
9 10
 	"github.com/docker/docker/cli/command"
10 11
 	"github.com/docker/docker/cli/command/formatter"
11
-
12
-	"io/ioutil"
13
-
12
+	"github.com/docker/docker/opts"
14 13
 	"github.com/docker/docker/utils/templates"
15 14
 	"github.com/spf13/cobra"
16 15
 )
... ...
@@ -23,12 +22,12 @@ type psOptions struct {
23 23
 	nLatest bool
24 24
 	last    int
25 25
 	format  string
26
-	filter  []string
26
+	filter  opts.FilterOpt
27 27
 }
28 28
 
29 29
 // NewPsCommand creates a new cobra.Command for `docker ps`
30 30
 func NewPsCommand(dockerCli *command.DockerCli) *cobra.Command {
31
-	var opts psOptions
31
+	opts := psOptions{filter: opts.NewFilterOpt()}
32 32
 
33 33
 	cmd := &cobra.Command{
34 34
 		Use:   "ps [OPTIONS]",
... ...
@@ -48,7 +47,7 @@ func NewPsCommand(dockerCli *command.DockerCli) *cobra.Command {
48 48
 	flags.BoolVarP(&opts.nLatest, "latest", "l", false, "Show the latest created container (includes all states)")
49 49
 	flags.IntVarP(&opts.last, "last", "n", -1, "Show n last created containers (includes all states)")
50 50
 	flags.StringVarP(&opts.format, "format", "", "", "Pretty-print containers using a Go template")
51
-	flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided")
51
+	flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
52 52
 
53 53
 	return cmd
54 54
 }
... ...
@@ -65,26 +64,17 @@ func (p *preProcessor) Size() bool {
65 65
 }
66 66
 
67 67
 func buildContainerListOptions(opts *psOptions) (*types.ContainerListOptions, error) {
68
-
69 68
 	options := &types.ContainerListOptions{
70 69
 		All:    opts.all,
71 70
 		Limit:  opts.last,
72 71
 		Size:   opts.size,
73
-		Filter: filters.NewArgs(),
72
+		Filter: opts.filter.Value(),
74 73
 	}
75 74
 
76 75
 	if opts.nLatest && opts.last == -1 {
77 76
 		options.Limit = 1
78 77
 	}
79 78
 
80
-	for _, f := range opts.filter {
81
-		var err error
82
-		options.Filter, err = filters.ParseFlag(f, options.Filter)
83
-		if err != nil {
84
-			return nil, err
85
-		}
86
-	}
87
-
88 79
 	// Currently only used with Size, so we can determine if the user
89 80
 	// put {{.Size}} in their format.
90 81
 	pre := &preProcessor{opts: options}
... ...
@@ -1,8 +1,16 @@
1 1
 package container
2 2
 
3
-import "testing"
3
+import (
4
+	"testing"
5
+
6
+	"github.com/docker/docker/opts"
7
+	"github.com/docker/docker/pkg/testutil/assert"
8
+)
4 9
 
5 10
 func TestBuildContainerListOptions(t *testing.T) {
11
+	filters := opts.NewFilterOpt()
12
+	assert.NilError(t, filters.Set("foo=bar"))
13
+	assert.NilError(t, filters.Set("baz=foo"))
6 14
 
7 15
 	contexts := []struct {
8 16
 		psOpts          *psOptions
... ...
@@ -16,7 +24,7 @@ func TestBuildContainerListOptions(t *testing.T) {
16 16
 				all:    true,
17 17
 				size:   true,
18 18
 				last:   5,
19
-				filter: []string{"foo=bar", "baz=foo"},
19
+				filter: filters,
20 20
 			},
21 21
 			expectedAll:   true,
22 22
 			expectedSize:  true,
... ...
@@ -42,27 +50,12 @@ func TestBuildContainerListOptions(t *testing.T) {
42 42
 
43 43
 	for _, c := range contexts {
44 44
 		options, err := buildContainerListOptions(c.psOpts)
45
-		if err != nil {
46
-			t.Fatal(err)
47
-		}
48
-
49
-		if c.expectedAll != options.All {
50
-			t.Fatalf("Expected All to be %t but got %t", c.expectedAll, options.All)
51
-		}
52
-
53
-		if c.expectedSize != options.Size {
54
-			t.Fatalf("Expected Size to be %t but got %t", c.expectedSize, options.Size)
55
-		}
56
-
57
-		if c.expectedLimit != options.Limit {
58
-			t.Fatalf("Expected Limit to be %d but got %d", c.expectedLimit, options.Limit)
59
-		}
45
+		assert.NilError(t, err)
60 46
 
61
-		f := options.Filter
62
-
63
-		if f.Len() != len(c.expectedFilters) {
64
-			t.Fatalf("Expected %d filters but got %d", len(c.expectedFilters), f.Len())
65
-		}
47
+		assert.Equal(t, c.expectedAll, options.All)
48
+		assert.Equal(t, c.expectedSize, options.Size)
49
+		assert.Equal(t, c.expectedLimit, options.Limit)
50
+		assert.Equal(t, options.Filter.Len(), len(c.expectedFilters))
66 51
 
67 52
 		for k, v := range c.expectedFilters {
68 53
 			f := options.Filter
... ...
@@ -4,10 +4,10 @@ import (
4 4
 	"golang.org/x/net/context"
5 5
 
6 6
 	"github.com/docker/docker/api/types"
7
-	"github.com/docker/docker/api/types/filters"
8 7
 	"github.com/docker/docker/cli"
9 8
 	"github.com/docker/docker/cli/command"
10 9
 	"github.com/docker/docker/cli/command/formatter"
10
+	"github.com/docker/docker/opts"
11 11
 	"github.com/spf13/cobra"
12 12
 )
13 13
 
... ...
@@ -19,12 +19,12 @@ type imagesOptions struct {
19 19
 	noTrunc     bool
20 20
 	showDigests bool
21 21
 	format      string
22
-	filter      []string
22
+	filter      opts.FilterOpt
23 23
 }
24 24
 
25 25
 // NewImagesCommand creates a new `docker images` command
26 26
 func NewImagesCommand(dockerCli *command.DockerCli) *cobra.Command {
27
-	var opts imagesOptions
27
+	opts := imagesOptions{filter: opts.NewFilterOpt()}
28 28
 
29 29
 	cmd := &cobra.Command{
30 30
 		Use:   "images [OPTIONS] [REPOSITORY[:TAG]]",
... ...
@@ -45,7 +45,7 @@ func NewImagesCommand(dockerCli *command.DockerCli) *cobra.Command {
45 45
 	flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Don't truncate output")
46 46
 	flags.BoolVar(&opts.showDigests, "digests", false, "Show digests")
47 47
 	flags.StringVar(&opts.format, "format", "", "Pretty-print images using a Go template")
48
-	flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided")
48
+	flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
49 49
 
50 50
 	return cmd
51 51
 }
... ...
@@ -53,23 +53,10 @@ func NewImagesCommand(dockerCli *command.DockerCli) *cobra.Command {
53 53
 func runImages(dockerCli *command.DockerCli, opts imagesOptions) error {
54 54
 	ctx := context.Background()
55 55
 
56
-	// Consolidate all filter flags, and sanity check them early.
57
-	// They'll get process in the daemon/server.
58
-	imageFilterArgs := filters.NewArgs()
59
-	for _, f := range opts.filter {
60
-		var err error
61
-		imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs)
62
-		if err != nil {
63
-			return err
64
-		}
65
-	}
66
-
67
-	matchName := opts.matchName
68
-
69 56
 	options := types.ImageListOptions{
70
-		MatchName: matchName,
57
+		MatchName: opts.matchName,
71 58
 		All:       opts.all,
72
-		Filters:   imageFilterArgs,
59
+		Filters:   opts.filter.Value(),
73 60
 	}
74 61
 
75 62
 	images, err := dockerCli.Client().ImageList(ctx, options)
... ...
@@ -9,10 +9,10 @@ import (
9 9
 	"golang.org/x/net/context"
10 10
 
11 11
 	"github.com/docker/docker/api/types"
12
-	"github.com/docker/docker/api/types/filters"
13 12
 	registrytypes "github.com/docker/docker/api/types/registry"
14 13
 	"github.com/docker/docker/cli"
15 14
 	"github.com/docker/docker/cli/command"
15
+	"github.com/docker/docker/opts"
16 16
 	"github.com/docker/docker/pkg/stringutils"
17 17
 	"github.com/docker/docker/registry"
18 18
 	"github.com/spf13/cobra"
... ...
@@ -22,7 +22,7 @@ type searchOptions struct {
22 22
 	term    string
23 23
 	noTrunc bool
24 24
 	limit   int
25
-	filter  []string
25
+	filter  opts.FilterOpt
26 26
 
27 27
 	// Deprecated
28 28
 	stars     uint
... ...
@@ -31,7 +31,7 @@ type searchOptions struct {
31 31
 
32 32
 // NewSearchCommand creates a new `docker search` command
33 33
 func NewSearchCommand(dockerCli *command.DockerCli) *cobra.Command {
34
-	var opts searchOptions
34
+	opts := searchOptions{filter: opts.NewFilterOpt()}
35 35
 
36 36
 	cmd := &cobra.Command{
37 37
 		Use:   "search [OPTIONS] TERM",
... ...
@@ -46,7 +46,7 @@ func NewSearchCommand(dockerCli *command.DockerCli) *cobra.Command {
46 46
 	flags := cmd.Flags()
47 47
 
48 48
 	flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Don't truncate output")
49
-	flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided")
49
+	flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
50 50
 	flags.IntVar(&opts.limit, "limit", registry.DefaultSearchLimit, "Max number of search results")
51 51
 
52 52
 	flags.BoolVar(&opts.automated, "automated", false, "Only show automated builds")
... ...
@@ -74,19 +74,10 @@ func runSearch(dockerCli *command.DockerCli, opts searchOptions) error {
74 74
 		return err
75 75
 	}
76 76
 
77
-	searchFilters := filters.NewArgs()
78
-	for _, f := range opts.filter {
79
-		var err error
80
-		searchFilters, err = filters.ParseFlag(f, searchFilters)
81
-		if err != nil {
82
-			return err
83
-		}
84
-	}
85
-
86 77
 	options := types.ImageSearchOptions{
87 78
 		RegistryAuth:  encodedAuth,
88 79
 		PrivilegeFunc: requestPrivilege,
89
-		Filters:       searchFilters,
80
+		Filters:       opts.filter.Value(),
90 81
 		Limit:         opts.limit,
91 82
 	}
92 83
 
... ...
@@ -6,10 +6,10 @@ import (
6 6
 	"golang.org/x/net/context"
7 7
 
8 8
 	"github.com/docker/docker/api/types"
9
-	"github.com/docker/docker/api/types/filters"
10 9
 	"github.com/docker/docker/cli"
11 10
 	"github.com/docker/docker/cli/command"
12 11
 	"github.com/docker/docker/cli/command/formatter"
12
+	"github.com/docker/docker/opts"
13 13
 	"github.com/spf13/cobra"
14 14
 )
15 15
 
... ...
@@ -23,11 +23,11 @@ type listOptions struct {
23 23
 	quiet   bool
24 24
 	noTrunc bool
25 25
 	format  string
26
-	filter  []string
26
+	filter  opts.FilterOpt
27 27
 }
28 28
 
29 29
 func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
30
-	var opts listOptions
30
+	opts := listOptions{filter: opts.NewFilterOpt()}
31 31
 
32 32
 	cmd := &cobra.Command{
33 33
 		Use:     "ls [OPTIONS]",
... ...
@@ -43,7 +43,7 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
43 43
 	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only display network IDs")
44 44
 	flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Do not truncate the output")
45 45
 	flags.StringVar(&opts.format, "format", "", "Pretty-print networks using a Go template")
46
-	flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Provide filter values (i.e. 'dangling=true')")
46
+	flags.VarP(&opts.filter, "filter", "f", "Provide filter values (i.e. 'dangling=true')")
47 47
 
48 48
 	return cmd
49 49
 }
... ...
@@ -51,19 +51,7 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
51 51
 func runList(dockerCli *command.DockerCli, opts listOptions) error {
52 52
 	client := dockerCli.Client()
53 53
 
54
-	netFilterArgs := filters.NewArgs()
55
-	for _, f := range opts.filter {
56
-		var err error
57
-		netFilterArgs, err = filters.ParseFlag(f, netFilterArgs)
58
-		if err != nil {
59
-			return err
60
-		}
61
-	}
62
-
63
-	options := types.NetworkListOptions{
64
-		Filters: netFilterArgs,
65
-	}
66
-
54
+	options := types.NetworkListOptions{Filters: opts.filter.Value()}
67 55
 	networkResources, err := client.NetworkList(context.Background(), options)
68 56
 	if err != nil {
69 57
 		return err
... ...
@@ -11,9 +11,9 @@ import (
11 11
 
12 12
 	"github.com/docker/docker/api/types"
13 13
 	eventtypes "github.com/docker/docker/api/types/events"
14
-	"github.com/docker/docker/api/types/filters"
15 14
 	"github.com/docker/docker/cli"
16 15
 	"github.com/docker/docker/cli/command"
16
+	"github.com/docker/docker/opts"
17 17
 	"github.com/docker/docker/pkg/jsonlog"
18 18
 	"github.com/spf13/cobra"
19 19
 )
... ...
@@ -21,12 +21,12 @@ import (
21 21
 type eventsOptions struct {
22 22
 	since  string
23 23
 	until  string
24
-	filter []string
24
+	filter opts.FilterOpt
25 25
 }
26 26
 
27 27
 // NewEventsCommand creates a new cobra.Command for `docker events`
28 28
 func NewEventsCommand(dockerCli *command.DockerCli) *cobra.Command {
29
-	var opts eventsOptions
29
+	opts := eventsOptions{filter: opts.NewFilterOpt()}
30 30
 
31 31
 	cmd := &cobra.Command{
32 32
 		Use:   "events [OPTIONS]",
... ...
@@ -40,28 +40,16 @@ func NewEventsCommand(dockerCli *command.DockerCli) *cobra.Command {
40 40
 	flags := cmd.Flags()
41 41
 	flags.StringVar(&opts.since, "since", "", "Show all events created since timestamp")
42 42
 	flags.StringVar(&opts.until, "until", "", "Stream events until this timestamp")
43
-	flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided")
43
+	flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
44 44
 
45 45
 	return cmd
46 46
 }
47 47
 
48 48
 func runEvents(dockerCli *command.DockerCli, opts *eventsOptions) error {
49
-	eventFilterArgs := filters.NewArgs()
50
-
51
-	// Consolidate all filter flags, and sanity check them early.
52
-	// They'll get process in the daemon/server.
53
-	for _, f := range opts.filter {
54
-		var err error
55
-		eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs)
56
-		if err != nil {
57
-			return err
58
-		}
59
-	}
60
-
61 49
 	options := types.EventsOptions{
62 50
 		Since:   opts.since,
63 51
 		Until:   opts.until,
64
-		Filters: eventFilterArgs,
52
+		Filters: opts.filter.Value(),
65 53
 	}
66 54
 
67 55
 	responseBody, err := dockerCli.Client().Events(context.Background(), options)
... ...
@@ -6,10 +6,10 @@ import (
6 6
 	"golang.org/x/net/context"
7 7
 
8 8
 	"github.com/docker/docker/api/types"
9
-	"github.com/docker/docker/api/types/filters"
10 9
 	"github.com/docker/docker/cli"
11 10
 	"github.com/docker/docker/cli/command"
12 11
 	"github.com/docker/docker/cli/command/formatter"
12
+	"github.com/docker/docker/opts"
13 13
 	"github.com/spf13/cobra"
14 14
 )
15 15
 
... ...
@@ -24,11 +24,11 @@ func (r byVolumeName) Less(i, j int) bool {
24 24
 type listOptions struct {
25 25
 	quiet  bool
26 26
 	format string
27
-	filter []string
27
+	filter opts.FilterOpt
28 28
 }
29 29
 
30 30
 func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
31
-	var opts listOptions
31
+	opts := listOptions{filter: opts.NewFilterOpt()}
32 32
 
33 33
 	cmd := &cobra.Command{
34 34
 		Use:     "ls [OPTIONS]",
... ...
@@ -44,24 +44,14 @@ func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
44 44
 	flags := cmd.Flags()
45 45
 	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only display volume names")
46 46
 	flags.StringVar(&opts.format, "format", "", "Pretty-print volumes using a Go template")
47
-	flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Provide filter values (e.g. 'dangling=true')")
47
+	flags.VarP(&opts.filter, "filter", "f", "Provide filter values (e.g. 'dangling=true')")
48 48
 
49 49
 	return cmd
50 50
 }
51 51
 
52 52
 func runList(dockerCli *command.DockerCli, opts listOptions) error {
53 53
 	client := dockerCli.Client()
54
-
55
-	volFilterArgs := filters.NewArgs()
56
-	for _, f := range opts.filter {
57
-		var err error
58
-		volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
59
-		if err != nil {
60
-			return err
61
-		}
62
-	}
63
-
64
-	volumes, err := client.VolumeList(context.Background(), volFilterArgs)
54
+	volumes, err := client.VolumeList(context.Background(), opts.filter.Value())
65 55
 	if err != nil {
66 56
 		return err
67 57
 	}
... ...
@@ -344,7 +344,7 @@ func (s *DockerRegistrySuite) TestListDanglingImagesWithDigests(c *check.C) {
344 344
 	dockerCmd(c, "pull", imageReference2)
345 345
 
346 346
 	// list images
347
-	out, _ = dockerCmd(c, "images", "--digests", "--filter=\"dangling=true\"")
347
+	out, _ = dockerCmd(c, "images", "--digests", "--filter=dangling=true")
348 348
 
349 349
 	// make sure repo shown, tag=<none>, digest = $digest1
350 350
 	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) {
357 357
 	dockerCmd(c, "pull", repoName+":dangle1")
358 358
 
359 359
 	// list images
360
-	out, _ = dockerCmd(c, "images", "--digests", "--filter=\"dangling=true\"")
360
+	out, _ = dockerCmd(c, "images", "--digests", "--filter=dangling=true")
361 361
 
362 362
 	// make sure image 1 has repo, tag, <none> AND repo, <none>, digest
363 363
 	reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*dangle1\s*` + digest1.String() + `\s`)
... ...
@@ -379,7 +379,7 @@ func (s *DockerRegistrySuite) TestListDanglingImagesWithDigests(c *check.C) {
379 379
 	c.Assert(reWithDigest2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest2.String(), out))
380 380
 
381 381
 	// list images, no longer dangling, should not match
382
-	out, _ = dockerCmd(c, "images", "--digests", "--filter=\"dangling=true\"")
382
+	out, _ = dockerCmd(c, "images", "--digests", "--filter=dangling=true")
383 383
 
384 384
 	// make sure image 1 has repo, tag, digest
385 385
 	c.Assert(reWithDigest1.MatchString(out), checker.False, check.Commentf("unexpected %q: %s", reWithDigest1.String(), out))