Skip to content

Instantly share code, notes, and snippets.

@FriendlyNeighborhoodShane
Last active October 18, 2022 01:25
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FriendlyNeighborhoodShane/41593680b39c0c04cd82b5497ca25a26 to your computer and use it in GitHub Desktop.
Save FriendlyNeighborhoodShane/41593680b39c0c04cd82b5497ca25a26 to your computer and use it in GitHub Desktop.
Recursive package dependency removal tool for kisslinux
#!/bin/sh -e
# Interactively and recursively remove packages with dependencies
# Check if terminal is interactive
[ -t 1 ] || {
echo "error: launched in non-interactive environment";
exit 1;
}
# Check if all given packages are installed
[ "$*" ] && kiss list "$@" >/dev/null || {
echo "usage: [kiss-rmdeps [pkg]...]";
exit 1;
}
# Conditionally use sexy kiss-accurate colors for prompts
if [ "$KISS_COLOR" != "0" ]; then
col0="$(printf "\033[m")";
col1="$(printf "\033[1;33m")";
col2="$(printf "\033[1;34m")";
else
col0="";
col1="";
col2="";
fi;
prompt="${col1}->${col0}";
# Check if $1 is an item in space-separated list $2
is_item() {
case "$2" in
"$1"|"$1 "*|*" $1 "*|*" $1")
return 0;
;;
esac;
return 1;
}
cd "$KISS_ROOT/var/db/kiss/installed";
# List of packages explicitly marked for keeping
keep="";
count=0;
# Keep looping until we stop marking new items to be removed (in $@)
while [ "$#" != "$count" ]; do
count="$#";
# Find all of the dependencies of explicitly marked packages
# They are all candidates for removal
deps="$(
for pkg in "$@"; do
cat "./$pkg/depends" 2>/dev/null;
done | awk '{ print $1 }' | sort -u | grep -v "#" || true;
)";
for pkg in $deps; do
# Check if candidate has been marked for removal already
is_item "$pkg" "$*" && continue;
# Check if candidate has been marked for keeping already
is_item "$pkg" "$keep" && continue;
# Find all dependants of the candidate
dependant="";
for revdep in $(grep "^$pkg" -- ./*/depends | awk '{ print $1 }'); do
# Strip grep candy
revdep="${revdep##./}";
revdep="${revdep%%/depends*}";
# Check if dependant is also marked for removal
is_item "$revdep" "$*" || {
dependant="yes";
break;
}
done;
# If depended on by packages not being removed, can't mark for removal
# But don't explicitly mark for keeping either
# The dependants that retain it may themselves be marked for removal later
[ "$dependant" = "yes" ] && continue;
# We ignore a missing package
# Could be a maketime dep or a broken tree
# Either way, we don't want kiss to error out in between
kiss list "$pkg" >/dev/null 2>/dev/null || continue;
# The candidate will be orphaned when everything marked until now is removed
# So it is possible to remove it
# But it may be a package the user actually needs (a user-facing package)
# Ask the only one who really knows: the user
echo;
printf "${prompt} ${col2}${pkg}${col0} mark for removal?: [y/n] ";
read -r REPLY;
case $REPLY in
Y*|y*)
# Decisive yes, mark candidate for removal
set -- "$@" "$pkg";
continue;
;;
N*|n*)
# Decisive no, mark candidate for keeping
keep="$keep $pkg";
continue;
;;
esac;
# Ambiguous answer from user, possible auto decision mechanisms go here
# They can make a decisive decision
# We should generally avoid making a removal decision automatically
# The condition could be, for example, to keep everything except libs
# (case "$pkg" in lib*) false ;; *) true ;; esac;)
# if BOT_SAYS_DEFINITELY_NO; then
# echo;
# echo "${prompt} ${col2}${pkg}${col0} marking for keeping (auto)";
# keep="$keep $pkg";
# continue;
# elif BOT_SAYS_DEFINITELY_YES; then
# echo;
# echo "${prompt} ${col2}${pkg}${col0} marking for removal (auto)";
# set -- "$@" "$pkg";
# continue;
# fi;
# Consider reaching this point undecided as a decisive no, mark for keeping
keep="$keep $pkg";
done;
done;
# Show the user the result and give a chance to abort
echo;
echo "${prompt} Removing: ${col2}$*${col0}";
echo;
echo "${prompt} Continue?: Press Enter to continue or Ctrl+C to abort here";
read -r REPLY;
# Run kiss remove
echo kiss remove "$@";
@FriendlyNeighborhoodShane
Copy link
Author

scrot

@FriendlyNeighborhoodShane
Copy link
Author

Simply run it with one or more orphans as arguments, and it will show you an interactive y/n prompt for removing every package that would become an orphan once the given packages are removed, and then descends recursively for packages you've selected out of those.

At the end, it will give you a single kiss remove command to uninstall everything you've chosen to remove (remove echo from the last line if you actually want it to execute the command and not just give you one to copy.)

Just a fun idea I had while reading the FAQ. It just automates the loop of reading kiss orphans and running kiss remove over and over, without actually removing anything and just giving you a single command to do everything in the end.

It makes no decisions on its own and the user still decides which of those packages need to be kept (though you can add conditional logic for making keep/remove decisions automatically, see comments).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment