Разбор Crab Mysqldump2Git
Различия
Здесь показаны различия между двумя версиями данной страницы.
правила_разработки:как_надо_делать:разбор_crab_mysqldump2git [03.09.2018 14:11] admin Approved(admin 2018/09/03 14:11) |
правила_разработки:как_надо_делать:разбор_crab_mysqldump2git [20.05.2019 15:18] |
||
---|---|---|---|
Строка 1: | Строка 1: | ||
- | ===== Правим до идеала, спрашиваем все, что непонятно===== | ||
- | Все неверные решения добавляем в комменты и потом уже правим\\ | ||
- | |||
- | <code bash> | ||
- | #!/bin/bash | ||
- | |||
- | echo "$0 $@ [$$] START" >&2 | ||
- | set -euE | ||
- | |||
- | if [ "${1:---help}" = "--help" ]; then | ||
- | echo 'Info: Создает бекап mysql бд и отправляет его в git origin, таблицы пофайлово' | ||
- | echo "Usage: $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="${ARG_DB_NAME}.sql" | ||
- | |||
- | prepare(){ | ||
- | if [ ! -d .git ]; then | ||
- | git init . | ||
- | echo '*.sql' > .gitignore | ||
- | git add .gitignore | ||
- | git commit -m init | ||
- | fi | ||
- | if git remote show origin; then | ||
- | git pull origin master | ||
- | fi | ||
- | return 0 | ||
- | } | ||
- | |||
- | 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 | ||
- | return 0 | ||
- | } | ||
- | |||
- | 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(){ | ||
- | local ret | ||
- | git add . | ||
- | ret=$( git status ) | ||
- | if [[ "$ret" != *'nothing to commit'* ]]; then | ||
- | git commit -am $(date +%Y-%m-%d_%H-%M) | ||
- | fi | ||
- | git gc | ||
- | if git remote show origin; then | ||
- | git push origin master | ||
- | fi | ||
- | return 0 | ||
- | } | ||
- | |||
- | main(){ | ||
- | cd "$ARG_BACKUP_DIR" | ||
- | rm -f "$PREFIX.table."* | ||
- | mysqldump_csplit_per_table | ||
- | table_split_per_size10MB | ||
- | git_commit_push | ||
- | return 0 | ||
- | } | ||
- | main | ||
- | |||
- | echo "$0 $@ [$$] SUCCESS" >&2 | ||
- | exit 0 | ||
- | </code> | ||
- | |||
- | ===== Разбор скрипта ===== | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | ### Весь bash скрипт рассматриваем как инстанс объекта crab_mysqldump2git | ||
- | ### Глобальные переменные - это атрибуты(property) объекта | ||
- | ### функции - это методы объекта, либо иногда, это аналоги команд OS. | ||
- | ### если функция работает с переменной, которая не является атрибутом объекта, | ||
- | ### то она должна быть с входными параметрами | ||
- | |||
- | echo "$0 $@ [$$] START" >&2 | ||
- | ### падаем при любых необработанных ошибках | ||
- | set -euE | ||
- | |||
- | ### Делаем --help самом верху скрипта тк он же является и инфо о скрипте и сразу понятно, что делает скрипт | ||
- | if [ "${1:---help}" = "--help" ]; then | ||
- | echo 'Info: Создает бекап mysql бд и отправляет его в git origin, таблицы пофайлово' | ||
- | echo "Usage: $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 | ||
- | ### по сути понимаем, что $ARG_USER - это self.user или crab_mysqldump2git.user | ||
- | ### все аргументы записываем в ARG_NAME=значение, если это опция ARG_OPTNAME=TRUE, если позиционная в массив ARGV[$ARGC]="$i" | ||
- | |||
- | ### стараемся глобальные переменные устанавливать в начале скрипта так удобней для чтения | ||
- | # self.ARG_USER="${1/--user=/}" | ||
- | ARG_USER="${1/--user=/}" | ||
- | # self.ARG_PASSWORD="${2/--password=/}" и т.д. | ||
- | ARG_PASSWORD="${2/--password=/}" | ||
- | ARG_DB_HOST="${3/--host=/}" | ||
- | ARG_DB_NAME="${4}" | ||
- | ARG_BACKUP_DIR="${5}" | ||
- | PREFIX="${ARG_DB_NAME}.sql" | ||
- | |||
- | ### подготовительная работа действия, инициализация каталога при необходимости и тп | ||
- | prepare(){ | ||
- | ### Присвоение глобальных переменных и ARG_NAME здесь не делаем, делаем в начале скрипта | ||
- | if [ ! -d .git ]; then | ||
- | git init . | ||
- | echo '*.sql' > .gitignore | ||
- | git add .gitignore | ||
- | git commit -m init | ||
- | fi | ||
- | if git remote show origin; then | ||
- | git pull origin master | ||
- | fi | ||
- | return 0 | ||
- | } | ||
- | |||
- | ### Что такое объектный подход в stronbash | ||
- | ### Описание пользовательских команд(методов) и функций | ||
- | ### метод может работать с глобальными переменным без входящих значений | ||
- | ### если эти переменные это атрибут объекта self-script или его ARG_NAME CONF_NAME переменные | ||
- | ### но если это иные переменные, то обязательно делать через входные значения | ||
- | ### например ТОЛЬКО аргументом если мы обрабатываем файлы циклом, | ||
- | ### через for file in /tmp/mysql/*; do funct_name "$file"; done | ||
- | |||
- | # self.mysqldump_csplit_per_table() | ||
- | 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 | ||
- | return 0 | ||
- | } | ||
- | |||
- | # self.table_split_per_size10MB() | ||
- | 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 всегда обязательно, иначе вызов функции может упасть тк вернется не ноль после цикла или if, | ||
- | ### а код возврата от последней команды даже если мы его обработали и он не приведет к локальному падению | ||
- | return 0 | ||
- | } | ||
- | |||
- | git_commit_push(){ | ||
- | local ret | ||
- | git add . | ||
- | ret=$( git status ) | ||
- | if [[ "$ret" != *'nothing to commit'* ]]; then | ||
- | git commit -am $(date +%Y-%m-%d_%H-%M) | ||
- | fi | ||
- | git gc | ||
- | if git remote show origin; then | ||
- | git push origin master | ||
- | fi | ||
- | return 0 | ||
- | } | ||
- | |||
- | ### основной алгоритм скрипта, это последовательность команд и методов | ||
- | ### простейшие команды не выносим в отдельные методы | ||
- | main(){ | ||
- | ### КОМАНДА №1 | ||
- | cd "$ARG_BACKUP_DIR" | ||
- | ### КОМАНДА №2 | ||
- | rm -f "$PREFIX.table."* | ||
- | ### КОМАНДА №3 - это Команда-Метод объекта self-script, он использует глобальные переменные, которые по сути атрибуты объекта self-script и это нормально, что мы не передаем параметры | ||
- | mysqldump_csplit_per_table | ||
- | ### КОМАНДА №4 - это Команда-Метод | ||
- | table_split_per_size10MB | ||
- | ### КОМАНДА №5 - это Команда-Метод | ||
- | git_commit_push | ||
- | return 0 | ||
- | } | ||
- | main | ||
- | |||
- | echo "$0 $@ [$$] SUCCESS" >&2 | ||
- | ### exit 0 обязателен потому что, если в конце будет условие или выход из цикла и забудешь написать exit 0, то вернется не ноль и все упадет. Всегда надо делать exit 0 и return 0 и не думать каждый раз - это позволит избежать кучу проблем и освобождает мозг. | ||
- | ### Если нужно вернуть не 0 делаем явно [ $ret != 0 ] && exit $ret | ||
- | exit 0 | ||
- | </code> | ||
- | |||
- | {(rater>id=1|name=правила_разработки:как_надо_делать:разбор_crab_mysqldump2git|type=vote|trace=user|tracedetails=1)} | ||