#!/bin/sh root=$( realpath "$( dirname "$0" )" ) direction=$1 ALIAS="$root/alias" EXCLUDES="$root/excludes" DOTEXCLUDES="$root/.excludes" FILES="$root/files" USERS="$root/users" RSYNC="rsync -a -s --progress --delete" LOCAL="storage" host_name() { local host=$1 local alias_path="$ALIAS/$host" if [ -f "$alias_path" ] then cat "$alias_path" else echo "$host" fi } host_prefix() { local host=$1 local hostname=$( hostname ) local user_path="$USERS/$host.txt" local user for local in $LOCAL do if [ "$host" = "$local" ] then return fi done if [ "$host" = "$hostname" ] then return fi if [ -f "$user_path" ] then user=$( cat "$user_path" ) echo "$user@$host:" else echo "$host:" fi } host_files_list() { local host=$1 local qualifier=$2 local host_files_path="$FILES/$host.txt" local qualifier_host_files_path="$FILES/$qualifier/$host.txt" local descriptor if [ -f "$host_files_path" ] then cat "$host_files_path" | while read descriptor do eval echo "$descriptor" done fi if [ -f "$qualifier_host_files_path" ] then cat "$qualifier_host_files_path" | while read descriptor do eval echo "$descriptor" done fi } host_file_path() { local host_file_descriptor=$1 echo "$host_file_descriptor" | sed "s,:.*,," } host_file_name() { local host_file_descriptor=$1 shift local host_file_suffix=$( echo "$host_file_descriptor" | sed -n "s,.*:\(.*\)$,\1,p" ) local host_file_name local test=$@ if [ -z "$host_file_suffix" ] then host_file_name=$( basename "$host_file_descriptor" ) else host_file_name=$host_file_suffix fi if [ -z "$test" ] then echo "$host_file_name" return fi for name in "$@" do if [ "$host_file_name" = "$name" ] then echo "$name" fi done } host_file_match() { local destination=$1 local source_file_name=$2 local descriptor local name host_files_list "$destination" "destination" | while read descriptor do name=$( host_file_name "$descriptor" ) if [ "$source_file_name" = "$name" ] then echo "$descriptor" fi done } host_excludes() { local host=$1 local name=$2 local excludes_path="$EXCLUDES/$name.txt" local host_excludes_path="$EXCLUDES/$host/$name.txt" if [ -f "$excludes_path" ] then cat "$excludes_path" fi if [ -f "$host_excludes_path" ] then cat "$host_excludes_path" fi } usage() { printf "$0 [source] [destination] (names)\n" >&2 } sync() { local source=$1 shift local destination=$1 shift local source_prefix local source_path local destination_prefix local destination_path local descriptor local name local match local dry local dry_description set -e if [ -z "$source" ] || [ -z "$destination" ] then usage exit 1 fi source_name=$( host_name "$source" ) destination_name=$( host_name "$destination" ) source_prefix=$( host_prefix "$source" ) destination_prefix=$( host_prefix "$destination" ) host_files_list "$source_name" "source" | while read descriptor do name=$( host_file_name "$descriptor" "$@" ) if [ -z "$name" ] then continue fi match=$( host_file_match "$destination_name" "$name" ) if [ -z "$match" ] then continue fi if [ -n "$DRY" ] then dry="--dry-run" dry_description=" \e[1;31m(dry run)\e[0m" fi source_path=$( host_file_path "$descriptor" ) destination_path=$( host_file_path "$match" ) echo -n "" > "$DOTEXCLUDES" host_excludes "$destination_name" "$name" >> "$DOTEXCLUDES" host_excludes "$source_name" "$name" >> "$DOTEXCLUDES" echo -e "Sync \e[1;34m$name\e[0m from \e[1;33m$source\e[0m to \e[1;33m$destination\e[0m$dry_description" $RSYNC $dry --exclude-from="$DOTEXCLUDES" "$source_prefix$source_path" "$destination_prefix$destination_path" rm "$DOTEXCLUDES" done } sync "$@"