shell-base/modules/utility/copy.lib

296 lines
8.4 KiB
Bash

#!/bin/bash
export COPY_MODULE_PATH="$(dirname $(realpath "${BASH_SOURCE:-$0}"))"
module_load debug
module_load confirm
module_load helpers
copy () {
if ! which rsync &> /dev/null; then echo rsync must be installed to use this function; return 6; fi
local SHOST; local DHOST; local sshargs; local args
local SRC; local DEST; local mirror; local quiet; local Mirror
local SPATH; local DPATH; local exec; local list; local verbose
local usesudo;local cmd;local noconfirm;local insert
args=()
help() {
cat <<EOF
usage:
rsync <script options> source destination <rsync options> --- <ssh options>
Available Script Options
-r, run the command by this script uses --dry-run. When ready pass this flag.
-s, run command as sudo
-l, list the rsync command that will be run instead of running it. removes --dry-run.
great for generating a rsync command to be used elsewhere
-p, make path at destination if need be. careful will creating missing subdirectories
-e, rsync --exclude , as many of these as desired
-i, insert source inside destination instead of making folder at destination, good for changing destination folder name
-m, copy as "mirror" uses options. -a --numeric-ids --delete --force
-M, copy as "mirror" above -m plus '--delete-excluded' added. A perfect mirror
-f, rsync --exclude-from <path>, can have multiple
-F, copy a filesystem, uses -M mirror plus -xHAXS, and uses sudo (i.e. -s script option)
-n, no confirm, will always confirm command unless this is set
-q, quiet, suppress progress
-v, verbose, same as -v for rsync option, unset if -q is set
-a, archive, same as -a for rsync option, basic identical copy with recursion
-c, clean tranfer meaning will not transfer folder with trash, cache, log, nodemodules
-C, show excludes for clean transfer
-h, this help text
source or destination may include a <host>: prefix but not both
use 'fcopy <src> <dest>' for fast copy uses -r -q -m -n -a
EOF
}
# parse sshcp options
local OPTION
local OPTARG
local OPTIND
while getopts 'avMqpf:le:rcCmd:shnFi' OPTION; do
# echo OPTION $OPTION ARG $OPTARG INDX $OPTIND
case "$OPTION" in
# TODO add D and S for destion and source path
s)
usesudo=sudo
;;
c)
# clean out unneeded folders like cache, trash, log
args+=("--exclude-from=$COPY_MODULE_PATH/cache-trash-log.exc")
;;
C)
echo "## clean transfer exclusions found in $COPY_MODULE_PATH/cache-trash-log.exc ##"
cat "$COPY_MODULE_PATH/cache-trash-log.exc"
echo -e "\n##############################################"
return 0
;;
q)
quiet=true
;;
n)
noconfirm=true
;;
e)
args+=("--exclude=$OPTARG")
;;
f)
args+=("--exclude-from=$OPTARG")
;;
F)
args+=("-xHAXS")
mirror=true
usesudo=sudo
args+=("--exclude-from=$COPY_MODULE_PATH/cache-trash-log.exc")
;;
p)
args+=("--mkpath")
;;
i)
insert=true
;;
m)
mirror=true
;;
M)
Mirror=true
mirror=true
;;
l)
list=true
;;
v)
verbose="-v"
;;
r)
exec=true
;;
a)
args+=("-a")
;;
h)
help
return 0
;;
*)
>&2 echo fatal: unknown remote script option $OPTION, aborting
help
return 1
;;
esac
done
shift $((OPTIND - 1))
[ $# -lt 2 ] && echo both a source and destination need to be passed && return 2
# source parse
SRC=$1; shift
if [[ $SRC =~ ":" ]]; then
echo source is remote
SHOST=${SHOST:-$(sed 's/\(.*\):.*/\1/' <<< "$SRC")}
SPATH=$(sed 's/.*:\(.*\)/\1/' <<< "$SRC")
else
# echo source is local
SPATH=$SRC
fi
# destination parse
DEST=$1;shift
if [[ $DEST =~ ":" ]]; then
# echo destination is remote
DHOST=${DHOST:-$(sed 's/\(.*\):.*/\1/' <<< "$DEST")}
DPATH=$(sed 's/.*:\(.*\)/\1/' <<< "$DEST")
else
# echo destination is local
DPATH=$DEST
fi
[[ $DHOST && $SHOST ]] && echo this script can not process remote host to remote host transfer && return 5
# is source or destination is remote, create -e ssh sync option
if [[ $DHOST || $SHOST ]]; then
# echo remote copy, loading ssh
if ! module_load ssh &>/dev/null; then
echo unable to load ssh module
echo likely the uci network repo has not been installed
echo to do a remote copy this repo which contains the ssh module
echo "must be installed. Try \"module_load uci-shell-install; install_shell_network\""
return 6
fi
if [[ ! $(get_user_host ${DHOST:-$SHOST}) ]]; then
>&2 echo fatal: the host ${DHOST:-$SHOST} is not valid, aborting remote copy
return 1
fi
# else
# echo local rsync copy
fi
[[ ! $SHOST ]] && SPATH=$(realpath $SPATH)
[[ ! $DHOST ]] && DPATH=$(realpath $DPATH)
# parse ssh arguments from the rest
debug $( ( IFS=$','; echo all arguments: "$*" ) )
for ((d=1; d<$#; ++d)); do
[[ ${!d} == "---" ]] && break
done
if [[ $d -lt $# ]]; then # if there are extra ssh arguments
debug found --- at $d
sshargs=("${@:$d+1:$#}")
debug $( ( IFS=$','; echo "ssh arguments: ${sshargs[*]}" ) )
args+=("${@:1:$d-1}")
debug $( ( IFS=$','; echo remaining arguments to parse: "$*" ) )
else
args+=("${@:1}")
fi
[[ $DHOST || $SHOST ]] && args+=( "$(remove_end_spaces "-e '$(ssh -l "${sshargs[*]}")'")")
# assemble options
[[ ! $exec ]] && args+=(--dry-run -v)
[[ ! $quiet ]] && args+=(--info=progress2 $verbose)
[[ $mirror ]] && args+=(-a --numeric-ids --delete --force)
[[ $Mirror ]] && args+=(--delete-excluded)
[[ ! -v PS1 ]] && noconfirm=true
if [[ ! $noconfirm && ! $list ]]; then
if [[ $insert ]]; then
# todo mirror option
confirm The contents within $([[ $SHOST ]] && echo $SHOST:)$SPATH will be \
$([[ $mirror ]] && echo mirrored || echo placed ) inside $([[ $DHOST ]] && echo $DHOST:)$DPATH || return 0
else
confirm the directory $(basename $SPATH) of $([[ $SHOST ]] && echo $SHOST:)$SPATH will be \
$([[ $mirror ]] && echo mirrored || echo put ) at destination $([[ $DHOST ]] && echo $DHOST:)$DPATH/$(basename $SPATH)? || return 0
fi
fi
cmd="$usesudo $(which rsync) ${args[*]} $SRC$([[ $insert ]] && echo "/") $DEST"
[[ $list ]] && echo "$cmd" && return 0
if [[ ! $quiet ]]; then [[ $exec ]] && echo executing the copy command || echo dry run of command, use -r to execute; fi
if eval $cmd; then
[[ ! $quiet ]] && echo copy success!
debug $cmd
else
>&2 echo remote copy failed
>&2 echo $cmd
return 1
fi
}
alias fcpy="copy -r -q -i -n -a "
# alias mirror="copy -i -a -M"
mirror_shell () {
local dir; local dest
#TODO don't overwrite hostname
[ $# -lt 2 ] && echo "both a directory and remote host need to be passed" && return 2
dir=$1
[[ ! -d $dir ]] && echo no directory $dir to mirror && return 1
dest=$2
shift 2
copy $@ -i -a -c -M "$dir" "$dest:$dir" --exclude=archive*
}
rpush () {
local dir; local dest
#TODO don't overwrite hostname
[ $# -lt 2 ] && echo "both a directory and remote host need to be passed" && return 2
dir=$1
[[ ! -d $dir ]] && echo no directory $dir to mirror && return 1
dest=$2
shift 2
copy "$@" -i -a "$dir" "$dest:$dir"
}
rpull () {
local dir; local src; local dest
#TODO don't overwrite hostname
[ $# -lt 2 ] && echo "remote pull, both a directory and remote host need to be passed" && return 2
dir=$1
src=$2
shift 2
if [[ ! $1 == "-"* ]]; then
dest=$1
shift
echo pulling to alternate directory $dest
fi
copy "$@" -l -i "$src:$dir" "${dest:-dir}"
copy "$@" -i "$src:$dir" "${dest:-dir}"
}
rpushmirror () {
rpush "$@" -M -c
}
rpullmirror () {
rpull "$@" -M -c
}
rbrowser_copy () {
local browser; local dest
[ $# -lt 2 ] && echo "both a browser directory (within /opt/chromium) and remote host need to be passed" && return 2
browser=$1
[[ ! -d /opt/chromium/$browser ]] && echo no browser directory /opt/chromium/$browser && return 1
dest=$2
shift 2
copy $@ -a -c -M "/opt/chromium/$browser" "$dest:/opt/chromium" --exclude=Singleton*
}