This repository has been archived on 2024-03-04. You can view files and clone it, but cannot push or open issues or pull requests.
linux/.config/bash/module/Archive.sh

309 lines
7.4 KiB
Bash
Raw Normal View History

2023-12-07 04:02:47 +03:00
export _archive_pattern="_[0-9]{12}-[[:alnum:]]{40}.t[xg]z"
2023-12-16 22:52:36 +03:00
export _archive_pattern_fast="_[0-9]{12}-[[:alnum:]]{40}.tgz"
2023-12-07 01:44:42 +03:00
2023-12-07 04:02:47 +03:00
# Archive directories.
# All directories by default.
# Usage: archive [DIRS]
2023-12-07 01:44:42 +03:00
function archive() {
2023-12-05 21:50:45 +03:00
local IFS=$'\n'
2023-12-16 22:52:36 +03:00
local targets=(${@})
[[ "${targets}" = "" ]] && targets=($(_ls_dir))
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
process() {
local date=$(_archive_date)
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
# Parse name.
2023-12-17 23:46:41 +03:00
local name=$(parse_pascal ${target})
2023-12-05 21:50:45 +03:00
# create archive.
2023-12-16 22:52:36 +03:00
local hash=$(tar -c ${target} | pv -s $(/usr/bin/du -sb ${target} | awk '{print $1}') | xz -9e | tee ${name}.txz | sha1sum | cut -d\ -f1)
2023-12-10 04:31:03 +03:00
# append hash to target name.
local new_name="${name}_${date}-${hash}.txz"
mv -- ${name}.txz ${new_name} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Archive using multiple threads. Uses 50% of free RAM.
# All directories by default.
# Usage: archive_mt [DIRS]
function archive_mt() {
local IFS=$'\n'
local targets=(${@})
[[ "${targets}" = "" ]] && targets=($(_ls_dir))
process() {
local date=$(_archive_date)
# Parse name.
local name=$(parse_pascal ${target})
# Determine memory limit.
local mem_free=$(_mem_free)
local mem_limit=$((mem_free/2))
# create archive.
local hash=$(tar -c ${target} | pv -s $(/usr/bin/du -sb ${target} | awk '{print $1}') | xz -9e --threads=0 --memlimit=${mem_limit}MiB | tee ${name}.txz | sha1sum | cut -d\ -f1)
2023-12-05 21:50:45 +03:00
# append hash to target name.
2023-12-17 16:27:21 +03:00
local new_name="${name}_${date}-${hash}.txz"
mv -- ${name}.txz ${new_name} && echo ${new_name}
2023-12-16 22:52:36 +03:00
}
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
_iterate_targets process ${targets[@]}
2023-08-08 16:24:15 +03:00
}
2023-12-07 04:02:47 +03:00
# Archive directories with fast compression.
# All directories by default.
# Usage: archive_fast [DIRS]
2023-12-07 01:44:42 +03:00
function archive_fast() {
2023-12-05 21:50:45 +03:00
local IFS=$'\n'
2023-12-06 02:31:52 +03:00
local targets=("${@}")
2023-12-16 22:52:36 +03:00
[[ "${targets}" = "" ]] && targets=($(_ls_dir))
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
process() {
2023-12-17 16:27:21 +03:00
# Start timestamp.
2023-12-16 22:52:36 +03:00
local date=$(_archive_date)
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
# Parse name.
2023-12-17 23:46:41 +03:00
local name=$(parse_pascal "${target}")
2023-12-05 21:50:45 +03:00
# create archive.
local hash=$(tar -c "${target}" | pv -s $(/usr/bin/du -sb "${target}" | awk '{print $1}') | gzip -1 | tee "${name}".tgz | sha1sum | cut -d\ -f1)
2023-12-10 04:31:03 +03:00
2023-12-05 21:50:45 +03:00
# append hash to target name.
2023-12-17 16:27:21 +03:00
local new_name="${name}_${date}-${hash}.tgz"
mv -- "${name}".tgz ${new_name} && echo ${new_name}
2023-12-16 22:52:36 +03:00
}
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
_iterate_targets process ${targets[@]}
2023-08-08 16:24:15 +03:00
}
2023-12-07 04:02:47 +03:00
# Check archives integrity.
# Checks all archives by default.
# Usage: archive_check [FILES]
2023-12-07 01:44:42 +03:00
function archive_check() {
2023-12-05 21:50:45 +03:00
local IFS=$'\n'
2023-12-16 22:52:36 +03:00
local targets=(${@})
[[ "${targets}" = "" ]] && targets=($(ls | grep -E ${_archive_pattern}))
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
process() {
2023-12-05 21:50:45 +03:00
# extract hash from name.
local data=($(_archive_parse ${target}))
local saved=${data[2]}
# calculate actual hash.
2023-12-16 22:52:36 +03:00
local actual=$(pv ${target} | sha1sum | cut -d\ -f1)
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
# compare hashes.
[[ "${actual}" = "${saved}" ]]
}
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
_iterate_targets process ${targets[@]}
2023-08-08 16:24:15 +03:00
}
2023-12-07 04:36:44 +03:00
# Delete old versions of archives.
2023-12-07 04:02:47 +03:00
# All archives by default.
# Usage: archive_prune [NAME]
2023-12-07 01:44:42 +03:00
function archive_prune() {
2023-12-05 21:50:45 +03:00
local IFS=$'\n'
2023-12-16 22:52:36 +03:00
local targets=(${@})
[[ "${targets}" = "" ]] && targets=($(ls | grep -E ${_archive_pattern}))
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
process() {
2023-12-05 21:50:45 +03:00
local data=($(_archive_parse ${target}))
2023-12-16 22:52:36 +03:00
local name=${data[0]}
local time=${data[1]}
2023-12-05 21:50:45 +03:00
local copies=($(ls ${name}_*))
# Iterate each copy.
2023-12-16 22:52:36 +03:00
for copy in ${copies[@]}; do
2023-12-05 21:50:45 +03:00
local copy_data=($(_archive_parse ${copy}))
2023-12-16 22:52:36 +03:00
local copy_time=${copy_data[1]}
2023-12-05 21:50:45 +03:00
if [[ "${copy_time}" -lt "${time}" ]]; then
2023-12-17 16:27:21 +03:00
rm -- ${copy} && echo "${name}: Prune ${copy_time}."
2023-12-05 21:50:45 +03:00
fi
done
2023-12-16 22:52:36 +03:00
}
2023-12-05 21:50:45 +03:00
2023-12-16 22:52:36 +03:00
_iterate_targets process ${targets[@]}
}
2023-12-10 04:31:03 +03:00
# Delete specified or all archive files.
# Usage: archive_rm [FILES]
function archive_rm() {
local IFS=$'\n'
2023-12-16 22:52:36 +03:00
local targets=(${@})
[[ "${targets}" = "" ]] && targets=($(ls | grep -E ${_archive_pattern}))
2023-12-10 04:31:03 +03:00
2023-12-16 22:52:36 +03:00
process() {
2023-12-17 16:27:21 +03:00
rm -- "${target}"
2023-12-16 22:52:36 +03:00
}
2023-12-10 04:31:03 +03:00
2023-12-16 22:52:36 +03:00
_iterate_targets process ${targets[@]}
2023-12-10 04:31:03 +03:00
}
2023-12-16 21:56:30 +03:00
# Recompress previously created archive_fast with better compression.
# Usage: archive_xz [FILES]
function archive_xz() {
2023-12-16 22:52:36 +03:00
local IFS=$'\n'
2023-12-17 16:27:21 +03:00
local targets=(${@})
2023-12-16 22:52:36 +03:00
[[ "${targets}" = "" ]] && targets=$(ls | grep -E ${_archive_pattern_fast})
2023-12-16 21:56:30 +03:00
2023-12-16 22:52:36 +03:00
process() {
2023-12-16 21:56:30 +03:00
local data=($(_archive_parse "${target}"))
local tmp="${data[0]}.txz"
2023-12-05 21:50:45 +03:00
2023-12-16 21:56:30 +03:00
# Check that old format.
if [[ "${data[3]}" != "tgz" ]]; then
2023-12-17 16:27:21 +03:00
_error "Not in .tgz format!"
2023-12-16 21:56:30 +03:00
return 1
fi
2023-12-16 21:56:30 +03:00
# Recompress.
local hash=$(pv "${target}" | gzip -d | xz -9e | tee "${tmp}" | sha1sum | cut -d\ -f1)
2023-12-05 21:50:45 +03:00
2023-12-16 21:56:30 +03:00
# Rename.
2023-12-17 16:27:21 +03:00
local new_name="${data[0]}_${data[1]}-${hash}.txz"
mv -- ${tmp} ${new_name} && rm ${target} && echo ${new_name}
}
_iterate_targets process ${targets[@]}
}
# Rename archives.
# If no name specified, it simplifies archive's name.
# If no archives specified, apply to all archives.
# Usage: archive_name [ARCHIVE] [NAME]
function archive_name() {
local IFS=$'\n'
local targets="${1}"
local name="${2}"
[[ "${targets}" = "" ]] && targets=($(ls | grep -E ${_archive_pattern}))
process() {
# simplify name by default.
if [[ "${name}" = "" || ${count} -gt 1 ]]; then
name="${target%_*}"
2023-12-17 23:46:41 +03:00
name="$(parse_pascal ${name})"
2023-12-17 16:27:21 +03:00
fi
# remove old name.
local data="${target##*_}"
local new_name="${name}_${data}"
# check for the same name.
[[ "${target}" = "${new_name}" ]] && return 0
# check for existing target.
if [[ -f "${new_name}" ]]; then
_error "${new_name}: Already exists!"
return 1
fi
# rename.
mv -- ${target} ${new_name} && echo ${new_name}
2023-12-16 21:56:30 +03:00
}
2023-12-05 21:50:45 +03:00
2023-12-16 21:56:30 +03:00
_iterate_targets process ${targets[@]}
}
2023-12-16 17:13:06 +03:00
# Extract previously created archive with checksum validation.
# Usage: unarchive [FILES]
function unarchive() {
local IFS=$'\n'
2023-12-16 22:52:36 +03:00
local targets=(${@})
[[ "${targets}" = "" ]] && targets=$(ls | grep -E ${_archive_pattern})
2023-12-16 17:13:06 +03:00
2023-12-16 22:52:36 +03:00
process() {
2023-12-16 17:13:06 +03:00
# extract hash from name.
2023-12-16 22:52:36 +03:00
local data=($(_archive_parse ${target}))
local saved=${data[2]}
2023-12-16 17:13:06 +03:00
# calculate actual hash.
2023-12-16 22:52:36 +03:00
local actual=$(pv ${target} | sha1sum | cut -d\ -f1)
2023-12-16 17:13:06 +03:00
# extract if hash matched or show error if not.
if [[ "${saved}" = "${actual}" ]]; then
case "${target##*.}" in
"txz")
2023-12-16 22:52:36 +03:00
pv ${target} | xz -d | tar -xf -
2023-12-16 17:13:06 +03:00
;;
"tgz")
2023-12-16 22:52:36 +03:00
pv ${target} | gzip -d | tar -xf -
2023-12-16 17:13:06 +03:00
;;
esac
else
2023-12-17 20:12:33 +03:00
_error "Failed."
2023-12-17 16:27:21 +03:00
return 1
2023-12-16 17:13:06 +03:00
fi
2023-12-16 22:52:36 +03:00
}
2023-12-16 17:13:06 +03:00
2023-12-16 22:52:36 +03:00
_iterate_targets process ${targets[@]}
2023-12-16 17:13:06 +03:00
}
2023-12-16 21:56:30 +03:00
# Parse archive file name to get: name, date, hash and format.
# Usage: _archive_parse <FILENAME>
function _archive_parse() {
local input="${1}"
local name="${input%_*}"
local format="${input##*.}"
local data="${input##*_}"; data="${data%.*}"
local date="${data%%-*}"
local hash="${data##*-}"
echo "${name}"
echo "${date}"
echo "${hash}"
echo "${format}"
}
# Autocomplete for archive_name function.
# First arg is the archives list, second one is selected archive's current name.
function _archive_name() {
local IFS=$'\n'
COMPREPLY=()
local cur="${COMP_WORDS[COMP_CWORD]}"
local prev="${COMP_WORDS[COMP_CWORD-1]}"
local command="${COMP_WORDS[0]}"
if [[ "${prev}" = "${command}" ]]; then
COMPREPLY=( $(compgen -W "$(ls | grep -E ${_archive_pattern})" -- ${cur}) )
return 0
else
local name="${prev%_*}"
COMPREPLY=( $(compgen -W "${name}" -- ${cur}) )
return 0
fi
}
2023-12-07 04:02:47 +03:00
# Autocomplete with archives in current dir.
2023-12-07 01:44:42 +03:00
function _archive_grep() {
2023-12-07 04:02:47 +03:00
_autocomplete_grep ${_archive_pattern}
}
2023-12-16 22:52:36 +03:00
# Autocomplete with fast archives in current dir.
function _archive_grep_fast() {
_autocomplete_grep ${_archive_pattern_fast}
}
2023-12-07 04:02:47 +03:00
# Get date for a new archive.
function _archive_date() {
date +%Y%m%d%H%M
2023-10-30 14:22:24 +03:00
}
# Check if file is an archive.
function _is_archive() {
local out=$(echo "${*}" | grep -E ${_archive_pattern})
[[ "${out}" != "" ]]
}
2023-12-10 04:31:03 +03:00
complete -o filenames -F _archive_grep archive_check unarchive archive_rm
2023-12-16 22:52:36 +03:00
complete -o filenames -F _archive_grep_fast archive_xz
complete -o filenames -F _archive_name archive_name