Last active
November 21, 2015 10:12
-
-
Save wackazong/4e7da34c4c2173a23bb2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# deploys the distribution directory of a repo to a remote host | |
# remote host needs to be configured in .ssh/config with | |
# public key authentication, use LogLevel ERROR | |
# remote host must only have ls, rm and mkdir installed | |
# no other tools are needed on the remote host | |
# distribution directory must contain only files to be deployed | |
# only new files are transferred (using a saved checksum for | |
# each file saved in a directory tree in the repo) | |
# all other files and directories in the hostpath are deleted | |
# run in the root of the repo, e.g. with grunt-shell | |
# set distribution directory below | |
# constants | |
# path to the directory which should be deployed | |
distdir=dist | |
# root of the checksum directory tree | |
ckroot=.cksums | |
# hostname in ssh config | |
hostname=$1 | |
#hostpath | |
hostpath=$2 | |
#loglevel | |
loglevel=$3 | |
if [ -z "$hostname" ]; then | |
echo "No hostname supplied" | |
exit 3 | |
fi | |
if [ -z "$hostpath" ]; then | |
echo "No host path supplied" | |
exit 2 | |
fi | |
if [[ ! "${ckroot}" == "${ckroot% *}" ]] ; then | |
echo ckroot cannot contain spaces | |
exit 4 | |
fi | |
if [[ ! "${hostpath}" == "${hostpath% *}" ]] ; then | |
echo hostpath cannot contain spaces | |
exit 4 | |
fi | |
# check if root of checksum directory tree exists | |
if [[ ! -d ${distdir} ]]; then | |
echo deploy directory ${distdir} does not exist, exiting | |
exit 1 | |
fi | |
# check if root of checksum directory tree exists | |
if [[ ! -d ${ckroot} ]]; then | |
echo creating root directory ${ckroot} | |
mkdir ${ckroot} | |
fi | |
function debug { | |
if [[ ${loglevel} = debug ]]; then | |
echo $1 | |
fi | |
} | |
# update checksum tree with contents of dist | |
debug ========================================================================================== | |
echo Updating checksum tree with contents of ${distdir} | |
# loop via http://unix.stackexchange.com/questions/9496/looping-through-files-with-spaces-in-the-names | |
find ${distdir} -print0 | while IFS= read -r -d '' file; do | |
#skip dist dir itself. find ${distdir}/* does not work because it skips hidden files like .htaccess | |
if [[ ${file} = ${distdir} ]]; then | |
continue | |
fi | |
#get only the file name | |
file=$(echo ${file} | sed "s/${distdir}\///") | |
debug ---------------------------------------------------------------------------------- | |
debug "working on ${file}" | |
found=false | |
ckfile=${ckroot}/${file} | |
# compare and create new checksums, deploy if file is new | |
if [[ -d ${distdir}/${file} ]]; then | |
debug "${file} is a directory, checking ${ckfile}" | |
#check if directory exists in cksum tree | |
if [[ -e ${ckfile} ]]; then | |
#check if its a directory | |
if [[ -d ${ckfile} ]]; then | |
#all good | |
found=true | |
debug "Directory ${ckfile} found" | |
else | |
#something else is here, delete it | |
debug "Found something else in ckroot instead of directory ${ckfile}, deleting it" | |
rm -rf ${ckfile} | |
fi | |
fi | |
fi | |
if [[ -f ${distdir}/${file} ]]; then | |
debug "${file} is a file, checking ${ckfile}.cksum" | |
#check if file exists in cksum tree | |
if [[ -e ${ckfile}.cksum ]]; then | |
#check if its a file | |
if [[ -f ${ckfile}.cksum ]]; then | |
#check if the checksum matches | |
oldchecksum=$(cat "${ckfile}.cksum") | |
newchecksum=$(cksum "${distdir}/${file}") | |
debug "old checksum is ${oldchecksum}" | |
debug "new checksum is ${newchecksum}" | |
if [[ ${oldchecksum} = ${newchecksum} ]]; then | |
found=true | |
debug "Checksum of file ${file} is not different, skipping it" | |
fi | |
else | |
#something else is here, delete it | |
debug "Found something else in ckroot instead of file ${ckfile}.cksum, deleting it" | |
rm -rf ${ckfile}.cksum | |
fi | |
fi | |
fi | |
# create file or directory if it does not exist | |
if [[ ${found} = false ]]; then | |
echo ${file} was not found or checksum is different, deploying it | |
hostfile=${hostpath}/${file} | |
debug "hostfile is ${hostfile}" | |
if [[ -d ${distdir}/${file} ]]; then | |
#delete what was there on the host, there should not be anything | |
debug "deleting ${hostfile} on host before creating new directory" | |
#the n flag is needed so that ssh does not read all remaining files in the loop from stdin | |
ssh -n ${hostname} rm -rf "\"${hostfile}\"" | |
#create directory on host | |
debug "create directory ${hostfile} on host" | |
ssh -n ${hostname} mkdir "\"${hostfile}\"" | |
#create directory in ckroot tree | |
debug "Creating directory ${ckfile}" | |
mkdir "${ckfile}" | |
fi | |
if [[ -f ${distdir}/${file} ]]; then | |
#transfer the file | |
debug "transferring with scp" | |
scp "${distdir}/${file}" ${hostname}:"\"${hostfile}\"" > /dev/null | |
#create a new checksum | |
debug "creating new checksum for ${file} and storing it in ${ckfile}.cksum" | |
cksum "${distdir}/${file}" > "${ckfile}.cksum" | |
fi | |
fi | |
debug "finished ${file}" | |
done | |
debug ========================================================================================== | |
# delete old files from checksum tree | |
echo Delete unmatched files in checksum tree ${ckroot} | |
# loop via http://unix.stackexchange.com/questions/9496/looping-through-files-with-spaces-in-the-names | |
find ${ckroot} -print0 | while IFS= read -r -d '' cksumfile; do | |
#skip ckroot dir itself. find ${ckroot}/* does not work because it skips hidden files like .htaccess | |
if [[ ${cksumfile} = ${ckroot} ]]; then | |
continue | |
fi | |
debug ---------------------------------------------------------------------------------- | |
debug "working on ${cksumfile}" | |
#remove leading directory | |
file=$(echo ${cksumfile} | sed "s/^${ckroot}\///") | |
if [[ -f ${cksumfile} ]]; then | |
#remove .cksum ending | |
file=$(echo ${file} | sed "s/\.cksum$//") | |
fi | |
debug "checking if checksum file ${cksumfile} has existing file ${file} in ${distdir}" | |
#delete chksum file if file does not exist in distdir | |
if [[ ! -e ${distdir}/${file} ]]; then | |
echo removing ${cksumfile} | |
rm -rf "${cksumfile}" | |
fi | |
debug "finished ${cksumfile}" | |
done | |
OFS=${IFS} | |
IFS=$'\n' | |
debug ========================================================================================== | |
# delete old directories on host | |
echo Delete unmatched directories from host | |
# getting recursive full path ls output: http://stackoverflow.com/questions/1767384/ls-command-how-can-i-get-a-recursive-full-path-listing-one-line-per-file | |
# fixing case statements in command substitutions: http://wiki.bash-hackers.org/syntax/expansion/cmdsubst | |
dirs=$(ssh ${hostname} ls -apR1 ${hostpath} | while read l; do case $l in (*:) d=${l%:};; ("") d=;; (*) echo "$d/$l";; esac; done | grep -v "\/\.\.\/$" | grep -v "\/\.\/$" | grep \/$) | |
for file in ${dirs}; do | |
debug ---------------------------------------------------------------------------------- | |
file=$(echo ${file} | sed "s/${hostpath}\///") | |
debug "working on host directory ${file}, see if ${ckroot}/${file} exists" | |
if [[ ! -d ${ckroot}/${file} ]]; then | |
echo directory ${file} does not exist in source, deleting | |
ssh -n ${hostname} rm -rf "\"${hostpath}/${file}\"" | |
fi | |
debug "finished ${file}" | |
done | |
# delete old files on host | |
debug ========================================================================================== | |
echo Delete unmatched files from host | |
dirs=$(ssh ${hostname} ls -apR1 ${hostpath} | while read l; do case $l in (*:) d=${l%:};; ("") d=;; (*) echo "$d/$l";; esac; done | grep -v "\/\.\.\/$" | grep -v "\/\.\/$" | grep -v \/$) | |
for file in ${dirs}; do | |
file=$(echo ${file} | sed "s/${hostpath}\///") | |
#skip if its a directory | |
if [[ ! -d ${ckroot}/${file} ]]; then | |
debug ---------------------------------------------------------------------------------- | |
debug "working on host file ${file}, see if ${ckroot}/${file}.cksum exists" | |
if [[ ! -e ${ckroot}/${file}.cksum ]]; then | |
echo file ${file} does not exist in source, deleting | |
ssh -n ${hostname} rm -rf "\"${hostpath}/${file}\"" | |
fi | |
debug "finished ${file}" | |
fi | |
done | |
IFS=${OFS} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment