init: docker-migrate universal migration tool

This commit is contained in:
2026-05-22 19:58:09 +04:00
commit ddb2ae9501
34 changed files with 2431 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
"""
runner.py — запуск shell-команд с логированием и перехватом ошибок
"""
import subprocess
import shlex
import os
from core.color import log_cmd, error, info
def run(cmd, cwd=None, env=None, check=True, capture=True, shell=True, timeout=300):
"""
Выполняет команду. При ошибке (check=True) бросает RuntimeError с stdout+stderr.
"""
if not shell and isinstance(cmd, str):
cmd = shlex.split(cmd)
if isinstance(cmd, list):
display = " ".join(shlex.quote(str(x)) for x in cmd)
else:
display = cmd
log_cmd(display)
merged_env = os.environ.copy()
if env:
merged_env.update(env)
try:
result = subprocess.run(
cmd,
cwd=cwd,
env=merged_env,
shell=shell,
capture_output=capture,
text=True,
timeout=timeout,
check=False,
)
except subprocess.TimeoutExpired:
raise RuntimeError(f"Команда зависла (timeout {timeout}s): {display}")
if check and result.returncode != 0:
raise RuntimeError(
f"Команда завершилась с кодом {result.returncode}: {display}\n"
f"STDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}"
)
return result
def run_quiet(cmd, **kwargs):
"""Выполняет без вывода команды, только результат"""
return run(cmd, capture=True, **kwargs)
def run_json(cmd, **kwargs):
"""Выполняет и парсит JSON вывод"""
import json
r = run(cmd, **kwargs)
if not r.stdout.strip():
return {}
try:
return json.loads(r.stdout)
except json.JSONDecodeError:
raise RuntimeError(f"Не удалось распарсить JSON из: {cmd}\nВывод:\n{r.stdout}")
def exists(cmd_list):
"""Проверяет наличие команды в PATH"""
import shutil
return bool(shutil.which(cmd_list[0]) if isinstance(cmd_list, list) else shutil.which(cmd_list))