@@ -14,6 +14,8 @@ import (
1414 "github.com/containers/common/pkg/util"
1515 "github.com/containers/podman/v5/libpod"
1616 "github.com/containers/podman/v5/libpod/define"
17+ "github.com/containers/podman/v5/pkg/domain/entities/types"
18+ "github.com/containers/storage"
1719)
1820
1921// GenerateContainerFilterFuncs return ContainerFilter functions based of filter.
@@ -282,6 +284,10 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
282284 }
283285 return false
284286 }, filterValueError
287+ case "command" :
288+ return func (c * libpod.Container ) bool {
289+ return util .StringMatchRegexSlice (c .Command ()[0 ], filterValues )
290+ }, nil
285291 }
286292 return nil , fmt .Errorf ("%s is an invalid filter" , filter )
287293}
@@ -315,3 +321,112 @@ func prepareUntilFilterFunc(filterValues []string) (func(container *libpod.Conta
315321 return false
316322 }, nil
317323}
324+
325+ // GenerateContainerFilterFuncs return ContainerFilter functions based of filter.
326+ func GenerateExternalContainerFilterFuncs (filter string , filterValues []string , r * libpod.Runtime ) (func (listContainer * types.ListContainer ) bool , error ) {
327+ switch filter {
328+ case "id" :
329+ return func (listContainer * types.ListContainer ) bool {
330+ return filters .FilterID (listContainer .Id (), filterValues )
331+ }, nil
332+ case "name" :
333+ // we only have to match one name
334+ return func (listContainer * types.ListContainer ) bool {
335+ namesList := listContainer .NamesList ()
336+
337+ for _ , f := range filterValues {
338+ f = strings .ReplaceAll (f , "/" , "" )
339+ if util .StringMatchRegexSlice (f , namesList ) {
340+ return true
341+ }
342+ }
343+
344+ return false
345+ }, nil
346+ case "command" :
347+ return func (listContainer * types.ListContainer ) bool {
348+ return util .StringMatchRegexSlice (listContainer .Commands ()[0 ], filterValues )
349+ }, nil
350+ case "ancestor" :
351+ // This needs to refine to match docker
352+ // - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
353+ return func (listContainer * types.ListContainer ) bool {
354+ for _ , filterValue := range filterValues {
355+ rootfsImageID , rootfsImageName := listContainer .ImageInfo ()
356+ var imageTag string
357+ var imageNameWithoutTag string
358+ // Compare with ImageID, ImageName
359+ // Will match ImageName if running image has tag latest for other tags exact complete filter must be given
360+ name , tag , hasColon := strings .Cut (rootfsImageName , ":" )
361+ if hasColon {
362+ imageNameWithoutTag = name
363+ imageTag = tag
364+ }
365+
366+ if (rootfsImageID == filterValue ) ||
367+ util .StringMatchRegexSlice (rootfsImageName , filterValues ) ||
368+ (util .StringMatchRegexSlice (imageNameWithoutTag , filterValues ) && imageTag == "latest" ) {
369+ return true
370+ }
371+ }
372+ return false
373+ }, nil
374+ case "before" :
375+ var createTime time.Time
376+ var externCons []storage.Container
377+ externCons , err := r .StorageContainers ()
378+ if err != nil {
379+ return nil , err
380+ }
381+
382+ for _ , filterValue := range filterValues {
383+ for _ , ctr := range externCons {
384+ if slices .Contains (ctr .Names , filterValue ) {
385+ if createTime .IsZero () || createTime .After (ctr .Created ) {
386+ createTime = ctr .Created
387+ }
388+ }
389+ }
390+ }
391+
392+ return func (listContainer * types.ListContainer ) bool {
393+ return createTime .After (listContainer .CreatedTime ())
394+ }, nil
395+ case "since" :
396+ var createTime time.Time
397+ var externCons []storage.Container
398+ externCons , err := r .StorageContainers ()
399+ if err != nil {
400+ return nil , err
401+ }
402+
403+ for _ , filterValue := range filterValues {
404+ for _ , ctr := range externCons {
405+ if slices .Contains (ctr .Names , filterValue ) {
406+ if createTime .IsZero () || createTime .After (ctr .Created ) {
407+ createTime = ctr .Created
408+ }
409+ }
410+ }
411+ }
412+
413+ return func (listContainer * types.ListContainer ) bool {
414+ return createTime .Before (listContainer .CreatedTime ())
415+ }, nil
416+ case "until" :
417+ until , err := filters .ComputeUntilTimestamp (filterValues )
418+ if err != nil {
419+ return nil , err
420+ }
421+ return func (listContainer * types.ListContainer ) bool {
422+ if ! until .IsZero () && listContainer .CreatedTime ().Before (until ) {
423+ return true
424+ }
425+ return false
426+ }, nil
427+ case "restart-policy" , "network" , "pod" , "volume" , "health" , "label" , "exited" , "status" :
428+ return nil , fmt .Errorf ("filter %s is not applicable for external containers" , filter )
429+ }
430+
431+ return nil , fmt .Errorf ("%s is an invalid filter" , filter )
432+ }
0 commit comments