-
-
Notifications
You must be signed in to change notification settings - Fork 2
Description
@bartkleinreesink shared their sync script modifications that include making the script executable from any directory, as well as separating the configuration so that it's entirely in the WP-CLI config
A while ago I bought your sync script to try it out and I’m trying to make it a little more easy to use. Thought I’d give you an update on what I have.
Added the script to my PATH variable to make it executable from anywhere and made it check if wp-cli.yml is present in the current working directory. I’ve also made it parse the YAML file to be able to configurate the entire script from wp-cli.yml to decouple the script from the project.
#!/bin/bash
##########################################################################################################
##
## Syncing WordPress environments with WP-CLI aliases
## Copyright (c) Ben Word
##
##########################################################################################################
##
## Put this file somewhere on your computer, for instance, in your home folder in a directory.
## Add this directory to your PATH variable so you can execute it from anywhere.
## Make sure this file is executable: chmod +x wp-sync
##
## Run wp-sync in a folder where wp-cli.yml is present. Typically the project root.
##
## Usage: wp-sync [[--skip-db] [--skip-assets] [--remote]] [ENV_FROM] [ENV_TO]
##
## Note: WP-CLI is required on development, testing, acceptance and production environments for
## this script to work.
##
##
##########################################################################################################
##
## ------------- No need to touch things below this line -------------
##
##########################################################################################################
CONFIG=./wp-cli.yml
if [ ! -f "$CONFIG" ]; then
echo "Make sure wp-cli.yml is present in current working directory"
exit;
fi
check_vars() {
var_names=("$@")
for var_name in "${var_names[@]}"; do
[ -z "${!var_name}" ] && echo "$var_name is unset." && var_unset=true
done
[ -n "$var_unset" ] && exit 1
return 0
}
function parse_yaml {
local prefix=$2
local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
sed -ne "s|^\($s\):|\1|" \
-e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" $1 |
awk -F$fs '{
indent = length($1)/2;
vname[indent] = $2;
for (i in vname) {if (i > indent) {delete vname[i]}}
if (length($3) > 0) {
vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, $2, $3);
}
}'
}
# Parse wp-cli.yml in current working directory
eval $(parse_yaml ${CONFIG})
check_vars remote_user__production remote_host__production env_url__production remote_user__testing remote_host__testing env_url__testing remote_user__acceptance remote_host__acceptance env_url__acceptance uploads_dir__remote uploads_dir__local env_url__development
PRODDIR="${remote_user__production}@${remote_host__production}:${uploads_dir__remote}"
PRODSITE=${env_url__production}
ACCDIR="${remote_user__acceptance}@${remote_host__acceptance}:${uploads_dir__remote}"
ACCSITE=${env_url__acceptance}
TESTDIR="${remote_user__testing}@${remote_host__testing}:${uploads_dir__remote}"
TESTSITE=${env_url__testing}
DEVDIR=${uploads_dir__local}
DEVSITE=${env_url__development}
LOCAL=true
SKIP_DB=false
SKIP_ASSETS=false
POSITIONAL_ARGS=()
CYAN='\033[1;36m'
RED='\033[1;31m';
NC='\033[0m'
while [[ $# -gt 0 ]]; do
case $1 in
--skip-db)
SKIP_DB=true
shift
;;
--skip-assets)
SKIP_ASSETS=true
shift
;;
--remote)
LOCAL=false
shift
;;
--*)
echo "Unknown option $1"
exit 1
;;
*)
POSITIONAL_ARGS+=("$1")
shift
;;
esac
done
set -- "${POSITIONAL_ARGS[@]}"
if [ $# != 2 ]
then
echo "Usage: $0 [[--skip-db] [--skip-assets] [--remote]] [ENV_FROM] [ENV_TO]"
exit;
fi
FROM=$1
TO=$2
bold=$(tput bold)
normal=$(tput sgr0)
case "$1-$2" in
production-development) DIR="down ⬇️ " FROMSITE=$PRODSITE; FROMDIR=$PRODDIR; TOSITE=$DEVSITE; TODIR=$DEVDIR; ;;
acceptance-development) DIR="down ⬇️ " FROMSITE=$ACCSITE; FROMDIR=$ACCDIR; TOSITE=$DEVSITE; TODIR=$DEVDIR; ;;
testing-development) DIR="down ⬇️ " FROMSITE=$TESTSITE; FROMDIR=$TESTDIR; TOSITE=$DEVSITE; TODIR=$DEVDIR; ;;
development-production) DIR="up ⬆️ " FROMSITE=$DEVSITE; FROMDIR=$DEVDIR; TOSITE=$PRODSITE; TODIR=$PRODDIR; ;;
development-acceptance) DIR="up ⬆️ " FROMSITE=$DEVSITE; FROMDIR=$DEVDIR; TOSITE=$ACCSITE; TODIR=$ACCDIR; ;;
development-testing) DIR="up ⬆️ " FROMSITE=$DEVSITE; FROMDIR=$DEVDIR; TOSITE=$TESTSITE; TODIR=$TESTDIR; ;;
production-acceptance) DIR="horizontally ↔️ "; FROMSITE=$PRODSITE; FROMDIR=$PRODDIR; TOSITE=$ACCSITE; TODIR=$ACCDIR; ;;
acceptance-production) DIR="horizontally ↔️ "; FROMSITE=$ACCSITE; FROMDIR=$ACCDIR; TOSITE=$PRODSITE; TODIR=$PRODDIR; ;;
acceptance-testing) DIR="horizontally ↔️ "; FROMSITE=$ACCSITE; FROMDIR=$ACCDIR; TOSITE=$TESTSITE; TODIR=$TESTDIR; ;;
testing-acceptance) DIR="horizontally ↔️ "; FROMSITE=$TESTSITE; FROMDIR=$TESTDIR; TOSITE=$ACCSITE; TODIR=$ACCDIR; ;;
*) echo "usage: $0 [[--skip-db] [--skip-assets] [--remote]] production development | acceptance development | development acceptance | development production | acceptance production | production acceptance" && exit 1 ;;
esac
if [ "$SKIP_DB" = false ]
then
DB_MESSAGE=" - replace the ${bold}$TO${normal} database${normal} ($TOSITE) with the ${bold}$FROM${normal} database ($FROMSITE)"
fi
if [ "$SKIP_ASSETS" = false ]
then
ASSETS_MESSAGE=" - sync ${bold}$FROMDIR${normal} from ${bold}$FROM${normal} ($FROMSITE) to ${bold}$TODIR${normal} on ${bold}$TO${normal} ($TOSITE)?"
fi
if [ "$SKIP_DB" = true ] && [ "$SKIP_ASSETS" = true ]
then
echo "Nothing to synchronize."
exit;
fi
echo
printf "${CYAN}Heads up! Would you really like to:${NC}\n\n"
echo $DB_MESSAGE
echo $ASSETS_MESSAGE
printf "\n\n"
if [ $TOSITE = $PRODSITE ]
then
printf "${RED}You're about to sync to production, are you really sure?${NC}\n"
fi
read -r -p " [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
# Change to site directory
# Commented out because we want this sync script above the public folder
# cd ../ &&
echo
# Make sure both environments are available before we continue
availfrom() {
local AVAILFROM
if [[ "$LOCAL" = true && $FROM == "development" ]]; then
AVAILFROM=$(wp option get home 2>&1)
else
AVAILFROM=$(wp "@$FROM" option get home 2>&1)
fi
if [[ $AVAILFROM == *"Error"* ]]; then
echo $AVAILFROM
echo "❌ Unable to connect to $FROM"
exit 1
else
echo "✅ Able to connect to $FROM"
fi
};
availfrom
availto() {
local AVAILTO
if [[ "$LOCAL" = true && $TO == "development" ]]; then
AVAILTO=$(wp option get home 2>&1)
else
AVAILTO=$(wp "@$TO" option get home 2>&1)
fi
if [[ $AVAILTO == *"Error"* ]]; then
echo $AVAILTO
echo "❌ Unable to connect to $TO $AVAILTO"
exit 1
else
echo "✅ Able to connect to $TO"
fi
};
availto
if [ "$SKIP_DB" = false ]
then
echo "Syncing database..."
# Export/import database, run search & replace
if [[ "$LOCAL" = true && $TO == "development" ]]; then
wp db export --default-character-set=utf8mb4 &&
printf "${CYAN}Notice:${NC} Exported $TO database to working directory\n" &&
wp db reset --yes &&
wp "@$FROM" db export --default-character-set=utf8mb4 - | wp db import - &&
wp search-replace "$FROMSITE" "$TOSITE" --all-tables-with-prefix
elif [[ "$LOCAL" = true && $FROM == "development" ]]; then
wp "@$TO" db export --default-character-set=utf8mb4 &&
printf "${CYAN}Notice:${NC} Exported $TO database to home folder on server\n" &&
wp "@$TO" db reset --yes &&
wp db export --default-character-set=utf8mb4 - | wp "@$TO" db import - &&
wp "@$TO" search-replace "$FROMSITE" "$TOSITE" --all-tables-with-prefix
else
wp "@$TO" db export --default-character-set=utf8mb4 &&
printf "${CYAN}Notice:${NC} Exported $TO database to home folder on server\n" &&
wp "@$TO" db reset --yes &&
wp "@$FROM" db export --default-character-set=utf8mb4 - | wp "@$TO" db import - &&
wp "@$TO" search-replace "$FROMSITE" "$TOSITE" --all-tables-with-prefix
fi
fi
if [ "$SKIP_ASSETS" = false ]
then
echo "Syncing assets..."
# Make uploads dir if non existent
mkdir -p "$uploads_dir__local"
# Sync uploads directory
chmod -R 755 "$uploads_dir__local" &&
if [[ $DIR == "horizontally"* ]]; then
[[ $FROMDIR =~ ^(.*): ]] && FROMHOST=${BASH_REMATCH[1]}
[[ $FROMDIR =~ ^(.*):(.*)$ ]] && FROMDIR=${BASH_REMATCH[2]}
[[ $TODIR =~ ^(.*): ]] && TOHOST=${BASH_REMATCH[1]}
[[ $TODIR =~ ^(.*):(.*)$ ]] && TODIR=${BASH_REMATCH[2]}
ssh -o ForwardAgent=yes $FROMHOST "rsync -aze 'ssh -o StrictHostKeyChecking=no' --progress $FROMDIR $TOHOST:$TODIR"
else
rsync -az --progress "$FROMDIR" "$TODIR"
fi
fi
# Slack notification when sync direction is up or horizontal
# if [[ $DIR != "down"* ]]; then
# USER="$(git config user.name)"
# curl -X POST -H "Content-type: application/json" --data "{\"attachments\":[{\"fallback\": \"\",\"color\":\"#36a64f\",\"text\":\"🔄 Sync from ${FROMSITE} to ${TOSITE} by ${USER} complete \"}],\"channel\":\"#site\"}" https://hooks.slack.com/services/xx/xx/xx
# fi
echo -e "🔄 Sync from $FROM to $TO complete.\n\n ${bold}$TOSITE${normal}\n"
fi# Global parameter defaults
path: public/wp
user: admin
disabled_commands:
- db drop
# Aliases to other WordPress installs (e.g. `wp @testing rewrite flush`)
@testing:
ssh: ssh_user@123.123.123.123
user: admin
path: /home/ssh_user/domains/wptesting.com/public_html/wp
@acceptance:
ssh: ssh_user@123.123.123.123
user: admin
path: /home/ssh_user/domains/wpacceptance.com/public_html/wp
@production:
ssh: ssh_user@123.123.123.123
user: admin
path: /data/home/ssh_user/domains/wp.com/public_html/wp
# Custom keys for wp-sync script
remote_user:
testing: ssh_user
acceptance: ssh_user
production: ssh_user
remote_host:
testing: "123.123.123.123"
acceptance: "123.123.123.123"
production: "123.123.123.123"
env_url:
development: "https://wpdevelopment.com"
testing: "https://wptesting.com"
acceptance: "https://wpacceptance.com"
production: "https://wp.com"
uploads_dir:
local: "public/content/uploads/"
remote: "~/builds/shared/uploads/"Obviously this is not perfect, since I’m repeating myself in the configuration. And ‘@’ variables aren’t properly parsed with the parse function. It could also be more cohesive, but these are just some ideas to maybe work out a finer solution.