初始化模板仓库
This commit is contained in:
156
scripts/gen_index.py
Normal file
156
scripts/gen_index.py
Normal file
@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
gen_index.py - Generate index.typ from questions.json.
|
||||
|
||||
This script generates an index.typ file that includes all questions
|
||||
and their answers in the specified format.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from rich.console import Console
|
||||
|
||||
from common import DATA_DIR, setup_logging
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
def load_questions_json() -> list[dict]:
|
||||
"""Load questions from questions.json."""
|
||||
questions_path = DATA_DIR / "questions.json"
|
||||
if not questions_path.exists():
|
||||
console.print(f"[red]Error: questions.json not found at {questions_path}[/red]")
|
||||
sys.exit(1)
|
||||
import json
|
||||
|
||||
with open(questions_path, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def read_typ_content(target: str) -> str | None:
|
||||
"""Read typ file content."""
|
||||
typ_path = DATA_DIR / target
|
||||
if not typ_path.exists():
|
||||
console.print(f"[yellow]Warning: {target} not found[/yellow]")
|
||||
return None
|
||||
try:
|
||||
return typ_path.read_text(encoding="utf-8")
|
||||
except Exception as e:
|
||||
console.print(f"[yellow]Warning: Failed to read {target}: {e}[/yellow]")
|
||||
return None
|
||||
|
||||
|
||||
def indent_text(text: str, indent: int = 2) -> str:
|
||||
"""Indent text by specified spaces."""
|
||||
lines = text.strip().split("\n")
|
||||
spaces = " " * indent
|
||||
return "\n".join(spaces + line if line.strip() else "" for line in lines)
|
||||
|
||||
|
||||
def generate_index(questions: list[dict], dry_run: bool, logger) -> str:
|
||||
"""Generate index.typ content."""
|
||||
lines = [
|
||||
'#import "@local/phomework:0.1.0": homework, question, answer, shadow',
|
||||
"",
|
||||
]
|
||||
|
||||
enable_shadow = (
|
||||
"true"
|
||||
if any(DATA_DIR / f"A_{q['question']}.md" for q in questions)
|
||||
else "false"
|
||||
)
|
||||
|
||||
lines.append(
|
||||
f'#homework(title: "计算机网络第三次作业", secret: read(".secret"), enable_shadow: {enable_shadow})['
|
||||
)
|
||||
|
||||
def sort_key(q: dict) -> tuple:
|
||||
name = q["question"]
|
||||
prefix = name[0]
|
||||
try:
|
||||
num = int(name[1:])
|
||||
except ValueError:
|
||||
num = float("inf")
|
||||
return (0 if prefix == "R" else 1, prefix, num)
|
||||
|
||||
sorted_questions = sorted(questions, key=sort_key)
|
||||
|
||||
for q in sorted_questions:
|
||||
question_name = q["question"]
|
||||
typ_target = q["target"]
|
||||
|
||||
lines.append(f' #question(title: "{question_name}")[')
|
||||
content = read_typ_content(typ_target)
|
||||
if content:
|
||||
lines.append(indent_text(content, 4))
|
||||
else:
|
||||
lines.append(" [题目内容加载失败]")
|
||||
lines.append(" ]")
|
||||
lines.append("")
|
||||
lines.append(" #answer[")
|
||||
|
||||
answer_file = DATA_DIR / f"A_{question_name}.md"
|
||||
if answer_file.exists():
|
||||
lines.append(" 请填写答案。")
|
||||
lines.append("")
|
||||
lines.append(f' #shadow(read("./data/A_{question_name}.md"))')
|
||||
else:
|
||||
lines.append(" [答案文件不存在]")
|
||||
|
||||
lines.append(" ]")
|
||||
|
||||
lines.append("]")
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
"""Parse command line arguments."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate index.typ from questions.json"
|
||||
)
|
||||
parser.add_argument("--dry-run", action="store_true", help="Do not write files")
|
||||
parser.add_argument(
|
||||
"--force", action="store_true", help="Force overwrite without warning"
|
||||
)
|
||||
parser.add_argument("--verbose", action="store_true", help="Enable debug logging")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Main entry point."""
|
||||
args = parse_args()
|
||||
logger = setup_logging("gen_index", args.verbose)
|
||||
|
||||
questions = load_questions_json()
|
||||
logger.info(f"Loaded {len(questions)} questions")
|
||||
|
||||
if not questions:
|
||||
console.print("[yellow]No questions found in questions.json[/yellow]")
|
||||
sys.exit(1)
|
||||
|
||||
content = generate_index(questions, args.dry_run, logger)
|
||||
|
||||
output_path = Path("index.typ")
|
||||
|
||||
if output_path.exists() and not args.force and not args.dry_run:
|
||||
console.print(
|
||||
f"[yellow]Warning: {output_path} already exists and will be overwritten![/yellow]"
|
||||
)
|
||||
response = input("Continue? [y/N]: ")
|
||||
if response.lower() != "y":
|
||||
console.print("[yellow]Aborted.[/yellow]")
|
||||
sys.exit(0)
|
||||
|
||||
if args.dry_run:
|
||||
logger.info(f"[DRY-RUN] Would write {output_path}")
|
||||
logger.debug(f"Content preview:\n{content[:500]}...")
|
||||
else:
|
||||
output_path.write_text(content, encoding="utf-8")
|
||||
logger.info(f"Wrote {output_path}")
|
||||
console.print(f"[green]Successfully wrote {output_path}[/green]")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user