#!/usr/bin/env bash
# tarball - archive away a directory

. lib.bash || exit

set -e

opt_attributes=0

usage() {
	echo "Usage: $progname [-aAfkO] <directory> [<archive>]"
	echo ""
	echo_opt "-a" "keep extended attributes"
	echo_opt "-A" "do not automatically move archive to /home"
	echo_opt "-f" "overwrite existing archive"
	echo_opt "-k" "keep original directory"
	echo_opt "-O" "set archive owner to that of original directory"
}

do_archive() {
	local dir=$1 out=$2

	if (( opt_attributes )); then
		lib:echo "dumping extended attributes"
		local attr_tmp=$(mktemp /tmp/attrib.XXXXXXXX)
		getfattr -Rhd "$dir" \
			| grep -v '^user\.com\.dropbox\.' \
			| sed 's/^user\.org\.eu\.nullroute\./user.http./' \
			> "$attr_tmp"
		if [[ -s "$attr_tmp" ]]; then
			mv "$attr_tmp" "$dir/_attributes"
		else
			rm -f "$attr_tmp"
		fi
	fi

	lib:echo "archiving files"
	set -o pipefail
	case $out in
	    *.tgz) tar -cvzf "$out" "$dir" | progress;;
	    *.zip) zip -ry "$out" "$dir";;
	esac || return

	[[ -s "$out" ]] || { rm -f "$out"; false; }
}

get_timestamp() {
	local t=$(find "$1" -type f -not -name '_attributes' -printf '%Ts\n' \
		| sort -n | tail -1)
	[[ $t ]] || t=$(find "$1" -maxdepth 0 -type d -printf '%Ts\n')
	echo $t
}

get_fstag() {
	local dir=$1;				debug "dir='$dir'"
	if [[ -e $dir ]]; then
		local fsid=$(stat -fc %i "$dir");	debug " - fsid='$fsid'"
		local mtpt=$(stat -c %m "$dir");	debug " - mount='$mtpt'"
		local devno=$(mountpoint -d "$mtpt");	debug " - devno='$devno'"
		echo "$fsid,$mtpt,$devno"
	else
		echo "-,$dir,-"
	fi
}

# environment

if (( UID == 0 )); then
	umask 077
fi

if [[ ! $OLD_TAR ]]; then
	export TAR_OPTIONS="--xattrs"
fi

# parse command line

auto_move=0
auto_remove=1
do_chown=0
do_overwrite=0

case ${0##*/} in
    tarball) ext=tgz;;
    zipball) ext=zip;;
esac

while getopts ":aAfkO" OPT; do
	case $OPT in
	a) opt_attributes=1;;
	A) auto_move=0;;
	f) do_overwrite=1;;
	k) auto_remove=0;;
	O) do_chown=1;;
	*) lib:die_getopts;;
	esac
done; shift $((OPTIND-1))

dir=${1%/}

if (( do_chown && UID != 0 )); then
	die "must be root in order to change file ownership"
fi

if [[ ! $dir ]]; then
	die "directory to archive not specified"
elif [[ ! -d $dir ]]; then
	die "path is not a directory"
fi

# prepare: find the timestamp

ts=$(get_timestamp "$dir")
debug "timestamp of '$dir' = '$ts'"

if [[ ! $ts ]]; then
	die "could not obtain timestamp of '$dir'"
fi

if [[ $2 == --now ]]; then
	out=${dir}-$(date +%F).$ext
elif [[ $2 == --date ]]; then
	out=${dir}_$(date +%F -d "@$ts").$ext
elif [[ -d $2 ]]; then
	die "target '$2' already exists"
else
	out=${2:-$dir}.$ext
fi

if (( auto_move )); then
	if ! case $(get_fstag "$dir") in
		($(get_fstag ~)) true;;
		($(get_fstag ~/Private)) true;;
		(*) false;;
	esac; then
		out=~/$out
	fi
fi

# check for existing archives

for file in "$out"; do # "${1%/}".{{t,tar.}{gz,bz2,xz},zip}; do
	if [[ -e "$file" ]]; then
		if (( do_overwrite )); then
			warn "archive already exists: $file"
		else
			die "archive already exists: $file"
		fi
	fi
done

# create the tarball/zipball

log2 "creating archive \"$out\""

if do_archive "$dir" "$out"; then
	touch -d "@$ts" "$out"
	chmod a-w "$out"
	if (( do_chown )); then
		owner=$(stat -c %u:%g "$dir")
		chown "$owner" "$out"
	fi
	lib:echo "archived to \"$out\""
	ls -lh "$out"
	if (( auto_remove )); then
		lib:echo "removing original"
		if [[ -e ~/.local/share/Trash ]]; then
			trash "$dir/"
		else
			rm -rf "$dir/"
		fi
		lib:echo "original directory removed"
	else
		lib:echo "original directory preserved"
	fi
else
	die "archiving failed"
fi
