@@ -2770,7 +2770,7 @@ async def compose_up(compose: PodmanCompose, args):
2770
2770
diff_hashes = [i for i in hashes if i and i != compose .yaml_hash ]
2771
2771
if args .force_recreate or len (diff_hashes ):
2772
2772
log .info ("recreating: ..." )
2773
- down_args = argparse .Namespace (** dict (args .__dict__ , volumes = False ))
2773
+ down_args = argparse .Namespace (** dict (args .__dict__ , volumes = False , rmi = None ))
2774
2774
await compose .commands ["down" ](compose , down_args )
2775
2775
log .info ("recreating: done\n \n " )
2776
2776
# args.no_recreate disables check for changes (which is not implemented)
@@ -2810,7 +2810,7 @@ async def handle_sigint():
2810
2810
log .info ("Caught SIGINT or Ctrl+C, shutting down..." )
2811
2811
try :
2812
2812
log .info ("Shutting down gracefully, please wait..." )
2813
- down_args = argparse .Namespace (** dict (args .__dict__ , volumes = False ))
2813
+ down_args = argparse .Namespace (** dict (args .__dict__ , volumes = False , rmi = None ))
2814
2814
await compose .commands ["down" ](compose , down_args )
2815
2815
except Exception as e :
2816
2816
log .error ("Error during shutdown: %s" , e )
@@ -2899,7 +2899,6 @@ async def compose_down(compose: PodmanCompose, args):
2899
2899
containers = list (reversed (compose .containers ))
2900
2900
2901
2901
down_tasks = []
2902
-
2903
2902
for cnt in containers :
2904
2903
if cnt ["_service" ] in excluded :
2905
2904
continue
@@ -2920,8 +2919,10 @@ async def compose_down(compose: PodmanCompose, args):
2920
2919
if cnt ["_service" ] in excluded :
2921
2920
continue
2922
2921
await compose .podman .run ([], "rm" , [cnt ["name" ]])
2922
+
2923
+ orphaned_images = set ()
2923
2924
if args .remove_orphans :
2924
- names = (
2925
+ orphaned_containers = (
2925
2926
(
2926
2927
await compose .podman .output (
2927
2928
[],
@@ -2931,13 +2932,15 @@ async def compose_down(compose: PodmanCompose, args):
2931
2932
f"label=io.podman.compose.project={ compose .project_name } " ,
2932
2933
"-a" ,
2933
2934
"--format" ,
2934
- "{{ .Names }}" ,
2935
+ "{{ .Image }} {{ . Names }}" ,
2935
2936
],
2936
2937
)
2937
2938
)
2938
2939
.decode ("utf-8" )
2939
2940
.splitlines ()
2940
2941
)
2942
+ orphaned_images = {item .split ()[0 ] for item in orphaned_containers }
2943
+ names = {item .split ()[1 ] for item in orphaned_containers }
2941
2944
for name in names :
2942
2945
await compose .podman .run ([], "stop" , [* podman_args , name ])
2943
2946
for name in names :
@@ -2953,6 +2956,17 @@ async def compose_down(compose: PodmanCompose, args):
2953
2956
if volume_name in vol_names_to_keep :
2954
2957
continue
2955
2958
await compose .podman .run ([], "volume" , ["rm" , volume_name ])
2959
+ if args .rmi :
2960
+ images_to_remove = set ()
2961
+ for cnt in containers :
2962
+ if cnt ["_service" ] in excluded :
2963
+ continue
2964
+ if args .rmi == "local" and not is_local (cnt ):
2965
+ continue
2966
+ images_to_remove .add (cnt ["image" ])
2967
+ images_to_remove .update (orphaned_images )
2968
+ log .debug ("images to remove: %s" , images_to_remove )
2969
+ await compose .podman .run ([], "rmi" , ["--ignore" , "--force" ] + list (images_to_remove ))
2956
2970
2957
2971
if excluded :
2958
2972
return
@@ -3455,6 +3469,15 @@ def compose_down_parse(parser):
3455
3469
action = "store_true" ,
3456
3470
help = "Remove containers for services not defined in the Compose file." ,
3457
3471
)
3472
+ parser .add_argument (
3473
+ "--rmi" ,
3474
+ type = str ,
3475
+ nargs = "?" ,
3476
+ const = "all" ,
3477
+ choices = ["local" , "all" ],
3478
+ help = "Remove images used by services. `local` remove only images that don't have a "
3479
+ "custom tag. (`local` or `all`)" ,
3480
+ )
3458
3481
3459
3482
3460
3483
@cmd_parse (podman_compose , "run" )
0 commit comments