#!/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