-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun.py
More file actions
executable file
·151 lines (121 loc) · 3.9 KB
/
run.py
File metadata and controls
executable file
·151 lines (121 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import os
import shutil
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
import subprocess
PROJECT_ROOT = Path.cwd()
SRC_DIR = PROJECT_ROOT / "src"
BUILD_ROOT = PROJECT_ROOT / "build"
PDF_ROOT = PROJECT_ROOT / "pdfs"
LOG_ROOT = PROJECT_ROOT / "logs"
# --------------------------------------------------
# File discovery
# --------------------------------------------------
def find_main_tex_files(root, suffix="_main.tex", exclude_patterns=None):
if exclude_patterns is None:
exclude_patterns = []
files = []
for path in root.rglob(f"*{suffix}"):
path_str = str(path)
if any(pat in path_str for pat in exclude_patterns):
continue
files.append(path)
return files
# --------------------------------------------------
# Path helpers
# --------------------------------------------------
def mirror_under(root_dir, src_file):
"""
Mirrors src/... under root_dir/...
Example:
src/ch1/sec1/main.tex
-> build/ch1/sec1/
"""
rel = src_file.parent.relative_to(SRC_DIR)
target = root_dir / rel
target.mkdir(parents=True, exist_ok=True)
return target
# --------------------------------------------------
# Compilation
# --------------------------------------------------
def compile_latex(tex_file: Path):
job_name = tex_file.stem
build_dir = mirror_under(BUILD_ROOT, tex_file)
pdf_dir = mirror_under(PDF_ROOT, tex_file)
log_dir = mirror_under(LOG_ROOT, tex_file)
cmd = [
"latexmk",
"-pdf",
"-shell-escape",
"-interaction=nonstopmode",
"-halt-on-error",
f"-outdir={build_dir}",
f"{job_name}.tex",
]
try:
result = subprocess.run(
cmd,
cwd=tex_file.parent, # per-thread working directory
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False
)
# Copy PDF
pdf_src = build_dir / f"{job_name}.pdf"
if pdf_src.exists():
shutil.copy2(pdf_src, pdf_dir / pdf_src.name)
# Move log
log_src = build_dir / f"{job_name}.log"
if log_src.exists():
shutil.move(log_src, log_dir / log_src.name)
return result.returncode == 0
except Exception:
return False
# --------------------------------------------------
# Main
# --------------------------------------------------
if __name__ == "__main__":
exclude_patterns = ["legacy", "templates", "tmp", "temp"]
tex_files = find_main_tex_files(SRC_DIR, "_main.tex", exclude_patterns)
print("Found the following files to compile:")
for f in tex_files:
print(" ", f)
successes = []
failures = []
"""
Non parallel version
for tex in tex_files:
ok = compile_latex(tex)
if ok:
successes.append(tex)
else:
failures.append(tex)
"""
MAX_WORKERS = min(8, os.cpu_count() or 1)
print(f"\nCompiling with {MAX_WORKERS} parallel workers...\n")
successes = []
failures = []
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
future_map = {executor.submit(compile_latex, tex): tex for tex in tex_files}
for future in as_completed(future_map):
tex = future_map[future]
try:
ok = future.result()
if ok:
successes.append(tex)
else:
failures.append(tex)
except Exception:
failures.append(tex)
print("\n===== Compilation Summary =====")
if successes:
print(f"Successfully compiled: {len(successes)}")
for f in successes:
print(" ", f)
if failures:
print(f"\nFailed to compile: {len(failures)}")
for f in failures:
print(" ", f)
exit(1)
else:
print("\nAll files compiled successfully")