Skip to content

Instantly share code, notes, and snippets.

@jschoolcraft
Forked from jhoffmann/dibs.sh
Created May 29, 2014 19:35
Show Gist options
  • Save jschoolcraft/6a0d5698b4ccdd87f247 to your computer and use it in GitHub Desktop.
Save jschoolcraft/6a0d5698b4ccdd87f247 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
# Symlink as ~/bin/dibs for happy fun time excitement.
# Nothing pisses me off more than CTRL-c'ing during an import script
# And just having it fire up the next bloody file to import
trap 'echo Control-C trap caught; exit 1' 2 #traps Ctrl-C (signal 2)
# Exit if there is any errors
set -e
CONFIG_FILE="$HOME/.dibsrc"
# Don't edit this file, instead put custom defaults into CONFIG_FILE
SELF=`basename $0`
HOST="localhost"
DBUSER="mysql"
DBPASS="unspecified"
DATABASE="sugarinternal"
LOGIN_PATH="" # New in mySQL 5.6, see mysql_config_editor
PRE_IMPORT_DIR="pre_import"
POST_IMPORT_DIR="post_import"
CDIR="$HOME/archive"
VERBOSE=false
QUICK=false
REVERSE=false
FULLER=false
MODE="unspecified"
APP="SI"
ARCHIVE="$USER@si-dev:~jhoffmann/archive"
DUMP="mysqldump"
DUMPOPTS="-e --max-allowed-packet=2048M -Q --opt --skip-comments --skip-dump-date --single-transaction"
MYSQL="mysql"
if [ -r "${CONFIG_FILE}" ]; then source "${CONFIG_FILE}"; fi
# These options are meant to be set in CONFIG_FILE and don't have command line
# equivalents.
DIFFCMD="php -f $HOME/iAppsUtilityScripts/db_diff_generator/mysqldiff.php"
DIFFARGS="--drop-tables"
DIFF1HOST=$HOST
DIFF1DB=$DATABASE
DIFF1USER=$DBUSER
DIFF1PASS=$DBPASS
DIFF2HOST=$DIFF1HOST
DIFF2DB="pristine"
DIFF2USER=$DIFF1USER
DIFF2PASS=$DIFF1PASS
SYNC_CMD="rsync -rlDcz --delete-after -e ssh"
LAST_SYNC="$HOME/.dibs_last_sync"
# Load this twice
if [ -r "${CONFIG_FILE}" ]; then source "${CONFIG_FILE}"; fi
define()
{
IFS='\n' read -r -d '' ${1} || true;
}
# A fuller dump for Cognos reporting
define SCHEMA_FULLER <<'EOF'
campaign_log
ci_email_log
email_cache
emails_email_addr_rel
emails_text
fts_queue
ganda_commentmeta
ganda_comments
ganda_links
ganda_options
ganda_postmeta
ganda_posts
ganda_term_relationships
ganda_term_taxonomy
ganda_terms
ganda_usermeta
ganda_users
job_queue
pardot_log
pardot_log_messages
round_robin_log
round_robin_tracker
sugar_updates
tracker
tracker_perf
tracker_queries
tracker_sessions
tracker_tracker_queries
EOF
# The blank is important, please do not remove it
define SCHEMA_ONLY <<'EOF'
calls
calls_cstm
campaign_log
ci_email_log
email_cache
emails
emails_accounts
emails_archive
emails_beans
emails_bugs
emails_cases
emails_contacts
emails_email_addr_rel
emails_leads
emails_opportunities
emails_project_tasks
emails_projects
emails_prospects
emails_quotes
emails_tasks
emails_text
emails_users
fts_queue
ganda_commentmeta
ganda_comments
ganda_links
ganda_options
ganda_postmeta
ganda_posts
ganda_term_relationships
ganda_term_taxonomy
ganda_terms
ganda_usermeta
ganda_users
job_queue
notes
notes_cstm
pardot_log
pardot_log_messages
prospect_lists_prospects
prospects
round_robin_log
round_robin_tracker
session_history
sugar_installations
sugar_installations_cstm
sugar_updates
tracker
tracker_perf
tracker_queries
tracker_sessions
tracker_tracker_queries
EOF
say()
{
if [ -x /usr/bin/say ]; then
/usr/bin/say -v Victoria "${1}"
fi
}
dolog()
{
if $VERBOSE; then
echo `date "+%D %H:%M"` $1;
fi
}
usage()
{
cat <<EOF
Export/Import/Sync - iApps Team Databases - Project Diabetes
Usage: $SELF -m <EISDL> [options] [loglevel]
Arguments:
-m Mode [MODE:${MODE}]
-h Hostname [HOST:${HOST}]
-b Database [DATABASE:${DATABASE}]
-u User [DBUSER:${DBUSER}]
-p Password [DBPASS:xxxx]
-d Import/Export Directory [CDIR:${CDIR}]
-a Application [APP:${APP}]
Flags:
-v Verbose Output [VERBOSE:${VERBOSE}]
-q Quick Import (updated files only) [QUICK:${QUICK}]
-r Reverse Diff [REVERSE:${REVERSE}]
-f Full (almost) Export or Import [FULLER:${FULLER}]
Notes:
The full (-f) export can be very large. Use it carefully.
The full (-f) import includes the si_*view views where they are, by default,
excluded
Configuration:
Default values can be stored in $CONFIG_FILE, which will
be source'd.
Examples:
# Use rsync to fetch the latest archive to your home directory
$SELF -m S -v
# Import a local archive into the specific database (SI or D7)
$SELF -m I -d ~/archive -h localhost -u mysql -p banana -a SI -b si-local -v -q
# Use sed to update the log level in config_override.php
$SELF -m L info
EOF
say "Learn it. Love it."
exit $1
}
is_schema_only()
{
# Hack for whole word searching
RE="
$1
"
if $FULLER; then
# Fuller also includes all the audit tables
if [[ "${SCHEMA_FULLER}" =~ $RE ]]; then
return 0
fi
else
if [[ "${SCHEMA_ONLY}" =~ $RE ]]; then
return 0
elif [[ $1 =~ _audit ]]; then
return 0
fi
fi
return -1
}
optspec="h:b:u:p:d:m:a:qvrfc"
while getopts "${optspec}" optchar; do
case "${optchar}" in
h) HOST="${OPTARG}" ;;
b) DATABASE="${OPTARG}" ;;
u) DBUSER="${OPTARG}" ;;
p) DBPASS="${OPTARG}" ;;
d) CDIR="${OPTARG}" ;;
v) VERBOSE=true ;;
m) MODE="${OPTARG}" ;;
a) APP="${OPTARG}" ;;
q) QUICK=true ;;
r) REVERSE=true ;;
f) FULLER=true ;;
?) usage -1 ;;
esac
done
if [ -n "${LOGIN_PATH}" ]; then
MYSQL_AUTH="--login-path=${LOGIN_PATH}"
else
MYSQL_AUTH="-h$HOST -u$DBUSER -p$DBPASS"
fi
# check which application to work with, defaults to SI
if [ $APP == "D7" ]; then
APPNAME="drupal7"
elif [ $APP == "si7" ]; then
APPNAME="si7"
else
APPNAME="si2-production"
fi
# Preserve base path for pre and post dibs SQL scripts
BASEDIR=${CDIR}
case $MODE in
# Export Mode
E)
if $FULLER; then
CDIR=${CDIR}/${APPNAME}-full
else
CDIR=${CDIR}/${APPNAME}
fi
if [ ! -d "${CDIR}/full" -o ! -d "${CDIR}/schema" ]; then
mkdir -p "${CDIR}/full"
mkdir -p "${CDIR}/schema"
else
/bin/rm -f "${CDIR}/full/*.sql"
/bin/rm -f "${CDIR}/schema/*.sql"
fi
TABLES=`$MYSQL $MYSQL_AUTH -NB $DATABASE -e "SHOW TABLES"`
for table in $TABLES; do
TYPE="full"
DUMPOPTS_TMP="$DUMPOPTS"
if is_schema_only $table; then
TYPE="schema"
DUMPOPTS_TMP="$DUMPOPTS --no-data"
fi
FILE="${CDIR}/${TYPE}/${table}.sql"
dolog "Exporting ${DBUSER}@${HOST}:${DATABASE}.${table} to ${FILE}"
$DUMP ${MYSQL_AUTH} ${DUMPOPTS_TMP} ${DATABASE} ${table} > ${FILE}
done
say "Export done."
;;
# Import Mode
I)
FIND_OPTS=""
if $FULLER; then
CDIR=${CDIR}/${APPNAME}-full
else
CDIR=${CDIR}/${APPNAME}
fi
if $QUICK; then
if [ -e ${LAST_SYNC} ]; then
FIND_OPTS="-newer ${LAST_SYNC}"
fi
fi
# Run any pre-import scripts
pre_import_dirs=""
if [ -d ${BASEDIR}/${PRE_IMPORT_DIR} ]; then
pre_import_dirs="${pre_import_dirs} ${BASEDIR}/${PRE_IMPORT_DIR}"
fi
if [ -d ${BASEDIR}/${PRE_IMPORT_DIR}/${APP} ]; then
pre_import_dirs="${pre_import_dirs} ${BASEDIR}/${PRE_IMPORT_DIR}/${APP}"
fi
if [ -n "${pre_import_dirs}" ]; then
dolog "Running pre-import SQL scripts"
for PREIMPORT in `find ${pre_import_dirs} -maxdepth 1 -type f -name "*.sql"`; do
dolog "Running ${PREIMPORT} on ${DBUSER}@${HOST}:${DATABASE}"
$MYSQL ${MYSQL_AUTH} ${DATABASE} < ${PREIMPORT}
done
fi
# Do the dibs import
dolog "Running main import"
for FILE in `find "${CDIR}" ${FIND_OPTS} -type f -name "*.sql"`; do
if [[ ! $FILE == */si_*view.sql ]] || $FULLER; then
dolog "Importing ${FILE} to ${DBUSER}@${HOST}:${DATABASE}.${table}"
$MYSQL ${MYSQL_AUTH} ${DATABASE} < ${FILE}
else
dolog "Skipping ${FILE}"
fi
done
#if it's drupal7, need to make some modifications
if [ $APP == "D7" ]; then
dolog "Creating temp file to truncate cache tables and update cache variables"
# create a temp sql file and get the tables to trunc
FILE="${CDIR}/cache_updates.sql"
echo "UPDATE drupal7_variable SET value = 'i:0;' WHERE name='cache' OR name='preprocess_js' OR name='preprocess_css';" > ${FILE}
TABLES=`$MYSQL ${MYSQL_AUTH} -NB ${DATABASE} -e "SHOW TABLES LIKE '%cache%'"`
for table in $TABLES; do
echo "TRUNCATE TABLE ${table};" >> ${FILE}
done
# run it and then delete it
dolog "Running the file and then deleting it"
$MYSQL ${MYSQL_AUTH} ${DATABASE} < ${FILE}
/bin/rm -f ${FILE}
fi
# Run any post-import scripts
post_import_dirs=""
if [ -d ${BASEDIR}/${POST_IMPORT_DIR} ]; then
post_import_dirs="${post_import_dirs} ${BASEDIR}/${POST_IMPORT_DIR}"
fi
if [ -d ${BASEDIR}/${POST_IMPORT_DIR}/${APP} ]; then
post_import_dirs="${post_import_dirs} ${BASEDIR}/${POST_IMPORT_DIR}/${APP}"
fi
if [ -n "${post_import_dirs}" ]; then
dolog "Running post-import SQL scripts"
for POSTIMPORT in `find ${post_import_dirs} -maxdepth 1 -type f -name "*.sql"`; do
dolog "Running ${POSTIMPORT} on ${DBUSER}@${HOST}:${DATABASE}"
$MYSQL ${MYSQL_AUTH} ${DATABASE} < ${POSTIMPORT}
done
fi
say "Import done."
;;
S)
if $FULLER; then
ARCHIVE=${ARCHIVE}/${APPNAME}-full
else
ARCHIVE=${ARCHIVE}/${APPNAME}
fi
dolog "Starting rsync, this could take a few minutes."
START=`date "+%y%m%d%H%M.%S"`
SYNC_OPTS=""
if $VERBOSE; then
SYNC_OPTS="-i"
fi
${SYNC_CMD} ${SYNC_OPTS} --filter='- sync.sql' ${ARCHIVE} ${CDIR}
dolog "Done!"
# Record the time we started the sync by touching a file for find -newer
touch -t ${START} ${LAST_SYNC}
say "Sync done."
;;
D)
dolog "-- Starting data diff, this could take a few minutes."
if $REVERSE; then
${DIFFCMD} -- ${DIFFARGS} \
--host1 ${DIFF2HOST} --user1 "${DIFF2USER}" --pwd1 "${DIFF2PASS}" --database1 ${DIFF2DB} \
--host2 ${DIFF1HOST} --user2 "${DIFF1USER}" --pwd2 "${DIFF1PASS}" --database2 ${DIFF1DB}
else
${DIFFCMD} -- ${DIFFARGS} \
--host1 ${DIFF1HOST} --user1 "${DIFF1USER}" --pwd1 "${DIFF1PASS}" --database1 ${DIFF1DB} \
--host2 ${DIFF2HOST} --user2 "${DIFF2USER}" --pwd2 "${DIFF2PASS}" --database2 ${DIFF2DB}
fi
;;
L)
OVERRIDE_FILE=config_override.php
if [ -f $OVERRIDE_FILE ]; then
shift $(($OPTIND - 1))
ERROR_LEVEL=$1
dolog "Setting error level to: ${ERROR_LEVEL}"
cp $OVERRIDE_FILE ${OVERRIDE_FILE}.bak
sed -i'' -re "s/(\['level'\] =).*/\1 '${ERROR_LEVEL}';/" $OVERRIDE_FILE
if $VERBOSE; then diff -dU0 ${OVERRIDE_FILE}.bak $OVERRIDE_FILE | tail -3; fi
else
dolog "Unable to find ${OVERRIDE_FILE}."
fi
rm ${OVERRIDE_FILE}.bak
;;
*) usage -1 ;;
esac
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment