Browse Source

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 <vincent@sbr.pm>
Vincent Demeester 9 years ago
parent
commit
750e16f57c

+ 11 - 1
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
 			;;

+ 4 - 1
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
                 ;;

+ 31 - 0
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 {

+ 0 - 6
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

+ 1 - 0
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
 

+ 2 - 0
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`=(`<image-name>[:<tag>]`,  `<image id>` or `<image@digest>`)
+  -   `since`=(`<image-name>[:<tag>]`,  `<image id>` or `<image@digest>`)
 -   **filter** - only return images with the specified name
 
 ### Build image from a Dockerfile

+ 46 - 3
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=<key> or label=<key>=<value>
+                           - before=(<image-name>[:tag]|<image-id>|<image@digest>)
+                           - since=(<image-name>[:tag]|<image-id>|<image@digest>)
       --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=<key>` or `label=<key>=<value>`)
+* before (`<image-name>[:<tag>]`,  `<image id>` or `<image@digest>`) - filters images created before given id or references
+* since (`<image-name>[:<tag>]`,  `<image id>` or `<image@digest>`) - 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

+ 69 - 0
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"

+ 5 - 1
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=<key> or label=<key>=<value>
+   - before=(<image-name>[:tag]|<image-id>|<image@digest>)
+   - since=(<image-name>[:tag]|<image-id>|<image@digest>)
 
 **--format**="*TEMPLATE*"
    Pretty-print containers using a Go template.