diff --git a/CHANGELOG b/CHANGELOG index 9c917a9..759fd6f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,13 @@ -0.4.1 2024-07-14: Fixes "Cancel" option not exiting on package resolution - Fixes whitespace preventing package list matches on "remove all" +0.5.0 2024-07-18: "Decide in editor" package conflict resolution strategy + 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.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.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.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 diff --git a/src/configuration.sh b/src/configuration.sh index a50086f..71a3d5a 100644 --- a/src/configuration.sh +++ b/src/configuration.sh @@ -29,12 +29,8 @@ scan_packages() { user_packages="$(get_user_packages)" if [ "$system_packages" = "$user_packages" ]; then - log debug "packages match" + log debug "Packages match" else - log debug "packages mismatch" - log debug "system:\n$system_packages" - log debug "user:\n$user_packages" - log user "System and configuration packages differ" resolve_packages fi diff --git a/src/index.sh b/src/index.sh index 17e9813..f168b74 100644 --- a/src/index.sh +++ b/src/index.sh @@ -7,4 +7,5 @@ . "$TORI_ROOT/src/package/package_conflict_resolution.sh" . "$TORI_ROOT/src/package/package_tracking.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" diff --git a/src/package/package_conflict_input_parser.sh b/src/package/package_conflict_input_parser.sh new file mode 100644 index 0000000..6c5d9e7 --- /dev/null +++ b/src/package/package_conflict_input_parser.sh @@ -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" +} diff --git a/src/package/package_conflict_resolution.sh b/src/package/package_conflict_resolution.sh index e73a8d6..f2ba8dd 100644 --- a/src/package/package_conflict_resolution.sh +++ b/src/package/package_conflict_resolution.sh @@ -57,6 +57,8 @@ not_on_configuration_dialog() { if validate_input_packages "$input_packages"; then track_packages "$input_packages" fi + elif [ "$strategy" = 5 ]; then + package_conflict_input_parser "$conflicted_packages" 'not_on_configuration' else log debug "[resolve_packages] Unexpected input: $strategy" 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 log debug "Input: input_packages = $input_packages" untrack_packages "$input_packages" + elif [ "$strategy" = 5 ]; then + package_conflict_input_parser "$conflicted_packages" 'not_installed' else log debug "[resolve_packages] Unexpected input: $strategy" not_installed_dialog "$conflicted_packages" diff --git a/src/package/package_manager.sh b/src/package/package_manager.sh index 10930ca..f96f132 100644 --- a/src/package/package_manager.sh +++ b/src/package/package_manager.sh @@ -8,9 +8,9 @@ package_manager() { local args__get_manually_installed local args__get_available - set_opts + + set_opts off local args__user_args="$2" - set_opts - + set_opts on if [ "$OS" = "FreeBSD" ]; then manager="pkg" diff --git a/src/package/package_tracking.sh b/src/package/package_tracking.sh index f8eeb06..9567efc 100644 --- a/src/package/package_tracking.sh +++ b/src/package/package_tracking.sh @@ -9,10 +9,10 @@ track_packages() { untrack_packages() { 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 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 } diff --git a/src/package/update_package_cache.sh b/src/package/update_package_cache.sh index 1169508..c01b750 100644 --- a/src/package/update_package_cache.sh +++ b/src/package/update_package_cache.sh @@ -1,7 +1,7 @@ update_package_cache() { - set_opts + + set_opts off local argument="$1" - set_opts - + set_opts on if [ -f "$PACKAGE_CACHE" ]; then local last_update="$(date -r "$PACKAGE_CACHE" +%Y-%m-%d)" diff --git a/src/utility.sh b/src/utility.sh index 868ed91..441ed38 100644 --- a/src/utility.sh +++ b/src/utility.sh @@ -4,21 +4,73 @@ log() { local level="$1" local message="$2" - if [ $level = fatal ]; then - printf "[tori] $(date "+%H:%M:%S"): $message\n" 1>&2 - elif [ $level = user ]; then - printf "[tori] $(date "+%H:%M:%S"): $message\n" 1>&2 - elif [ -n "$DEBUG" ] && [ $level = debug ]; then - printf "$(date "+%H:%M:%N") $message\n" 1>&2 + print_user_message() { + echo "[tori] $(date "+%H:%M:%S"): $1" 1>&2 + } + + print_debug_message() { + 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 } set_opts() { - sign="$1" + local target="$1" + local sign= - set "${sign}o" errexit - set "${sign}o" nounset - set "${sign}o" pipefail + if [ "$target" = on ]; then + sign='-' + 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() { diff --git a/tori b/tori index 261c82b..6009659 100755 --- a/tori +++ b/tori @@ -2,31 +2,31 @@ main() { # paths - VERSION="0.4.1 2024-07-14" + VERSION="0.5.0 2024-07-18" TORI_ROOT="$HOME/.local/share/tori" CONFIG_ROOT="$HOME/.config/tori" TMP_DIR="/tmp/tori" CACHE_DIR="$HOME/.cache/tori" - check_core_paths - - . "$TORI_ROOT/src/index.sh" - - # state + # os-independent state DEBUG=$DEBUG + DEBUG_DISABLED_WARNING= ## user input argument="$1" 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)" PACKAGE_CACHE="$CACHE_DIR/${OS}_packages.cache" - ## global state base_files= bkp_files= user_packages= @@ -69,7 +69,6 @@ check_core_paths() { exit 1 fi - [ -n "$DEBUG" ] && echo "TORI_ROOT: $TORI_ROOT" } main "$1" "$2"