#!/bin/bash
#
# Drupal management script.
#
BASE=${BASE:="/var/www/data"}
SITES=${SITES:="$BASE/drupal"}
SERIES="6 7 8 9"
LATEST_SERIES="9"
# Ensure we have a proper path, useful when called through cron
export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
# Read a parameter from user
function drupal_user_input {
local input
param="$1"
default="$2"
shift 2
if echo $param | grep -q 'passwd'; then
read -s -rep "$* (defaults to $default): " input
else
read -rep "$* (defaults to $default): " input
fi
if [ -z "$input" ]; then
export $param="$default"
else
export $param="$input"
fi
}
# Get drupal major version
function drupal_get_major {
echo $1 | sed -e 's/\(^.\).*/\1/'
}
# Check for existing installations
function drupal_check_existing {
if [ -e "$BASE/drupal-$1" ]; then
if [ "$SILENT" != "yes" ]; then
echo "Folder $BASE/drupal-$1 already exists, skipping"
fi
exit
fi
}
# Check for non existing installations
function drupal_check_not_existing {
if [ ! -e "$BASE/drupal-$1" ]; then
if [ "$SILENT" != "yes" ]; then
echo "Folder $BASE/drupal-$1 does not exist, skipping"
fi
exit 1
fi
}
# Iterate through all drupal instances
function drupal_iterate {
local command="$1"
if [ -z "$command" ]; then
return
fi
if [ "$command" != "cron" ] && [ "$SILENT" != "yes" ]; then
echo "Issuing $command in all installed instances..."
fi
for version in $SERIES; do
# Setup base folder
base="$BASE/drupal-$version"
if [ ! -d "$base/sites" ]; then
continue
fi
# Only cron action is available for drupal 6
if [ "$version" == "6" ] && [ "$command" != "cron" ]; then
continue
fi
# Setup site folders with .onion sites in the end of the list
# and ignoring site names without dots
cd $base/sites
drupals="`ls -1 -I default -I all -I example.sites.php -I '*.onion' | grep "\." | xargs`"
drupals="$drupals `ls -1 | grep '.onion$' | xargs`"
# Issue updates
for drupal in $drupals; do
if [ -e "$drupal/settings.php" ]; then
hash="`sha1sum $drupal/settings.php | cut -d ' ' -f 1`"
# Process sites just once, avoiding symlinks
if echo $settings_hash | grep -q -v "$command:$hash"; then
settings_hash="$settings_hash-$command:$hash"
if [ "$command" != "cron" ] && [ "$SILENT" != "yes" ]; then
echo "Processing $drupal..."
fi
if [ "$command" == "update" ] || [ "$command" == "cron-update" ]; then
shift
drupal_update $command $drupal $*
else
drush -l $drupal $*
fi
fi
fi
done
# Fix permissions
#if [ "`whoami`" == "root" ]; then
# chown -R drupal.drupal $base/modules
# chown -R drupal.drupal $base/themes
# if [ -e "$base/sites/all/modules" ]; then
# chown -R drupal.drupal $base/sites/all/modules
# fi
# if [ -e "$base/sites/all/themes" ]; then
# chown -R drupal.drupal $base/sites/all/themes
# fi
#fi
done
}
# Update a drupal instance
function drupal_update {
local method="$1"
local instance="$2"
local confirm
local line
shift 2
if [ "$method" == "cron-update" ]; then
confirm="-y"
fi
# See https://drupal.org/node/823146#comment-3319070
drush -l $instance up -u 1 --pipe | \
grep -v -E 'Unknown|Up-to-date|Atualizado|Desconhecido|^Array$|^\($|^\)$|OK' | while read line ; do
# Avoid automated core updates
code="`echo $line | cut -d " " -f1`"
if [ "$code" == "drupal" ]; then
echo "Core update available: $line"
else
echo "Updating $code on instance $instance..."
drush -l $instance up -u 1 $confirm $* $code
fi
done
}
# Get the current installed version of a given series
function drupal_current {
local series="$1"
if [ -z "$series" ]; then
series="$LATEST_SERIES"
fi
if [ -e "$BASE/drupal-${series}" ]; then
readlink $BASE/drupal-${series} | sed -e 's/^drupal-//'
else
echo 0
fi
}
# Get the latest version of a given series
# Operate only on stable releases, filtering out dev, alpha, beta and rc releases
# https://drupal.stackexchange.com/questions/23700/how-to-find-download-latest-drupal-version-via-bash#23704
function drupal_latest {
local series="$1"
if [ -z "$series" ]; then
series="$LATEST_SERIES"
fi
if [ "$series" == "9" ]; then
latest="`wget -O- -q https://www.drupal.org/node/3060/release/feed | grep "" ~/load/feed | grep "releases/9." | cut -d "/" -f 7 | cut -d '<' -f 1 | sort -r | head -1`"
echo $latest
else
latest="`wget -O- -q https://updates.drupal.org/release-history/drupal/${series}.x | grep -oPm1 "(?<=)[^<]+" | grep -v -- '-dev' | grep -v -- '-alpha' | grep -v -- '-beta' | grep -v -- '-rc' | head -1`"
latest="`basename $latest`"
echo $latest | sed -e 's/^drupal-//' -e 's/.tar.gz$//'
fi
}
# Deploy a fresh drupal tree
function drupal_download {
if [ -z "$1" ]; then
echo "Usage: `basename $0` download [--upgrade]"
exit 1
else
new="$1"
fi
# Check for latest releases if no specific version was given
if [ "$new" == "9" ]; then
drupal_series="9"
new="`drupal_latest 9`"
elif [ "$new" == "8" ]; then
drupal_series="8"
new="`drupal_latest 8`"
elif [ "$new" == "7" ]; then
drupal_series="7"
new="`drupal_latest 7`"
elif [ "$new" == "6" ]; then
drupal_series="6"
new="`drupal_latest 6`"
else
drupal_series="`drupal_get_major $new`"
fi
cd $BASE
drupal_check_existing $new
# Deploy a fresh drupal tree
wget http://ftp.drupal.org/files/projects/drupal-$new.tar.gz
tar zxvf drupal-$new.tar.gz && rm drupal-$new.tar.gz
if [ "`whoami`" == "root" ]; then
chown -R drupal.drupal drupal-$new/
fi
# Upgrade mode, erase sites folder as the previous should be copied.
if [ "$2" == "--upgrade" ]; then
cd drupal-$new && rm -rf sites
fi
# Make symlink if needed.
if [ ! -e "$BASE/drupal-$drupal_series/CHANGELOG.txt" ]; then
# Deal with a possibly empty drupal folder
rmdir $BASE/drupal-$drupal_series &> /dev/null
( cd $BASE && ln -s drupal-$new drupal-$drupal_series )
fi
}
# Upgrade a drupal instance using upstream source
function drupal_upgrade {
if [ "$#" != "1" ] && [ "$#" != "2" ]; then
echo "Usage: `basename $0` upgrade [new_version]"
exit 1
fi
# Get versions
old="$1"
new="$2"
# Fix versions if just a series is given
if [ "$old" == "9" ] && [ -z "$new" ]; then
old="`drupal_current 9`"
new="`drupal_latest 9`"
drupal_series="9"
elif [ "$old" == "8" ] && [ -z "$new" ]; then
old="`drupal_current 8`"
new="`drupal_latest 8`"
drupal_series="8"
elif [ "$old" == "7" ] && [ -z "$new" ]; then
old="`drupal_current 7`"
new="`drupal_latest 7`"
drupal_series="7"
elif [ "$old" == "6" ] && [ -z "$new" ]; then
old="`drupal_current 6`"
new="`drupal_latest 6`"
drupal_series="6"
else
old_major="`drupal_get_major $old`"
new_major="`drupal_get_major $new`"
drupal_series="$new_major"
fi
if [ "$old_major" != "$new_major" ]; then
echo "Major versions doesn't match"
exit 1
fi
drupal_check_existing $new
drupal_check_not_existing $old
cd $BASE
# Deploy a fresh drupal tree
drupal_download $new --upgrade
# Ensure we're in the new drupal folder
cd $BASE/drupal-$new
# Copy files
for file in sites; do
if [ ! -h "../drupal-$old/$file" ]; then
cp -alf ../drupal-$old/$file . &> /dev/null
else
# Symlink handling
ln -sf $file `readlink ../drupal-$old/$file`
fi
done
extra_folders=""
# Extra folder
for extra_folder in $extra_folders; do
if [ -d ../drupal-$old/$extra_folder ]; then
cp -Rp ../drupal-$old/$extra_folder .
fi
done
# Copy installation profiles
rsync -av --exclude=default ../drupal-$old/profiles/ profiles/
# Copy installation themes and modules for Drupal 8 or newer
if [ "$new_major" != "5" ] && [ "$new_major" != "6" ] && [ "$new_major" != "7" ]; then
rsync -av ../drupal-$old/modules/ modules/
rsync -av ../drupal-$old/themes/ themes/
rsync -av ../drupal-$old/libraries/ libraries/
fi
# Change symlink to point to the new location
cd $BASE ; rm -rf drupal-$drupal_series && ln -sf drupal-$new drupal-$drupal_series
# Done
echo "Audit: `du -hs drupal-$old`"
echo "Audit: `du -hs drupal-$new`"
echo "Check procedure and remove drupal-$old once you make sure that everything is fine."
}
# Run a drupal makefile
function drupal_make {
if [ -z "$1" ]; then
echo "Usage: `basename $0` make "
exit 1
fi
series="$1"
base="$BASE/drupal-$series"
makefile="/usr/local/share/drupal/drupal$series.make"
makefile_themes="/usr/local/share/drupal/themes$series.make"
if [ -e "$makefile" ]; then
if [ ! -e "$base" ]; then
echo "Please download drupal code at $base first"
exit 1
fi
drush dl drush_make
( cd $base && drush make -y --no-core $makefile )
( cd $base && drush make -y --no-core $makefile_themes )
else
echo "Makefile not found: $makefile"
exit 1
fi
}
# Ensure base is absolute
if [ ! -d "$BASE" ]; then
echo "Folder $BASE does not exist"
exit 1
else
BASE="`cd $BASE &> /dev/null && pwd`"
fi
# Main procedure
if [ -z "$1" ]; then
echo "Usage: `basename $0` [arguments]"
exit 1
elif [ "$1" == "cron" ]; then
drupal_iterate cron
elif [ "$1" == "cron-update" ]; then
SILENT="yes"
drupal_iterate pm-refresh &> /dev/null
drupal_iterate cron-update
elif [ "$1" == "download" ] || [ "$1" == "dl" ]; then
shift
drupal_download $*
elif [ "$1" == "update" ]; then
shift
drupal_iterate pm-refresh
drupal_iterate update $*
# Update alone might not trigger updatedb in a farm for all instances.
drupal_iterate updatedb $*
drupal_iterate cc all $*
elif [ "$1" == "updatedb" ]; then
shift
drupal_iterate updatedb $*
elif [ "$1" == "upgrade" ]; then
shift
drupal_upgrade $*
elif [ "$1" == "current" ]; then
shift
drupal_current $*
elif [ "$1" == "latest" ]; then
shift
drupal_latest $*
elif [ "$1" == "run" ]; then
shift
drupal_iterate $*
elif [ "$1" == "make" ]; then
shift
drupal_make $*
else
echo "No action $1"
exit 1
fi