Implement rmi argument for down command

Fixes #387

Signed-off-by: Frank Stettner <frank-stettner@gmx.net>
This commit is contained in:
Frank Stettner 2025-04-07 08:04:11 +02:00
parent c46ecb226b
commit cefa68dc75
2 changed files with 29 additions and 5 deletions

View File

@ -0,0 +1 @@
- Add the `--rmi` argument to the `down` command to remove images.

View File

@ -2770,7 +2770,7 @@ async def compose_up(compose: PodmanCompose, args):
diff_hashes = [i for i in hashes if i and i != compose.yaml_hash] diff_hashes = [i for i in hashes if i and i != compose.yaml_hash]
if args.force_recreate or len(diff_hashes): if args.force_recreate or len(diff_hashes):
log.info("recreating: ...") log.info("recreating: ...")
down_args = argparse.Namespace(**dict(args.__dict__, volumes=False)) down_args = argparse.Namespace(**dict(args.__dict__, volumes=False, rmi=None))
await compose.commands["down"](compose, down_args) await compose.commands["down"](compose, down_args)
log.info("recreating: done\n\n") log.info("recreating: done\n\n")
# args.no_recreate disables check for changes (which is not implemented) # args.no_recreate disables check for changes (which is not implemented)
@ -2810,7 +2810,7 @@ async def compose_up(compose: PodmanCompose, args):
log.info("Caught SIGINT or Ctrl+C, shutting down...") log.info("Caught SIGINT or Ctrl+C, shutting down...")
try: try:
log.info("Shutting down gracefully, please wait...") log.info("Shutting down gracefully, please wait...")
down_args = argparse.Namespace(**dict(args.__dict__, volumes=False)) down_args = argparse.Namespace(**dict(args.__dict__, volumes=False, rmi=None))
await compose.commands["down"](compose, down_args) await compose.commands["down"](compose, down_args)
except Exception as e: except Exception as e:
log.error("Error during shutdown: %s", e) log.error("Error during shutdown: %s", e)
@ -2899,7 +2899,6 @@ async def compose_down(compose: PodmanCompose, args):
containers = list(reversed(compose.containers)) containers = list(reversed(compose.containers))
down_tasks = [] down_tasks = []
for cnt in containers: for cnt in containers:
if cnt["_service"] in excluded: if cnt["_service"] in excluded:
continue continue
@ -2920,8 +2919,10 @@ async def compose_down(compose: PodmanCompose, args):
if cnt["_service"] in excluded: if cnt["_service"] in excluded:
continue continue
await compose.podman.run([], "rm", [cnt["name"]]) await compose.podman.run([], "rm", [cnt["name"]])
orphaned_images = set()
if args.remove_orphans: if args.remove_orphans:
names = ( orphaned_containers = (
( (
await compose.podman.output( await compose.podman.output(
[], [],
@ -2931,13 +2932,15 @@ async def compose_down(compose: PodmanCompose, args):
f"label=io.podman.compose.project={compose.project_name}", f"label=io.podman.compose.project={compose.project_name}",
"-a", "-a",
"--format", "--format",
"{{ .Names }}", "{{ .Image }} {{ .Names }}",
], ],
) )
) )
.decode("utf-8") .decode("utf-8")
.splitlines() .splitlines()
) )
orphaned_images = {item.split()[0] for item in orphaned_containers}
names = {item.split()[1] for item in orphaned_containers}
for name in names: for name in names:
await compose.podman.run([], "stop", [*podman_args, name]) await compose.podman.run([], "stop", [*podman_args, name])
for name in names: for name in names:
@ -2953,6 +2956,17 @@ async def compose_down(compose: PodmanCompose, args):
if volume_name in vol_names_to_keep: if volume_name in vol_names_to_keep:
continue continue
await compose.podman.run([], "volume", ["rm", volume_name]) await compose.podman.run([], "volume", ["rm", volume_name])
if args.rmi:
images_to_remove = set()
for cnt in containers:
if cnt["_service"] in excluded:
continue
if args.rmi == "local" and not is_local(cnt):
continue
images_to_remove.add(cnt["image"])
images_to_remove.update(orphaned_images)
log.debug("images to remove: %s", images_to_remove)
await compose.podman.run([], "rmi", ["--ignore", "--force"] + list(images_to_remove))
if excluded: if excluded:
return return
@ -3455,6 +3469,15 @@ def compose_down_parse(parser):
action="store_true", action="store_true",
help="Remove containers for services not defined in the Compose file.", help="Remove containers for services not defined in the Compose file.",
) )
parser.add_argument(
"--rmi",
type=str,
nargs="?",
const="all",
choices=["local", "all"],
help="Remove images used by services. `local` remove only images that don't have a "
"custom tag. (`local` or `all`)",
)
@cmd_parse(podman_compose, "run") @cmd_parse(podman_compose, "run")