docs: update README and docs with strict Quick Start (docker-compose-prod), fix WebSocket paths, enforce strict tone
This commit is contained in:
101
release/generate_compose.py
Normal file
101
release/generate_compose.py
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Генерация docker-compose-prod.yaml из шаблона и env.example.
|
||||
|
||||
Автор: Сергей Антропов
|
||||
Сайт: https://devops.org.ru
|
||||
|
||||
Поведение:
|
||||
- Читает env.example и подставляет значения в docker-compose-prod.tmpl.yaml
|
||||
- Запрашивает (или берет из ENV/CLI) REGISTRY_HOST, IMAGE_NAME_FULL, IMAGE_TAG
|
||||
- Заменяет плейсхолдеры REGISTRY_PLACEHOLDER/IMAGE_NAME_PLACEHOLDER/IMAGE_TAG_PLACEHOLDER
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
from typing import Dict
|
||||
|
||||
|
||||
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
|
||||
|
||||
|
||||
def parse_env_file(env_path: str) -> Dict[str, str]:
|
||||
variables: Dict[str, str] = {}
|
||||
with io.open(env_path, "r", encoding="utf-8") as fh:
|
||||
for raw in fh:
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
if "=" not in line:
|
||||
continue
|
||||
key, val = line.split("=", 1)
|
||||
key = key.strip()
|
||||
val = val.strip()
|
||||
if (val.startswith('"') and val.endswith('"')) or (
|
||||
val.startswith("'") and val.endswith("'")
|
||||
):
|
||||
val = val[1:-1]
|
||||
variables[key] = val
|
||||
return variables
|
||||
|
||||
|
||||
def substitute_placeholders(text: str, env: Dict[str, str]) -> str:
|
||||
pattern = re.compile(r"\$\{([A-Za-z_][A-Za-z0-9_]*)\}")
|
||||
return pattern.sub(lambda m: env.get(m.group(1), m.group(0)), text)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Генерация docker-compose-prod.yaml")
|
||||
parser.add_argument("--template", default=os.path.join(ROOT, "release", "docker-compose-prod.tmpl.yaml"))
|
||||
parser.add_argument("--output", default=os.path.join(ROOT, "docker-compose-prod.yaml"))
|
||||
parser.add_argument("--env", dest="env_path", default=os.path.join(ROOT, "env.example"))
|
||||
parser.add_argument("--registry", default=os.getenv("REGISTRY_HOST", ""))
|
||||
parser.add_argument("--image", dest="image", default=os.getenv("IMAGE_NAME_FULL", ""))
|
||||
parser.add_argument("--tag", dest="tag", default=os.getenv("IMAGE_TAG", ""))
|
||||
args = parser.parse_args()
|
||||
|
||||
env = parse_env_file(args.env_path)
|
||||
# Подстановка ${VAR} из env.example
|
||||
with io.open(args.template, "r", encoding="utf-8") as fh:
|
||||
content = fh.read()
|
||||
content = substitute_placeholders(content, env)
|
||||
|
||||
# Комментирование строк, где остались неразрешенные ${VAR}
|
||||
# Ищем строки формата 'KEY: "${VAR}"' или 'KEY: ${VAR}' и комментируем их
|
||||
lines = content.splitlines()
|
||||
commented: list[str] = []
|
||||
unresolved_pattern = re.compile(r"^([ \t-]*[^:#\n]+:\s*)(\"?\$\{[A-Za-z_][A-Za-z0-9_]*\}\"?)\s*$")
|
||||
for line in lines:
|
||||
if unresolved_pattern.match(line):
|
||||
commented.append("# " + line)
|
||||
else:
|
||||
commented.append(line)
|
||||
content = "\n".join(commented) + ("\n" if content.endswith("\n") else "")
|
||||
|
||||
# Плейсхолдеры реестра/имени/тега
|
||||
registry = args.registry.strip() or input("Введите Docker Registry (например, ghcr.io или docker.io): ").strip() or "docker.io"
|
||||
if registry == "registry.hub.docker.com":
|
||||
registry = "docker.io"
|
||||
image = args.image.strip() or input(f"Введите имя образа (например, inecs/logboard) (по умолчанию: logboard): ").strip() or "logboard"
|
||||
tag = args.tag.strip() or input("Введите тег образа (по умолчанию: latest): ").strip() or "latest"
|
||||
|
||||
content = content.replace("REGISTRY_PLACEHOLDER", registry)
|
||||
content = content.replace("IMAGE_NAME_PLACEHOLDER", image)
|
||||
content = content.replace("IMAGE_TAG_PLACEHOLDER", tag)
|
||||
|
||||
with io.open(args.output, "w", encoding="utf-8") as fh:
|
||||
fh.write(content)
|
||||
|
||||
print(f"Файл {os.path.relpath(args.output, ROOT)} сгенерирован")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user