From 68f9c2305e7ea436d894b646ef06ec8a780d2425 Mon Sep 17 00:00:00 2001 From: Boris Yumankulov Date: Thu, 20 Jun 2024 17:59:09 +0500 Subject: [PATCH] distrobox-rm: add --image/-i for delete container image --- distrobox-rm | 133 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 27 deletions(-) diff --git a/distrobox-rm b/distrobox-rm index b8ed16066b..448a0ebbd5 100755 --- a/distrobox-rm +++ b/distrobox-rm @@ -113,6 +113,8 @@ fi container_name_default="my-distrobox" container_name_list="" +image="0" + # show_help will print usage to stdout. # Arguments: # None @@ -134,6 +136,7 @@ Usage: Options: --all/-a: delete all distroboxes + --image/-i delete container image --force/-f: force deletion --rm-home: remove the mounted home if it differs from the host user's one --root/-r: launch podman/docker/lilipod with root privileges. Note that if you need root this is the preferred @@ -155,7 +158,15 @@ while :; do ;; -a | --all) shift - all=1 + if [ "${image}" -ne 1 ]; then + all=1 + else + printf "--all not supported with --image" + fi + ;; + -i | --image) + shift + image=1 ;; -r | --root) shift @@ -276,7 +287,7 @@ if [ "${all}" -ne 0 ]; then # prepend sudo (or the specified sudo program) if we want our container manager to be rootful # shellcheck disable=SC2086,2248 container_name_list="$("${distrobox_path}"/distrobox-list ${distrobox_flags} --no-color | - tail -n +2 | cut -d'|' -f2 | tr -d ' ' | tr '\n' ' ')" + tail -n +2 | cut -d'|' -f2 | tr -d ' ' | tr '\n' ' ')" fi if [ -z "${container_name_list}" ] && [ "${all}" -ne 0 ]; then @@ -409,47 +420,115 @@ delete_container() fi } -# Prompt for confirmation -if [ "${non_interactive}" -eq 0 ] && [ "${force}" -eq 0 ]; then - printf "Do you really want to delete containers:%s? [Y/n]: " "${container_name_list}" - read -r response - response="${response:-"Y"}" -else - response="yes" -fi +# delete_image will remove input container image +# Arguments: +# image_name: string image name +# Expected global variables: +# container_manager: string container manager to use +# distrobox_flags: string distrobox additional flags +# non_interactive: bool non interactive mode +# force_flag: bool force mode +# verbose: bool verbose +# Expected env variables: +# None +# Outputs: +# None +delete_image() +{ + image_name="$1" + container_name="$(${container_manager} ps -a --filter ancestor="${image_name}" --format "{{.Names}}")" + # Inspect the image we're working with. + image_status="$(${container_manager} inspect --type image "${image_name}" || :)" + # Does the image exist? check if inspect reported errors + if [ -z "${image_status}" ]; then + # If not, prompt to create it first + printf >&2 "Cannot find image %s.\n" "${image_name}" + return + fi -for container in ${container_name_list}; do - if [ "$(${container_manager} inspect --type container --format '{{.State.Status}}' "${container}")" = "running" ]; then - if [ "${non_interactive}" -eq 0 ] && [ "${force}" -eq 0 ]; then - printf "Container %s running, do you want to force delete them? [Y/n]: " "${container_name_list}" - read -r response_force - response_force="${response_force:-"Y"}" - else - response_force="yes" - fi + # Remove the container image + printf "Removing image and containers...\n" + cleanup_exports "${container_name}" + verbose_arg="" + if [ "${verbose}" -ne 0 ]; then + verbose_arg="--verbose" + fi + "$(dirname "$(realpath "${0}")")/distrobox-generate-entry" "${container_name}" --delete "${verbose_arg}" + delete_container "${container_name}" + image_id=$(${container_manager} images -q "${image_name}") + ${container_manager} rmi "${image_id}" "${force_flag}" +} + +if [ "${image}" -eq 0 ]; then + # Prompt for confirmation + if [ "${non_interactive}" -eq 0 ] && [ "${force}" -eq 0 ]; then + printf "Do you really want to delete containers:%s? [Y/n]: " "${container_name_list}" + read -r response + response="${response:-"Y"}" + else + response="yes" fi + for container in ${container_name_list}; do + if [ "$(${container_manager} inspect --type container --format '{{.State.Status}}' "${container}")" = "running" ]; then + if [ "${non_interactive}" -eq 0 ] && [ "${force}" -eq 0 ]; then + printf "Container %s running, do you want to force delete them? [Y/n]: " "${container_name_list}" + read -r response_force + response_force="${response_force:-"Y"}" + else + response_force="yes" + fi + fi + + # Accept only y,Y,Yes,yes,n,N,No,no. + case "${response_force:-"N"}" in + y | Y | Yes | yes | YES) + force=1 + force_flag="--force" + break + ;; + n | N | No | no | NO) ;; + + *) # Default case: If no more options then break out of the loop. + printf >&2 "Invalid input.\n" + printf >&2 "The available choices are: y,Y,Yes,yes,YES or n,N,No,no,NO.\nExiting.\n" + ;; + esac + done + # Accept only y,Y,Yes,yes,n,N,No,no. - case "${response_force:-"N"}" in + case "${response}" in y | Y | Yes | yes | YES) - force=1 - force_flag="--force" - break + for container in ${container_name_list}; do + delete_container "${container}" + done + ;; + n | N | No | no | NO) + printf "Aborted.\n" + exit 0 ;; - n | N | No | no | NO) ;; - *) # Default case: If no more options then break out of the loop. printf >&2 "Invalid input.\n" printf >&2 "The available choices are: y,Y,Yes,yes,YES or n,N,No,no,NO.\nExiting.\n" + exit 1 ;; esac -done +fi + +# Prompt for confirmation +if [ "${non_interactive}" -eq 0 ] && [ "${force}" -eq 0 ]; then + printf "Do you really want to delete containers image:%s? [Y/n]: " "${container_name_list}" + read -r response + response="${response:-"Y"}" +else + response="yes" +fi # Accept only y,Y,Yes,yes,n,N,No,no. case "${response}" in y | Y | Yes | yes | YES) for container in ${container_name_list}; do - delete_container "${container}" + delete_image "${container}" done ;; n | N | No | no | NO)