Отчёт
This commit is contained in:
143
Report/append_sources_to_report.py
Normal file
143
Report/append_sources_to_report.py
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/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())
|
||||
Reference in New Issue
Block a user