diff --git a/020_yazi-plugin_nicotine.sh b/020_yazi-plugin_nicotine.sh new file mode 100644 index 0000000..6d89bf1 --- /dev/null +++ b/020_yazi-plugin_nicotine.sh @@ -0,0 +1,681 @@ +#!/usr/bin/env bash + +: <&2 + exit 0 +} + +print_usage() { + local nicotine="\e[31mnicotine\e[0m" + local httm="\e[31mhttm\e[0m" + local git="\e[31mgit\e[0m" + local tar="\e[31mtar\e[0m" + + printf "\ +$nicotine is a wrapper script for $httm which converts unique snapshot file versions to a $git archive. + +USAGE: + nicotine [OPTIONS]... [file1 file2...] + +OPTIONS: + --output-dir: + Select the output directory. Default is current working directory. + --no-archive + Disable archive creation. Create a new $git repository. + --single-repo: + Add all provided files/dirs into a single git repository instead of one per argument. + --debug: + Show $git and $tar command output. + --help: + Display this dialog. + --version: + Display script version. + +" 1>&2 + exit 1 +} + +prep_exec() { + for cmd in find readlink git tar mktemp mkdir httm; do + command -v "$cmd" >/dev/null 2>&1 || { printf "Error: '$cmd' is required.\n" 1>&2; exit 1; } + done +} + +function copy_add_commit { + local debug=$1; shift + local path="$1"; shift + local dest_dir="$1"; shift + + if [[ -d "$path" ]]; then + cp -a "$path" "$dest_dir/" + return 0 + else + cp -a "$path" "$dest_dir" + fi + + local commit_date + commit_date=$(date -d "$(stat -c %y "$path")") + + if [[ "$debug" = true ]]; then + git add --all "$dest_dir" + git commit -m "httm commit from ZFS snapshot: $(basename "$path")" --date "$commit_date" || true + else + git add --all "$dest_dir" > /dev/null + git commit -q -m "httm commit from ZFS snapshot: $(basename "$path")" --date "$commit_date" > /dev/null || true + fi +} + +function get_unique_versions { + local debug=$1; shift + local path="$1"; shift + local dest_dir="$1"; shift + + local -a version_list=() + if [[ ! -d "$path" ]]; then + while read -r line; do + [[ -n "$line" ]] && version_list+=("$line") + done <<<"$(httm -n --omit-ditto "$path")" + fi + + if [[ -d "$path" ]] || [[ ${#version_list[@]} -le 1 ]]; then + copy_add_commit "$debug" "$path" "$dest_dir" + else + for version in "${version_list[@]}"; do + copy_add_commit "$debug" "$version" "$dest_dir" + done + fi +} + +function traverse { + local debug=$1; shift + local path="$1"; shift + local dest_dir="$1"; shift + + get_unique_versions "$debug" "$path" "$dest_dir" + [[ -d "$path" ]] || return 0 + + local basename + basename=$(basename "$path") + + while read -r entry; do + [[ -z "$entry" ]] && continue + if [[ -d "$entry" ]]; then + traverse "$debug" "$entry" "$dest_dir/$basename" + else + get_unique_versions "$debug" "$entry" "$dest_dir/$basename" + fi + done <<<"$(find "$path" -mindepth 1 -maxdepth 1)" +} + +function nicotine { + ( + prep_exec + + local debug=false + local no_archive=false + local single_repo=false + local output_dir="$(pwd)" + local -a input_files=() + + while [[ $# -ge 1 ]]; do + case "$1" in + --output-dir) shift; output_dir="$(realpath "$1")"; shift ;; + --debug) debug=true; shift ;; + --no-archive) no_archive=true; shift ;; + --single-repo) single_repo=true; shift ;; + --help|-h) print_usage ;; + --version|-V) print_version ;; + *) input_files+=("$1"); shift ;; + esac + done + + [[ ${#input_files[@]} -gt 0 ]] || { printf "Error: No input files.\n" 1>&2; exit 1; } + + local tmp_dir + tmp_dir="$(mktemp -d)" + trap 'rm -rf "$tmp_dir"' EXIT + + if [[ "$single_repo" = true ]]; then + local repo_name="nicotine-combined" + local archive_dir="$tmp_dir/$repo_name" + mkdir -p "$archive_dir" + cd "$archive_dir" + git init -q + + for file in "${input_files[@]}"; do + local can_path + can_path=$(realpath "$file" 2>/dev/null) || continue + [[ -e "$can_path" ]] || continue + + # if [[ -d "$can_path" ]]; then + # traverse "$debug" "$can_path" "$tmp_dir" + # else + # traverse "$debug" "$can_path" "$archive_dir" + # fi + + traverse "$debug" "$can_path" "$archive_dir" + done + + finalize_output "$debug" "$no_archive" "$tmp_dir" "$output_dir" "$repo_name" + else + for file in "${input_files[@]}"; do + local can_path + can_path=$(realpath "$file" 2>/dev/null) || continue + [[ -e "$can_path" ]] || continue + + local base + base=$(basename "$can_path") + base="${base#.}" + + local archive_dir="$tmp_dir/$base" + mkdir -p "$archive_dir" + ( + cd "$archive_dir" + git init -q + # + # if [[ -d "$can_path" ]]; then + # traverse "$debug" "$can_path" "$tmp_dir" + # else + # traverse "$debug" "$can_path" "$archive_dir" + # fi + + traverse "$debug" "$can_path" "$archive_dir" + ) + finalize_output "$debug" "$no_archive" "$tmp_dir" "$output_dir" "$base" + rm -rf "${archive_dir:?}" + done + fi + ) +} + +function finalize_output { + local debug=$1 no_archive=$2 tmp=$3 out=$4 base=$5 + if [[ "$no_archive" = true ]]; then + cp -ra "$tmp/$base" "$out/$base-git" + printf "Repository created: $out/$base-git\n" + else + local out_file="$out/$base-git.tar.gz" + tar -C "$tmp" -zcf "$out_file" "$base" + printf "Archive created: $out_file\n" + fi +} + +nicotine "${@}" +EOF +} +# So as to not loose the original nicotine bash script. +if [[ -f /usr/bin/nicotine ]]; then + if [[ -f /usr/bin/nicotine.bak ]]; then + sudo mv /usr/bin/nicotine.bak /usr/bin/nicotine + fi + sudo mv /usr/bin/nicotine /usr/bin/nicotine.bak + conf_print_nicotine_script | sudo tee /usr/bin/nicotine + sudo chmod +x /usr/bin/nicotine +fi