Разбор Crab Mysqldump2Git
Различия
Здесь показаны различия между двумя версиями данной страницы.
правила_разработки:как_надо_делать:разбор_crab_mysqldump2git [03.09.2018 13:13] admin |
правила_разработки:как_надо_делать:разбор_crab_mysqldump2git [20.05.2019 15:18] |
||
---|---|---|---|
Строка 1: | Строка 1: | ||
- | ===== Правим до идеала, спрашиваем все, что непонятно===== | ||
- | Все неверные решения добавляем в комменты и потом уже правим\\ | ||
- | Внимание скрипт не тестировался в продакш, пока идеализируем | ||
- | |||
- | <code bash> | ||
- | #!/bin/bash | ||
- | set -euE | ||
- | echo "$0 $@ [$$] START" >&2 | ||
- | |||
- | if [ "${1:---help}" = "--help" ]; then | ||
- | echo "Example: backup: $0 --user=root --password=mypass --host=localhost DB_NAME BACKUP_DIR" | ||
- | echo 'Example: restore: git log; git checkout;' | ||
- | echo 'Example: restore: for f in *.sql.*; do cat $f >>new.sql; done;' | ||
- | echo 'Example: restore: /usr/bin/mysql -uroot -p123 < new.sql' | ||
- | exit 0 | ||
- | fi | ||
- | |||
- | ARG_USER="${1/--user=/}" | ||
- | ARG_PASSWORD="${2/--password=/}" | ||
- | ARG_DB_HOST="${3/--host=/}" | ||
- | ARG_DB_NAME="${4}" | ||
- | ARG_BACKUP_DIR="${5}" | ||
- | PREFIX="${DB_NAME}.sql" | ||
- | cd "$BACKUP_DIR" | ||
- | rm -f "$PREFIX.table."* | ||
- | |||
- | prepare(){ | ||
- | ### Присвоение глобальных переменных и ARG_NAME здесь не делаем, делаем в начале скрипта | ||
- | if [ ! -d .git ]; then | ||
- | git init . | ||
- | echo '*.sql' > .gitignore | ||
- | git add .gitignore | ||
- | git commit -m init | ||
- | fi | ||
- | } | ||
- | |||
- | mysqldump_csplit_per_table(){ | ||
- | set -o pipefail | ||
- | mysqldump --user="$ARG_USER" --host="$ARG_DB_HOST" --password="$ARG_PASSWORD" \ | ||
- | --opt -c --databases "$ARG_DB_NAME" \ | ||
- | --skip-quick \ | ||
- | --add-drop-table --add-drop-database --skip-extended-insert \ | ||
- | --create-options --single-transaction \ | ||
- | | csplit -n 4 -s -f"$PREFIX.table." - '/-- Table structure for table/' '{*}' | ||
- | set +o pipefail | ||
- | } | ||
- | |||
- | table_split_per_size10MB(){ | ||
- | local table="" | ||
- | for table in "$PREFIX.table."*; do | ||
- | if [ $(stat -c %s "$table") -gt $((10*1024*1024)) ]; then | ||
- | split -a 4 -d -b 10M "$table" "$table.split." | ||
- | rm -f "$table"; | ||
- | fi | ||
- | done | ||
- | return 0 | ||
- | } | ||
- | |||
- | git_commit_push(){ | ||
- | git add . | ||
- | if ! git status | grep -q 'nothing to commit'; then | ||
- | git commit -am $(date +%Y-%m-%d_%H-%M) | ||
- | fi | ||
- | git gc | ||
- | if git remote show origin; then | ||
- | git pull origin master | ||
- | git push origin master | ||
- | fi | ||
- | } | ||
- | |||
- | main(){ | ||
- | cd "$BACKUP_DIR" | ||
- | rm -f "$PREFIX.table."* | ||
- | mysqldump_csplit_per_table | ||
- | table_split_per_size10MB | ||
- | git_commit_push | ||
- | } | ||
- | |||
- | echo "$0 $@ [$$] SUCCESS" >&2 | ||
- | |||
- | exit 0 | ||
- | </code> | ||
- | |||
- | |||
- | ===== Разбор и комменты ===== | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | |||
- | ### Весь bash скрипт рассматриваем как инстанс объекта crab_mysqldump2git | ||
- | ### Глобальные переменные - это атрибуты(property) объекта | ||
- | ### функции - это методы объекта, либо иногда, это аналоги команд OS. | ||
- | ### если функция работает с переменной, которая не является атрибутом объекта, | ||
- | ### то она должна быть с входными параметрами | ||
- | |||
- | ### падаем при любых необработанных ошибках | ||
- | set -euEo pipefail | ||
- | echo "$0 $@ [$$] START" >&2 | ||
- | |||
- | if [ "${1:---help}" = "--help" ]; then | ||
- | echo "Example: backup: $0 --user=root --password=mypass --host=localhost DB_NAME BACKUP_DIR" | ||
- | echo 'Example: restore: git log; git checkout;' | ||
- | echo 'Example: restore: for f in *.sql.*; do cat $f >>new.sql; done;' | ||
- | echo 'Example: restore: /usr/bin/mysql -uroot -p123 < new.sql' | ||
- | exit 0 | ||
- | fi | ||
- | ### Подготовительная работа | ||
- | ### Подготавливаем глобальные переменные, что тождественно приватным property объекта self | ||
- | ### по сути понимаем, что $USER - это self.user или crab_mysqldump2git.user | ||
- | ### парсинг аргументов не стандартизован, для простоты кода оставим позиционно зависимый | ||
- | |||
- | USER="${1/--user=/}" | ||
- | PASSWORD="${2/--password=/}" | ||
- | DB_HOST="${3/--host=/}" | ||
- | DB_NAME="${4}" | ||
- | BACKUP_DIR="${5}" | ||
- | PREFIX="${DB_NAME}.sql" | ||
- | |||
- | ### подготовительная работа инициализация каталога при необходимости | ||
- | ### можно вынести в метод git_check_and_init() | ||
- | if [ ! -d .git ]; then | ||
- | git init . | ||
- | echo '*.sql' > .gitignore | ||
- | git add .gitignore | ||
- | git commit -m init | ||
- | fi | ||
- | |||
- | ### Описание пользовательских команд(методов) и функций | ||
- | ### метод может работать с глобальными переменным без входящих значений | ||
- | ### если эти переменные это атрибут объекта self-script или его CONF_NAME переменные | ||
- | ### но если это иные переменные, то обязательно делать через входные значения | ||
- | ### например Только аргументом если мы обрабатываем файлы, | ||
- | ### через for file in /tmp/mysql/*; do funct_name "$file"; done | ||
- | |||
- | mysql_dumpsplit(){ | ||
- | local table="" | ||
- | for table in "$PREFIX.table."*; do | ||
- | if [ $(stat -c %s "$table") -gt $((10*1024*1024)) ]; then | ||
- | split -a 4 -d -b 10M "$table" "$table.split." | ||
- | rm -f "$table"; | ||
- | fi | ||
- | done | ||
- | ### return 0 всегда обязательно, иначе вызов функции может упасть тк вернется не ноль, | ||
- | ### а код возврата от последней команды даже если мы его обработали и он не приведет к локальному падению | ||
- | return 0 | ||
- | } | ||
- | |||
- | ### основной алгоритм скрипта, это последовательность команд и методов | ||
- | ### простейшие команды не выносим в отдельные методы | ||
- | |||
- | ### КОМАНДА №1 | ||
- | cd "$BACKUP_DIR" | ||
- | |||
- | ### КОМАНДА №2 всегда стараемся избежать rm -rf | ||
- | rm -f "$PREFIX.table."* | ||
- | |||
- | ### КОМАНДА №3 | ||
- | mysqldump --user="$USER" --host="$DB_HOST" --password="$PASSWORD" \ | ||
- | --opt -c --databases "$DB_NAME" \ | ||
- | --skip-quick \ | ||
- | --add-drop-table --add-drop-database --skip-extended-insert \ | ||
- | --create-options --single-transaction \ | ||
- | | csplit -n 4 -s -f"$PREFIX.table." - '/-- Table structure for table/' '{*}' | ||
- | |||
- | ### КОМАНДА №4 - это команда-метод он использует глобальные переменные, которые по сути атрибуты объекта и это нормально | ||
- | mysql_dumpsplit | ||
- | |||
- | ### КОМАНДА №5 | ||
- | git add . | ||
- | |||
- | ### КОМАНДА №6 пример обработки команды у которой бывает код возврата не ноль, | ||
- | ### но при этом это не ошибка std_err='nothing to commit' | ||
- | ### это разрешенный и достаточно понятный сахар, | ||
- | ### мы разрешаем такой сахар, хоть он и нарушает правило, что нельзя условие делать без && | ||
- | ### другие вариации этой конструкции тоже разрешены | ||
- | error=$( git commit -am $(date +%Y-%m-%d_%H-%M) 2>&1 ) \ | ||
- | || [[ "$error" == *'nothing to commit'* ]] || { echo "$error"; exit 1; } | ||
- | |||
- | ### КОМАНДА №7 | ||
- | git gc | ||
- | |||
- | ### КОМАНДА №8 | ||
- | error=$( git push origin master 2>&1 )\ | ||
- | || echo "$error" | grep -qm1 'does not appear to be a git repositor' \ | ||
- | || { echo "$error"; exit 1; } | ||
- | |||
- | echo "$0 $@ [$$] SUCCESS" >&2 | ||
- | |||
- | ### обязательно ставим exit 0, | ||
- | ### Иначе не гарантии кода возврата 0 даже если скрип выполнился успешно | ||
- | ### тк скрипт может вернуть НЕ 0, а например последний резалт от grep и тп | ||
- | ### даже если мы его отловили | ||
- | ### при этом не нужно думать, что скрипт всегда вернет 0, | ||
- | ### скрипт вернет 0 только если все команды успешно выполнилось. | ||
- | exit 0 | ||
- | </code> | ||
- | |||
- | {(rater>id=1|name=правила_разработки:как_надо_делать:разбор_crab_mysqldump2git|type=vote|trace=user|tracedetails=1)} | ||