diff --git a/sync.sh b/sync.sh new file mode 100755 index 0000000..e9e750c --- /dev/null +++ b/sync.sh @@ -0,0 +1,155 @@ +#!/bin/bash + +source .env + +set -e +set -o pipefail + +log() { + echo -e "\e[92m---\e[39m $*" +} + +warn() { + echo -e "\e[93m***\e[39m $*" >&2 +} + +err() { + echo -e "\e[91m!!!\e[39m $*" >&2 +} + +if [ -z "${INPUT_HASHFILE}" ]; then + err "Invalid hash file" + exit 1 +fi + +case "${INPUT_HASHTYPE}" in + sha256) + hashcmd=sha256sum + ;; + + sha512) + hashcmd=sha512sum + ;; + + md5) + hashcmd=md5sum + ;; + + *) + err "Unsupported hash type \"${INPUT_HASHTYPE}\"" + exit 1 +esac + +autoconfirm=yes +case "${INPUT_PROTOCOL}" in + ftp) + if [ ! -z "${INPUT_HOSTKEY}" ]; then + err "Unexpected host public key in FTP mode" + exit 1 + fi + + if [ ! -z "${INPUT_CLIENTKEY}" ]; then + err "Unexpected client private key in FTP mode" + exit 1 + fi + + ;; + + sftp) + [ -d /root/.ssh/ ] || mkdir -p /root/.ssh/ + + if [ ! -z "${INPUT_PASSWORD}" ]; then + err "Unexpected user password in SFTP mode" + exit 1 + fi + + if [ -z "${INPUT_HOSTKEY}" ]; then + warn "Not checking host SSH key" + else + log "Configuring host SSH key" + autoconfirm=no + echo "${INPUT_HOST} ${INPUT_HOSTKEY}" >>/root/.ssh/known_hosts + # Hash key, or else the SSH command ignores it + ssh-keygen -H -f /root/.ssh/known_hosts + fi + + if [ ! -z "${INPUT_CLIENTKEY}" ]; then + log "Configuring client SSH key" + echo -n "${INPUT_CLIENTKEY}" >>/root/.ssh/id_rsa + chmod 0600 /root/.ssh/id_rsa + fi + + ;; + + *) + err "Invalid protocol \"${INPUT_PROTOCOL}\"" + exit 1 +esac + +log "Hashing files with $hashcmd" + +cd "${INPUT_SOURCE}" + +# Sort by file name +find -type f -print0 | xargs -0 "$hashcmd" | sort -k 2 > ./localhashes + +log "Fetching remote hash list" + +export LFTP_PASSWORD="${INPUT_PASSWORD}" +if [ -z "${LFTP_PASSWORD}" ]; then + # Also works as placeholder for LFTP when using SFTP with public key authentication + export LFTP_PASSWORD=anonymous +fi + +connect_boilerplate=$(cat <./remotehashes +else + warn "Could not fetch remote files - assuming file did not exist" + echo "">./remotehashes +fi + +log "Creating sync script" + +cat <./syncscript +${connect_boilerplate} +cd "${INPUT_DESTINATION}" +EOF + +# Make directories +find -type d | sed -nr 's|^\./(.*)|mkdir -f "\1"|p' >>./syncscript + +# Diff returns non-zero if there are differences - disable error checking for the next line +set +e + +# Diff, then remove first 3 lines (with filenames) +diff -U0 ./remotehashes ./localhashes | tail -n +3 >./hashdiff + +# Reenable error checking +set -e + +# First RMs +sed -nr 's|^-[^ ]+ +\./(.*)$|rm "\1"|p' ./hashdiff >>./syncscript + +# The PUTs +sed -nr 's|^\+[^ ]+ +\./(.*)$|put "\1" -o "\1"|p' ./hashdiff >>./syncscript + +cat <>./syncscript +put ./localhashes -o "${INPUT_HASHFILE}" +EOF + +log "Running script" + +cat ./syncscript +lftp -f ./syncscript + +log "Done" \ No newline at end of file