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>
| ... | ... |
@@ -10,10 +10,12 @@ import ( |
| 10 | 10 |
"golang.org/x/net/context" |
| 11 | 11 |
|
| 12 | 12 |
Cli "github.com/docker/docker/cli" |
| 13 |
+ "github.com/docker/docker/opts" |
|
| 13 | 14 |
flag "github.com/docker/docker/pkg/mflag" |
| 14 | 15 |
"github.com/docker/docker/pkg/stringutils" |
| 15 | 16 |
"github.com/docker/docker/registry" |
| 16 | 17 |
"github.com/docker/engine-api/types" |
| 18 |
+ "github.com/docker/engine-api/types/filters" |
|
| 17 | 19 |
registrytypes "github.com/docker/engine-api/types/registry" |
| 18 | 20 |
) |
| 19 | 21 |
|
| ... | ... |
@@ -21,14 +23,32 @@ import ( |
| 21 | 21 |
// |
| 22 | 22 |
// Usage: docker search [OPTIONS] TERM |
| 23 | 23 |
func (cli *DockerCli) CmdSearch(args ...string) error {
|
| 24 |
+ var ( |
|
| 25 |
+ err error |
|
| 26 |
+ |
|
| 27 |
+ filterArgs = filters.NewArgs() |
|
| 28 |
+ |
|
| 29 |
+ flFilter = opts.NewListOpts(nil) |
|
| 30 |
+ ) |
|
| 31 |
+ |
|
| 24 | 32 |
cmd := Cli.Subcmd("search", []string{"TERM"}, Cli.DockerCommands["search"].Description, true)
|
| 25 | 33 |
noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Don't truncate output")
|
| 26 |
- automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
|
|
| 27 |
- stars := cmd.Uint([]string{"s", "-stars"}, 0, "Only displays with at least x stars")
|
|
| 34 |
+ cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
|
|
| 35 |
+ |
|
| 36 |
+ // Deprecated since Docker 1.12 in favor of "--filter" |
|
| 37 |
+ automated := cmd.Bool([]string{"#-automated"}, false, "Only show automated builds - DEPRECATED")
|
|
| 38 |
+ stars := cmd.Uint([]string{"s", "#-stars"}, 0, "Only displays with at least x stars - DEPRECATED")
|
|
| 39 |
+ |
|
| 28 | 40 |
cmd.Require(flag.Exact, 1) |
| 29 | 41 |
|
| 30 | 42 |
cmd.ParseFlags(args, true) |
| 31 | 43 |
|
| 44 |
+ for _, f := range flFilter.GetAll() {
|
|
| 45 |
+ if filterArgs, err = filters.ParseFlag(f, filterArgs); err != nil {
|
|
| 46 |
+ return err |
|
| 47 |
+ } |
|
| 48 |
+ } |
|
| 49 |
+ |
|
| 32 | 50 |
name := cmd.Arg(0) |
| 33 | 51 |
v := url.Values{}
|
| 34 | 52 |
v.Set("term", name)
|
| ... | ... |
@@ -49,6 +69,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
|
| 49 | 49 |
options := types.ImageSearchOptions{
|
| 50 | 50 |
RegistryAuth: encodedAuth, |
| 51 | 51 |
PrivilegeFunc: requestPrivilege, |
| 52 |
+ Filters: filterArgs, |
|
| 52 | 53 |
} |
| 53 | 54 |
|
| 54 | 55 |
unorderedResults, err := cli.client.ImageSearch(context.Background(), name, options) |
| ... | ... |
@@ -62,6 +83,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
|
| 62 | 62 |
w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0) |
| 63 | 63 |
fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n") |
| 64 | 64 |
for _, res := range results {
|
| 65 |
+ // --automated and -s, --stars are deprecated since Docker 1.12 |
|
| 65 | 66 |
if (*automated && !res.IsAutomated) || (int(*stars) > res.StarCount) {
|
| 66 | 67 |
continue |
| 67 | 68 |
} |
| ... | ... |
@@ -39,5 +39,5 @@ type importExportBackend interface {
|
| 39 | 39 |
type registryBackend interface {
|
| 40 | 40 |
PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
| 41 | 41 |
PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
| 42 |
- SearchRegistryForImages(ctx context.Context, term string, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error) |
|
| 42 |
+ SearchRegistryForImages(ctx context.Context, filtersArgs string, term string, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error) |
|
| 43 | 43 |
} |
| ... | ... |
@@ -301,7 +301,7 @@ func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter |
| 301 | 301 |
headers[k] = v |
| 302 | 302 |
} |
| 303 | 303 |
} |
| 304 |
- query, err := s.backend.SearchRegistryForImages(ctx, r.Form.Get("term"), config, headers)
|
|
| 304 |
+ query, err := s.backend.SearchRegistryForImages(ctx, r.Form.Get("filters"), r.Form.Get("term"), config, headers)
|
|
| 305 | 305 |
if err != nil {
|
| 306 | 306 |
return err |
| 307 | 307 |
} |
| ... | ... |
@@ -1907,15 +1907,29 @@ _docker_save() {
|
| 1907 | 1907 |
} |
| 1908 | 1908 |
|
| 1909 | 1909 |
_docker_search() {
|
| 1910 |
+ local key=$(__docker_map_key_of_current_option '--filter|-f') |
|
| 1911 |
+ case "$key" in |
|
| 1912 |
+ is-automated) |
|
| 1913 |
+ COMPREPLY=( $( compgen -W "false true" -- "${cur##*=}" ) )
|
|
| 1914 |
+ return |
|
| 1915 |
+ ;; |
|
| 1916 |
+ is-official) |
|
| 1917 |
+ COMPREPLY=( $( compgen -W "false true" -- "${cur##*=}" ) )
|
|
| 1918 |
+ return |
|
| 1919 |
+ ;; |
|
| 1920 |
+ esac |
|
| 1921 |
+ |
|
| 1910 | 1922 |
case "$prev" in |
| 1911 |
- --stars|-s) |
|
| 1923 |
+ --filter|-f) |
|
| 1924 |
+ COMPREPLY=( $( compgen -S = -W "is-automated is-official stars" -- "$cur" ) ) |
|
| 1925 |
+ __docker_nospace |
|
| 1912 | 1926 |
return |
| 1913 | 1927 |
;; |
| 1914 | 1928 |
esac |
| 1915 | 1929 |
|
| 1916 | 1930 |
case "$cur" in |
| 1917 | 1931 |
-*) |
| 1918 |
- COMPREPLY=( $( compgen -W "--automated --help --no-trunc --stars -s" -- "$cur" ) ) |
|
| 1932 |
+ COMPREPLY=( $( compgen -W "--filter --help --no-trunc" -- "$cur" ) ) |
|
| 1919 | 1933 |
;; |
| 1920 | 1934 |
esac |
| 1921 | 1935 |
} |
| ... | ... |
@@ -311,6 +311,30 @@ __docker_complete_ps_filters() {
|
| 311 | 311 |
return ret |
| 312 | 312 |
} |
| 313 | 313 |
|
| 314 |
+__docker_complete_search_filters() {
|
|
| 315 |
+ [[ $PREFIX = -* ]] && return 1 |
|
| 316 |
+ integer ret=1 |
|
| 317 |
+ declare -a boolean_opts opts |
|
| 318 |
+ |
|
| 319 |
+ boolean_opts=('true' 'false')
|
|
| 320 |
+ opts=('is-automated' 'is-official' 'stars')
|
|
| 321 |
+ |
|
| 322 |
+ if compset -P '*='; then |
|
| 323 |
+ case "${${words[-1]%=*}#*=}" in
|
|
| 324 |
+ (is-automated|is-official) |
|
| 325 |
+ _describe -t boolean-filter-opts "filter options" boolean_opts && ret=0 |
|
| 326 |
+ ;; |
|
| 327 |
+ *) |
|
| 328 |
+ _message 'value' && ret=0 |
|
| 329 |
+ ;; |
|
| 330 |
+ esac |
|
| 331 |
+ else |
|
| 332 |
+ _describe -t filter-opts "filter options" opts -qS "=" && ret=0 |
|
| 333 |
+ fi |
|
| 334 |
+ |
|
| 335 |
+ return ret |
|
| 336 |
+} |
|
| 337 |
+ |
|
| 314 | 338 |
__docker_network_complete_ls_filters() {
|
| 315 | 339 |
[[ $PREFIX = -* ]] && return 1 |
| 316 | 340 |
integer ret=1 |
| ... | ... |
@@ -1126,10 +1150,15 @@ __docker_subcommand() {
|
| 1126 | 1126 |
(search) |
| 1127 | 1127 |
_arguments $(__docker_arguments) \ |
| 1128 | 1128 |
$opts_help \ |
| 1129 |
- "($help)--automated[Only show automated builds]" \ |
|
| 1129 |
+ "($help)*"{-f=,--filter=}"[Filter values]:filter:->filter-options" \
|
|
| 1130 | 1130 |
"($help)--no-trunc[Do not truncate output]" \ |
| 1131 |
- "($help -s --stars)"{-s=,--stars=}"[Only display with at least X stars]:stars:(0 10 100 1000)" \
|
|
| 1132 | 1131 |
"($help -):term: " && ret=0 |
| 1132 |
+ |
|
| 1133 |
+ case $state in |
|
| 1134 |
+ (filter-options) |
|
| 1135 |
+ __docker_complete_search_filters && ret=0 |
|
| 1136 |
+ ;; |
|
| 1137 |
+ esac |
|
| 1133 | 1138 |
;; |
| 1134 | 1139 |
(start) |
| 1135 | 1140 |
_arguments $(__docker_arguments) \ |
| ... | ... |
@@ -15,6 +15,7 @@ import ( |
| 15 | 15 |
"path/filepath" |
| 16 | 16 |
"regexp" |
| 17 | 17 |
"runtime" |
| 18 |
+ "strconv" |
|
| 18 | 19 |
"strings" |
| 19 | 20 |
"sync" |
| 20 | 21 |
"syscall" |
| ... | ... |
@@ -64,6 +65,7 @@ import ( |
| 64 | 64 |
volumedrivers "github.com/docker/docker/volume/drivers" |
| 65 | 65 |
"github.com/docker/docker/volume/local" |
| 66 | 66 |
"github.com/docker/docker/volume/store" |
| 67 |
+ "github.com/docker/engine-api/types/filters" |
|
| 67 | 68 |
"github.com/docker/go-connections/nat" |
| 68 | 69 |
"github.com/docker/libnetwork" |
| 69 | 70 |
nwconfig "github.com/docker/libnetwork/config" |
| ... | ... |
@@ -1427,12 +1429,85 @@ func (daemon *Daemon) AuthenticateToRegistry(ctx context.Context, authConfig *ty |
| 1427 | 1427 |
return daemon.RegistryService.Auth(authConfig, dockerversion.DockerUserAgent(ctx)) |
| 1428 | 1428 |
} |
| 1429 | 1429 |
|
| 1430 |
+var acceptedSearchFilterTags = map[string]bool{
|
|
| 1431 |
+ "is-automated": true, |
|
| 1432 |
+ "is-official": true, |
|
| 1433 |
+ "stars": true, |
|
| 1434 |
+} |
|
| 1435 |
+ |
|
| 1430 | 1436 |
// SearchRegistryForImages queries the registry for images matching |
| 1431 | 1437 |
// term. authConfig is used to login. |
| 1432 |
-func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, term string, |
|
| 1438 |
+func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs string, term string, |
|
| 1433 | 1439 |
authConfig *types.AuthConfig, |
| 1434 | 1440 |
headers map[string][]string) (*registrytypes.SearchResults, error) {
|
| 1435 |
- return daemon.RegistryService.Search(term, authConfig, dockerversion.DockerUserAgent(ctx), headers) |
|
| 1441 |
+ |
|
| 1442 |
+ searchFilters, err := filters.FromParam(filtersArgs) |
|
| 1443 |
+ if err != nil {
|
|
| 1444 |
+ return nil, err |
|
| 1445 |
+ } |
|
| 1446 |
+ if err := searchFilters.Validate(acceptedSearchFilterTags); err != nil {
|
|
| 1447 |
+ return nil, err |
|
| 1448 |
+ } |
|
| 1449 |
+ |
|
| 1450 |
+ unfilteredResult, err := daemon.RegistryService.Search(term, authConfig, dockerversion.DockerUserAgent(ctx), headers) |
|
| 1451 |
+ if err != nil {
|
|
| 1452 |
+ return nil, err |
|
| 1453 |
+ } |
|
| 1454 |
+ |
|
| 1455 |
+ var isAutomated, isOfficial bool |
|
| 1456 |
+ var hasStarFilter = 0 |
|
| 1457 |
+ if searchFilters.Include("is-automated") {
|
|
| 1458 |
+ if searchFilters.ExactMatch("is-automated", "true") {
|
|
| 1459 |
+ isAutomated = true |
|
| 1460 |
+ } else if !searchFilters.ExactMatch("is-automated", "false") {
|
|
| 1461 |
+ return nil, fmt.Errorf("Invalid filter 'is-automated=%s'", searchFilters.Get("is-automated"))
|
|
| 1462 |
+ } |
|
| 1463 |
+ } |
|
| 1464 |
+ if searchFilters.Include("is-official") {
|
|
| 1465 |
+ if searchFilters.ExactMatch("is-official", "true") {
|
|
| 1466 |
+ isOfficial = true |
|
| 1467 |
+ } else if !searchFilters.ExactMatch("is-official", "false") {
|
|
| 1468 |
+ return nil, fmt.Errorf("Invalid filter 'is-official=%s'", searchFilters.Get("is-official"))
|
|
| 1469 |
+ } |
|
| 1470 |
+ } |
|
| 1471 |
+ if searchFilters.Include("stars") {
|
|
| 1472 |
+ hasStars := searchFilters.Get("stars")
|
|
| 1473 |
+ for _, hasStar := range hasStars {
|
|
| 1474 |
+ iHasStar, err := strconv.Atoi(hasStar) |
|
| 1475 |
+ if err != nil {
|
|
| 1476 |
+ return nil, fmt.Errorf("Invalid filter 'stars=%s'", hasStar)
|
|
| 1477 |
+ } |
|
| 1478 |
+ if iHasStar > hasStarFilter {
|
|
| 1479 |
+ hasStarFilter = iHasStar |
|
| 1480 |
+ } |
|
| 1481 |
+ } |
|
| 1482 |
+ } |
|
| 1483 |
+ |
|
| 1484 |
+ filteredResults := []registrytypes.SearchResult{}
|
|
| 1485 |
+ for _, result := range unfilteredResult.Results {
|
|
| 1486 |
+ if searchFilters.Include("is-automated") {
|
|
| 1487 |
+ if isAutomated != result.IsAutomated {
|
|
| 1488 |
+ continue |
|
| 1489 |
+ } |
|
| 1490 |
+ } |
|
| 1491 |
+ if searchFilters.Include("is-official") {
|
|
| 1492 |
+ if isOfficial != result.IsOfficial {
|
|
| 1493 |
+ continue |
|
| 1494 |
+ } |
|
| 1495 |
+ } |
|
| 1496 |
+ if searchFilters.Include("stars") {
|
|
| 1497 |
+ if result.StarCount < hasStarFilter {
|
|
| 1498 |
+ continue |
|
| 1499 |
+ } |
|
| 1500 |
+ } |
|
| 1501 |
+ filteredResults = append(filteredResults, result) |
|
| 1502 |
+ } |
|
| 1503 |
+ |
|
| 1504 |
+ return ®istrytypes.SearchResults{
|
|
| 1505 |
+ Query: unfilteredResult.Query, |
|
| 1506 |
+ NumResults: len(filteredResults), |
|
| 1507 |
+ Results: filteredResults, |
|
| 1508 |
+ }, nil |
|
| 1436 | 1509 |
} |
| 1437 | 1510 |
|
| 1438 | 1511 |
// IsShuttingDown tells whether the daemon is shutting down or not |
| ... | ... |
@@ -58,6 +58,15 @@ defining it at container creation (`POST /containers/create`). |
| 58 | 58 |
The `docker ps --before` and `docker ps --since` options are deprecated. |
| 59 | 59 |
Use `docker ps --filter=before=...` and `docker ps --filter=since=...` instead. |
| 60 | 60 |
|
| 61 |
+### Docker search 'automated' and 'stars' options |
|
| 62 |
+ |
|
| 63 |
+**Deprecated in Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)** |
|
| 64 |
+ |
|
| 65 |
+**Removed In Release: v1.14** |
|
| 66 |
+ |
|
| 67 |
+The `docker search --automated` and `docker search --stars` options are deprecated. |
|
| 68 |
+Use `docker search --filter=is-automated=...` and `docker search --filter=stars=...` instead. |
|
| 69 |
+ |
|
| 61 | 70 |
### Command line short variant options |
| 62 | 71 |
**Deprecated In Release: v1.9** |
| 63 | 72 |
|
| ... | ... |
@@ -118,6 +118,7 @@ This section lists each version from latest to oldest. Each listing includes a |
| 118 | 118 |
* `POST /containers/create` now takes `MaximumIOps` and `MaximumIOBps` fields. Windows daemon only. |
| 119 | 119 |
* `POST /containers/create` now returns a HTTP 400 "bad parameter" message |
| 120 | 120 |
if no command is specified (instead of a HTTP 500 "server error") |
| 121 |
+* `GET /images/search` now takes a `filters` query parameter. |
|
| 121 | 122 |
|
| 122 | 123 |
### v1.23 API changes |
| 123 | 124 |
|
| ... | ... |
@@ -2133,6 +2133,10 @@ Search for an image on [Docker Hub](https://hub.docker.com). |
| 2133 | 2133 |
Query Parameters: |
| 2134 | 2134 |
|
| 2135 | 2135 |
- **term** – term to search |
| 2136 |
+- **filters** – a JSON encoded value of the filters (a map[string][]string) to process on the images list. Available filters: |
|
| 2137 |
+ - `stars=<number>` |
|
| 2138 |
+ - `is-automated=(true|false)` |
|
| 2139 |
+ - `is-official=(true|false)` |
|
| 2136 | 2140 |
|
| 2137 | 2141 |
Status Codes: |
| 2138 | 2142 |
|
| ... | ... |
@@ -14,10 +14,12 @@ parent = "smn_cli" |
| 14 | 14 |
|
| 15 | 15 |
Search the Docker Hub for images |
| 16 | 16 |
|
| 17 |
- --automated Only show automated builds |
|
| 17 |
+ --filter=[] Filter output based on these conditions: |
|
| 18 |
+ - is-automated=(true|false) |
|
| 19 |
+ - is-official=(true|false) |
|
| 20 |
+ - stars=<number> - image has at least 'number' stars |
|
| 18 | 21 |
--help Print usage |
| 19 | 22 |
--no-trunc Don't truncate output |
| 20 |
- -s, --stars=0 Only displays with at least x stars |
|
| 21 | 23 |
|
| 22 | 24 |
Search [Docker Hub](https://hub.docker.com) for images |
| 23 | 25 |
|
| ... | ... |
@@ -61,37 +63,59 @@ This example displays images with a name containing 'busybox': |
| 61 | 61 |
scottabernethy/busybox 0 [OK] |
| 62 | 62 |
marclop/busybox-solr |
| 63 | 63 |
|
| 64 |
-### Search images by name and number of stars (-s, --stars) |
|
| 64 |
+### Display non-truncated description (--no-trunc) |
|
| 65 |
+ |
|
| 66 |
+This example displays images with a name containing 'busybox', |
|
| 67 |
+at least 3 stars and the description isn't truncated in the output: |
|
| 68 |
+ |
|
| 69 |
+ $ docker search --stars=3 --no-trunc busybox |
|
| 70 |
+ NAME DESCRIPTION STARS OFFICIAL AUTOMATED |
|
| 71 |
+ busybox Busybox base image. 325 [OK] |
|
| 72 |
+ progrium/busybox 50 [OK] |
|
| 73 |
+ radial/busyboxplus Full-chain, Internet enabled, busybox made from scratch. Comes in git and cURL flavors. 8 [OK] |
|
| 74 |
+ |
|
| 75 |
+## Filtering |
|
| 76 |
+ |
|
| 77 |
+The filtering flag (`-f` or `--filter`) format is a `key=value` pair. If there is more |
|
| 78 |
+than one filter, then pass multiple flags (e.g. `--filter "foo=bar" --filter "bif=baz"`) |
|
| 79 |
+ |
|
| 80 |
+The currently supported filters are: |
|
| 81 |
+ |
|
| 82 |
+* stars (int - number of stars the image has) |
|
| 83 |
+* is-automated (true|false) - is the image automated or not |
|
| 84 |
+* is-official (true|false) - is the image official or not |
|
| 85 |
+ |
|
| 86 |
+ |
|
| 87 |
+### stars |
|
| 65 | 88 |
|
| 66 | 89 |
This example displays images with a name containing 'busybox' and at |
| 67 | 90 |
least 3 stars: |
| 68 | 91 |
|
| 69 |
- $ docker search --stars=3 busybox |
|
| 92 |
+ $ docker search --filter stars=3 busybox |
|
| 70 | 93 |
NAME DESCRIPTION STARS OFFICIAL AUTOMATED |
| 71 | 94 |
busybox Busybox base image. 325 [OK] |
| 72 | 95 |
progrium/busybox 50 [OK] |
| 73 | 96 |
radial/busyboxplus Full-chain, Internet enabled, busybox made... 8 [OK] |
| 74 | 97 |
|
| 75 | 98 |
|
| 76 |
-### Search automated images (--automated) |
|
| 99 |
+### is-automated |
|
| 77 | 100 |
|
| 78 |
-This example displays images with a name containing 'busybox', at |
|
| 79 |
-least 3 stars and are automated builds: |
|
| 101 |
+This example displays images with a name containing 'busybox' |
|
| 102 |
+and are automated builds: |
|
| 80 | 103 |
|
| 81 |
- $ docker search --stars=3 --automated busybox |
|
| 104 |
+ $ docker search --filter is-automated busybox |
|
| 82 | 105 |
NAME DESCRIPTION STARS OFFICIAL AUTOMATED |
| 83 | 106 |
progrium/busybox 50 [OK] |
| 84 | 107 |
radial/busyboxplus Full-chain, Internet enabled, busybox made... 8 [OK] |
| 85 | 108 |
|
| 109 |
+### is-official |
|
| 86 | 110 |
|
| 87 |
-### Display non-truncated description (--no-trunc) |
|
| 111 |
+This example displays images with a name containing 'busybox', at least |
|
| 112 |
+3 stars and are official builds: |
|
| 88 | 113 |
|
| 89 |
-This example displays images with a name containing 'busybox', |
|
| 90 |
-at least 3 stars and the description isn't truncated in the output: |
|
| 114 |
+ $ docker search --filter "is-automated=true" --filter "stars=3" busybox |
|
| 115 |
+ NAME DESCRIPTION STARS OFFICIAL AUTOMATED |
|
| 116 |
+ progrium/busybox 50 [OK] |
|
| 117 |
+ radial/busyboxplus Full-chain, Internet enabled, busybox made... 8 [OK] |
|
| 91 | 118 |
|
| 92 |
- $ docker search --stars=3 --no-trunc busybox |
|
| 93 |
- NAME DESCRIPTION STARS OFFICIAL AUTOMATED |
|
| 94 |
- busybox Busybox base image. 325 [OK] |
|
| 95 |
- progrium/busybox 50 [OK] |
|
| 96 |
- radial/busyboxplus Full-chain, Internet enabled, busybox made from scratch. Comes in git and cURL flavors. 8 [OK] |
|
| 97 | 119 |
|
| ... | ... |
@@ -16,34 +16,78 @@ func (s *DockerSuite) TestSearchOnCentralRegistry(c *check.C) {
|
| 16 | 16 |
} |
| 17 | 17 |
|
| 18 | 18 |
func (s *DockerSuite) TestSearchStarsOptionWithWrongParameter(c *check.C) {
|
| 19 |
- out, _, err := dockerCmdWithError("search", "--stars=a", "busybox")
|
|
| 19 |
+ out, _, err := dockerCmdWithError("search", "--filter", "stars=a", "busybox")
|
|
| 20 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 21 |
+ c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
|
|
| 22 |
+ |
|
| 23 |
+ out, _, err = dockerCmdWithError("search", "-f", "stars=a", "busybox")
|
|
| 24 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 25 |
+ c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
|
|
| 26 |
+ |
|
| 27 |
+ out, _, err = dockerCmdWithError("search", "-f", "is-automated=a", "busybox")
|
|
| 28 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 29 |
+ c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
|
|
| 30 |
+ |
|
| 31 |
+ out, _, err = dockerCmdWithError("search", "-f", "is-official=a", "busybox")
|
|
| 32 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 33 |
+ c.Assert(out, checker.Contains, "Invalid filter", check.Commentf("couldn't find the invalid filter warning"))
|
|
| 34 |
+ |
|
| 35 |
+ // -s --stars deprecated since Docker 1.13 |
|
| 36 |
+ out, _, err = dockerCmdWithError("search", "--stars=a", "busybox")
|
|
| 20 | 37 |
c.Assert(err, check.NotNil, check.Commentf(out)) |
| 21 | 38 |
c.Assert(out, checker.Contains, "invalid value", check.Commentf("couldn't find the invalid value warning"))
|
| 22 | 39 |
|
| 40 |
+ // -s --stars deprecated since Docker 1.13 |
|
| 23 | 41 |
out, _, err = dockerCmdWithError("search", "-s=-1", "busybox")
|
| 24 | 42 |
c.Assert(err, check.NotNil, check.Commentf(out)) |
| 25 | 43 |
c.Assert(out, checker.Contains, "invalid value", check.Commentf("couldn't find the invalid value warning"))
|
| 26 | 44 |
} |
| 27 | 45 |
|
| 28 | 46 |
func (s *DockerSuite) TestSearchCmdOptions(c *check.C) {
|
| 29 |
- testRequires(c, Network) |
|
| 47 |
+ testRequires(c, Network, DaemonIsLinux) |
|
| 30 | 48 |
|
| 31 | 49 |
out, _ := dockerCmd(c, "search", "--help") |
| 32 | 50 |
c.Assert(out, checker.Contains, "Usage:\tdocker search [OPTIONS] TERM") |
| 33 | 51 |
|
| 34 | 52 |
outSearchCmd, _ := dockerCmd(c, "search", "busybox") |
| 35 | 53 |
outSearchCmdNotrunc, _ := dockerCmd(c, "search", "--no-trunc=true", "busybox") |
| 54 |
+ |
|
| 36 | 55 |
c.Assert(len(outSearchCmd) > len(outSearchCmdNotrunc), check.Equals, false, check.Commentf("The no-trunc option can't take effect."))
|
| 37 | 56 |
|
| 38 |
- outSearchCmdautomated, _ := dockerCmd(c, "search", "--automated=true", "busybox") //The busybox is a busybox base image, not an AUTOMATED image. |
|
| 57 |
+ outSearchCmdautomated, _ := dockerCmd(c, "search", "--filter", "is-automated=true", "busybox") //The busybox is a busybox base image, not an AUTOMATED image. |
|
| 39 | 58 |
outSearchCmdautomatedSlice := strings.Split(outSearchCmdautomated, "\n") |
| 40 | 59 |
for i := range outSearchCmdautomatedSlice {
|
| 41 |
- c.Assert(strings.HasPrefix(outSearchCmdautomatedSlice[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an AUTOMATED image: %s", out))
|
|
| 60 |
+ c.Assert(strings.HasPrefix(outSearchCmdautomatedSlice[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an AUTOMATED image: %s", outSearchCmdautomated))
|
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ outSearchCmdNotOfficial, _ := dockerCmd(c, "search", "--filter", "is-official=false", "busybox") //The busybox is a busybox base image, official image. |
|
| 64 |
+ outSearchCmdNotOfficialSlice := strings.Split(outSearchCmdNotOfficial, "\n") |
|
| 65 |
+ for i := range outSearchCmdNotOfficialSlice {
|
|
| 66 |
+ c.Assert(strings.HasPrefix(outSearchCmdNotOfficialSlice[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an OFFICIAL image: %s", outSearchCmdNotOfficial))
|
|
| 42 | 67 |
} |
| 43 | 68 |
|
| 44 |
- outSearchCmdStars, _ := dockerCmd(c, "search", "-s=2", "busybox") |
|
| 69 |
+ outSearchCmdOfficial, _ := dockerCmd(c, "search", "--filter", "is-official=true", "busybox") //The busybox is a busybox base image, official image. |
|
| 70 |
+ outSearchCmdOfficialSlice := strings.Split(outSearchCmdOfficial, "\n") |
|
| 71 |
+ c.Assert(outSearchCmdOfficialSlice, checker.HasLen, 3) // 1 header, 1 line, 1 carriage return |
|
| 72 |
+ c.Assert(strings.HasPrefix(outSearchCmdOfficialSlice[1], "busybox "), check.Equals, true, check.Commentf("The busybox is an OFFICIAL image: %s", outSearchCmdNotOfficial))
|
|
| 73 |
+ |
|
| 74 |
+ outSearchCmdStars, _ := dockerCmd(c, "search", "--filter", "stars=2", "busybox") |
|
| 45 | 75 |
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))
|
| 46 | 76 |
|
| 77 |
+ dockerCmd(c, "search", "--filter", "is-automated=true", "--filter", "stars=2", "--no-trunc=true", "busybox") |
|
| 78 |
+ |
|
| 79 |
+ // --automated deprecated since Docker 1.13 |
|
| 80 |
+ outSearchCmdautomated1, _ := dockerCmd(c, "search", "--automated=true", "busybox") //The busybox is a busybox base image, not an AUTOMATED image. |
|
| 81 |
+ outSearchCmdautomatedSlice1 := strings.Split(outSearchCmdautomated1, "\n") |
|
| 82 |
+ for i := range outSearchCmdautomatedSlice1 {
|
|
| 83 |
+ c.Assert(strings.HasPrefix(outSearchCmdautomatedSlice1[i], "busybox "), check.Equals, false, check.Commentf("The busybox is not an AUTOMATED image: %s", outSearchCmdautomated))
|
|
| 84 |
+ } |
|
| 85 |
+ |
|
| 86 |
+ // -s --stars deprecated since Docker 1.13 |
|
| 87 |
+ outSearchCmdStars1, _ := dockerCmd(c, "search", "--stars=2", "busybox") |
|
| 88 |
+ 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))
|
|
| 89 |
+ |
|
| 90 |
+ // -s --stars deprecated since Docker 1.13 |
|
| 47 | 91 |
dockerCmd(c, "search", "--stars=2", "--automated=true", "--no-trunc=true", "busybox") |
| 48 | 92 |
} |
| 49 | 93 |
|
| ... | ... |
@@ -6,10 +6,9 @@ docker-search - Search the Docker Hub for images |
| 6 | 6 |
|
| 7 | 7 |
# SYNOPSIS |
| 8 | 8 |
**docker search** |
| 9 |
-[**--automated**] |
|
| 9 |
+[**-f**|**--filter**[=*[]*]] |
|
| 10 | 10 |
[**--help**] |
| 11 | 11 |
[**--no-trunc**] |
| 12 |
-[**-s**|**--stars**[=*0*]] |
|
| 13 | 12 |
TERM |
| 14 | 13 |
|
| 15 | 14 |
# DESCRIPTION |
| ... | ... |
@@ -21,8 +20,12 @@ of stars awarded, whether the image is official, and whether it is automated. |
| 21 | 21 |
*Note* - Search queries will only return up to 25 results |
| 22 | 22 |
|
| 23 | 23 |
# OPTIONS |
| 24 |
-**--automated**=*true*|*false* |
|
| 25 |
- Only show automated builds. The default is *false*. |
|
| 24 |
+ |
|
| 25 |
+**-f**, **--filter**=[] |
|
| 26 |
+ Filter output based on these conditions: |
|
| 27 |
+ - stars=<numberOfStar> |
|
| 28 |
+ - is-automated=(true|false) |
|
| 29 |
+ - is-official=(true|false) |
|
| 26 | 30 |
|
| 27 | 31 |
**--help** |
| 28 | 32 |
Print usage statement |
| ... | ... |
@@ -30,9 +33,6 @@ of stars awarded, whether the image is official, and whether it is automated. |
| 30 | 30 |
**--no-trunc**=*true*|*false* |
| 31 | 31 |
Don't truncate output. The default is *false*. |
| 32 | 32 |
|
| 33 |
-**-s**, **--stars**=*X* |
|
| 34 |
- Only displays with at least X stars. The default is zero. |
|
| 35 |
- |
|
| 36 | 33 |
# EXAMPLES |
| 37 | 34 |
|
| 38 | 35 |
## Search Docker Hub for ranked images |
| ... | ... |
@@ -40,7 +40,7 @@ of stars awarded, whether the image is official, and whether it is automated. |
| 40 | 40 |
Search a registry for the term 'fedora' and only display those images |
| 41 | 41 |
ranked 3 or higher: |
| 42 | 42 |
|
| 43 |
- $ docker search -s 3 fedora |
|
| 43 |
+ $ docker search --filter=stars=3 fedora |
|
| 44 | 44 |
NAME DESCRIPTION STARS OFFICIAL AUTOMATED |
| 45 | 45 |
mattdm/fedora A basic Fedora image corresponding roughly... 50 |
| 46 | 46 |
fedora (Semi) Official Fedora base image. 38 |
| ... | ... |
@@ -52,7 +52,7 @@ ranked 3 or higher: |
| 52 | 52 |
Search Docker Hub for the term 'fedora' and only display automated images |
| 53 | 53 |
ranked 1 or higher: |
| 54 | 54 |
|
| 55 |
- $ docker search --automated -s 1 fedora |
|
| 55 |
+ $ docker search --filter=is-automated=true --filter=stars=1 fedora |
|
| 56 | 56 |
NAME DESCRIPTION STARS OFFICIAL AUTOMATED |
| 57 | 57 |
goldmann/wildfly A WildFly application server running on a ... 3 [OK] |
| 58 | 58 |
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) |
| 62 | 62 |
based on docker.com source material and internal work. |
| 63 | 63 |
June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au> |
| 64 | 64 |
April 2015, updated by Mary Anthony for v2 <mary@docker.com> |
| 65 |
+April 2016, updated by Vincent Demeester <vincent@sbr.pm> |
|
| 65 | 66 |
|