implement multiple archive creation
This commit is contained in:
@@ -115,9 +115,11 @@ utaz()
|
||||
# shellcheck disable=SC2329
|
||||
_unlha()
|
||||
{
|
||||
# lha typically extracts into the current directory
|
||||
# We ensure it hits the target directory
|
||||
(cd "$2" && lha -x "../$1") >/dev/null 2>&1
|
||||
# lha extracts into the current directory, so we cd into the target
|
||||
# directory and feed it an absolute path to the archive.
|
||||
local src
|
||||
src=$(realpath -- "$1") || return 1
|
||||
(cd "$2" && lha -x "$src") >/dev/null 2>&1
|
||||
}
|
||||
|
||||
local _ununace
|
||||
@@ -146,8 +148,11 @@ utaz()
|
||||
# shellcheck disable=SC2329
|
||||
_uncpio()
|
||||
{
|
||||
# CPIO requires careful directory handling
|
||||
(cd "$2" && cpio -id < "../$1") >/dev/null 2>&1
|
||||
# cpio extracts into the current directory, so we cd into the target
|
||||
# directory and read from an absolute path to the archive.
|
||||
local src
|
||||
src=$(realpath -- "$1") || return 1
|
||||
(cd "$2" && cpio -id < "$src") >/dev/null 2>&1
|
||||
}
|
||||
|
||||
local _uncabextract
|
||||
@@ -249,8 +254,10 @@ utaz()
|
||||
esac
|
||||
fi
|
||||
|
||||
[[ -n ${createdir} && -n ${nodir} ]] && \
|
||||
[[ -n ${createdir} && -n ${nodir} ]] && {
|
||||
disp E "The --create-dir and --no-dir options are mutually exclusive."
|
||||
return 1
|
||||
}
|
||||
|
||||
for zitem in "${FILES[@]}"; do
|
||||
# Build list of input files to process, with whitespace-safe handling.
|
||||
@@ -353,6 +360,10 @@ utaz()
|
||||
fi
|
||||
|
||||
disp I "Processing archive ${f} with ${extractor}..."
|
||||
# Track whether we create the target directory so a corrupted
|
||||
# archive never wipes a pre-existing directory of the same name.
|
||||
local dir_created=0
|
||||
[[ -d "${dir}" ]] || dir_created=1
|
||||
if ! mkdir -p "${dir}"; then
|
||||
disp E "The filesystem can't create directories, exit!" &&
|
||||
return 1
|
||||
@@ -373,7 +384,7 @@ utaz()
|
||||
;;
|
||||
*)
|
||||
disp E "The compressed file ${f} seems corrupted, failed."
|
||||
rm -rf "${dir}" >/dev/null 2>&1
|
||||
[[ ${dir_created} -eq 1 ]] && rm -rf "${dir}" >/dev/null 2>&1
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
@@ -444,6 +455,17 @@ taz()
|
||||
printf "%s\n" "$cpus"
|
||||
}
|
||||
|
||||
# Render a byte count as a human-readable size (B/KB/MB/GB/...), base 1024.
|
||||
local _taz_human
|
||||
# shellcheck disable=SC2329
|
||||
_taz_human()
|
||||
{
|
||||
if command -v numfmt >/dev/null 2>&1; then
|
||||
numfmt --to=iec --suffix=B -- "$1" 2>/dev/null && return 0
|
||||
fi
|
||||
printf "%sB\n" "$1"
|
||||
}
|
||||
|
||||
local _doxz
|
||||
# shellcheck disable=SC2329
|
||||
_doxz()
|
||||
@@ -575,6 +597,7 @@ taz()
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
local compforms=()
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
@@ -608,7 +631,12 @@ taz()
|
||||
;;
|
||||
|
||||
-f|--format)
|
||||
local compform=$2
|
||||
# Accept comma/space separated lists and repeated -f flags.
|
||||
local _f
|
||||
# shellcheck disable=SC2086 # intentional word splitting on the list
|
||||
for _f in ${2//,/ }; do
|
||||
compforms+=("$_f")
|
||||
done
|
||||
shift 2
|
||||
;;
|
||||
|
||||
@@ -628,7 +656,7 @@ taz()
|
||||
;;
|
||||
|
||||
-[1-9])
|
||||
complevel="${1#-}"
|
||||
local complevel="${1#-}"
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
@@ -647,11 +675,32 @@ taz()
|
||||
local FILES=("$@")
|
||||
[[ ${#FILES[@]} -eq 0 ]] && FILES=(".")
|
||||
|
||||
[[ ! $compform ]] && compform=${TAZ_DEFAULT_FORMAT:-lz}
|
||||
[[ ! $nproc ]] && nproc=${TAZ_DEFAULT_THREADS:-auto}
|
||||
[[ ! $complevel ]] && complevel=${TAZ_DEFAULT_LEVEL:-6}
|
||||
[[ $verbose -gt 1 && $quiet -gt 1 ]] &&
|
||||
[[ ! $compform ]] && local compform=${TAZ_DEFAULT_FORMAT:-lz}
|
||||
[[ ! $nproc ]] && local nproc=${TAZ_DEFAULT_THREADS:-auto}
|
||||
[[ ! $complevel ]] && local complevel=${TAZ_DEFAULT_LEVEL:-6}
|
||||
[[ -n $verbose && -n $quiet ]] && {
|
||||
disp E "The --verbose and --quiet options can't be used together."
|
||||
return 1
|
||||
}
|
||||
|
||||
# Fall back to the configured (or built-in) default format list.
|
||||
local _f
|
||||
if [[ ${#compforms[@]} -eq 0 ]]; then
|
||||
local _deffmt=${TAZ_DEFAULT_FORMAT:-lz}
|
||||
# shellcheck disable=SC2086 # intentional word splitting on the list
|
||||
for _f in ${_deffmt//,/ }; do
|
||||
compforms+=("$_f")
|
||||
done
|
||||
fi
|
||||
|
||||
# Reject unknown formats early so we never dispatch to a missing _do*.
|
||||
local _supported=" lz xz bz2 gz lzo tar "
|
||||
for _f in "${compforms[@]}"; do
|
||||
[[ $_supported == *" $_f "* ]] || {
|
||||
disp E "Unsupported format '${_f}' (supported: lz xz bz2 gz lzo tar)."
|
||||
return 1
|
||||
}
|
||||
done
|
||||
|
||||
# Backward compatibility: 0 previously meant auto-detect.
|
||||
[[ $nproc == 0 ]] && nproc=auto
|
||||
@@ -662,6 +711,10 @@ taz()
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Map each format to the extension its compressor appends. "tar" performs
|
||||
# no compression, so its candidate is the tar (or source file) itself.
|
||||
local -A _taz_ext=( [lz]=lz [xz]=xz [bz2]=bz2 [gz]=gz [lzo]=lzo [tar]="" )
|
||||
|
||||
for item in "${FILES[@]}"; do
|
||||
local donetar=0
|
||||
disp I "Processing $item..."
|
||||
@@ -680,31 +733,91 @@ taz()
|
||||
local fname=$item
|
||||
[[ $donetar -gt 0 ]] && fname=$item.tar
|
||||
|
||||
# Skip compression part if tar is asked
|
||||
if [[ $compform != "tar" ]]; then
|
||||
disp I "\t Compressing archive..."
|
||||
local exec_code=0
|
||||
"_do$compform" "$fname" "$nproc" "$complevel" "$verbose" || exec_code=$?
|
||||
[[ ! $exec_code -eq 0 ]] && case $exec_code in
|
||||
# Compress the archive with every requested format; the smallest
|
||||
# resulting file is kept and the others are discarded.
|
||||
local candidates=() fmt exec_code aborted=0
|
||||
for fmt in "${compforms[@]}"; do
|
||||
if [[ $fmt == tar ]]; then
|
||||
candidates+=("$fname")
|
||||
continue
|
||||
fi
|
||||
|
||||
disp I "\t Compressing archive with ${fmt}..."
|
||||
exec_code=0
|
||||
"_do$fmt" "$fname" "$nproc" "$complevel" "$verbose" || exec_code=$?
|
||||
case $exec_code in
|
||||
0)
|
||||
candidates+=("$fname.${_taz_ext[$fmt]}")
|
||||
;;
|
||||
127)
|
||||
disp E "Compression program unavailable, aborting."
|
||||
return 127
|
||||
disp E "Compression program for '${fmt}' unavailable, aborting."
|
||||
aborted=1
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Compression program returned an error, not deleting anything if asked, skipping to next item."
|
||||
continue
|
||||
disp W "Compression with '${fmt}' failed, skipping this format."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ $donetar -gt 0 ]] && rm "$fname"
|
||||
# Remove partial output produced before an unrecoverable abort.
|
||||
local c
|
||||
if [[ $aborted -eq 1 ]]; then
|
||||
for c in "${candidates[@]}"; do
|
||||
[[ $c != "$fname" ]] && rm -f -- "$c"
|
||||
done
|
||||
[[ $donetar -gt 0 ]] && rm -f -- "$fname"
|
||||
return 127
|
||||
fi
|
||||
|
||||
# Select the smallest archive among the produced candidates.
|
||||
local winner="" winner_size=-1 sz
|
||||
local -A _csize=()
|
||||
for c in "${candidates[@]}"; do
|
||||
[[ -f $c ]] || continue
|
||||
sz=$(stat -c%s -- "$c" 2>/dev/null) || continue
|
||||
_csize["$c"]=$sz
|
||||
if [[ $winner_size -lt 0 || $sz -lt $winner_size ]]; then
|
||||
winner_size=$sz
|
||||
winner=$c
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z $winner ]]; then
|
||||
disp E "No archive could be produced for ${item}, skipping to next item."
|
||||
[[ $donetar -gt 0 ]] && rm -f -- "$fname"
|
||||
continue
|
||||
fi
|
||||
|
||||
# In verbose mode, list every produced archive with its size and how
|
||||
# much larger it is than the smallest one that will be kept.
|
||||
if [[ -n $verbose && ${#_csize[@]} -gt 0 ]]; then
|
||||
disp I "\t Produced archives:"
|
||||
for c in "${candidates[@]}"; do
|
||||
[[ -n ${_csize[$c]+x} ]] || continue
|
||||
if [[ $c == "$winner" ]]; then
|
||||
disp "\t ${c} $(_taz_human "${_csize[$c]}") (kept, smallest)"
|
||||
else
|
||||
disp "\t ${c} $(_taz_human "${_csize[$c]}") (+$(_taz_human "$(( _csize[$c] - winner_size ))"))"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Discard every archive but the smallest, then drop the intermediate
|
||||
# tar unless it is the kept archive.
|
||||
for c in "${candidates[@]}"; do
|
||||
[[ $c != "$winner" ]] && rm -f -- "$c"
|
||||
done
|
||||
[[ $donetar -gt 0 && $fname != "$winner" ]] && rm -f -- "$fname"
|
||||
|
||||
[[ ${#compforms[@]} -gt 1 ]] &&
|
||||
disp I "\t Kept smallest archive: ${winner} ($(_taz_human "$winner_size"))."
|
||||
|
||||
if [[ $willrm ]]; then
|
||||
disp I "\t Deleting original source as asked... "
|
||||
rm -r "$item"
|
||||
fi
|
||||
done
|
||||
unset quiet
|
||||
}
|
||||
export -f taz
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user