adding tests and allowing for easy passing of filters.Args from client
to server.
Docker-DCO-1.1-Signed-off-by: Vincent Batts <vbatts@redhat.com> (github: vbatts)
| ... | ... |
@@ -1160,10 +1160,10 @@ func (cli *DockerCli) CmdImages(args ...string) error {
|
| 1160 | 1160 |
|
| 1161 | 1161 |
// Consolidate all filter flags, and sanity check them early. |
| 1162 | 1162 |
// They'll get process in the daemon/server. |
| 1163 |
- imageFilters := map[string]string{}
|
|
| 1163 |
+ imageFilterArgs := filters.Args{}
|
|
| 1164 | 1164 |
for _, f := range flFilter.GetAll() {
|
| 1165 | 1165 |
var err error |
| 1166 |
- imageFilters, err = filters.ParseFlag(f, imageFilters) |
|
| 1166 |
+ imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs) |
|
| 1167 | 1167 |
if err != nil {
|
| 1168 | 1168 |
return err |
| 1169 | 1169 |
} |
| ... | ... |
@@ -1174,7 +1174,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
|
| 1174 | 1174 |
if *flViz || *flTree {
|
| 1175 | 1175 |
v := url.Values{
|
| 1176 | 1176 |
"all": []string{"1"},
|
| 1177 |
- "filters": []string{filters.ToParam(imageFilters)},
|
|
| 1177 |
+ "filters": []string{filters.ToParam(imageFilterArgs)},
|
|
| 1178 | 1178 |
} |
| 1179 | 1179 |
body, _, err := readBody(cli.call("GET", "/images/json?"+v.Encode(), nil, false))
|
| 1180 | 1180 |
if err != nil {
|
| ... | ... |
@@ -1238,7 +1238,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
|
| 1238 | 1238 |
} |
| 1239 | 1239 |
} else {
|
| 1240 | 1240 |
v := url.Values{
|
| 1241 |
- "filters": []string{filters.ToParam(imageFilters)},
|
|
| 1241 |
+ "filters": []string{filters.ToParam(imageFilterArgs)},
|
|
| 1242 | 1242 |
} |
| 1243 | 1243 |
if cmd.NArg() == 1 {
|
| 1244 | 1244 |
// FIXME rename this parameter, to not be confused with the filters flag |
| ... | ... |
@@ -189,7 +189,7 @@ func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseW |
| 189 | 189 |
) |
| 190 | 190 |
|
| 191 | 191 |
job.Setenv("filters", r.Form.Get("filters"))
|
| 192 |
- // FIXME rename this parameter, to not be confused with the filters flag |
|
| 192 |
+ // FIXME this parameter could just be a match filter |
|
| 193 | 193 |
job.Setenv("filter", r.Form.Get("filter"))
|
| 194 | 194 |
job.Setenv("all", r.Form.Get("all"))
|
| 195 | 195 |
|
| ... | ... |
@@ -700,12 +700,19 @@ func (srv *Server) Images(job *engine.Job) engine.Status {
|
| 700 | 700 |
filt_tagged = true |
| 701 | 701 |
) |
| 702 | 702 |
|
| 703 |
- imageFilters, err := filters.ParseFlag(job.Getenv("filters"), nil)
|
|
| 703 |
+ utils.Debugf("SUCH JOB: %#v", job)
|
|
| 704 |
+ utils.Debugf("SUCH ENV: %#v", *job.Env())
|
|
| 705 |
+ imageFilters, err := filters.FromParam(job.Getenv("filters"))
|
|
| 704 | 706 |
if err != nil {
|
| 705 | 707 |
return job.Error(err) |
| 706 | 708 |
} |
| 707 |
- if i, ok := imageFilters["untagged"]; ok && strings.ToLower(i) == "true" {
|
|
| 708 |
- filt_tagged = false |
|
| 709 |
+ utils.Debugf("SUCH FILTERS: %#v", imageFilters)
|
|
| 710 |
+ if i, ok := imageFilters["untagged"]; ok {
|
|
| 711 |
+ for _, value := range i {
|
|
| 712 |
+ if strings.ToLower(value) == "true" {
|
|
| 713 |
+ filt_tagged = false |
|
| 714 |
+ } |
|
| 715 |
+ } |
|
| 709 | 716 |
} |
| 710 | 717 |
|
| 711 | 718 |
if job.GetenvBool("all") && !filt_tagged {
|
| ... | ... |
@@ -2,46 +2,51 @@ package filters |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"errors" |
| 5 |
+ "github.com/dotcloud/docker/pkg/beam/data" |
|
| 5 | 6 |
"strings" |
| 6 | 7 |
) |
| 7 | 8 |
|
| 9 |
+type Args map[string][]string |
|
| 10 |
+ |
|
| 8 | 11 |
/* |
| 9 | 12 |
Parse the argument to the filter flag. Like |
| 10 | 13 |
|
| 11 |
- `docker ps -f 'created=today;image.name=ubuntu*'` |
|
| 12 |
- |
|
| 13 |
-Filters delimited by ';', and expected to be 'name=value' |
|
| 14 |
+ `docker ps -f 'created=today' -f 'image.name=ubuntu*'` |
|
| 14 | 15 |
|
| 15 | 16 |
If prev map is provided, then it is appended to, and returned. By default a new |
| 16 | 17 |
map is created. |
| 17 | 18 |
*/ |
| 18 |
-func ParseFlag(arg string, prev map[string]string) (map[string]string, error) {
|
|
| 19 |
- var filters map[string]string |
|
| 20 |
- if prev != nil {
|
|
| 21 |
- filters = prev |
|
| 22 |
- } else {
|
|
| 23 |
- filters = map[string]string{}
|
|
| 19 |
+func ParseFlag(arg string, prev Args) (Args, error) {
|
|
| 20 |
+ var filters Args = prev |
|
| 21 |
+ if prev == nil {
|
|
| 22 |
+ filters = Args{}
|
|
| 24 | 23 |
} |
| 25 | 24 |
if len(arg) == 0 {
|
| 26 | 25 |
return filters, nil |
| 27 | 26 |
} |
| 28 | 27 |
|
| 29 |
- for _, chunk := range strings.Split(arg, ";") {
|
|
| 30 |
- if !strings.Contains(chunk, "=") {
|
|
| 31 |
- return filters, ErrorBadFormat |
|
| 32 |
- } |
|
| 33 |
- f := strings.SplitN(chunk, "=", 2) |
|
| 34 |
- filters[f[0]] = f[1] |
|
| 28 |
+ if !strings.Contains(arg, "=") {
|
|
| 29 |
+ return filters, ErrorBadFormat |
|
| 35 | 30 |
} |
| 31 |
+ |
|
| 32 |
+ f := strings.SplitN(arg, "=", 2) |
|
| 33 |
+ filters[f[0]] = append(filters[f[0]], f[1]) |
|
| 34 |
+ |
|
| 36 | 35 |
return filters, nil |
| 37 | 36 |
} |
| 38 | 37 |
|
| 39 | 38 |
var ErrorBadFormat = errors.New("bad format of filter (expected name=value)")
|
| 40 | 39 |
|
| 41 |
-func ToParam(f map[string]string) string {
|
|
| 42 |
- fs := []string{}
|
|
| 43 |
- for k, v := range f {
|
|
| 44 |
- fs = append(fs, k+"="+v) |
|
| 45 |
- } |
|
| 46 |
- return strings.Join(fs, ";") |
|
| 40 |
+/* |
|
| 41 |
+packs the Args into an string for easy transport from client to server |
|
| 42 |
+*/ |
|
| 43 |
+func ToParam(a Args) string {
|
|
| 44 |
+ return data.Encode(a) |
|
| 45 |
+} |
|
| 46 |
+ |
|
| 47 |
+/* |
|
| 48 |
+unpacks the filter Args |
|
| 49 |
+*/ |
|
| 50 |
+func FromParam(p string) (Args, error) {
|
|
| 51 |
+ return data.Decode(p) |
|
| 47 | 52 |
} |
| 48 | 53 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,60 @@ |
| 0 |
+package filters |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "sort" |
|
| 4 |
+ "testing" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+func TestParseArgs(t *testing.T) {
|
|
| 8 |
+ // equivalent of `docker ps -f 'created=today' -f 'image.name=ubuntu*' -f 'image.name=*untu'` |
|
| 9 |
+ flagArgs := []string{
|
|
| 10 |
+ "created=today", |
|
| 11 |
+ "image.name=ubuntu*", |
|
| 12 |
+ "image.name=*untu", |
|
| 13 |
+ } |
|
| 14 |
+ var ( |
|
| 15 |
+ args = Args{}
|
|
| 16 |
+ err error |
|
| 17 |
+ ) |
|
| 18 |
+ for i := range flagArgs {
|
|
| 19 |
+ args, err = ParseFlag(flagArgs[i], args) |
|
| 20 |
+ if err != nil {
|
|
| 21 |
+ t.Errorf("failed to parse %s: %s", flagArgs[i], err)
|
|
| 22 |
+ } |
|
| 23 |
+ } |
|
| 24 |
+ if len(args["created"]) != 1 {
|
|
| 25 |
+ t.Errorf("failed to set this arg")
|
|
| 26 |
+ } |
|
| 27 |
+ if len(args["image.name"]) != 2 {
|
|
| 28 |
+ t.Errorf("the args should have collapsed")
|
|
| 29 |
+ } |
|
| 30 |
+} |
|
| 31 |
+ |
|
| 32 |
+func TestParam(t *testing.T) {
|
|
| 33 |
+ a := Args{
|
|
| 34 |
+ "created": []string{"today"},
|
|
| 35 |
+ "image.name": []string{"ubuntu*", "*untu"},
|
|
| 36 |
+ } |
|
| 37 |
+ |
|
| 38 |
+ v := ToParam(a) |
|
| 39 |
+ v1, err := FromParam(v) |
|
| 40 |
+ if err != nil {
|
|
| 41 |
+ t.Errorf("%s", err)
|
|
| 42 |
+ } |
|
| 43 |
+ for key, vals := range v1 {
|
|
| 44 |
+ if _, ok := a[key]; !ok {
|
|
| 45 |
+ t.Errorf("could not find key %s in original set", key)
|
|
| 46 |
+ } |
|
| 47 |
+ sort.Strings(vals) |
|
| 48 |
+ sort.Strings(a[key]) |
|
| 49 |
+ if len(vals) != len(a[key]) {
|
|
| 50 |
+ t.Errorf("value lengths ought to match")
|
|
| 51 |
+ continue |
|
| 52 |
+ } |
|
| 53 |
+ for i := range vals {
|
|
| 54 |
+ if vals[i] != a[key][i] {
|
|
| 55 |
+ t.Errorf("expected %s, but got %s", a[key][i], vals[i])
|
|
| 56 |
+ } |
|
| 57 |
+ } |
|
| 58 |
+ } |
|
| 59 |
+} |