144 lines
4.2 KiB
Python
144 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Append source code listings to a Markdown report.
|
|
|
|
Usage example:
|
|
python3 Report/append_sources_to_report.py \
|
|
--input Report/lab2/zivro-lab2-report.md \
|
|
--output Report/lab2/zivro-lab2-report-with-code.md \
|
|
--base . \
|
|
--include "Minint/**/*.cs" \
|
|
--include "Minint.Core/**/*.cs" \
|
|
--include "Minint.Infrastructure/**/*.cs" \
|
|
--include "Minint.Tests/**/*.cs"
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
|
|
EXT_TO_LANG: dict[str, str] = {
|
|
".cs": "csharp",
|
|
".axaml": "xml",
|
|
".xml": "xml",
|
|
".json": "json",
|
|
".md": "markdown",
|
|
".sh": "bash",
|
|
".py": "python",
|
|
}
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="Append code listings to report markdown.")
|
|
parser.add_argument("--input", required=True, help="Path to source markdown report.")
|
|
parser.add_argument("--output", required=True, help="Path to resulting markdown report.")
|
|
parser.add_argument(
|
|
"--base",
|
|
default=".",
|
|
help="Project root path used for resolving include patterns.",
|
|
)
|
|
parser.add_argument(
|
|
"--include",
|
|
action="append",
|
|
default=[],
|
|
help="Glob pattern relative to --base. Can be passed multiple times.",
|
|
)
|
|
parser.add_argument(
|
|
"--exclude-substring",
|
|
action="append",
|
|
default=["/bin/", "/obj/", ".git/"],
|
|
help="Skip files that contain this substring in path.",
|
|
)
|
|
parser.add_argument(
|
|
"--title",
|
|
default="Приложение A. Исходные тексты",
|
|
help="Heading title for generated appendix.",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def detect_lang(path: Path) -> str:
|
|
return EXT_TO_LANG.get(path.suffix.lower(), "text")
|
|
|
|
|
|
def should_skip(path: Path, excludes: list[str]) -> bool:
|
|
normalized = str(path).replace("\\", "/")
|
|
return any(sub in normalized for sub in excludes)
|
|
|
|
|
|
def collect_files(base: Path, patterns: list[str], excludes: list[str]) -> list[Path]:
|
|
files: list[Path] = []
|
|
seen: set[Path] = set()
|
|
for pattern in patterns:
|
|
for p in base.glob(pattern):
|
|
if not p.is_file():
|
|
continue
|
|
if should_skip(p, excludes):
|
|
continue
|
|
rp = p.resolve()
|
|
if rp in seen:
|
|
continue
|
|
seen.add(rp)
|
|
files.append(rp)
|
|
files.sort(key=lambda p: str(p).replace("\\", "/"))
|
|
return files
|
|
|
|
|
|
def build_appendix(base: Path, files: list[Path], title: str) -> str:
|
|
lines: list[str] = []
|
|
lines.append("")
|
|
lines.append("---")
|
|
lines.append("")
|
|
lines.append(f"## {title}")
|
|
lines.append("")
|
|
lines.append(
|
|
f"Сформировано автоматически скриптом `Report/append_sources_to_report.py` (файлов: {len(files)})."
|
|
)
|
|
lines.append("")
|
|
|
|
for i, file_path in enumerate(files, start=1):
|
|
rel = file_path.relative_to(base).as_posix()
|
|
lang = detect_lang(file_path)
|
|
content = file_path.read_text(encoding="utf-8", errors="replace").rstrip()
|
|
lines.append(f"### A.{i}. `{rel}`")
|
|
lines.append("")
|
|
lines.append(f"```{lang}")
|
|
if content:
|
|
lines.append(content)
|
|
lines.append("```")
|
|
lines.append("")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
|
|
input_md = Path(args.input).resolve()
|
|
output_md = Path(args.output).resolve()
|
|
base = Path(args.base).resolve()
|
|
patterns = args.include or ["**/*.cs"]
|
|
|
|
if not input_md.is_file():
|
|
raise FileNotFoundError(f"Input markdown not found: {input_md}")
|
|
if not base.exists():
|
|
raise FileNotFoundError(f"Base path not found: {base}")
|
|
|
|
report_body = input_md.read_text(encoding="utf-8")
|
|
files = collect_files(base, patterns, args.exclude_substring)
|
|
appendix = build_appendix(base, files, args.title)
|
|
|
|
output_md.parent.mkdir(parents=True, exist_ok=True)
|
|
output_md.write_text(report_body.rstrip() + "\n" + appendix + "\n", encoding="utf-8")
|
|
|
|
print(f"Input: {input_md}")
|
|
print(f"Output: {output_md}")
|
|
print(f"Files appended: {len(files)}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|