@@ -2786,7 +2786,7 @@ async def compose_up(compose: PodmanCompose, args):
2786
2786
diff_hashes = [i for i in hashes if i and i != compose .yaml_hash ]
2787
2787
if args .force_recreate or len (diff_hashes ):
2788
2788
log .info ("recreating: ..." )
2789
- down_args = argparse .Namespace (** dict (args .__dict__ , volumes = False ))
2789
+ down_args = argparse .Namespace (** dict (args .__dict__ , volumes = False , rmi = None ))
2790
2790
await compose .commands ["down" ](compose , down_args )
2791
2791
log .info ("recreating: done\n \n " )
2792
2792
# args.no_recreate disables check for changes (which is not implemented)
@@ -2826,7 +2826,7 @@ async def handle_sigint():
2826
2826
log .info ("Caught SIGINT or Ctrl+C, shutting down..." )
2827
2827
try :
2828
2828
log .info ("Shutting down gracefully, please wait..." )
2829
- down_args = argparse .Namespace (** dict (args .__dict__ , volumes = False ))
2829
+ down_args = argparse .Namespace (** dict (args .__dict__ , volumes = False , rmi = None ))
2830
2830
await compose .commands ["down" ](compose , down_args )
2831
2831
except Exception as e :
2832
2832
log .error ("Error during shutdown: %s" , e )
@@ -2915,7 +2915,6 @@ async def compose_down(compose: PodmanCompose, args):
2915
2915
containers = list (reversed (compose .containers ))
2916
2916
2917
2917
down_tasks = []
2918
-
2919
2918
for cnt in containers :
2920
2919
if cnt ["_service" ] in excluded :
2921
2920
continue
@@ -2936,8 +2935,10 @@ async def compose_down(compose: PodmanCompose, args):
2936
2935
if cnt ["_service" ] in excluded :
2937
2936
continue
2938
2937
await compose .podman .run ([], "rm" , [cnt ["name" ]])
2938
+
2939
+ orphaned_images = set ()
2939
2940
if args .remove_orphans :
2940
- names = (
2941
+ orphaned_containers = (
2941
2942
(
2942
2943
await compose .podman .output (
2943
2944
[],
@@ -2947,13 +2948,15 @@ async def compose_down(compose: PodmanCompose, args):
2947
2948
f"label=io.podman.compose.project={ compose .project_name } " ,
2948
2949
"-a" ,
2949
2950
"--format" ,
2950
- "{{ .Names }}" ,
2951
+ "{{ .Image }} {{ . Names }}" ,
2951
2952
],
2952
2953
)
2953
2954
)
2954
2955
.decode ("utf-8" )
2955
2956
.splitlines ()
2956
2957
)
2958
+ orphaned_images = {item .split ()[0 ] for item in orphaned_containers }
2959
+ names = {item .split ()[1 ] for item in orphaned_containers }
2957
2960
for name in names :
2958
2961
await compose .podman .run ([], "stop" , [* podman_args , name ])
2959
2962
for name in names :
@@ -2969,6 +2972,17 @@ async def compose_down(compose: PodmanCompose, args):
2969
2972
if volume_name in vol_names_to_keep :
2970
2973
continue
2971
2974
await compose .podman .run ([], "volume" , ["rm" , volume_name ])
2975
+ if args .rmi :
2976
+ images_to_remove = set ()
2977
+ for cnt in containers :
2978
+ if cnt ["_service" ] in excluded :
2979
+ continue
2980
+ if args .rmi == "local" and not is_local (cnt ):
2981
+ continue
2982
+ images_to_remove .add (cnt ["image" ])
2983
+ images_to_remove .update (orphaned_images )
2984
+ log .debug ("images to remove: %s" , images_to_remove )
2985
+ await compose .podman .run ([], "rmi" , ["--ignore" , "--force" ] + list (images_to_remove ))
2972
2986
2973
2987
if excluded :
2974
2988
return
@@ -3472,6 +3486,15 @@ def compose_down_parse(parser):
3472
3486
action = "store_true" ,
3473
3487
help = "Remove containers for services not defined in the Compose file." ,
3474
3488
)
3489
+ parser .add_argument (
3490
+ "--rmi" ,
3491
+ type = str ,
3492
+ nargs = "?" ,
3493
+ const = "all" ,
3494
+ choices = ["local" , "all" ],
3495
+ help = "Remove images used by services. `local` remove only images that don't have a "
3496
+ "custom tag. (`local` or `all`)" ,
3497
+ )
3475
3498
3476
3499
3477
3500
@cmd_parse (podman_compose , "run" )
0 commit comments