# pg-stand-sync Перенос базы PostgreSQL со стенда на локальный сервер: `pg_dump -Fc` → пересоздание локальной БД → `pg_restore -j`. Только stdlib Python 3.10+, внешних зависимостей нет. Утилиты берутся из поставки pgAdmin 4. Работает в двух режимах: интерактивное меню (запуск без аргументов) и команды CLI. ## Быстрый старт ```bash copy config.example.json config.json ``` Заполнить `source` (стенд) и `target` (локальная PG), затем: ```bash python pg_stand_sync.py ``` Появится меню: ``` стенд: postgres@postgresql.lan:5432 локально: postgres@localhost:5432 1. Dump + Restore — снять со стенда и залить локально 2. Dump — только снять дамп со стенда 3. Restore — залить локально готовый дамп 0. Выход ``` После выбора пункта показывается список: для Dump — базы стенда, для Restore — файлы из `dumps`. Ввод в списке работает так: | Ввод | Что делает | |---|---| | текст | фильтрует список по подстроке (регистр не важен) | | номер | выбирает пункт; в Dump можно `2,5,7` — несколько баз | | пусто | сбрасывает фильтр | | `q` | назад в меню | `config.json` в `.gitignore` — пароли в репозиторий не попадают. ## CLI ```bash python pg_stand_sync.py list # базы на стенде python pg_stand_sync.py dumps # локальные дампы python pg_stand_sync.py dump zpas # только дамп python pg_stand_sync.py sync zpas --target-db zpas_l # дамп + restore python pg_stand_sync.py restore dumps/zpas-20260820-031332.dump ``` Имя базы (или файла) можно не указывать — тогда откроется тот же список с фильтрацией. | Команда / ключ | Что делает | |---|---| | `sync [DB…]` | dump со стенда + restore локально | | `dump [DB…]` | только снять дампы со стенда (можно несколько баз) | | `restore [FILE]` | залить готовый `.dump` локально, без обращения к стенду | | `list` / `dumps` | базы стенда / файлы дампов | | `menu` | интерактивное меню (то же, что запуск без команды) | | `--target-db NAME` | имя локальной базы (по умолчанию как на стенде) | | `--no-recreate` | не делать DROP/CREATE DATABASE, накатить поверх (`pg_restore --clean --if-exists`) | | `-c, --config PATH` | другой конфиг (несколько стендов — несколько json) | | `--dry-run` | напечатать команды, ничего не выполнять | ## Конфиг | Поле | Значение по умолчанию | Смысл | |---|---|---| | `pg_bin_dir` | из `PATH` | каталог с `pg_dump.exe`, `pg_restore.exe`, `psql.exe` | | `dump_dir` | `dumps` | куда складывать дампы (относительный путь — от каталога скрипта) | | `keep_dumps` | `5` | сколько последних дампов хранить, `0` — не чистить | | `source.maintenance_database` | `postgres` | база, к которой подключаться для чтения списка баз | | `source.password_env` | — | имя переменной окружения с паролем вместо `password` в файле | | `target.database` | `null` | имя локальной базы; `null` — как на стенде | | `target.recreate` | `true` | DROP + CREATE локальной базы перед восстановлением | | `dump.schemas` / `exclude_*` | `[]` | ограничение состава: схемы, таблицы, данные таблиц | | `restore.jobs` | `4` | параллельные воркеры `pg_restore` | | `restore.exit_on_error` | `false` | падать на первой ошибке восстановления | | `post_restore_sql` | `[]` | список SQL, выполняемых в целевой базе после восстановления | Пароль ищется в три шага: `password` в конфиге → переменная окружения из `password_env` → запрос с терминала (один раз за запуск, ввод скрыт). В неинтерактивном запуске третьего шага нет — либо `password_env`, либо `pgpass.conf`. Пароль всегда уходит в дочерний процесс через `PGPASSWORD`, в командной строке не появляется; если пароля нет вовсе, утилиты вызываются с `--no-password`, чтобы скрипт не подвисал на приглашении. ```powershell $env:STAND_PGPASSWORD = '...' python pg_stand_sync.py sync zpas ``` ## Как это работает ``` config.json │ ├─ pg_dump -Fc ──► dumps/-.dump (стенд, только чтение) │ ├─ psql: pg_terminate_backend → DROP DATABASE → CREATE DATABASE (локально) │ ├─ pg_restore --jobs N --no-owner --no-privileges │ └─ post_restore_sql: анонимизация, правка настроек, GRANT'ы ``` Обезличивание данных стенда, если оно нужно, делается через `post_restore_sql` — уже в локальной базе, чтобы стенд оставался нетронутым.