@@ -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