فهرست منبع

Add a --filter option to `docker search`

The filtering is made server-side, and the following filters are
supported:

* is-official (boolean)
* is-automated (boolean)
* has-stars (integer)

Signed-off-by: Fabrizio Soppelsa <fsoppelsa@mirantis.com>
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Fabrizio Soppelsa 9 سال پیش
والد
کامیت
e009ebdf4c

+ 24 - 2
api/client/search.go

@@ -10,10 +10,12 @@ import (
 	"golang.org/x/net/context"
 
 	Cli "github.com/docker/docker/cli"
+	"github.com/docker/docker/opts"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/stringutils"
 	"github.com/docker/docker/registry"
 	"github.com/docker/engine-api/types"
+	"github.com/docker/engine-api/types/filters"
 	registrytypes "github.com/docker/engine-api/types/registry"
 )
 
@@ -21,14 +23,32 @@ import (
 //
 // Usage: docker search [OPTIONS] TERM
 func (cli *DockerCli) CmdSearch(args ...string) error {
+	var (
+		err error
+
+		filterArgs = filters.NewArgs()
+
+		flFilter = opts.NewListOpts(nil)
+	)
+
 	cmd := Cli.Subcmd("search", []string{"TERM"}, Cli.DockerCommands["search"].Description, true)
 	noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Don't truncate output")
-	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
-	stars := cmd.Uint([]string{"s", "-stars"}, 0, "Only displays with at least x stars")
+	cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
+
+	// Deprecated since Docker 1.12 in favor of "--filter"
+	automated := cmd.Bool([]string{"#-automated"}, false, "Only show automated builds - DEPRECATED")
+	stars := cmd.Uint([]string{"s", "#-stars"}, 0, "Only displays with at least x stars - DEPRECATED")
+
 	cmd.Require(flag.Exact, 1)
 
 	cmd.ParseFlags(args, true)
 
+	for _, f := range flFilter.GetAll() {
+		if filterArgs, err = filters.ParseFlag(f, filterArgs); err != nil {
+			return err
+		}
+	}
+
 	name := cmd.Arg(0)
 	v := url.Values{}
 	v.Set("term", name)
@@ -49,6 +69,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
 	options := types.ImageSearchOptions{
 		RegistryAuth:  encodedAuth,
 		PrivilegeFunc: requestPrivilege,
+		Filters:       filterArgs,
 	}
 
 	unorderedResults, err := cli.client.ImageSearch(context.Background(), name, options)
@@ -62,6 +83,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
 	w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
 	fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n")
 	for _, res := range results {
+		// --automated and -s, --stars are deprecated since Docker 1.12
 		if (*automated && !res.IsAutomated) || (int(*stars) > res.StarCount) {
 			continue
 		}

+ 1 - 1
api/server/router/image/backend.go

@@ -39,5 +39,5 @@ type importExportBackend interface {
 type registryBackend interface {
 	PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
 	PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
-	SearchRegistryForImages(ctx context.Context, term string, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error)
+	SearchRegistryForImages(ctx context.Context, filtersArgs string, term string, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error)
 }

+ 1 - 1
api/server/router/image/image_routes.go

@@ -301,7 +301,7 @@ func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter
 			headers[k] = v
 		}
 	}
-	query, err := s.backend.SearchRegistryForImages(ctx, r.Form.Get("term"), config, headers)
+	query, err := s.backend.SearchRegistryForImages(ctx, r.Form.Get("filters"), r.Form.Get("term"), config, headers)
 	if err != nil {
 		return err
 	}

+ 16 - 2
contrib/completion/bash/docker

@@ -1907,15 +1907,29 @@ _docker_save() {
 }
 
 _docker_search() {
+	local key=$(__docker_map_key_of_current_option '--filter|-f')
+	case "$key" in
+		is-automated)
+			COMPREPLY=( $( compgen -W "false true" -- "${cur##*=}" ) )
+			return
+			;;
+		is-official)
+			COMPREPLY=( $( compgen -W "false true" -- "${cur##*=}" ) )
+			return
+			;;
+	esac
+
 	case "$prev" in
-		--stars|-s)
+		--filter|-f)
+			COMPREPLY=( $( compgen -S = -W "is-automated is-official stars" -- "$cur" ) )
+			__docker_nospace
 			return
 			;;
 	esac
 
 	case "$cur" in
 		-*)
-			COMPREPLY=( $( compgen -W "--automated --help --no-trunc --stars -s" -- "$cur" ) )
+			COMPREPLY=( $( compgen -W "--filter --help --no-trunc" -- "$cur" ) )
 			;;
 	esac
 }

+ 31 - 2
contrib/completion/zsh/_docker

@@ -311,6 +311,30 @@ __docker_complete_ps_filters() {
     return ret
 }
 
+__docker_complete_search_filters() {
+    [[ $PREFIX = -* ]] && return 1
+    integer ret=1
+    declare -a boolean_opts opts
+
+    boolean_opts=('true' 'false')
+    opts=('is-automated' 'is-official' 'stars')
+
+    if compset -P '*='; then
+        case "${${words[-1]%=*}#*=}" in
+            (is-automated|is-official)
+                _describe -t boolean-filter-opts "filter options" boolean_opts && ret=0
+                ;;
+            *)
+                _message 'value' && ret=0
+                ;;
+        esac
+    else
+        _describe -t filter-opts "filter options" opts -qS "=" && ret=0
+    fi
+
+    return ret
+}
+
 __docker_network_complete_ls_filters() {
     [[ $PREFIX = -* ]] && return 1
     integer ret=1
@@ -1126,10 +1150,15 @@ __docker_subcommand() {
         (search)
             _arguments $(__docker_arguments) \
                 $opts_help \
-                "($help)--automated[Only show automated builds]" \
+                "($help)*"{-f=,--filter=}"[Filter values]:filter:->filter-options" \
                 "($help)--no-trunc[Do not truncate output]" \
-                "($help -s --stars)"{-s=,--stars=}"[Only display with at least X stars]:stars:(0 10 100 1000)" \
                 "($help -):term: " && ret=0
+
+            case $state in
+                (filter-options)
+                    __docker_complete_search_filters && ret=0
+                    ;;
+            esac
             ;;
         (start)
             _arguments $(__docker_arguments) \

+ 77 - 2
daemon/daemon.go

@@ -15,6 +15,7 @@ import (
 	"path/filepath"
 	"regexp"
 	"runtime"
+	"strconv"
 	"strings"
 	"sync"
 	"syscall"
@@ -64,6 +65,7 @@ import (
 	volumedrivers "github.com/docker/docker/volume/drivers"
 	"github.com/docker/docker/volume/local"
 	"github.com/docker/docker/volume/store"
+	"github.com/docker/engine-api/types/filters"
 	"github.com/docker/go-connections/nat"
 	"github.com/docker/libnetwork"
 	nwconfig "github.com/docker/libnetwork/config"
@@ -1427,12 +1429,85 @@ func (daemon *Daemon) AuthenticateToRegistry(ctx context.Context, authConfig *ty
 	return daemon.RegistryService.Auth(authConfig, dockerversion.DockerUserAgent(ctx))
 }
 
+var acceptedSearchFilterTags = map[string]bool{
+	"is-automated": true,
+	"is-official":  true,
+	"stars":        true,
+}
+
 // SearchRegistryForImages queries the registry for images matching
 // term. authConfig is used to login.
-func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, term string,
+func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs string, term string,
 	authConfig *types.AuthConfig,
 	headers map[string][]string) (*registrytypes.SearchResults, error) {
-	return daemon.RegistryService.Search(term, authConfig, dockerversion.DockerUserAgent(ctx), headers)
+
+	searchFilters, err := filters.FromParam(filtersArgs)
+	if err != nil {
+		return nil, err
+	}
+	if err := searchFilters.Validate(acceptedSearchFilterTags); err != nil {
+		return nil, err
+	}
+
+	unfilteredResult, err := daemon.RegistryService.Search(term, authConfig, dockerversion.DockerUserAgent(ctx), headers)
+	if err != nil {
+		return nil, err
+	}
+
+	var isAutomated, isOfficial bool
+	var hasStarFilter = 0
+	if searchFilters.Include("is-automated") {
+		if searchFilters.ExactMatch("is-automated", "true") {
+			isAutomated = true
+		} else if !searchFilters.ExactMatch("is-automated", "false") {
+			return nil, fmt.Errorf("Invalid filter 'is-automated=%s'", searchFilters.Get("is-automated"))
+		}
+	}
+	if searchFilters.Include("is-official") {
+		if searchFilters.ExactMatch("is-official", "true") {
+			isOfficial = true
+		} else if !searchFilters.ExactMatch("is-official", "false") {
+			return nil, fmt.Errorf("Invalid filter 'is-official=%s'", searchFilters.Get("is-official"))
+		}
+	}
+	if searchFilters.Include("stars") {
+		hasStars := searchFilters.Get("stars")
+		for _, hasStar := range hasStars {
+			iHasStar, err := strconv.Atoi(hasStar)
+			if err != nil {
+				return nil, fmt.Errorf("Invalid filter 'stars=%s'", hasStar)
+			}
+			if iHasStar > hasStarFilter {
+				hasStarFilter = iHasStar
+			}
+		}
+	}
+
+	filteredResults := []registrytypes.SearchResult{}
+	for _, result := range unfilteredResult.Results {
+		if searchFilters.Include("is-automated") {
+			if isAutomated != result.IsAutomated {
+				continue
+			}
+		}
+		if searchFilters.Include("is-official") {
+			if isOfficial != result.IsOfficial {
+				continue
+			}
+		}
+		if searchFilters.Include("stars") {
+			if result.StarCount < hasStarFilter {
+				continue
+			}
+		}
+		filteredResults = append(filteredResults, result)
+	}
+
+	return &registrytypes.SearchResults{
+		Query:      unfilteredResult.Query,
+		NumResults: len(filteredResults),
+		Results:    filteredResults,
+	}, nil
 }
 
 // IsShuttingDown tells whether the daemon is shutting down or not

+ 9 - 0
docs/deprecated.md

@@ -58,6 +58,15 @@ defining it at container creation (`POST /containers/create`).
 The `docker ps --before` and `docker ps --since` options are deprecated.
 Use `docker ps --filter=before=...` and `docker ps --filter=since=...` instead.
 
+### Docker search 'automated' and 'stars' options
+
+**Deprecated in Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
+
+**Removed In Release: v1.14**
+
+The `docker search --automated` and `docker search --stars` options are deprecated.
+Use `docker search --filter=is-automated=...` and `docker search --filter=stars=...` instead.
+
 ### Command line short variant options
 **Deprecated In Release: v1.9**
 

+ 1 - 0
docs/reference/api/docker_remote_api.md

@@ -118,6 +118,7 @@ This section lists each version from latest to oldest.  Each listing includes a
 * `POST /containers/create` now takes `MaximumIOps` and `MaximumIOBps` fields. Windows daemon only.
 * `POST /containers/create` now returns a HTTP 400 "bad parameter" message
   if no command is specified (instead of a HTTP 500 "server error")
+* `GET /images/search` now takes a `filters` query parameter.
 
 ### v1.23 API changes
 

+ 4 - 0
docs/reference/api/docker_remote_api_v1.24.md

@@ -2133,6 +2133,10 @@ Search for an image on [Docker Hub](https://hub.docker.com).
 Query Parameters:
 
 -   **term** – term to search
+-   **filters** – a JSON encoded value of the filters (a map[string][]string) to process on the images list. Available filters:
+  -   `stars=<number>`
+  -   `is-automated=(true|false)`
+  -   `is-official=(true|false)`
 
 Status Codes:
 

+ 40 - 16
docs/reference/commandline/search.md

@@ -14,10 +14,12 @@ parent = "smn_cli"
 
     Search the Docker Hub for images
 
-      --automated          Only show automated builds
+      --filter=[]          Filter output based on these conditions:
+                           - is-automated=(true|false)
+                           - is-official=(true|false)
+                           - stars=<number> - image has at least 'number' stars
       --help               Print usage
       --no-trunc           Don't truncate output
-      -s, --stars=0        Only displays with at least x stars
 
 Search [Docker Hub](https://hub.docker.com) for images
 
@@ -61,37 +63,59 @@ This example displays images with a name containing 'busybox':
     scottabernethy/busybox                                                           0                    [OK]
     marclop/busybox-solr
 
-### Search images by name and number of stars (-s, --stars)
+### Display non-truncated description (--no-trunc)
+
+This example displays images with a name containing 'busybox',
+at least 3 stars and the description isn't truncated in the output:
+
+    $ docker search --stars=3 --no-trunc busybox
+    NAME                 DESCRIPTION                                                                               STARS     OFFICIAL   AUTOMATED
+    busybox              Busybox base image.                                                                       325       [OK]       
+    progrium/busybox                                                                                               50                   [OK]
+    radial/busyboxplus   Full-chain, Internet enabled, busybox made from scratch. Comes in git and cURL flavors.   8                    [OK]
+
+## Filtering
+
+The filtering flag (`-f` or `--filter`) format is a `key=value` pair. If there is more
+than one filter, then pass multiple flags (e.g. `--filter "foo=bar" --filter "bif=baz"`)
+
+The currently supported filters are:
+
+* stars (int - number of stars the image has)
+* is-automated (true|false) - is the image automated or not
+* is-official (true|false) - is the image official or not
+
+
+### stars
 
 This example displays images with a name containing 'busybox' and at
 least 3 stars:
 
-    $ docker search --stars=3 busybox
+    $ docker search --filter stars=3 busybox
     NAME                 DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
     busybox              Busybox base image.                             325       [OK]       
     progrium/busybox                                                     50                   [OK]
     radial/busyboxplus   Full-chain, Internet enabled, busybox made...   8                    [OK]
 
 
-### Search automated images (--automated)
+### is-automated
 
-This example displays images with a name containing 'busybox', at
-least 3 stars and are automated builds:
+This example displays images with a name containing 'busybox'
+and are automated builds:
 
-    $ docker search --stars=3 --automated busybox
+    $ docker search --filter is-automated busybox
     NAME                 DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
     progrium/busybox                                                     50                   [OK]
     radial/busyboxplus   Full-chain, Internet enabled, busybox made...   8                    [OK]
 
+### is-official
 
-### Display non-truncated description (--no-trunc)
+This example displays images with a name containing 'busybox', at least
+3 stars and are official builds:
 
-This example displays images with a name containing 'busybox',
-at least 3 stars and the description isn't truncated in the output:
+    $ docker search --filter "is-automated=true" --filter "stars=3" busybox
+    NAME                 DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
+    progrium/busybox                                                     50                   [OK]
+    radial/busyboxplus   Full-chain, Internet enabled, busybox made...   8                    [OK]
 
-    $ docker search --stars=3 --no-trunc busybox
-    NAME                 DESCRIPTION                                                                               STARS     OFFICIAL   AUTOMATED
-    busybox              Busybox base image.                                                                       325       [OK]       
-    progrium/busybox                                                                                               50                   [OK]
-    radial/busyboxplus   Full-chain, Internet enabled, busybox made from scratch. Comes in git and cURL flavors.   8                    [OK]
 

+ 49 - 5
integration-cli/docker_cli_search_test.go

@@ -16,34 +16,78 @@ func (s *DockerSuite) TestSearchOnCentralRegistry(c *check.C) {
 }
 
 func (s *DockerSuite) TestSearchStarsOptionWithWrongParameter(c *check.C) {
-	out, _, err := dockerCmdWithError("search", "--stars=a", "busybox")
+	out, _, err := dockerCmdWithError("search", "--filter", "stars=a", "busybox")
+	c.Assert(err, check.NotNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
+
+	out, _, err = dockerCmdWithError("search", "-f", "stars=a", "busybox")
+	c.Assert(err, check.NotNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
+
+	out, _, err = dockerCmdWithError("search", "-f", "is-automated=a", "busybox")
+	c.Assert(err, check.NotNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
+
+	out, _, err = dockerCmdWithError("search", "-f", "is-official=a", "busybox")
+	c.Assert(err, check.NotNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
+
+	// -s --stars deprecated since Docker 1.13
+	out, _, err = dockerCmdWithError("search", "--stars=a", "busybox")
 	c.Assert(err, check.NotNil, check.Commentf(out))
 	c.Assert(out, checker.Contains, "invalid value", check.Commentf("couldn't find the invalid value warning"))
 
+	// -s --stars deprecated since Docker 1.13
 	out, _, err = dockerCmdWithError("search", "-s=-1", "busybox")
 	c.Assert(err, check.NotNil, check.Commentf(out))
 	c.Assert(out, checker.Contains, "invalid value", check.Commentf("couldn't find the invalid value warning"))
 }
 
 func (s *DockerSuite) TestSearchCmdOptions(c *check.C) {
-	testRequires(c, Network)
+	testRequires(c, Network, DaemonIsLinux)
 
 	out, _ := dockerCmd(c, "search", "--help")
 	c.Assert(out, checker.Contains, "Usage:\tdocker search [OPTIONS] TERM")
 
 	outSearchCmd, _ := dockerCmd(c, "search", "busybox")
 	outSearchCmdNotrunc, _ := dockerCmd(c, "search", "--no-trunc=true", "busybox")
+
 	c.Assert(len(outSearchCmd) > len(outSearchCmdNotrunc), check.Equals, false, check.Commentf("The no-trunc option can't take effect."))
 
-	outSearchCmdautomated, _ := dockerCmd(c, "search", "--automated=true", "busybox") //The busybox is a busybox base image, not an AUTOMATED image.
+	outSearchCmdautomated, _ := dockerCmd(c, "search", "--filter", "is-automated=true", "busybox") //The busybox is a busybox base image, not an AUTOMATED image.
 	outSearchCmdautomatedSlice := strings.Split(outSearchCmdautomated, "\n")
 	for i := range outSearchCmdautomatedSlice {
-		c.Assert(strings.HasPrefix(outSearchCmdautomatedSlice[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an AUTOMATED image: %s", out))
+		c.Assert(strings.HasPrefix(outSearchCmdautomatedSlice[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an AUTOMATED image: %s", outSearchCmdautomated))
+	}
+
+	outSearchCmdNotOfficial, _ := dockerCmd(c, "search", "--filter", "is-official=false", "busybox") //The busybox is a busybox base image, official image.
+	outSearchCmdNotOfficialSlice := strings.Split(outSearchCmdNotOfficial, "\n")
+	for i := range outSearchCmdNotOfficialSlice {
+		c.Assert(strings.HasPrefix(outSearchCmdNotOfficialSlice[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an OFFICIAL image: %s", outSearchCmdNotOfficial))
 	}
 
-	outSearchCmdStars, _ := dockerCmd(c, "search", "-s=2", "busybox")
+	outSearchCmdOfficial, _ := dockerCmd(c, "search", "--filter", "is-official=true", "busybox") //The busybox is a busybox base image, official image.
+	outSearchCmdOfficialSlice := strings.Split(outSearchCmdOfficial, "\n")
+	c.Assert(outSearchCmdOfficialSlice, checker.HasLen, 3) // 1 header, 1 line, 1 carriage return
+	c.Assert(strings.HasPrefix(outSearchCmdOfficialSlice[1], "busybox "), check.Equals, true, check.Commentf("The busybox is an OFFICIAL image: %s", outSearchCmdNotOfficial))
+
+	outSearchCmdStars, _ := dockerCmd(c, "search", "--filter", "stars=2", "busybox")
 	c.Assert(strings.Count(outSearchCmdStars, "[OK]") > strings.Count(outSearchCmd, "[OK]"), check.Equals, false, check.Commentf("The quantity of images with stars should be less than that of all images: %s", outSearchCmdStars))
 
+	dockerCmd(c, "search", "--filter", "is-automated=true", "--filter", "stars=2", "--no-trunc=true", "busybox")
+
+	// --automated deprecated since Docker 1.13
+	outSearchCmdautomated1, _ := dockerCmd(c, "search", "--automated=true", "busybox") //The busybox is a busybox base image, not an AUTOMATED image.
+	outSearchCmdautomatedSlice1 := strings.Split(outSearchCmdautomated1, "\n")
+	for i := range outSearchCmdautomatedSlice1 {
+		c.Assert(strings.HasPrefix(outSearchCmdautomatedSlice1[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an AUTOMATED image: %s", outSearchCmdautomated))
+	}
+
+	// -s --stars deprecated since Docker 1.13
+	outSearchCmdStars1, _ := dockerCmd(c, "search", "--stars=2", "busybox")
+	c.Assert(strings.Count(outSearchCmdStars1, "[OK]") > strings.Count(outSearchCmd, "[OK]"), check.Equals, false, check.Commentf("The quantity of images with stars should be less than that of all images: %s", outSearchCmdStars1))
+
+	// -s --stars deprecated since Docker 1.13
 	dockerCmd(c, "search", "--stars=2", "--automated=true", "--no-trunc=true", "busybox")
 }
 

+ 10 - 9
man/docker-search.1.md

@@ -6,10 +6,9 @@ docker-search - Search the Docker Hub for images
 
 # SYNOPSIS
 **docker search**
-[**--automated**]
+[**-f**|**--filter**[=*[]*]]
 [**--help**]
 [**--no-trunc**]
-[**-s**|**--stars**[=*0*]]
 TERM
 
 # DESCRIPTION
@@ -21,8 +20,12 @@ of stars awarded, whether the image is official, and whether it is automated.
 *Note* - Search queries will only return up to 25 results
 
 # OPTIONS
-**--automated**=*true*|*false*
-   Only show automated builds. The default is *false*.
+
+**-f**, **--filter**=[]
+   Filter output based on these conditions:
+   - stars=<numberOfStar>
+   - is-automated=(true|false)
+   - is-official=(true|false)
 
 **--help**
   Print usage statement
@@ -30,9 +33,6 @@ of stars awarded, whether the image is official, and whether it is automated.
 **--no-trunc**=*true*|*false*
    Don't truncate output. The default is *false*.
 
-**-s**, **--stars**=*X*
-   Only displays with at least X stars. The default is zero.
-
 # EXAMPLES
 
 ## Search Docker Hub for ranked images
@@ -40,7 +40,7 @@ of stars awarded, whether the image is official, and whether it is automated.
 Search a registry for the term 'fedora' and only display those images
 ranked 3 or higher:
 
-    $ docker search -s 3 fedora
+    $ docker search --filter=stars=3 fedora
     NAME                  DESCRIPTION                                    STARS OFFICIAL  AUTOMATED
     mattdm/fedora         A basic Fedora image corresponding roughly...  50
     fedora                (Semi) Official Fedora base image.             38
@@ -52,7 +52,7 @@ ranked 3 or higher:
 Search Docker Hub for the term 'fedora' and only display automated images
 ranked 1 or higher:
 
-    $ docker search --automated -s 1 fedora
+    $ docker search --filter=is-automated=true --filter=stars=1 fedora
     NAME               DESCRIPTION                                     STARS OFFICIAL  AUTOMATED
     goldmann/wildfly   A WildFly application server running on a ...   3               [OK]
     tutum/fedora-20    Fedora 20 image with SSH access. For the r...   1               [OK]
@@ -62,4 +62,5 @@ April 2014, Originally compiled by William Henry (whenry at redhat dot com)
 based on docker.com source material and internal work.
 June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
 April 2015, updated by Mary Anthony for v2 <mary@docker.com>
+April 2016, updated by Vincent Demeester <vincent@sbr.pm>