Skip to content

Commit 3a39461

Browse files
Check patches individually and then provide summary for easier debugging
1 parent e76ec37 commit 3a39461

File tree

1 file changed

+75
-11
lines changed

1 file changed

+75
-11
lines changed

check_patches_clean_apply.py

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
*source* and a stub *build* section remain.
2727
* Automatically invokes ``rattler-build build`` if *--dry* is **not**
2828
given.
29+
30+
Modification summary
31+
--------------------
32+
* Each recipe is built individually (not batch)
33+
* All outputs collected; failures reported with summary and details
34+
* No early stopping; CI-friendly non-zero exit if any failures
2935
"""
3036

3137
from __future__ import annotations
@@ -38,6 +44,12 @@
3844
from typing import Any, Dict, List, Union
3945
import yaml
4046

47+
# Make console writes UTF-8 and never crash on unknown glyphs (Windows-safe)
48+
try:
49+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
50+
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
51+
except Exception:
52+
pass
4153

4254
ROOT_DIR = Path.cwd()
4355
RECIPES_DIR = ROOT_DIR / "recipes"
@@ -130,15 +142,68 @@ def prepare_patch_recipes() -> List[Path]:
130142
return recreated
131143

132144

133-
def run_rattler_build() -> None:
134-
cmd = [
135-
"rattler-build",
136-
"build",
137-
"--recipe-dir",
138-
str(PATCH_RECIPES_DIR)
139-
]
140-
print("\n Running:", " ".join(cmd), "\n", flush=True)
141-
subprocess.run(cmd, check=True)
145+
def run_rattler_build_individually(recipes: List[Path]) -> None:
146+
results = []
147+
for recipe_file in recipes:
148+
cmd = [
149+
"rattler-build",
150+
"build",
151+
"--recipe-dir",
152+
str(recipe_file.parent),
153+
]
154+
print("\n Running:", " ".join(cmd), "\n", flush=True)
155+
try:
156+
proc = subprocess.run(cmd, text=True, capture_output=True, errors="replace", encoding="utf-8")
157+
success = proc.returncode == 0
158+
results.append(
159+
{
160+
"recipe": str(recipe_file.parent.relative_to(PATCH_RECIPES_DIR)),
161+
"ok": success,
162+
"stdout": proc.stdout,
163+
"stderr": proc.stderr,
164+
"rc": proc.returncode,
165+
}
166+
)
167+
print(" ->", "OK" if success else f"FAIL (rc={proc.returncode})", flush=True)
168+
except Exception as e:
169+
results.append(
170+
{
171+
"recipe": str(recipe_file.parent.relative_to(PATCH_RECIPES_DIR)),
172+
"ok": False,
173+
"stdout": "",
174+
"stderr": str(e),
175+
"rc": -1,
176+
}
177+
)
178+
print(" -> EXCEPTION:", e, flush=True)
179+
180+
# Summary
181+
failed = [r for r in results if not r["ok"]]
182+
print("\n================ Patch Application Summary ================\n")
183+
print(f"Total recipes tested: {len(results)}")
184+
print(f"Passed: {len(results) - len(failed)}")
185+
print(f"Failed: {len(failed)}")
186+
187+
if not failed:
188+
print("\nAll patches applied cleanly.\n")
189+
return
190+
191+
print("\n---------------- Failures (Summary) ----------------")
192+
for r in failed:
193+
print(f"- {r['recipe']} (rc={r['rc']})")
194+
195+
print("\n---------------- Failures (Details) ----------------")
196+
for r in failed:
197+
print(f"\n### {r['recipe']} (rc={r['rc']})")
198+
if r["stdout"]:
199+
print("\n[stdout]")
200+
print(r["stdout"].rstrip())
201+
if r["stderr"]:
202+
print("\n[stderr]")
203+
print(r["stderr"].rstrip())
204+
print("\n----------------------------------------------------\n")
205+
206+
sys.exit(2 if failed else 0)
142207

143208

144209
def main() -> None:
@@ -165,11 +230,10 @@ def main() -> None:
165230
print(f"Prepared {len(recreated)} minimal recipe(s) in {PATCH_RECIPES_DIR}/")
166231

167232
if not args.dry:
168-
run_rattler_build()
233+
run_rattler_build_individually(recreated)
169234
else:
170235
print("--dry given – rattler-build not executed.")
171236

172237

173238
if __name__ == "__main__":
174239
main()
175-

0 commit comments

Comments
 (0)