317 lines
7.5 KiB
Bash
Executable File
317 lines
7.5 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
FORCE=FALSE
|
|
IS_USER=FALSE
|
|
|
|
usage() {
|
|
echo "[ERROR] Usage: $0 [-f] [-u] [environment]"
|
|
exit 1
|
|
}
|
|
|
|
while getopts ":fu" option
|
|
do
|
|
case $option in
|
|
f)
|
|
FORCE=TRUE
|
|
;;
|
|
u)
|
|
IS_USER=TRUE
|
|
;;
|
|
\?|:)
|
|
usage
|
|
;;
|
|
esac
|
|
done
|
|
|
|
shift $(($OPTIND - 1))
|
|
ENV=$1
|
|
|
|
CONFIG_FILE="myvc.config.json"
|
|
|
|
if [ ! -f "$CONFIG_FILE" ]; then
|
|
echo "[ERROR] Config file not found in working directory."
|
|
exit 2
|
|
fi
|
|
|
|
DIR="$(dirname "${BASH_SOURCE[0]}")"
|
|
CODE=$(jq -r ".code" "$CONFIG_FILE")
|
|
|
|
# Production protection
|
|
|
|
if [ "$ENV" == "production" ]; then
|
|
echo ""
|
|
echo " ( ( ) ( ( ) ) "
|
|
echo " )\ ))\ ) ( /( )\ ) ( ))\ ) ( /( ( /( "
|
|
echo "(()/(()/( )\()|()/( ( )\ ) /(()/( )\()) )\())"
|
|
echo " /(_))(_)|(_)\ /(_)) )\ (((_) ( )(_))(_)|(_)\ ((_)\ "
|
|
echo "(_))(_)) ((_|_))_ _ ((_))\___(_(_()|__)) ((_) _((_)"
|
|
echo "| _ \ _ \ / _ \| \| | | ((/ __|_ _|_ _| / _ \| \| |"
|
|
echo "| _/ /| (_) | |) | |_| || (__ | | | | | (_) | . |"
|
|
echo "|_| |_|_\ \___/|___/ \___/ \___| |_| |___| \___/|_|\_|"
|
|
echo ""
|
|
|
|
if [ "$FORCE" != "TRUE" ]; then
|
|
read -p "[INTERACTIVE] Are you sure? (Default: no) [yes|no]: " ANSWER
|
|
|
|
if [ "$ANSWER" != "yes" ]; then
|
|
echo "[INFO] Aborting changes."
|
|
exit
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Configuration file
|
|
|
|
if [ -z "$ENV" ]; then
|
|
INI_FILE="$DIR/db.ini"
|
|
else
|
|
INI_FILE="$PWD/db.$ENV.ini"
|
|
fi
|
|
|
|
if [ ! -f "$INI_FILE" ]; then
|
|
echo "[ERROR] DB config file doesn't exists: $INI_FILE"
|
|
exit 2
|
|
fi
|
|
|
|
echo "[INFO] Using config file: $INI_FILE"
|
|
|
|
# Query functions
|
|
|
|
dbQuery() {
|
|
SQL=$1
|
|
RETVAL=`echo "$SQL" | mysql --defaults-file="$INI_FILE" --silent --raw`
|
|
}
|
|
dbExec() {
|
|
SQL=$1
|
|
echo "$SQL" | mysql --defaults-file="$INI_FILE"
|
|
}
|
|
dbExecFromFile() {
|
|
FILE_PATH=$1
|
|
SCHEMA=$2
|
|
mysql --defaults-file="$INI_FILE" --default-character-set=utf8 --comments "$SCHEMA" < $FILE_PATH
|
|
}
|
|
|
|
# Fetches database version
|
|
|
|
COMMIT_SHA=$(git rev-parse HEAD)
|
|
echo "[INFO] Commit: $COMMIT_SHA"
|
|
|
|
dbQuery "SELECT number, gitCommit FROM util.version WHERE code = '$CODE'"
|
|
RETVAL=($RETVAL)
|
|
DB_VERSION=${RETVAL[0]}
|
|
DB_COMMIT=${RETVAL[1]}
|
|
|
|
echo "[INFO] Database information:"
|
|
echo "[INFO] -> Version: $DB_VERSION"
|
|
echo "[INFO] -> Commit: $DB_COMMIT"
|
|
|
|
if [[ ! "$DB_VERSION" =~ ^[0-9]*$ ]]; then
|
|
echo "[ERROR] Wrong database version."
|
|
exit 3
|
|
fi
|
|
if [[ -z "$DB_VERSION" ]]; then
|
|
DB_VERSION=10000
|
|
fi
|
|
|
|
if [ "$IS_USER" == "TRUE" ]; then
|
|
echo "[INFO] User information:"
|
|
|
|
dbQuery "SELECT LEFT(USER(), INSTR(USER(), '@') - 1)"
|
|
DB_USER=$RETVAL
|
|
echo "[INFO] -> Name: $DB_USER"
|
|
|
|
dbQuery "SELECT number, gitCommit FROM util.versionUser WHERE code = '$CODE' AND user = '$DB_USER'"
|
|
RETVAL=($RETVAL)
|
|
USER_VERSION=${RETVAL[0]}
|
|
USER_COMMIT=${RETVAL[1]}
|
|
|
|
echo "[INFO] -> Version: $USER_VERSION"
|
|
echo "[INFO] -> Commit: $USER_COMMIT"
|
|
|
|
if [ ! -z "$USER_VERSION" ]; then
|
|
if [ "$USER_VERSION" -gt "$DB_VERSION" ]; then
|
|
DB_VERSION=$USER_VERSION
|
|
DB_COMMIT=$USER_COMMIT
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Applies changes
|
|
|
|
N_CHANGES=0
|
|
LAST_APPLIED_VERSION=$DB_VERSION
|
|
|
|
for DIR_PATH in "$PWD/changes/"*; do
|
|
DIR_NAME=$(basename $DIR_PATH)
|
|
DIR_VERSION=${DIR_NAME:0:5}
|
|
|
|
if [ "$DIR_NAME" == "README.md" ]; then
|
|
continue
|
|
fi
|
|
if [[ ! "$DIR_NAME" =~ ^[0-9]{5}(-[a-zA-Z0-9]+)?$ ]]; then
|
|
echo "[WARN] Ignoring wrong directory name: $DIR_NAME"
|
|
continue
|
|
fi
|
|
if [ "$DB_VERSION" -ge "$DIR_VERSION" ]; then
|
|
echo "[INFO] Ignoring already applied version: $DIR_NAME"
|
|
continue
|
|
fi
|
|
|
|
echo "[INFO] Applying version: $DIR_NAME"
|
|
|
|
for FILE in "$DIR_PATH/"*; do
|
|
FILE_NAME=$(basename "$FILE")
|
|
|
|
if [ "$FILE_NAME" == "*" ]; then
|
|
continue
|
|
fi
|
|
if [[ ! "$FILE_NAME" =~ ^[0-9]{2}-[a-zA-Z0-9_]+\.sql$ ]]; then
|
|
echo "[WARN] Ignoring wrong file name: $FILE_NAME"
|
|
continue
|
|
fi
|
|
|
|
echo "[INFO] -> $FILE_NAME"
|
|
dbExecFromFile "$FILE"
|
|
N_CHANGES=$((N_CHANGES + 1))
|
|
done
|
|
|
|
LAST_APPLIED_VERSION=$DIR_VERSION
|
|
done
|
|
|
|
# Applies routines
|
|
|
|
applyRoutines() {
|
|
FILES_CMD=$1
|
|
|
|
for FILE_PATH in `$FILES_CMD`; do
|
|
FILE_NAME=$(basename $FILE_PATH)
|
|
|
|
if [[ ! "$FILE_PATH" =~ ^routines/ ]]; then
|
|
continue
|
|
fi
|
|
if [[ ! "$FILE_NAME" =~ ^[a-zA-Z0-9_]+\.sql$ ]]; then
|
|
echo "[WARN] Ignoring wrong file name: $FILE_NAME"
|
|
continue
|
|
fi
|
|
|
|
FILE_REL_PATH=${FILE_PATH//routines\/}
|
|
|
|
IFS='/' read -ra SPLIT <<< "$FILE_REL_PATH"
|
|
SCHEMA=${SPLIT[0]}
|
|
NAME=${SPLIT[2]}
|
|
NAME=${NAME//\.sql/}
|
|
|
|
ROUTINE_TYPE=${SPLIT[1]}
|
|
case "$ROUTINE_TYPE" in
|
|
events)
|
|
ROUTINE_TYPE=EVENTS
|
|
;;
|
|
functions)
|
|
ROUTINE_TYPE=FUNCTION
|
|
;;
|
|
procedures)
|
|
ROUTINE_TYPE=PROCEDURE
|
|
;;
|
|
triggers)
|
|
ROUTINE_TYPE=TRIGGER
|
|
;;
|
|
views)
|
|
ROUTINE_TYPE=VIEW
|
|
;;
|
|
*)
|
|
echo "[WARN] Ignoring unknown routine type: $ROUTINE_TYPE"
|
|
continue
|
|
;;
|
|
esac
|
|
|
|
ROUTINE_NAME="\`$SCHEMA\`.\`$NAME\`"
|
|
|
|
if [[ -f "$FILE_PATH" ]]; then
|
|
ACTION="REPLACE"
|
|
else
|
|
ACTION="DROP"
|
|
fi
|
|
|
|
echo "[INFO] -> $ROUTINE_TYPE $ROUTINE_NAME: $ACTION"
|
|
|
|
if [ "$ACTION" == "REPLACE" ]; then
|
|
dbExecFromFile "$FILE_PATH" "$SCHEMA"
|
|
else
|
|
dbExec "DROP $ROUTINE_TYPE IF EXISTS $ROUTINE_NAME"
|
|
fi
|
|
|
|
ROUTINES_CHANGED=$((ROUTINES_CHANGED + 1))
|
|
done
|
|
}
|
|
|
|
echo "[INFO] Applying changed routines."
|
|
|
|
ROUTINES_CHANGED=0
|
|
|
|
PROCS_FILE=.procs-priv.sql
|
|
mysqldump \
|
|
--defaults-file="$INI_FILE" \
|
|
--no-create-info \
|
|
--skip-triggers \
|
|
--insert-ignore \
|
|
mysql procs_priv > "$PROCS_FILE"
|
|
|
|
if [[ -z "$DB_COMMIT" ]]; then
|
|
ROUTINES_CMD="find routines -type f"
|
|
else
|
|
ROUTINES_CMD="git diff --name-only $DB_COMMIT -- routines"
|
|
fi
|
|
|
|
applyRoutines "$ROUTINES_CMD"
|
|
applyRoutines "git ls-files --others --exclude-standard"
|
|
|
|
if [ "$ROUTINES_CHANGED" -gt "0" ]; then
|
|
dbExecFromFile "$PROCS_FILE" "mysql"
|
|
|
|
if [ "$?" -eq "0" ]; then
|
|
dbExec "FLUSH PRIVILEGES"
|
|
rm "$PROCS_FILE"
|
|
else
|
|
echo "[WARN] An error ocurred when restoring routine privileges, backup saved at $PROCS_FILE"
|
|
fi
|
|
|
|
echo "[INFO] -> $ROUTINES_CHANGED routines have changed."
|
|
else
|
|
echo "[INFO] -> No routines changed."
|
|
rm "$PROCS_FILE"
|
|
fi
|
|
|
|
N_CHANGES=$((N_CHANGES + ROUTINES_CHANGED))
|
|
|
|
# Displaying summary
|
|
|
|
if [ "$N_CHANGES" -gt "0" ]; then
|
|
if [ "$IS_USER" == "TRUE" ]; then
|
|
SQL=(
|
|
"INSERT INTO util.versionUser SET "
|
|
"code = '$CODE', "
|
|
"user = '$DB_USER', "
|
|
"number = '$LAST_APPLIED_VERSION', "
|
|
"gitCommit = '$COMMIT_SHA' "
|
|
"ON DUPLICATE KEY UPDATE "
|
|
"number = VALUES(number), "
|
|
"gitCommit = VALUES(gitCommit)"
|
|
)
|
|
else
|
|
SQL=(
|
|
"INSERT INTO util.version SET "
|
|
"code = '$CODE', "
|
|
"number = '$LAST_APPLIED_VERSION', "
|
|
"gitCommit = '$COMMIT_SHA' "
|
|
"ON DUPLICATE KEY UPDATE "
|
|
"number = VALUES(number), "
|
|
"gitCommit = VALUES(gitCommit)"
|
|
)
|
|
fi
|
|
|
|
dbExec "${SQL[*]}"
|
|
echo "[INFO] Changes applied succesfully."
|
|
else
|
|
echo "[INFO] No changes applied."
|
|
fi
|