From 750e16f57c0121aa8cdad1763f0bb6e54b8c6d75 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Wed, 25 May 2016 13:49:10 +0200 Subject: [PATCH] Add before and since filter to images Add support for two now filter on the `images` command : `before` and `since`. They work the same as the one on the `ps` command but for images. $ docker images --filter before=myimage # display all images older than myimage $ docker images --filter since=myimage # display all images younger than myimage Signed-off-by: Vincent Demeester --- contrib/completion/bash/docker | 12 +++- contrib/completion/zsh/_docker | 5 +- daemon/images.go | 31 +++++++++ daemon/list.go | 6 -- docs/reference/api/docker_remote_api.md | 1 + docs/reference/api/docker_remote_api_v1.24.md | 2 + docs/reference/commandline/images.md | 49 ++++++++++++- integration-cli/docker_cli_images_test.go | 69 +++++++++++++++++++ man/docker-images.1.md | 6 +- 9 files changed, 169 insertions(+), 12 deletions(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index 7652c91cce..4f60da7a49 100644 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -1104,6 +1104,11 @@ _docker_history() { _docker_images() { local key=$(__docker_map_key_of_current_option '--filter|-f') case "$key" in + before) + cur="${cur##*=}" + __docker_complete_images + return + ;; dangling) COMPREPLY=( $( compgen -W "false true" -- "${cur##*=}" ) ) return @@ -1111,11 +1116,16 @@ _docker_images() { label) return ;; + since) + cur="${cur##*=}" + __docker_complete_images + return + ;; esac case "$prev" in --filter|-f) - COMPREPLY=( $( compgen -S = -W "dangling label" -- "$cur" ) ) + COMPREPLY=( $( compgen -S = -W "before dangling label since" -- "$cur" ) ) __docker_nospace return ;; diff --git a/contrib/completion/zsh/_docker b/contrib/completion/zsh/_docker index 2132fe8722..8ac3e7fe49 100644 --- a/contrib/completion/zsh/_docker +++ b/contrib/completion/zsh/_docker @@ -341,10 +341,13 @@ __docker_complete_images_filters() { declare -a boolean_opts opts boolean_opts=('true' 'false') - opts=('dangling' 'label') + opts=('before' 'dangling' 'label' 'since') if compset -P '*='; then case "${${words[-1]%=*}#*=}" in + (before|since) + __docker_images && ret=0 + ;; (dangling) _describe -t boolean-filter-opts "filter options" boolean_opts && ret=0 ;; diff --git a/daemon/images.go b/daemon/images.go index e4c3797f6d..52dc67508b 100644 --- a/daemon/images.go +++ b/daemon/images.go @@ -15,6 +15,8 @@ import ( var acceptedImageFilterTags = map[string]bool{ "dangling": true, "label": true, + "before": true, + "since": true, } // byCreated is a temporary type used to sort a list of images by creation @@ -63,6 +65,23 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag allImages = daemon.imageStore.Map() } + var beforeFilter, sinceFilter *image.Image + err = imageFilters.WalkValues("before", func(value string) error { + beforeFilter, err = daemon.GetImage(value) + return err + }) + if err != nil { + return nil, err + } + + err = imageFilters.WalkValues("since", func(value string) error { + sinceFilter, err = daemon.GetImage(value) + return err + }) + if err != nil { + return nil, err + } + images := []*types.Image{} var filterTagged bool @@ -76,6 +95,18 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag } for id, img := range allImages { + if beforeFilter != nil { + if img.Created.Equal(beforeFilter.Created) || img.Created.After(beforeFilter.Created) { + continue + } + } + + if sinceFilter != nil { + if img.Created.Equal(sinceFilter.Created) || img.Created.Before(sinceFilter.Created) { + continue + } + } + if imageFilters.Include("label") { // Very old image that do not have image.Config (or even labels) if img.Config == nil { diff --git a/daemon/list.go b/daemon/list.go index 655ef6204a..ed596faddf 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -75,12 +75,6 @@ type listContext struct { // exitAllowed is a list of exit codes allowed to filter with exitAllowed []int - // FIXME Remove this for 1.12 as --since and --before are deprecated - // beforeContainer is a filter to ignore containers that appear before the one given - beforeContainer *container.Container - // sinceContainer is a filter to stop the filtering when the iterator arrive to the given container - sinceContainer *container.Container - // beforeFilter is a filter to ignore containers that appear before the one given // this is used for --filter=before= and --before=, the latter is deprecated. beforeFilter *container.Container diff --git a/docs/reference/api/docker_remote_api.md b/docs/reference/api/docker_remote_api.md index 626485effa..675d94bf34 100644 --- a/docs/reference/api/docker_remote_api.md +++ b/docs/reference/api/docker_remote_api.md @@ -121,6 +121,7 @@ This section lists each version from latest to oldest. Each listing includes a * `GET /images/search` now takes a `filters` query parameter. * `GET /events` now supports a `reload` event that is emitted when the daemon configuration is reloaded. * `GET /events` now supports filtering by daemon name or ID. +* `GET /images/json` now supports filters `since` and `before`. ### v1.23 API changes diff --git a/docs/reference/api/docker_remote_api_v1.24.md b/docs/reference/api/docker_remote_api_v1.24.md index b7d67d0f29..8d355e4d2e 100644 --- a/docs/reference/api/docker_remote_api_v1.24.md +++ b/docs/reference/api/docker_remote_api_v1.24.md @@ -1628,6 +1628,8 @@ Query Parameters: - **filters** – a JSON encoded value of the filters (a map[string][]string) to process on the images list. Available filters: - `dangling=true` - `label=key` or `label="key=value"` of an image label + - `before`=(`[:]`, `` or ``) + - `since`=(`[:]`, `` or ``) - **filter** - only return images with the specified name ### Build image from a Dockerfile diff --git a/docs/reference/commandline/images.md b/docs/reference/commandline/images.md index 9ab97684c4..b9f80980b0 100644 --- a/docs/reference/commandline/images.md +++ b/docs/reference/commandline/images.md @@ -16,7 +16,11 @@ parent = "smn_cli" -a, --all Show all images (default hides intermediate images) --digests Show digests - -f, --filter=[] Filter output based on conditions provided + -f, --filter=[] Filter output based on these conditions: + - dangling=(true|false) + - label= or label== + - before=([:tag]||) + - since=([:tag]||) --help Print usage --no-trunc Don't truncate output -q, --quiet Only show numeric IDs @@ -121,6 +125,8 @@ The currently supported filters are: * dangling (boolean - true or false) * label (`label=` or `label==`) +* before (`[:]`, `` or ``) - filters images created before given id or references +* since (`[:]`, `` or ``) - filters images created since given id or references ##### Untagged images (dangling) @@ -165,19 +171,56 @@ The following filter matches images with the `com.example.version` label regardl REPOSITORY TAG IMAGE ID CREATED SIZE match-me-1 latest eeae25ada2aa About a minute ago 188.3 MB - match-me-2 latest eeae25ada2aa About a minute ago 188.3 MB + match-me-2 latest dea752e4e117 About a minute ago 188.3 MB The following filter matches images with the `com.example.version` label with the `1.0` value. $ docker images --filter "label=com.example.version=1.0" REPOSITORY TAG IMAGE ID CREATED SIZE - match-me latest eeae25ada2aa About a minute ago 188.3 MB + match-me latest 511136ea3c5a About a minute ago 188.3 MB In this example, with the `0.1` value, it returns an empty set because no matches were found. $ docker images --filter "label=com.example.version=0.1" REPOSITORY TAG IMAGE ID CREATED SIZE +#### Before + +The `before` filter shows only images created before the image with +given id or reference. For example, having these images: + + $ docker images + REPOSITORY TAG IMAGE ID CREATED SIZE + image1 latest eeae25ada2aa 4 minutes ago 188.3 MB + image2 latest dea752e4e117 9 minutes ago 188.3 MB + image3 latest 511136ea3c5a 25 minutes ago 188.3 MB + +Filtering with `before` would give: + + $ docker images --filter "before=image1" + REPOSITORY TAG IMAGE ID CREATED SIZE + image2 latest dea752e4e117 9 minutes ago 188.3 MB + image3 latest 511136ea3c5a 25 minutes ago 188.3 MB + +#### Since + +The `since` filter shows only images created after the image with +given id or reference. For example, having these images: + + $ docker images + REPOSITORY TAG IMAGE ID CREATED SIZE + image1 latest eeae25ada2aa 4 minutes ago 188.3 MB + image2 latest dea752e4e117 9 minutes ago 188.3 MB + image3 latest 511136ea3c5a 25 minutes ago 188.3 MB + +Filtering with `since` would give: + + $ docker images --filter "since=image3" + REPOSITORY TAG IMAGE ID CREATED SIZE + image1 latest eeae25ada2aa 4 minutes ago 188.3 MB + image2 latest dea752e4e117 9 minutes ago 188.3 MB + + ## Formatting The formatting option (`--format`) will pretty print container output diff --git a/integration-cli/docker_cli_images_test.go b/integration-cli/docker_cli_images_test.go index dbceddf14e..7d390699db 100644 --- a/integration-cli/docker_cli_images_test.go +++ b/integration-cli/docker_cli_images_test.go @@ -121,6 +121,75 @@ func (s *DockerSuite) TestImagesFilterLabelWithCommit(c *check.C) { c.Assert(out, check.Equals, imageID) } +func (s *DockerSuite) TestImagesFilterSinceAndBefore(c *check.C) { + imageID1, err := buildImage("image:1", `FROM `+minimalBaseImage()+` +LABEL number=1`, true) + c.Assert(err, checker.IsNil) + imageID2, err := buildImage("image:2", `FROM `+minimalBaseImage()+` +LABEL number=2`, true) + c.Assert(err, checker.IsNil) + imageID3, err := buildImage("image:3", `FROM `+minimalBaseImage()+` +LABEL number=3`, true) + c.Assert(err, checker.IsNil) + + expected := []string{imageID3, imageID2} + + out, _ := dockerCmd(c, "images", "-f", "since=image:1", "image") + c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out)) + + out, _ = dockerCmd(c, "images", "-f", "since="+imageID1, "image") + c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out)) + + expected = []string{imageID3} + + out, _ = dockerCmd(c, "images", "-f", "since=image:2", "image") + c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out)) + + out, _ = dockerCmd(c, "images", "-f", "since="+imageID2, "image") + c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Image list is not in the correct order: %v\n%s", expected, out)) + + expected = []string{imageID2, imageID1} + + out, _ = dockerCmd(c, "images", "-f", "before=image:3", "image") + c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out)) + + out, _ = dockerCmd(c, "images", "-f", "before="+imageID3, "image") + c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out)) + + expected = []string{imageID1} + + out, _ = dockerCmd(c, "images", "-f", "before=image:2", "image") + c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out)) + + out, _ = dockerCmd(c, "images", "-f", "before="+imageID2, "image") + c.Assert(assertImageList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Image list is not in the correct order: %v\n%s", expected, out)) +} + +func assertImageList(out string, expected []string) bool { + lines := strings.Split(strings.Trim(out, "\n "), "\n") + + if len(lines)-1 != len(expected) { + return false + } + + imageIDIndex := strings.Index(lines[0], "IMAGE ID") + for i := 0; i < len(expected); i++ { + imageID := lines[i+1][imageIDIndex : imageIDIndex+12] + found := false + for _, e := range expected { + if imageID == e[7:19] { + found = true + break + } + } + if !found { + return false + } + } + + return true +} + func (s *DockerSuite) TestImagesFilterSpaceTrimCase(c *check.C) { testRequires(c, DaemonIsLinux) imageName := "images_filter_test" diff --git a/man/docker-images.1.md b/man/docker-images.1.md index 8410280a1d..fd551a58db 100644 --- a/man/docker-images.1.md +++ b/man/docker-images.1.md @@ -38,7 +38,11 @@ versions. Show image digests. The default is *false*. **-f**, **--filter**=[] - Filters the output. The dangling=true filter finds unused images. While label=com.foo=amd64 filters for images with a com.foo value of amd64. The label=com.foo filter finds images with the label com.foo of any value. + Filters the output based on these conditions: + - dangling=(true|false) - finds unused images. + - label= or label== + - before=([:tag]||) + - since=([:tag]||) **--format**="*TEMPLATE*" Pretty-print containers using a Go template.