Macで作成したSQLファイルをサーバー上のMySQLへ反映するとき、SQLを転送してSSHでログインしてからmysqlを実行する、という作業を毎回やるのは面倒。
SSHの標準入力へSQLをそのまま流せば、Macから直接実行できる。
1、MySQLの接続情報をサーバー側に保存複数のデータベースを使う場合は、サーバー側の ~/.my.cnf に接続情報をグループ別に登録しておく。
[client-project1]
user=example_user1
password=PASSWORD1
database=example_database1
[client-project2]
user=example_user2
password=PASSWORD2
database=example_database2パスワードが入っているので権限を絞る。
chmod 600 ~/.my.cnf接続確認。
mysql --defaults-group-suffix=-project1Mac側のSQLファイルを、SSH経由でサーバー側のmysqlへ直接渡す。
ssh example-server 'mysql --defaults-group-suffix=-project1' < project1_update.sqlこれならSQLファイルをサーバーへ転送しておく必要はない。
3、どうせならコマンド一発にするさらに、Downloadsにある最新のSQLを自動検出し、ファイル名から投入先を判定、実行前に確認し、成功したSQLだけ別フォルダへ退避するようにした。
実環境固有のファイル名や接続先はローカル設定ファイルへ分離しておけば、スクリプト本体にはサーバー情報を持たせなくて済む。
フルコードは以下。
# deploysql.zsh
# Upload the newest matching SQL file in ~/Downloads directly to a remote MySQL client over SSH.
# Environment-specific mappings live in ~/.config/deploysql/config.zsh and should not be committed.
deploysql() {
local dir="$HOME/Downloads"
local archive="$HOME/Desktop/deployed_sql"
local config="$HOME/.config/deploysql/config.zsh"
local file base target timestamp dest answer pattern
if [[ ! -r "$config" ]]; then
echo "設定ファイルがありません: $config"
echo "deploysql_config.example.zsh を参考に作成してください。"
return 1
fi
# shellcheck disable=SC1090
source "$config"
if [[ -z "$DEPLOYSQL_SSH_HOST" || ${#DEPLOYSQL_RULES[@]} -eq 0 ]]; then
echo "deploysql の設定が不完全です: $config"
return 1
fi
# Build find conditions from configured filename patterns.
local -a find_args
find_args=("$dir" -maxdepth 1 -type f '(')
local first=1
for pattern target in ${(kv)DEPLOYSQL_RULES}; do
if (( ! first )); then
find_args+=(-o)
fi
find_args+=(-name "$pattern")
first=0
done
find_args+=(')' -print0)
file=$(find "${find_args[@]}" | xargs -0 ls -t 2>/dev/null | head -1)
if [[ -z "$file" ]]; then
echo "投入対象のSQLがありません。"
return 1
fi
base="${file:t}"
target=""
for pattern target_name in ${(kv)DEPLOYSQL_RULES}; do
if [[ "$base" == ${~pattern} ]]; then
target="$target_name"
break
fi
done
if [[ -z "$target" ]]; then
echo "投入先を判定できません: $base"
return 1
fi
echo
echo "----------------------------------------"
echo " SQL : $base"
echo " DB : $target"
echo " HOST: $DEPLOYSQL_SSH_HOST"
echo "----------------------------------------"
echo
read "answer?このSQLを投入しますか? [y/N] "
if [[ "$answer" != [yY] ]]; then
echo "キャンセルしました。"
return 0
fi
if ssh "$DEPLOYSQL_SSH_HOST" "mysql --defaults-group-suffix=-$target" < "$file"; then
echo
echo "DBへの投入に成功しました。"
mkdir -p "$archive"
timestamp=$(date '+%Y%m%d_%H%M%S')
dest="$archive/${timestamp}_${base}"
mv "$file" "$dest"
echo "SQLを退避しました:"
echo "$dest"
else
echo
echo "ERROR: DBへの投入に失敗しました。"
echo "SQLはDownloadsに残しています。"
return 1
fi
}Macの ~/.zshrc から読み込む。
source "$HOME/git/samples/deploysql.zsh"実環境用の設定は例えば ~/.config/deploysql/config.zsh に置き、Gitでは管理しない。
DEPLOYSQL_SSH_HOST="example-server"
typeset -A DEPLOYSQL_RULES
DEPLOYSQL_RULES=(
'project1_*.sql' 'project1'
'project2_*.sql' 'project2'
)SQLをDownloadsへ保存したら、
deploysqlだけ。
対象SQLと投入先を表示して確認し、問題なければ y。実行に成功したSQLだけ ~/Desktop/deployed_sql/ へ日時付きで移動する。失敗した場合はDownloadsに残るので、修正して再実行できる。
毎回やっている短い作業ほど、コマンド一発にしてしまうと楽。


