set -euf -o pipefail
declare _alt_bowie_command=""
print_version() {
printf "\
bowie $(httm --version | cut -f2 -d' ')
" 1>&2
exit 0
}
print_usage() {
local bowie="\e[31mbowie\e[0m"
local httm="\e[31mhttm\e[0m"
printf "\
$bowie is a wrapper script for $httm which displays the difference between unique snapshot versions and the live file.
USAGE:
bowie [OPTIONS]... [file1 file2...]
OPTIONS:
--last:
Default mode. Display only the difference between the last unique snapshot version and the live file.
--all:
Display the difference between each unique snapshot version against the next version, and finally the live file.
--select
Start an $httm interactive session to select the snapshot difference to display against the live file.
--direct
Print difference with $bowie formatting.
--command
Print differences piped through a command instead only using file contents.
--help:
Display this dialog.
--version:
Display script version.
" 1>&2
exit 1
}
print_err_exit() {
print_err "${@}"
exit 1
}
print_err() {
printf "%s\n" "Error: $*" 1>&2
}
prep_exec() {
[[ -n "$(
command -v diff
exit 0
)" ]] || print_err_exit "'diff' is required to execute 'bowie'. Please check that 'diff' is in your path."
[[ -n "$(
command -v httm
exit 0
)" ]] || print_err_exit "'httm' is required to execute 'bowie'. Please check that 'httm' is in your path."
}
show_all_changes() {
local filename="$1"
local previous_version=""
local -a all_versions
local dedup_by=""
[[ ! -f "$filename" ]] || dedup_by="contents"
[[ -f "$filename" ]] || dedup_by="disable"
while read -r line; do
all_versions+=("$line")
done <<<"$(httm -n --dedup-by="$dedup_by" --omit-ditto "$filename")"
if [[ ${#all_versions[@]} -eq 0 ]]; then
print_err "No previous snapshot version available for: $filename"
return 0
elif [[ ${#all_versions[@]} -eq 1 ]]; then
show_single_change "$filename" "last"
return 0
fi
display_header "$filename"
for current_version in "${all_versions[@]}"; do
if [[ -z "$previous_version" ]]; then
previous_version="$current_version"
continue
fi
[[ ! -f "$filename" ]] || display_diff_file "$previous_version" "$current_version"
[[ -f "$filename" ]] || display_diff_directory "$previous_version" "$current_version"
previous_version="$current_version"
done
}
check_not_identical() {
local current_version="$1"
local previous_version="$2"
[[ "$previous_version" != "$current_version" ]] ||
print_err_exit "The selected/last snapshot version and live file are the same file."
[[ -n "$current_version" ]] ||
print_err_exit "The only snapshot version and live file are 'diff'-identical."
[[ -n "$(diff -q "$previous_version" "$current_version")" ]] ||
print_err_exit "The selected/last snapshot version and live file are 'diff'-identical, but have different modification times. Perhaps try --all."
}
show_single_change() {
local current_version="$1"
local previous_version=""
local mode="$2"
[[ "$mode" != "select" ]] || previous_version="$(httm -n --select "$current_version")"
[[ "$mode" != "last" ]] || previous_version="$(httm -n --dedup-by=contents --omit-ditto --last-snap "$current_version")"
display_header "$current_version"
check_not_identical "$previous_version" "$current_version"
[[ ! -f "$current_version" ]] || display_diff_file "$previous_version" "$current_version"
[[ -f "$current_version" ]] || display_diff_directory "$previous_version" "$current_version"
}
show_direct() {
local previous_version="$1"
local current_version="$2"
display_header "$current_version"
if [[ "$previous_version" == "$current_version" ]]; then
printf "The selected/last snapshot version and live file are the same file."
elif [[ -z "$(diff -q "$previous_version" "$current_version")" ]]; then
printf "The selected/last snapshot version and live file are 'diff'-identical, but have different modification times. Perhaps try --all."
else
display_diff_file "$previous_version" "$current_version"
fi
}
display_header() {
local filename="$1"
printf "\
$filename
__
"
}
display_diff_file() {
local previous_version="$1"
local current_version="$2"
if [[ -n "$_alt_bowie_command" && -n "$previous_version" ]]; then
(diff --color=always -q "$previous_version" "$current_version" || true)
(diff --color=always -T --label "$previous_version" <( "$_alt_bowie_command" "$previous_version" ) --label "$current_version" <( "$_alt_bowie_command" "$current_version" ) || true)
elif [[ -n "$previous_version" ]]; then
(diff --color=always -q "$previous_version" "$current_version" || true)
(diff --color=always -T "$previous_version" "$current_version" || true)
else
print_err "No previous snapshot version available for: $current_version"
fi
}
display_diff_directory() {
[[ -n "$(
command -v tree
exit 0
)" ]] || print_err_exit "'tree' is required to execute 'bowie' on directories. Please check that 'tree' is in your path."
local previous_version="$1"
local current_version="$2"
if [[ -n "$previous_version" ]]; then
local diff_head="$(diff --color=always -T --label "$previous_version" <( tree -RDsa "$previous_version" | tail -n +2 ) --label "$current_version" <( tree -RDsa "$current_version" | tail -n +2 ) || true)"
[[ -z "$diff_head" ]] || printf "Directories "$previous_version" and "$current_version" differ\n" && \
printf "$diff_head\n"
else
print_err "No previous snapshot version available for: $current_version"
fi
}
exec_main() {
prep_exec
local mode="last"
[[ $# -ge 1 ]] || print_usage
[[ "$1" != "-h" && "$1" != "--help" ]] || print_usage
[[ "$1" != "-V" && "$1" != "--version" ]] || print_version
while [[ $# -ge 1 ]]; do
if [[ $1 == "--all" ]]; then
mode="all"
shift
elif [[ $1 == "--select" ]]; then
mode="select"
shift
elif [[ $1 == "--direct" ]]; then
mode="direct"
shift
elif [[ $1 == "--command" ]]; then
shift
[[ $# -ge 1 ]] || print_err_exit "--command is empty"
program_name="$(
command -v "$1"
exit 0
)"
_alt_bowie_command="$program_name"
shift
elif [[ $1 == "--last" ]]; then
shift
else
break
fi
done
[[ ${#@} -ne 0 ]] || print_err_exit "No filenames specified. Quitting."
if [[ "$mode" == "direct" ]]; then
[[ -n "$1" ]] || print_err_exit "First required file name is unset. Quitting."
[[ -n "$2" ]] || print_err_exit "Second required file name is unset. Quitting."
local previous_version="$( realpath "$1" 2>/dev/null )"
[[ -n "$previous_version" ]] || print_err_exit "Could not determine canonical path for: "$previous_version". Quitting."
local current_version="$( realpath "$2" 2>/dev/null )"
[[ -n "$current_version" ]] || print_err_exit "Could not determine canonical path for: "$current_version". Quitting."
show_direct "$previous_version" "$current_version"
exit 0
fi
for a; do
if [[ -z "$a" ]]; then
print_err "File name is empty: "$a"."
continue
fi
local canonical_path="$( realpath "$a")"
if [[ -z "${canonical_path}" ]]; then
print_err "Could not determine canonical path for: "$a"."
continue
fi
if [[ ! -f "${canonical_path}" ]] && [[ -n "$_alt_bowie_command" ]] ; then
print_err "Skipping path which is not a file when --command is set: "$a"."
continue
fi
if [[ "$mode" == "all" ]]; then
show_all_changes "$canonical_path"
elif [[ "$mode" == "select" ]]; then
show_single_change "$canonical_path" "$mode"
else
show_single_change "$canonical_path" "$mode"
fi
done
}
exec_main "${@}"