@@ -15,6 +15,7 @@ import (
1515 "path/filepath"
1616 "regexp"
1717 "runtime"
18+ "strconv"
1819 "strings"
1920 "sync"
2021 "syscall"
@@ -64,6 +65,7 @@ import (
6465 volumedrivers "github.com/docker/docker/volume/drivers"
6566 "github.com/docker/docker/volume/local"
6667 "github.com/docker/docker/volume/store"
68+ "github.com/docker/engine-api/types/filters"
6769 "github.com/docker/go-connections/nat"
6870 "github.com/docker/libnetwork"
6971 nwconfig "github.com/docker/libnetwork/config"
@@ -1427,12 +1429,85 @@ func (daemon *Daemon) AuthenticateToRegistry(ctx context.Context, authConfig *ty
14271429 return daemon .RegistryService .Auth (authConfig , dockerversion .DockerUserAgent (ctx ))
14281430}
14291431
1432+ var acceptedSearchFilterTags = map [string ]bool {
1433+ "is-automated" : true ,
1434+ "is-official" : true ,
1435+ "stars" : true ,
1436+ }
1437+
14301438// SearchRegistryForImages queries the registry for images matching
14311439// term. authConfig is used to login.
1432- func (daemon * Daemon ) SearchRegistryForImages (ctx context.Context , term string ,
1440+ func (daemon * Daemon ) SearchRegistryForImages (ctx context.Context , filtersArgs string , term string ,
14331441 authConfig * types.AuthConfig ,
14341442 headers map [string ][]string ) (* registrytypes.SearchResults , error ) {
1435- return daemon .RegistryService .Search (term , authConfig , dockerversion .DockerUserAgent (ctx ), headers )
1443+
1444+ searchFilters , err := filters .FromParam (filtersArgs )
1445+ if err != nil {
1446+ return nil , err
1447+ }
1448+ if err := searchFilters .Validate (acceptedSearchFilterTags ); err != nil {
1449+ return nil , err
1450+ }
1451+
1452+ unfilteredResult , err := daemon .RegistryService .Search (term , authConfig , dockerversion .DockerUserAgent (ctx ), headers )
1453+ if err != nil {
1454+ return nil , err
1455+ }
1456+
1457+ var isAutomated , isOfficial bool
1458+ var hasStarFilter = 0
1459+ if searchFilters .Include ("is-automated" ) {
1460+ if searchFilters .ExactMatch ("is-automated" , "true" ) {
1461+ isAutomated = true
1462+ } else if ! searchFilters .ExactMatch ("is-automated" , "false" ) {
1463+ return nil , fmt .Errorf ("Invalid filter 'is-automated=%s'" , searchFilters .Get ("is-automated" ))
1464+ }
1465+ }
1466+ if searchFilters .Include ("is-official" ) {
1467+ if searchFilters .ExactMatch ("is-official" , "true" ) {
1468+ isOfficial = true
1469+ } else if ! searchFilters .ExactMatch ("is-official" , "false" ) {
1470+ return nil , fmt .Errorf ("Invalid filter 'is-official=%s'" , searchFilters .Get ("is-official" ))
1471+ }
1472+ }
1473+ if searchFilters .Include ("stars" ) {
1474+ hasStars := searchFilters .Get ("stars" )
1475+ for _ , hasStar := range hasStars {
1476+ iHasStar , err := strconv .Atoi (hasStar )
1477+ if err != nil {
1478+ return nil , fmt .Errorf ("Invalid filter 'stars=%s'" , hasStar )
1479+ }
1480+ if iHasStar > hasStarFilter {
1481+ hasStarFilter = iHasStar
1482+ }
1483+ }
1484+ }
1485+
1486+ filteredResults := []registrytypes.SearchResult {}
1487+ for _ , result := range unfilteredResult .Results {
1488+ if searchFilters .Include ("is-automated" ) {
1489+ if isAutomated != result .IsAutomated {
1490+ continue
1491+ }
1492+ }
1493+ if searchFilters .Include ("is-official" ) {
1494+ if isOfficial != result .IsOfficial {
1495+ continue
1496+ }
1497+ }
1498+ if searchFilters .Include ("stars" ) {
1499+ if result .StarCount < hasStarFilter {
1500+ continue
1501+ }
1502+ }
1503+ filteredResults = append (filteredResults , result )
1504+ }
1505+
1506+ return & registrytypes.SearchResults {
1507+ Query : unfilteredResult .Query ,
1508+ NumResults : len (filteredResults ),
1509+ Results : filteredResults ,
1510+ }, nil
14361511}
14371512
14381513// IsShuttingDown tells whether the daemon is shutting down or not
0 commit comments