From 21b5f8ff2d2970f58884c4b28d89fe97562484f5 Mon Sep 17 00:00:00 2001 From: jutty Date: Tue, 27 Aug 2024 11:28:29 -0300 Subject: [PATCH 01/13] Add interactive dialog utility functions --- src/utility.sh | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/utility.sh b/src/utility.sh index 441ed38..bb2025f 100644 --- a/src/utility.sh +++ b/src/utility.sh @@ -5,11 +5,11 @@ log() { local message="$2" print_user_message() { - echo "[tori] $(date "+%H:%M:%S"): $1" 1>&2 + printf "%b\n" "[tori] $(date "+%H:%M:%S"): $1" 1>&2 } print_debug_message() { - echo "$(date "+%H:%M:%N") $1" 1>&2 + printf "%b\n" "$(date "+%H:%M:%N") $1" 1>&2 } if [ -z "$DEBUG" ]; then @@ -43,6 +43,39 @@ log() { fi } +confirm() { + local question="$1" + local answer= + read -rp "$question [y/N] " answer + + if [ "$answer" == y ] || [ "$answer" == Y ]; then + return 0; + else + return 1; + fi +} + +ask() { + local question="$1" + local options="$2" + local answer= + local options_count=0 + local dialog_options= + + local IFS=, + for option in $options; do + _=$((options_count+=1)) + dialog_options="$dialog_options\n [$options_count] $option" + done; + IFS= + + printf "%s" "$question" >&2 + printf "%b" "$dialog_options" >&2 + printf "\n%s" "Choose an option [1-$options_count] " >&2 + read -r answer + echo "$answer" +} + set_opts() { local target="$1" local sign= From 91c4f6be4c798ac5f9f5370882224aa002420d6c Mon Sep 17 00:00:00 2001 From: jutty Date: Tue, 27 Aug 2024 11:28:43 -0300 Subject: [PATCH 02/13] Scaffold file comparison structure --- src/check.sh | 1 + src/configuration.sh | 2 +- src/file/merge_base.sh | 20 ++++++++++++++++++++ src/index.sh | 2 ++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/file/merge_base.sh diff --git a/src/check.sh b/src/check.sh index b0df8ff..598802a 100644 --- a/src/check.sh +++ b/src/check.sh @@ -6,4 +6,5 @@ check() { log debug "collected bkp files:\n$bkp_files" scan_packages + merge_base "$base_files" } diff --git a/src/configuration.sh b/src/configuration.sh index 71a3d5a..0a9faf3 100644 --- a/src/configuration.sh +++ b/src/configuration.sh @@ -15,7 +15,7 @@ scan_directory() { done fi - echo "$files" + printf "%b" "$files" } scan_packages() { diff --git a/src/file/merge_base.sh b/src/file/merge_base.sh new file mode 100644 index 0000000..42f9d0e --- /dev/null +++ b/src/file/merge_base.sh @@ -0,0 +1,20 @@ +merge_base() { + local base_files="$1" + local strategy= + + for file in $base_files; do + log debug "[merge-base] Processing $file" + local absolute_path="$(echo "$file" | sed 's/^base//')" + log debug "[merge-base] Absolute path: $absolute_path" + local config_path="$CONFIG_ROOT/$file" + log debug "[merge-base] Config path: $config_path" + + if diff "$absolute_path" "$config_path" > /dev/null; then + log debug "[merge-base] Files match" + else + log debug "[merge-base] Files differ" + strategy="$(ask "Configuration and system files differ" "Overwrite system,Overwrite config,Show difference")" + log debug "[merge-base] Chosen strategy: $strategy" + fi + done +} diff --git a/src/index.sh b/src/index.sh index f168b74..9899f9a 100644 --- a/src/index.sh +++ b/src/index.sh @@ -9,3 +9,5 @@ . "$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/file/merge_base.sh" From e0e1920b0b193abd9095aa066031c79599c434f2 Mon Sep 17 00:00:00 2001 From: jutty Date: Wed, 28 Aug 2024 09:27:06 -0300 Subject: [PATCH 03/13] Improve handling some edge cases in the ask utlity --- src/utility.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/utility.sh b/src/utility.sh index bb2025f..4ff19c4 100644 --- a/src/utility.sh +++ b/src/utility.sh @@ -72,8 +72,15 @@ ask() { printf "%s" "$question" >&2 printf "%b" "$dialog_options" >&2 printf "\n%s" "Choose an option [1-$options_count] " >&2 - read -r answer - echo "$answer" + read -r read_answer + answer="$(echo "$read_answer" | xargs)" + + if [ "$answer" -gt 0 ] 2> /dev/null && [ "$answer" -le $options_count ]; then + echo "$answer" + else + log debug "[ask] Invalid choice" + return 1 + fi } set_opts() { From 1b9e519e05c853a21b658e628c028e9f9abcb833 Mon Sep 17 00:00:00 2001 From: jutty Date: Fri, 30 Aug 2024 09:49:38 -0300 Subject: [PATCH 04/13] Implement tree strategy for file merging --- src/check.sh | 2 +- src/file/file_merge.sh | 61 ++++++++++++++++++++++++++++++++++++++++++ src/file/merge_base.sh | 20 -------------- src/index.sh | 2 +- src/utility.sh | 4 +++ 5 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 src/file/file_merge.sh delete mode 100644 src/file/merge_base.sh diff --git a/src/check.sh b/src/check.sh index 598802a..b3923b7 100644 --- a/src/check.sh +++ b/src/check.sh @@ -6,5 +6,5 @@ check() { log debug "collected bkp files:\n$bkp_files" scan_packages - merge_base "$base_files" + merge_files "$base_files" } diff --git a/src/file/file_merge.sh b/src/file/file_merge.sh new file mode 100644 index 0000000..7bc4d0a --- /dev/null +++ b/src/file/file_merge.sh @@ -0,0 +1,61 @@ +merge_files() { + local base_files="$1" + local strategy="${2:-tree}" + + if [ "$strategy" == tree ]; then + log info "[merge_files] Merging with $strategy strategy" + if ! file_scan_tree "$base_files"; then + file_merge_tree "$base_files" + log info "[merge_files] Recursing" + merge_files "$base_files" + fi + fi +} + +file_scan_tree() { + local base_files="$1" + + for file in $base_files; do + local absolute_path="$(echo "$file" | sed 's/^base//')" + local config_path="$CONFIG_ROOT/$file" + + if ! diff "$absolute_path" "$config_path" > /dev/null; then + return 1 + fi + done + return 0 +} + +# TODO Check if files exist before acting +file_merge_tree() { + local base_files="$1" + local strategy= + + for file in $base_files; do + log debug "[merge_tree] Processing $file" + local absolute_path="$(echo "$file" | sed 's/^base//')" + log debug "[merge_tree] Absolute path: $absolute_path" + local config_path="$CONFIG_ROOT/$file" + log debug "[merge_tree] Config path: $config_path" + + if diff "$absolute_path" "$config_path" > /dev/null; then + log debug "[merge_tree] Files match" + else + log debug "[merge_tree] Files differ" + strategy="$(ask "Differs: $(tildify "$absolute_path")" \ + "Overwrite system,Overwrite configuration,Show difference")" + log debug "[merge_tree] Chosen strategy: $strategy" + + if [ "$strategy" -eq 1 ]; then + cp -vi "$config_path" "$absolute_path" + elif [ "$strategy" -eq 2 ]; then + cp -vi "$absolute_path" "$config_path" + elif [ "$strategy" -eq 3 ]; then + echo "< $(tildify "$absolute_path") | $(echo "$config_path" | sed "s*$CONFIG_ROOT/**") >" + diff "$absolute_path" "$config_path" || return 0 + else + log user 'Invalid choice' + fi + fi + done +} diff --git a/src/file/merge_base.sh b/src/file/merge_base.sh deleted file mode 100644 index 42f9d0e..0000000 --- a/src/file/merge_base.sh +++ /dev/null @@ -1,20 +0,0 @@ -merge_base() { - local base_files="$1" - local strategy= - - for file in $base_files; do - log debug "[merge-base] Processing $file" - local absolute_path="$(echo "$file" | sed 's/^base//')" - log debug "[merge-base] Absolute path: $absolute_path" - local config_path="$CONFIG_ROOT/$file" - log debug "[merge-base] Config path: $config_path" - - if diff "$absolute_path" "$config_path" > /dev/null; then - log debug "[merge-base] Files match" - else - log debug "[merge-base] Files differ" - strategy="$(ask "Configuration and system files differ" "Overwrite system,Overwrite config,Show difference")" - log debug "[merge-base] Chosen strategy: $strategy" - fi - done -} diff --git a/src/index.sh b/src/index.sh index 9899f9a..95c9f91 100644 --- a/src/index.sh +++ b/src/index.sh @@ -10,4 +10,4 @@ . "$TORI_ROOT/src/package/package_conflict_input_parser.sh" . "$TORI_ROOT/src/package/update_package_cache.sh" -. "$TORI_ROOT/src/file/merge_base.sh" +. "$TORI_ROOT/src/file/file_merge.sh" diff --git a/src/utility.sh b/src/utility.sh index 4ff19c4..f713db0 100644 --- a/src/utility.sh +++ b/src/utility.sh @@ -83,6 +83,10 @@ ask() { fi } +tildify() { + echo "$1" | sed "s*$HOME*~*" +} + set_opts() { local target="$1" local sign= From 85151e1de6f0f36bd31045fb9e21ac6bfeb6bf65 Mon Sep 17 00:00:00 2001 From: jutty Date: Sat, 31 Aug 2024 07:56:35 -0300 Subject: [PATCH 05/13] Handle file not exiting when merging files --- src/file/file_merge.sh | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/file/file_merge.sh b/src/file/file_merge.sh index 7bc4d0a..97075d7 100644 --- a/src/file/file_merge.sh +++ b/src/file/file_merge.sh @@ -5,9 +5,9 @@ merge_files() { if [ "$strategy" == tree ]; then log info "[merge_files] Merging with $strategy strategy" if ! file_scan_tree "$base_files"; then - file_merge_tree "$base_files" - log info "[merge_files] Recursing" - merge_files "$base_files" + if ! file_merge_tree "$base_files"; then + merge_files "$base_files" + fi fi fi } @@ -19,14 +19,13 @@ file_scan_tree() { local absolute_path="$(echo "$file" | sed 's/^base//')" local config_path="$CONFIG_ROOT/$file" - if ! diff "$absolute_path" "$config_path" > /dev/null; then + if ! diff "$absolute_path" "$config_path" > /dev/null 2>&1; then return 1 fi done return 0 } -# TODO Check if files exist before acting file_merge_tree() { local base_files="$1" local strategy= @@ -38,21 +37,32 @@ file_merge_tree() { local config_path="$CONFIG_ROOT/$file" log debug "[merge_tree] Config path: $config_path" - if diff "$absolute_path" "$config_path" > /dev/null; then + if diff "$absolute_path" "$config_path" > /dev/null 2>&1; then log debug "[merge_tree] Files match" else log debug "[merge_tree] Files differ" - strategy="$(ask "Differs: $(tildify "$absolute_path")" \ - "Overwrite system,Overwrite configuration,Show difference")" + local prompt_verb="Differs" + local prompt_options="Overwrite system,Overwrite configuration,Show difference" + if ! [ -f "$absolute_path" ]; then + local prompt_verb="In configuration only" + local prompt_options="Copy to system" + fi + strategy="$(ask "$prompt_verb: $(tildify "$absolute_path")" "$prompt_options")" || + file_merge_tree "$base_files" log debug "[merge_tree] Chosen strategy: $strategy" - if [ "$strategy" -eq 1 ]; then + if [ "$strategy" -eq 0 ]; then + return 0 + elif [ "$strategy" -eq 1 ]; then cp -vi "$config_path" "$absolute_path" + return 1 elif [ "$strategy" -eq 2 ]; then cp -vi "$absolute_path" "$config_path" + return 1 elif [ "$strategy" -eq 3 ]; then echo "< $(tildify "$absolute_path") | $(echo "$config_path" | sed "s*$CONFIG_ROOT/**") >" - diff "$absolute_path" "$config_path" || return 0 + diff "$absolute_path" "$config_path" + return 1 else log user 'Invalid choice' fi From a0fdbe014937adce0dad19b99a278723afe6455c Mon Sep 17 00:00:00 2001 From: jutty Date: Sat, 31 Aug 2024 07:56:41 -0300 Subject: [PATCH 06/13] Add an exit option to ask dialog --- src/utility.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utility.sh b/src/utility.sh index f713db0..79afd4d 100644 --- a/src/utility.sh +++ b/src/utility.sh @@ -68,14 +68,15 @@ ask() { dialog_options="$dialog_options\n [$options_count] $option" done; IFS= + dialog_options="$dialog_options\n [0] Exit" printf "%s" "$question" >&2 printf "%b" "$dialog_options" >&2 - printf "\n%s" "Choose an option [1-$options_count] " >&2 + printf "\n%s" "Choose an option number: " >&2 read -r read_answer answer="$(echo "$read_answer" | xargs)" - if [ "$answer" -gt 0 ] 2> /dev/null && [ "$answer" -le $options_count ]; then + if [ "$answer" -ge 0 ] 2> /dev/null && [ "$answer" -le $options_count ]; then echo "$answer" else log debug "[ask] Invalid choice" From 005638bef42cd5d11e25467762e8619f6066c9b3 Mon Sep 17 00:00:00 2001 From: jutty Date: Sun, 1 Sep 2024 22:22:34 -0300 Subject: [PATCH 07/13] Improve edge cases for handling empty inputs --- src/file/file_merge.sh | 4 ++-- src/utility.sh | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/file/file_merge.sh b/src/file/file_merge.sh index 97075d7..7bf25dc 100644 --- a/src/file/file_merge.sh +++ b/src/file/file_merge.sh @@ -47,8 +47,7 @@ file_merge_tree() { local prompt_verb="In configuration only" local prompt_options="Copy to system" fi - strategy="$(ask "$prompt_verb: $(tildify "$absolute_path")" "$prompt_options")" || - file_merge_tree "$base_files" + strategy="$(ask "$prompt_verb: $(tildify "$absolute_path")" "$prompt_options")" log debug "[merge_tree] Chosen strategy: $strategy" if [ "$strategy" -eq 0 ]; then @@ -65,6 +64,7 @@ file_merge_tree() { return 1 else log user 'Invalid choice' + return 1 fi fi done diff --git a/src/utility.sh b/src/utility.sh index 79afd4d..b342897 100644 --- a/src/utility.sh +++ b/src/utility.sh @@ -76,10 +76,15 @@ ask() { read -r read_answer answer="$(echo "$read_answer" | xargs)" - if [ "$answer" -ge 0 ] 2> /dev/null && [ "$answer" -le $options_count ]; then + if [ -z "$answer" ]; then + log info "[ask] Invalid choice" + echo -1 + return 1 + elif [ "$answer" -ge 0 ] 2> /dev/null && [ "$answer" -le $options_count ]; then echo "$answer" else - log debug "[ask] Invalid choice" + log info "[ask] Invalid choice" + echo -1 return 1 fi } From 7b2f1494b944b89660122f78bd18a183e2a46094 Mon Sep 17 00:00:00 2001 From: jutty Date: Sun, 1 Sep 2024 22:23:28 -0300 Subject: [PATCH 08/13] Refactor directory variable names for uniformity --- src/package/package_conflict_input_parser.sh | 4 ++-- src/package/package_conflict_resolution.sh | 8 ++++---- src/utility.sh | 12 ++++++++---- tori | 7 ++++--- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/package/package_conflict_input_parser.sh b/src/package/package_conflict_input_parser.sh index 6c5d9e7..547db98 100644 --- a/src/package/package_conflict_input_parser.sh +++ b/src/package/package_conflict_input_parser.sh @@ -1,8 +1,8 @@ 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 input="$TMP_ROOT/package_conflict_input" + local input_choices="$TMP_ROOT/package_conflict_input_choices" local choices= local packages_to_install= local packages_to_uninstall= diff --git a/src/package/package_conflict_resolution.sh b/src/package/package_conflict_resolution.sh index f2ba8dd..e7b4efc 100644 --- a/src/package/package_conflict_resolution.sh +++ b/src/package/package_conflict_resolution.sh @@ -3,18 +3,18 @@ resolve_packages() { local input_packages= # shellcheck disable=SC2154 - ( echo "$system_packages" > "$TMP_DIR/system_packages" - echo "$user_packages" > "$TMP_DIR/user_packages" ) + ( echo "$system_packages" > "$TMP_ROOT/system_packages" + echo "$user_packages" > "$TMP_ROOT/user_packages" ) local packages_not_on_configuration="$(grep -v -x -f \ - "$TMP_DIR/user_packages" "$TMP_DIR/system_packages" | xargs)" + "$TMP_ROOT/user_packages" "$TMP_ROOT/system_packages" | xargs)" if [ -n "$packages_not_on_configuration" ]; then not_on_configuration_dialog "$packages_not_on_configuration" fi local packages_not_installed=$(grep -v -x -f \ - "$TMP_DIR/system_packages" "$TMP_DIR/user_packages" | xargs) + "$TMP_ROOT/system_packages" "$TMP_ROOT/user_packages" | xargs) if [ -n "$packages_not_installed" ]; then not_installed_dialog "$packages_not_installed" diff --git a/src/utility.sh b/src/utility.sh index b342897..82a8e91 100644 --- a/src/utility.sh +++ b/src/utility.sh @@ -124,12 +124,16 @@ set_opts() { } prepare_directories() { - if ! [ -d "$TMP_DIR" ]; then - mkdir "$TMP_DIR" + if ! [ -d "$TMP_ROOT" ]; then + mkdir "$TMP_ROOT" fi - if ! [ -d "$CACHE_DIR" ]; then - mkdir -p "$CACHE_DIR" + if ! [ -d "$CACHE_ROOT" ]; then + mkdir -p "$CACHE_ROOT" + fi + + if ! [ -d "$BACKUP_ROOT" ]; then + mkdir -p "$BACKUP_ROOT" fi if ! [ -d "$CONFIG_ROOT" ]; then diff --git a/tori b/tori index 6009659..e2e92e7 100755 --- a/tori +++ b/tori @@ -5,8 +5,9 @@ main() { 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" + BACKUP_ROOT="$HOME/.local/state/tori/backup" + TMP_ROOT="/tmp/tori" + CACHE_ROOT="$HOME/.cache/tori" # os-independent state @@ -25,7 +26,7 @@ main() { ## os-dependent state OS="$(get_operating_system)" - PACKAGE_CACHE="$CACHE_DIR/${OS}_packages.cache" + PACKAGE_CACHE="$CACHE_ROOT/${OS}_packages.cache" base_files= bkp_files= From 4b6a9569954df8f6688100ca77f7e9d79764f845 Mon Sep 17 00:00:00 2001 From: jutty Date: Sun, 1 Sep 2024 22:48:34 -0300 Subject: [PATCH 09/13] Implement backing up before overwriting files --- src/file/backup.sh | 28 ++++++++++++++++++++++++++++ src/file/file_merge.sh | 2 ++ src/index.sh | 1 + src/utility.sh | 6 ++++++ 4 files changed, 37 insertions(+) create mode 100644 src/file/backup.sh diff --git a/src/file/backup.sh b/src/file/backup.sh new file mode 100644 index 0000000..7a05c2c --- /dev/null +++ b/src/file/backup.sh @@ -0,0 +1,28 @@ +# takes a list of space-separated absolute paths +# backs each path up, creating canonical or ephemeral copies as needed +backup_paths() { + local paths="$1" + local canonical_path= + local ephemeral_path= + + for path in $paths; do + canonical_path="$BACKUP_ROOT/canonical$path" + timestamp="$(date +'%Y-%m-%dT%H-%M-%S')" + ephemeral_path="$BACKUP_ROOT/ephemeral${path}_$timestamp" + + if [ -f "$canonical_path" ]; then + log debug "[backup] Creating ephemeral copy for $path" + mkdir -p "$(dirname "$ephemeral_path")" + if [ -f "$ephemeral_path" ]; then + log debug "[backup] Overwriting ephemeral copy for $path" + cp -f "$path" "$ephemeral_path" + else + cp "$path" "$ephemeral_path" + fi + else + log debug "[backup] Creating canonical copy for $path" + mkdir -p "$(dirname "$canonical_path")" + cp "$path" "$canonical_path" + fi + done +} diff --git a/src/file/file_merge.sh b/src/file/file_merge.sh index 7bf25dc..46e75be 100644 --- a/src/file/file_merge.sh +++ b/src/file/file_merge.sh @@ -53,9 +53,11 @@ file_merge_tree() { if [ "$strategy" -eq 0 ]; then return 0 elif [ "$strategy" -eq 1 ]; then + backup_paths "$absolute_path" cp -vi "$config_path" "$absolute_path" return 1 elif [ "$strategy" -eq 2 ]; then + backup_paths "$config_path" cp -vi "$absolute_path" "$config_path" return 1 elif [ "$strategy" -eq 3 ]; then diff --git a/src/index.sh b/src/index.sh index 95c9f91..0af2c73 100644 --- a/src/index.sh +++ b/src/index.sh @@ -11,3 +11,4 @@ . "$TORI_ROOT/src/package/update_package_cache.sh" . "$TORI_ROOT/src/file/file_merge.sh" +. "$TORI_ROOT/src/file/backup.sh" diff --git a/src/utility.sh b/src/utility.sh index 82a8e91..78b6de3 100644 --- a/src/utility.sh +++ b/src/utility.sh @@ -134,6 +134,12 @@ prepare_directories() { if ! [ -d "$BACKUP_ROOT" ]; then mkdir -p "$BACKUP_ROOT" + if ! [ -d "$BACKUP_ROOT/canonical" ]; then + mkdir "$BACKUP_ROOT/canonical" + fi + if ! [ -d "$BACKUP_ROOT/ephemeral" ]; then + mkdir "$BACKUP_ROOT/ephemeral" + fi fi if ! [ -d "$CONFIG_ROOT" ]; then From 59e040d59789dcf75a78ff4da9e2c0ec3fdd254b Mon Sep 17 00:00:00 2001 From: jutty Date: Tue, 3 Sep 2024 08:57:55 -0300 Subject: [PATCH 10/13] Extract authorization command to top level --- src/package/package_manager.sh | 7 +++---- tori | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/package/package_manager.sh b/src/package/package_manager.sh index f96f132..4303ce8 100644 --- a/src/package/package_manager.sh +++ b/src/package/package_manager.sh @@ -2,7 +2,6 @@ package_manager() { local command="$1" local manager - local authorizer="sudo" local args__install local args__uninstall local args__get_manually_installed @@ -25,11 +24,11 @@ package_manager() { if [ "$command" = 'get_manually_installed' ]; then eval $manager "$args__get_manually_installed" elif [ "$command" = 'install' ]; then - $authorizer $manager $args__install $args__user_args + $AUTHORIZE_COMMAND $manager $args__install $args__user_args elif [ "$command" = 'uninstall' ]; then - $authorizer $manager $args__uninstall $args__user_args + $AUTHORIZE_COMMAND $manager $args__uninstall $args__user_args elif [ "$command" = 'update' ]; then - $authorizer $manager $args__update + $AUTHORIZE_COMMAND $manager $args__update elif [ "$command" = 'get_available' ]; then eval $manager "$args__get_available" else diff --git a/tori b/tori index e2e92e7..3c15354 100755 --- a/tori +++ b/tori @@ -19,14 +19,14 @@ main() { parameter="$2" # import source - check_core_paths . "$TORI_ROOT/src/index.sh" - set_opts on ## os-dependent state + set_opts on OS="$(get_operating_system)" PACKAGE_CACHE="$CACHE_ROOT/${OS}_packages.cache" + AUTHORIZE_COMMAND="sudo" base_files= bkp_files= From de634f3749c834b16ede0478eaa98af3dc0fdc5f Mon Sep 17 00:00:00 2001 From: jutty Date: Tue, 3 Sep 2024 09:23:37 -0300 Subject: [PATCH 11/13] Handle permissions when reading and writing files --- src/file/file_merge.sh | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/file/file_merge.sh b/src/file/file_merge.sh index 46e75be..c938431 100644 --- a/src/file/file_merge.sh +++ b/src/file/file_merge.sh @@ -54,15 +54,27 @@ file_merge_tree() { return 0 elif [ "$strategy" -eq 1 ]; then backup_paths "$absolute_path" - cp -vi "$config_path" "$absolute_path" + if [ -r "$config_path" ] && [ -w "$absolute_path" ]; then + cp -vi "$config_path" "$absolute_path" + else + $AUTHORIZE_COMMAND cp -vi "$config_path" "$absolute_path" + fi return 1 elif [ "$strategy" -eq 2 ]; then backup_paths "$config_path" - cp -vi "$absolute_path" "$config_path" + if [ -r "$absolute_path" ] && [ -w "$config_path" ]; then + cp -vi "$absolute_path" "$config_path" + else + $AUTHORIZE_COMMAND cp -vi "$absolute_path" "$config_path" + fi return 1 elif [ "$strategy" -eq 3 ]; then echo "< $(tildify "$absolute_path") | $(echo "$config_path" | sed "s*$CONFIG_ROOT/**") >" - diff "$absolute_path" "$config_path" + if [ -r "$absolute_path" ] && [ -r "$config_path" ]; then + diff "$absolute_path" "$config_path" + else + $AUTHORIZE_COMMAND diff "$absolute_path" "$config_path" + fi return 1 else log user 'Invalid choice' From e94e68540f7395359b0ede4f21f5b6b4769828ab Mon Sep 17 00:00:00 2001 From: jutty Date: Tue, 3 Sep 2024 12:09:40 -0300 Subject: [PATCH 12/13] Make file operations more permission-aware --- src/file/backup.sh | 20 ++++++++++++++++---- src/file/file_merge.sh | 14 +++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/file/backup.sh b/src/file/backup.sh index 7a05c2c..7f992a7 100644 --- a/src/file/backup.sh +++ b/src/file/backup.sh @@ -1,4 +1,4 @@ -# takes a list of space-separated absolute paths +# takes a list of newline-separated absolute paths # backs each path up, creating canonical or ephemeral copies as needed backup_paths() { local paths="$1" @@ -15,14 +15,26 @@ backup_paths() { mkdir -p "$(dirname "$ephemeral_path")" if [ -f "$ephemeral_path" ]; then log debug "[backup] Overwriting ephemeral copy for $path" - cp -f "$path" "$ephemeral_path" + if [ -r "$path" ]; then + cp -f "$path" "$ephemeral_path" + else + $AUTHORIZE_COMMAND cp -f "$path" "$ephemeral_path" + fi else - cp "$path" "$ephemeral_path" + if [ -r "$path" ]; then + cp "$path" "$ephemeral_path" + else + $AUTHORIZE_COMMAND cp "$path" "$ephemeral_path" + fi fi else log debug "[backup] Creating canonical copy for $path" mkdir -p "$(dirname "$canonical_path")" - cp "$path" "$canonical_path" + if [ -r "$path" ]; then + cp "$path" "$canonical_path" + else + $AUTHORIZE_COMMAND cp "$path" "$canonical_path" + fi fi done } diff --git a/src/file/file_merge.sh b/src/file/file_merge.sh index c938431..ffd61f4 100644 --- a/src/file/file_merge.sh +++ b/src/file/file_merge.sh @@ -28,7 +28,7 @@ file_scan_tree() { file_merge_tree() { local base_files="$1" - local strategy= + local overwrite_choice= for file in $base_files; do log debug "[merge_tree] Processing $file" @@ -47,12 +47,12 @@ file_merge_tree() { local prompt_verb="In configuration only" local prompt_options="Copy to system" fi - strategy="$(ask "$prompt_verb: $(tildify "$absolute_path")" "$prompt_options")" - log debug "[merge_tree] Chosen strategy: $strategy" + overwrite_choice="$(ask "$prompt_verb: $(tildify "$absolute_path")" "$prompt_options")" + log debug "[merge_tree] Overwrite choice: $overwrite_choice" - if [ "$strategy" -eq 0 ]; then + if [ "$overwrite_choice" -eq 0 ]; then return 0 - elif [ "$strategy" -eq 1 ]; then + elif [ "$overwrite_choice" -eq 1 ]; then backup_paths "$absolute_path" if [ -r "$config_path" ] && [ -w "$absolute_path" ]; then cp -vi "$config_path" "$absolute_path" @@ -60,7 +60,7 @@ file_merge_tree() { $AUTHORIZE_COMMAND cp -vi "$config_path" "$absolute_path" fi return 1 - elif [ "$strategy" -eq 2 ]; then + elif [ "$overwrite_choice" -eq 2 ]; then backup_paths "$config_path" if [ -r "$absolute_path" ] && [ -w "$config_path" ]; then cp -vi "$absolute_path" "$config_path" @@ -68,7 +68,7 @@ file_merge_tree() { $AUTHORIZE_COMMAND cp -vi "$absolute_path" "$config_path" fi return 1 - elif [ "$strategy" -eq 3 ]; then + elif [ "$overwrite_choice" -eq 3 ]; then echo "< $(tildify "$absolute_path") | $(echo "$config_path" | sed "s*$CONFIG_ROOT/**") >" if [ -r "$absolute_path" ] && [ -r "$config_path" ]; then diff "$absolute_path" "$config_path" From 67de45f5ba53e7fb61902e96c6fd4ea4a4c52579 Mon Sep 17 00:00:00 2001 From: jutty Date: Tue, 3 Sep 2024 12:09:51 -0300 Subject: [PATCH 13/13] Update strings for v0.6.0 --- CHANGELOG | 4 ++++ README.md | 2 +- tori | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 759fd6f..92c1843 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +0.6.0 2024-09-03: File management with the tree strategy + File backups + Extract authorization command to top level + ask and tildify utility functions 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 diff --git a/README.md b/README.md index c25a9a3..138a64c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ tori is a tool to track your personal systems' configurations and replicate them. -If you'd like a more detailed description of what it is, its purpose, origins and goals, see the [announcement blog post](https://blog.jutty.dev/posts/introducing-tori.html). +If you'd like a more detailed description of what it is, its purpose, origins and goals, see the [announcement blog post](https://blog.jutty.dev/posts/introducing-tori/). Refer to the [project website](https://tori.jutty.dev) for updates and access to [documentation](https://tori.jutty.dev/docs). diff --git a/tori b/tori index 3c15354..2d0e2b5 100755 --- a/tori +++ b/tori @@ -2,7 +2,7 @@ main() { # paths - VERSION="0.5.0 2024-07-18" + VERSION="0.6.0 2024-09-03" TORI_ROOT="$HOME/.local/share/tori" CONFIG_ROOT="$HOME/.config/tori" BACKUP_ROOT="$HOME/.local/state/tori/backup"