[UPDATE] интеграция: безопасные маунты, кэш в tmpdir, только .tex/.pdf
This commit is contained in:
@@ -16,3 +16,4 @@ build/
|
||||
|
||||
# Report
|
||||
report.md
|
||||
output/
|
||||
|
||||
+4
-3
@@ -20,8 +20,9 @@ RUN cd /tmp && \
|
||||
fc-cache -f && \
|
||||
rm -f /tmp/*.TTF /tmp/times32.exe
|
||||
|
||||
WORKDIR /app
|
||||
WORKDIR /build
|
||||
COPY . .
|
||||
RUN uv sync --frozen --no-dev
|
||||
RUN uv pip install --system --no-cache .
|
||||
|
||||
ENTRYPOINT ["uv", "run", "--no-dev", "md2gost"]
|
||||
ENV UV_CACHE_DIR=/tmp/uv-cache
|
||||
ENTRYPOINT ["md2gost"]
|
||||
|
||||
+59
-4
@@ -4,12 +4,67 @@ set -euo pipefail
|
||||
IMAGE="md2gost"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
usage() {
|
||||
echo "Использование: md2gost file.md [-o dir]"
|
||||
echo " file.md — исходный Markdown-файл"
|
||||
echo " -o dir — выходная директория (по умолчанию ./build)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Парсим аргументы
|
||||
INPUT_FILE=""
|
||||
OUTPUT_DIR="./build"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-o)
|
||||
OUTPUT_DIR="${2:-}"
|
||||
[[ -z "$OUTPUT_DIR" ]] && usage
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
-*)
|
||||
echo "неизвестный флаг: $1" >&2
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
INPUT_FILE="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -z "$INPUT_FILE" ]] && usage
|
||||
|
||||
# Проверяем входной файл
|
||||
if [[ ! -f "$INPUT_FILE" ]]; then
|
||||
echo "ошибка: $INPUT_FILE не найден" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Абсолютные пути
|
||||
INPUT_ABS="$(realpath "$INPUT_FILE")"
|
||||
OUTPUT_ABS="$(realpath -m "$OUTPUT_DIR")"
|
||||
mkdir -p "$OUTPUT_ABS"
|
||||
|
||||
INPUT_BASE="$(basename "$INPUT_FILE")"
|
||||
|
||||
# Собираем образ если нужно
|
||||
if ! docker image inspect "$IMAGE" &>/dev/null; then
|
||||
echo " образ $IMAGE не найден, собираю..."
|
||||
echo "образ $IMAGE не найден, собираю..."
|
||||
docker build -t "$IMAGE" "$SCRIPT_DIR"
|
||||
fi
|
||||
|
||||
echo "→ конвертация $INPUT_FILE → $OUTPUT_DIR/"
|
||||
|
||||
# Запуск контейнера:
|
||||
# - вход: только .md файл (read-only)
|
||||
# - выход: директория для .tex и .pdf
|
||||
# - user: текущий пользователь (не root)
|
||||
docker run --rm \
|
||||
-e UV_CACHE_DIR=/tmp/uv-cache \
|
||||
-v "$(pwd):/app" \
|
||||
"$IMAGE" "$@"
|
||||
-v "$INPUT_ABS:/input/$INPUT_BASE:ro" \
|
||||
-v "$OUTPUT_ABS:/output" \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
"$IMAGE" "/input/$INPUT_BASE" -o /output
|
||||
|
||||
+33
-17
@@ -1,6 +1,8 @@
|
||||
import argparse
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from md2gost.parser import Parser
|
||||
@@ -44,27 +46,41 @@ def main():
|
||||
renderer = Renderer(parser.tokens, parser.front_matter)
|
||||
latex = renderer.render()
|
||||
|
||||
tex_path = args.output / args.input.with_suffix(".tex").name
|
||||
tex_path.write_text(latex, encoding="utf-8")
|
||||
print(f"→ {tex_path}")
|
||||
# Собираем во временную директорию, копируем только .tex и .pdf
|
||||
with tempfile.TemporaryDirectory(prefix="md2gost-") as cache:
|
||||
cache_dir = Path(cache)
|
||||
|
||||
if not args.no_pdf:
|
||||
pdf_path = args.output / args.input.with_suffix(".pdf").name
|
||||
log_path = args.output / "report.log"
|
||||
# Генерируем .tex в кэш
|
||||
tex_name = args.input.with_suffix(".tex").name
|
||||
tex_path = cache_dir / tex_name
|
||||
tex_path.write_text(latex, encoding="utf-8")
|
||||
|
||||
if not run_xelatex(tex_path, args.output):
|
||||
print("ошибка: xelatex не собрал PDF", file=sys.stderr)
|
||||
if log_path.exists():
|
||||
for line in log_path.read_text(errors="replace").splitlines():
|
||||
if line.startswith("!"):
|
||||
print(f" {line}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
# Копируем .tex в выходную директорию
|
||||
final_tex = args.output / tex_name
|
||||
shutil.copy2(tex_path, final_tex)
|
||||
print(f"→ {final_tex}")
|
||||
|
||||
if not run_xelatex(tex_path, args.output):
|
||||
print("ошибка: xelatex (2-й проход) не собрал PDF", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
if not args.no_pdf:
|
||||
# Компилируем PDF в кэше (два прохода для TOC)
|
||||
if not run_xelatex(tex_path, cache_dir):
|
||||
print("ошибка: xelatex не собрал PDF", file=sys.stderr)
|
||||
log_path = cache_dir / "report.log"
|
||||
if log_path.exists():
|
||||
for line in log_path.read_text(errors="replace").splitlines():
|
||||
if line.startswith("!"):
|
||||
print(f" {line}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"→ {pdf_path}")
|
||||
if not run_xelatex(tex_path, cache_dir):
|
||||
print("ошибка: xelatex (2-й проход) не собрал PDF", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Копируем .pdf в выходную директорию
|
||||
pdf_name = args.input.with_suffix(".pdf").name
|
||||
pdf_path = cache_dir / pdf_name
|
||||
final_pdf = args.output / pdf_name
|
||||
shutil.copy2(pdf_path, final_pdf)
|
||||
print(f"→ {final_pdf}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user