"Decide-in-editor" package conflict resolution strategy #2

Merged
jutty merged 6 commits from editor-package-resolution-strategy into main 2024-07-20 22:04:29 +02:00
10 changed files with 170 additions and 34 deletions

View file

@ -1,9 +1,13 @@
0.4.1 2024-07-14: Fixes "Cancel" option not exiting on package resolution 0.5.0 2024-07-18: "Decide in editor" package conflict resolution strategy
Fixes whitespace preventing package list matches on "remove all" Drop pipefail shell option for dash compatibility
Add numerical debug levels to the log utility function
Check for shell option support before setting
0.4.1 2024-07-14: Fix "Cancel" option not exiting on package resolution
Fix whitespace preventing package list matches on "remove all"
0.4.0 2024-07-14: "Add/remove all from configuration" resolution strategy 0.4.0 2024-07-14: "Add/remove all from configuration" resolution strategy
0.3.1 2024-07-13: Refactor, new docs page, make cache refresh lazier 0.3.1 2024-07-13: Refactor, new docs page, make cache refresh lazier
0.3.0 2024-07-11: "Enter packages to install/uninstall" resolution strategy 0.3.0 2024-07-11: "Enter packages to install/uninstall" resolution strategy
0.2.1 2024-07-10: Rename package_resolution.sh, document package conflicts 0.2.1 2024-07-10: Rename package_resolution.sh, document package conflicts
0.2.0 2024-07-10: Implement "uninstall/instal all" package resolution strategies 0.2.0 2024-07-10: Implement "uninstall/instal all" package resolution strategies
0.1.1 2024-07-07: Handle missing tori.conf and invalid installation root path 0.1.1 2024-07-07: Handle missing tori.conf and invalid installation root path
0.1.0 2024-07-07: Added configuration parsing 0.1.0 2024-07-07: Add configuration parsing

View file

@ -29,12 +29,8 @@ scan_packages() {
user_packages="$(get_user_packages)" user_packages="$(get_user_packages)"
if [ "$system_packages" = "$user_packages" ]; then if [ "$system_packages" = "$user_packages" ]; then
log debug "packages match" log debug "Packages match"
else else
log debug "packages mismatch"
log debug "system:\n$system_packages"
log debug "user:\n$user_packages"
log user "System and configuration packages differ" log user "System and configuration packages differ"
resolve_packages resolve_packages
fi fi

View file

@ -7,4 +7,5 @@
. "$TORI_ROOT/src/package/package_conflict_resolution.sh" . "$TORI_ROOT/src/package/package_conflict_resolution.sh"
. "$TORI_ROOT/src/package/package_tracking.sh" . "$TORI_ROOT/src/package/package_tracking.sh"
. "$TORI_ROOT/src/package/validate_input_packages.sh" . "$TORI_ROOT/src/package/validate_input_packages.sh"
. "$TORI_ROOT/src/package/package_conflict_input_parser.sh"
. "$TORI_ROOT/src/package/update_package_cache.sh" . "$TORI_ROOT/src/package/update_package_cache.sh"

View file

@ -0,0 +1,80 @@
package_conflict_input_parser() {
local packages="$1"
local conflict_type="$2"
local input="$TMP_DIR/package_conflict_input"
local input_choices="$TMP_DIR/package_conflict_input_choices"
local choices=
local packages_to_install=
local packages_to_uninstall=
local packages_to_track=
local packages_to_untrack=
help_text_generator "$conflict_type" > "$input"
echo "$packages" | sed 's/ /\n/g' | while read -r package; do
echo "skip $package" >> "$input"
done
$EDITOR "$input"
choices="$(cat "$input" | grep -v '^#' | grep '.')"
echo "$choices" > "$input_choices"
# validation
while read -r action package; do
validate_input_packages "$package"
if [ "$action" = install ] || [ "$action" = i ]; then
packages_to_install="$packages_to_install $package"
elif [ "$action" = uninstall ] || [ "$action" = u ]; then
packages_to_uninstall="$packages_to_uninstall $package"
elif [ "$action" = add ] || [ "$action" = a ]; then
packages_to_track="$packages_to_track $package"
elif [ "$action" = remove ] || [ "$action" = r ]; then
packages_to_untrack="$packages_to_untrack $package"
elif [ "$action" = skip ] || [ "$action" = s ]; then
log debug "[package_conflict_input_parser] Skipped: $package"
else
log user "Invalid action provided for $package: $action"
fi
done < "$input_choices"
# actual system or configuration change
if [ -n "$packages_to_install" ]; then
package_manager install "$packages_to_install"
fi
if [ -n "$packages_to_uninstall" ]; then
package_manager uninstall "$packages_to_uninstall"
fi
if [ -n "$packages_to_track" ]; then
track_packages "$packages_to_track"
fi
if [ -n "$packages_to_untrack" ]; then
untrack_packages "$packages_to_untrack"
fi
}
help_text_generator() {
local conflict_type="$1"
echo "# Options:"
if [ "$conflict_type" == not_installed ]; then
echo "# [i]nstall Install package to system"
echo "# [r]emove Remove from configuration"
elif [ "$conflict_type" == not_on_configuration ]; then
echo "# [u]ninstall Uninstall package from system"
echo "# [a]dd Add to configuration"
else
debug fatal "Invalid conflict type provided: $conflict_type"
return 1
fi
echo "# [s]kip Do not take any action"
echo -e "\n# Providing just the value between brackets is sufficient"
echo -e "# Replace 'skip' below with the desired option\n"
}

View file

@ -57,6 +57,8 @@ not_on_configuration_dialog() {
if validate_input_packages "$input_packages"; then if validate_input_packages "$input_packages"; then
track_packages "$input_packages" track_packages "$input_packages"
fi fi
elif [ "$strategy" = 5 ]; then
package_conflict_input_parser "$conflicted_packages" 'not_on_configuration'
else else
log debug "[resolve_packages] Unexpected input: $strategy" log debug "[resolve_packages] Unexpected input: $strategy"
not_on_configuration_dialog "$conflicted_packages" not_on_configuration_dialog "$conflicted_packages"
@ -97,6 +99,8 @@ not_installed_dialog() {
read -r -p "Enter space-separated packages to remove from the configuation: " input_packages read -r -p "Enter space-separated packages to remove from the configuation: " input_packages
log debug "Input: input_packages = $input_packages" log debug "Input: input_packages = $input_packages"
untrack_packages "$input_packages" untrack_packages "$input_packages"
elif [ "$strategy" = 5 ]; then
package_conflict_input_parser "$conflicted_packages" 'not_installed'
else else
log debug "[resolve_packages] Unexpected input: $strategy" log debug "[resolve_packages] Unexpected input: $strategy"
not_installed_dialog "$conflicted_packages" not_installed_dialog "$conflicted_packages"

View file

@ -8,9 +8,9 @@ package_manager() {
local args__get_manually_installed local args__get_manually_installed
local args__get_available local args__get_available
set_opts + set_opts off
local args__user_args="$2" local args__user_args="$2"
set_opts - set_opts on
if [ "$OS" = "FreeBSD" ]; then if [ "$OS" = "FreeBSD" ]; then
manager="pkg" manager="pkg"

View file

@ -9,10 +9,10 @@ track_packages() {
untrack_packages() { untrack_packages() {
local packages="$1" local packages="$1"
log debug "[untrack_packages] Removing packages: $packages" log info "[untrack_packages] Removing packages: $packages"
echo "$packages" | xargs | sed 's/ /\n/g' | while read -r package; do echo "$packages" | xargs | sed 's/ /\n/g' | while read -r package; do
sed -i '' "/^[[:space:]]*$package[[:space:]]*$/d" "$CONFIG_ROOT/packages" sed -i '' "/^[[:space:]]*$package[[:space:]]*$/d" "$CONFIG_ROOT/packages"
log debug "[untrack_packages] Executed removal for $package with exit code $?" log info "[untrack_packages] Executed removal for $package with exit code $?"
done done
} }

View file

@ -1,7 +1,7 @@
update_package_cache() { update_package_cache() {
set_opts + set_opts off
local argument="$1" local argument="$1"
set_opts - set_opts on
if [ -f "$PACKAGE_CACHE" ]; then if [ -f "$PACKAGE_CACHE" ]; then
local last_update="$(date -r "$PACKAGE_CACHE" +%Y-%m-%d)" local last_update="$(date -r "$PACKAGE_CACHE" +%Y-%m-%d)"

View file

@ -4,21 +4,73 @@ log() {
local level="$1" local level="$1"
local message="$2" local message="$2"
if [ $level = fatal ]; then print_user_message() {
printf "[tori] $(date "+%H:%M:%S"): $message\n" 1>&2 echo "[tori] $(date "+%H:%M:%S"): $1" 1>&2
elif [ $level = user ]; then }
printf "[tori] $(date "+%H:%M:%S"): $message\n" 1>&2
elif [ -n "$DEBUG" ] && [ $level = debug ]; then print_debug_message() {
printf "$(date "+%H:%M:%N") $message\n" 1>&2 echo "$(date "+%H:%M:%N") $1" 1>&2
}
if [ -z "$DEBUG" ]; then
DEBUG=3
elif ! echo "$DEBUG" | grep -q '^[[:number:]]$'; then
echo "[log] Warning: DEBUG should always be set to a number. Assuming DEBUG=3 (warn)"
DEBUG=3
fi
if [ -z "$DEBUG_DISABLED_WARNING" ] && [ "$DEBUG" -eq 0 ]; then
echo "[log] Warning: Setting DEBUG=0 disables all logging except for user messages"
echo " Use a value beween 1 (fatal) and 5 (debug). The default level is 3 (warn)"
DEBUG_DISABLED_WARNING=1
elif [ "$DEBUG" -gt 5 ]; then
echo "[log] Warning: Assuming DEBUG maximum level of 5 (debug) over provided level $DEBUG"
DEBUG=5
fi
if [ "$level" = user ]; then
print_user_message "$message"
elif [ "$DEBUG" -ge 1 ] && [ "$level" = fatal ]; then
print_user_message "$message"
elif [ "$DEBUG" -ge 2 ] && [ "$level" = error ]; then
print_user_message "$message"
elif [ "$DEBUG" -ge 3 ] && [ "$level" = warn ]; then
print_user_message "$message"
elif [ "$DEBUG" -ge 4 ] && [ "$level" = info ]; then
print_debug_message "$message"
elif [ "$DEBUG" -ge 5 ] && [ "$level" = debug ]; then
print_debug_message "$message"
fi fi
} }
set_opts() { set_opts() {
sign="$1" local target="$1"
local sign=
set "${sign}o" errexit if [ "$target" = on ]; then
set "${sign}o" nounset sign='-'
set "${sign}o" pipefail elif [ "$target" = off ]; then
sign='+'
else
log fatal "Invalid set_opts target: $target. Expected on or off"
return 1
fi
set_opt() {
local opt="$1"
if set -o | grep -q "^$opt[[:space:]]"; then
set "${sign}o" "$opt"
log debug "[set_opts] Set: $(set -o | grep "^$opt[[:space:]]")"
else
log fatal "Unsupported shell: no $opt option support"
return 1
fi
}
set_opt errexit
set_opt nounset
set_opt pipefail
} }
prepare_directories() { prepare_directories() {

19
tori
View file

@ -2,31 +2,31 @@
main() { main() {
# paths # paths
VERSION="0.4.1 2024-07-14" VERSION="0.5.0 2024-07-18"
TORI_ROOT="$HOME/.local/share/tori" TORI_ROOT="$HOME/.local/share/tori"
CONFIG_ROOT="$HOME/.config/tori" CONFIG_ROOT="$HOME/.config/tori"
TMP_DIR="/tmp/tori" TMP_DIR="/tmp/tori"
CACHE_DIR="$HOME/.cache/tori" CACHE_DIR="$HOME/.cache/tori"
check_core_paths # os-independent state
. "$TORI_ROOT/src/index.sh"
# state
DEBUG=$DEBUG DEBUG=$DEBUG
DEBUG_DISABLED_WARNING=
## user input ## user input
argument="$1" argument="$1"
parameter="$2" parameter="$2"
set_opts - # import source
## global constants check_core_paths
. "$TORI_ROOT/src/index.sh"
set_opts on
## os-dependent state
OS="$(get_operating_system)" OS="$(get_operating_system)"
PACKAGE_CACHE="$CACHE_DIR/${OS}_packages.cache" PACKAGE_CACHE="$CACHE_DIR/${OS}_packages.cache"
## global state
base_files= base_files=
bkp_files= bkp_files=
user_packages= user_packages=
@ -69,7 +69,6 @@ check_core_paths() {
exit 1 exit 1
fi fi
[ -n "$DEBUG" ] && echo "TORI_ROOT: $TORI_ROOT"
} }
main "$1" "$2" main "$1" "$2"