Created
June 12, 2020 21:53
-
-
Save gammy/1cc3b8e72d471ac7e185a00bf93c590b to your computer and use it in GitHub Desktop.
DokuWiki upgrade helper which takes conf and data directories into account.
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
#!/usr/bin/env bash | |
# Gammies grimey dokuwiki updater. | |
# | |
# This script is dumb, but not as dumb as the upgrade plugin. | |
# Use with caution: I may not have considered all possible scenarios. | |
# One thing this script does not check is adequate permission to create files | |
# and subdirectories. Just basic sanity is performed. | |
# | |
# Written mainly for my own needs. | |
web_user=www-data | |
web_group=www-data | |
backup_dir=/tmp | |
do_backup=1 | |
show_usage() | |
{ | |
local me=$(basename $0) | |
echo "Gammies dokuwiki updater" | |
echo "Usage: $me [opts] <dokuwiki root> <dokuwiki tarball>" | |
echo "Example: $me -b -c ~/dokuwiki_conf /public_html/wiki /tmp/dokuwiki-rc.tgz" | |
echo | |
echo "You WILL be prompted before the update procedure begins." | |
echo | |
echo "Options:" | |
echo "-s Do NOT crate a backup tarball of all specified directories" | |
echo "-b <path> Path to place backup tarball (default: $backup_dir)" | |
echo "-w <path> Path to (dirty) working directory; defaults to 'mktemp -d'" | |
echo "-c <path> Path to non-default 'dokuwiki_conf' directory" | |
echo "-d <path> Path to non-default 'dokuwiki_data' directory" | |
echo "-u <user> Use <user> as the web-process owner (default: $web_user)" | |
echo "-g <group> Use <group> as the web-process group (default: $web_group)" | |
echo "-h Show this message" | |
exit 0 | |
} | |
wrap_realpath() | |
{ | |
# Although realpath will return a non-existing file, it will | |
# error out if a subdirectory is specified where the parent doesn't exit | |
local rp=$(realpath "$1" 2>/dev/null) | |
if [ -z "$rp" ] | |
then | |
echo "$1" | |
else | |
echo "$rp" | |
fi | |
} | |
if [ $# -lt 2 ] | |
then | |
show_usage | |
exit 0 | |
fi | |
deps=(find rsync wc whoami grep awk tar cat) | |
deps_missing= | |
for dep in ${deps[@]} | |
do | |
# While GNU Which prints its own nice message to stderr if the program is | |
# missing, other implementations do not. | |
# We thus show the message ourselves based on the errorcode. | |
if ! which $dep > /dev/null 2>&1 | |
then | |
echo "Missing dependency: $dep" >&2 | |
deps_missing=y | |
fi | |
done | |
if [ -n "$deps_missing" ] | |
then | |
echo "Fatal: Unable to continue" >&2 | |
exit 1 | |
fi | |
noopt_args=() | |
work_dir= | |
data_dir= | |
conf_dir= | |
wiki_dir= | |
while [ $# -gt 0 ] | |
do | |
case "$1" in | |
-s) do_backup= ;; | |
-b) backup_dir="$2"; shift ;; | |
-w) work_dir="$2"; shift ;; | |
-c) conf_dir="$2"; shift ;; | |
-d) data_dir="$2"; shift ;; | |
-u) web_user="$2"; shift ;; | |
-g) web_group="$2"; shift ;; | |
-h) show_usage; exit 0 ;; | |
*) noopt_args+=($1) ;; | |
esac | |
shift | |
done | |
if [ ${#noopt_args[@]} -ne 2 ] | |
then | |
show_usage | |
exit 0 | |
fi | |
wiki_dir="${noopt_args[0]}" | |
tar_file="${noopt_args[1]}" | |
[ -z "$data_dir" ] && data_dir="$wiki_dir/data" | |
[ -z "$conf_dir" ] && conf_dir="$wiki_dir/conf" | |
[ -z "$work_dir" ] && work_dir=$(mktemp -d) | |
backup_dir=$(wrap_realpath "$backup_dir") | |
work_dir=$(wrap_realpath "$work_dir") | |
data_dir=$(wrap_realpath "$data_dir") | |
conf_dir=$(wrap_realpath "$conf_dir") | |
wiki_dir=$(wrap_realpath "$wiki_dir") | |
tar_file=$(wrap_realpath "$tar_file") | |
echo "Paths" | |
echo "Tarball : '$tar_file'" | |
echo "Wiki root path: '$wiki_dir'" | |
echo "Data path : '$data_dir'" | |
echo "Config path : '$conf_dir'" | |
echo "Work path : '$work_dir'" | |
echo "Backup path : '$backup_dir'" | |
echo | |
echo "Users / Groups" | |
echo "Web user : '$web_user'" | |
echo "Web group : '$web_group'" | |
echo "Current user : '$(whoami)'" | |
echo "Current groups: '$(groups)'" | |
echo | |
echo -n "Perform backup: " | |
if [ -n "$do_backup" ]; then echo "Yes"; else echo "NO"; fi | |
echo | |
# Sanity | |
echo "Basic sanity check" | |
echo -n "Web user exists : " | |
if grep -q "$web_user" /etc/passwd | |
then | |
echo "Yes" | |
else | |
echo "NO" | |
echo "Fatal: $web_user: No such user" >&2 | |
exit 1 | |
fi | |
echo -n "Web group exists: " | |
if grep -q "$web_group" /etc/group | |
then | |
echo "Yes" | |
else | |
echo "NO" | |
echo "Fatal: $web_group: No such group" >&2 | |
exit 1 | |
fi | |
ok=1 | |
for f in "$wiki_dir" "$data_dir" "$conf_dir" | |
do | |
if [ -d "$f" ] | |
then | |
echo "$f: exists and is a directory" | |
if [ -r "$f" ] && [ -w "$f" ] | |
then | |
echo "$f: read/write access OK" | |
else | |
ok= | |
echo "$f: read and/or write access not granted" >&2 | |
fi | |
else | |
ok= | |
echo "$f: doesn't exist or isn't accessbile" >&2 | |
fi | |
done | |
if [ -f "$tar_file" ] | |
then | |
if [ -r "$tar_file" ] | |
then | |
echo "$tar_file: read access OK" | |
else | |
ok= | |
echo "$tar_file: read access not granted" >&2 | |
fi | |
else | |
ok= | |
echo "$tar_file: doesn't exist or isn't a file" >&2 | |
fi | |
if [ -z "$ok" ] | |
then | |
echo "Encountered one or more fatal errors" >&2 | |
exit 1 | |
fi | |
echo -n "Preload config matching configuration path: " | |
if [ -e "$wiki_dir/inc/preload.php" ] | |
then | |
preload_conf=$(grep ^define $wiki_dir/inc/preload.php \ | |
| grep DOKU_CONF \ | |
| cut -d"'" -f 4) | |
preload_conf=$(realpath "$preload_conf") | |
if [ "$preload_conf" = "$conf_dir" ] | |
then | |
echo "Yes" | |
else | |
echo "NO" | |
echo | |
echo -e "\n*** WARNING WARNING WARNING ***" >&2 | |
echo "$wiki_dir/inc/preload.php: " | |
echo "The DOKU_CONF parameter differs from the user-specified path:" | |
echo " DOKU_CONF: '$preload_conf'" | |
echo " Specified: '$conf_dir'" | |
echo -e "\n*** WARNING WARNING WARNING ***" >&2 | |
echo | |
fi | |
else | |
echo "NO" | |
echo "WARNING: $wiki_dir/inc/preload.php: File not found" >&2 | |
echo "This might indicate that the wiki path specified is incorrect," | |
echo "or that you are trying to perform an upgrade on a fresh install." | |
echo | |
fi | |
# Working directory | |
if [ ! -d "$work_dir" ] | |
then | |
echo "Fatal: '$work_dir': Failed to access unpack path" >&2 | |
echo "If one was supplied on the commandline, you must create it yourself" >&2 | |
exit 1 | |
fi | |
tcount=$(find $work_dir -maxdepth 1 | wc -l) | |
if [ "$tcount" != "1" ] | |
then | |
echo -e "\n*** WARNING WARNING WARNING ***" >&2 | |
echo "$work_dir: Working directory not empty" >&2 | |
echo "Make sure the correct path has been supplied or generated" | |
echo -e "*** WARNING WARNING WARNING ***\n" >&2 | |
echo "Press RETURN to continue, or ^C to abort" | |
read foo | |
fi | |
# Backup | |
if [ -n "$do_backup" ] | |
then | |
# Caveat emptor | |
echo | |
echo "Ready to start the backup process." | |
echo "Press RETURN to continue, or ^C to abort" | |
read foo | |
echo "Creating backup" | |
backup_file=$(date +"$backup_dir/%y%m%d_%H%M%S_DokuWiki_Backup.tgz") | |
tar cfz "$backup_file" "$wiki_dir" "$data_dir" "$conf_dir" || exit 1 | |
echo "Backup OK: $backup_file" | |
fi | |
echo | |
echo "Ready to start unpacking the tarball." | |
echo "Press RETURN to continue, or ^C to abort" | |
read foo | |
# Unpack | |
echo "Unpacking '$tar_file' to '$work_dir'" | |
cd "$work_dir" || exit 1 | |
tar zxf "$tar_file" || exit 1 | |
unpack_root="$(ls -1 | tail -n1 | grep ^dokuwiki-)" | |
unpack_root=$(realpath "$work_dir/$unpack_root") | |
if [ ! -d "$unpack_root" ] | |
then | |
echo "Unable to find root directory in unpack path $work_dir" >&2 | |
echo "Is the supplied tarball really a dokuwiki package?" >&2 | |
exit 1 | |
fi | |
echo "Unpacked root: '$unpack_root'" | |
# Check dokuwiki.php just in case | |
if ! cmp "$unpack_root/conf/dokuwiki.php" "$conf_dir/dokuwiki.php" | |
then | |
echo -e "\n*** WARNING WARNING WARNING ***" >&2 | |
echo "The default configuration file 'dokuwiki.php' differs from the one " | |
echo "located in $conf_dir." | |
echo "This might be something mundane, or it might hint at local changes" | |
echo "having been mistakenly been made to $conf_dir/mediawiki.php when" | |
echo "they should have been added to $conf_dir/local.php"! | |
echo "mediawiki.php should NOT be changed; local.php overrides it." | |
echo "Diff:" | |
diff "$conf_dir/dokuwiki.php" "$unpack_root/conf/dokuwiki.php" | |
echo -e "\n*** WARNING WARNING WARNING ***" >&2 | |
echo | |
echo "Press RETURN to continue, or ^C to abort" | |
echo | |
fi | |
# Delete deprecated files | |
del_file="$unpack_root/data/deleted.files" | |
del_queue_file="$work_dir/deletion_queue" | |
[ -e "$del_queue_file" ] && rm -v "$del_queue_file" | |
if [ ! -f "$del_file" ] | |
then | |
echo "$del_file: Not found (but was expected)." >&2 | |
echo "Aborting because I'm scared." >&2 | |
exit 1 | |
fi | |
echo "Checking deprecated data files" | |
grep -vE '^($|#)' "$del_file" | grep ^data/ | while read f | |
do | |
real_file="$data_dir/$f" | |
# echo "DATA: $real_file" | |
if [ -e "$real_file" ] | |
then | |
echo "$real_file" >> "$del_queue_file" | |
echo "$real_file: Marked for deletion" | |
fi | |
done | |
echo "Checking deprecated configuration files" | |
grep -vE '^($|#)' "$del_file" | grep ^conf/ | while read f | |
do | |
real_file="$conf_dir/$f" | |
# echo "CONF: $real_file" | |
if [ -e "$real_file" ] | |
then | |
echo "$real_file" >> "$del_queue_file" | |
echo "$real_file: Marked for deletion" | |
fi | |
done | |
echo "Checking deprecated wiki files" | |
grep -vE '^($|#)' "$del_file" | grep -v -e ^conf/ -e ^data/ | while read f | |
do | |
real_file="$wiki_dir/$f" | |
# echo "WIKI: $real_file" | |
if [ -e "$real_file" ] | |
then | |
echo "$real_file" >> "$del_queue_file" | |
echo "$real_file: Marked for deletion" | |
fi | |
done | |
echo | |
deletion_queued_count=0 | |
if [ -e "$del_queue_file" ] | |
then | |
deletion_queued_count=$(wc -l "$del_queue_file" | awk '{print $1}') | |
if [ "$deletion_queued_count" -gt 0 ] | |
then | |
echo "$deletion_queued_count files will be deleted:" | |
cat "$del_queue_file" | |
else | |
echo "No files queued for deletion" | |
fi | |
fi | |
# Caveat emptor | |
echo | |
echo "Ready to begin the upgrade process." | |
echo "Press RETURN to continue, or ^C to abort" | |
read foo | |
# Copy | |
( | |
echo "---------------------------------------------------------------" | |
echo "Syncing configuration files" | |
echo "Source: $unpack_root/conf" | |
echo "Target: $conf_dir" | |
cd "$unpack_root/conf" || exit 1 | |
rsync -acv ./ "$conf_dir/" || exit 1 | |
echo | |
) | |
( | |
echo "---------------------------------------------------------------" | |
echo "Syncing data files" | |
echo "Source: $unpack_root/data" | |
echo "Target: $data_dir" | |
cd "$unpack_root/data" || exit 1 | |
rsync -acv ./ "$data_dir/" || exit 1 | |
echo | |
) | |
( | |
echo "---------------------------------------------------------------" | |
echo "Syncing wiki files" | |
echo "Source: $unpack_root" | |
echo "Target: $wiki_dir" | |
cd "$unpack_root" || exit 1 | |
rsync -acv --exclude 'data' --exclude 'conf' ./ "$wiki_dir/" || exit 1 | |
echo | |
) | |
# Delete deprecated | |
if [ "$deletion_queued_count" -gt 0 ] | |
then | |
echo "Deleting deprecated files" | |
cat "$del_queue_file" | xargs rm -v | |
fi | |
# Permissions | |
echo "Updating permissions" | |
perm_change_file="$work_dir/permission_changes" | |
if [ -e "$perm_change_file" ] | |
then | |
rm -v "$perm_change_file" | |
fi | |
# Based on info from: | |
# https://www.dokuwiki.org/install:permissions | |
# "data/ and data/tmp/ directory: All files in and below these directories | |
# must be writable by the web process for DokuWiki to work." | |
#echo "Perms: $data_dir" | |
chown -Rv "$web_user:$web_group" "$data_dir" 2>&1 \ | |
| grep -v 'retained as' >> "$perm_change_file" | |
# "lib/ directory: This directory must be readable by the public for style | |
# sheets to display. 755 works fine." | |
#echo "Perms: $wiki_dir/lib" | |
chmod -v 755 "$wiki_dir/lib" 2>&1 \ | |
| grep -v 'retained as' >> "$perm_change_file" | |
# "lib/tpl directory must be writable for the webprocess to install templates" | |
#echo "Perms: $wiki_dir/lib/tpl" | |
chown -v "$web_user:$web_group" "$wiki_dir/lib/tpl" 2>&1 \ | |
| grep -v 'retained as' >> "$perm_change_file" | |
# Note: the permissions of files in conf/, as set from the dokuwiki tarball, | |
# are set to 1001:1002 by default, i.e commonly the first available | |
# users on a UNIX system. Point this out. | |
# "conf/ directory, following files must be writable by the web process:" | |
for f in 'local.php' \ | |
'local.php.bak' \ | |
'users.auth.php' \ | |
'acl.auth.php' \ | |
'plugins.local.php' \ | |
'plugins.local.php.bak' | |
do | |
# echo "Check: $conf_dir/$f" | |
if [ -e "$conf_dir/$f" ] | |
then | |
chown -v "$web_user:$web_group" "$conf_dir/$f" 2>&1 \ | |
| grep -v 'retained as' >> "$perm_change_file" | |
chmod -v 755 "$conf_dir/$f" 2>&1 \ | |
| grep -v 'retained as' >> "$perm_change_file" | |
fi | |
done | |
if [ -e "$perm_change_file" ] | |
then | |
perms_changed_count=$(wc -l "$perm_change_file" | awk '{print $1}') | |
echo "$perms_changed_count permission changes were made" | |
echo "See $perm_change_file for details." | |
else | |
echo "No permissions were updated." | |
fi | |
echo "Configuration files still owned by the default user:" | |
find $conf_dir/ -user 1001 -group 1002 | |
echo "Data files still owned by the default user:" | |
find $data_dir/ -user 1001 -group 1002 | |
echo "(If any were listed, you might want to correct them)" | |
# Touch local.php to reload cache | |
if [ -e "$conf_dir/local.php" ] | |
then | |
echo | |
echo "Updating timestamp on local.php to trigger cache reloading" | |
touch "$conf_dir/local.php" | |
fi | |
echo | |
echo "Finished" | |
echo "$work_dir was created during the upgrade and can now be deleted." | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment