From 242903ce18b3a85f45db1888f8944ab036d5df23 Mon Sep 17 00:00:00 2001 From: Omni Worker Date: Sat, 22 Nov 2025 06:39:54 -0500 Subject: feat: implement t-rWcmRMaWX.4 --- Omni/Bild/audit.sh | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100755 Omni/Bild/audit.sh (limited to 'Omni') diff --git a/Omni/Bild/audit.sh b/Omni/Bild/audit.sh new file mode 100755 index 0000000..1a0acd5 --- /dev/null +++ b/Omni/Bild/audit.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +""" +Audit codebase builds. + +Iterates through every namespace in the project and runs 'bild'. +For every build failure encountered, it automatically creates a new task. +""" + +# : out bild-audit + +import os +import sys +import subprocess +import argparse +import shutil +import re + +# Extensions supported by bild (from Omni/Bild.hs and Omni/Namespace.hs) +EXTENSIONS = {'.c', '.hs', '.lisp', '.nix', '.py', '.scm', '.rs', '.toml'} + +def strip_ansi(text): + """Strip ANSI escape codes from text.""" + ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') + return ansi_escape.sub('', text) + +def is_ignored(path): + """Check if a file is ignored by git.""" + res = subprocess.run( + ['git', 'check-ignore', path], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL + ) + return res.returncode == 0 + +def get_buildable_files(root_dir='.'): + """Find all files that bild can build.""" + targets = [] + for root, dirs, files in os.walk(root_dir): + # Skip hidden directories, build artifacts (_), and task db (.tasks) + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '_'] + + for f in files: + ext = os.path.splitext(f)[1] + if ext in EXTENSIONS: + path = os.path.join(root, f) + # Clean up path + if path.startswith('./'): + path = path[2:] + + if not is_ignored(path): + targets.append(path) + return targets + +def run_bild(target): + """Run bild on the target.""" + # --time 0 disables timeout + # --loud enables output (which we capture) + cmd = ['bild', '--time', '0', '--loud', target] + result = subprocess.run(cmd, capture_output=True, text=True) + return result + +def create_task(target, result, parent_id=None): + """Create a task for a build failure.""" + # Construct a descriptive title + # Try to get the last meaningful line of error output + lines = (result.stdout + result.stderr).strip().split('\n') + last_line = lines[-1] if lines else "Unknown error" + last_line = strip_ansi(last_line).strip() + + if len(last_line) > 50: + last_line = last_line[:47] + "..." + + title = f"Build failed: {target} - {last_line}" + + cmd = [ + 'task', 'create', title, + '--priority', '2', + '--json' + ] + + if parent_id: + cmd.append(f'--discovered-from={parent_id}') + + # Try to infer namespace + parts = target.split('/') + if len(parts) > 1: + # e.g. Omni/Bild.hs -> Omni/Bild + # Omni/Bild/Audit.py -> Omni/Bild + ns = os.path.dirname(target) + if ns: + cmd.append(f'--namespace={ns}') + + print(f"Creating task for {target}...") + proc = subprocess.run(cmd, capture_output=True, text=True) + + if proc.returncode != 0: + print(f"Error creating task: {proc.stderr}", file=sys.stderr) + else: + # task create --json returns the created task json + print(f"Task created: {proc.stdout.strip()}") + +def main(): + parser = argparse.ArgumentParser(description='Audit codebase builds.') + parser.add_argument('--parent', help='Parent task ID to link discovered tasks to') + parser.add_argument('paths', nargs='*', default=['.'], help='Paths to search for targets') + args = parser.parse_args() + + # Check if bild is available + if not shutil.which('bild'): + print("Warning: 'bild' command not found. Ensure it is in PATH.", file=sys.stderr) + + print(f"Scanning for targets in {args.paths}...") + targets = [] + for path in args.paths: + if os.path.isfile(path): + targets.append(path) + else: + targets.extend(get_buildable_files(path)) + + # Remove duplicates + targets = sorted(list(set(targets))) + print(f"Found {len(targets)} targets.") + + failures = 0 + for i, target in enumerate(targets): + print(f"[{i+1}/{len(targets)}] Building {target} ... ", end='', flush=True) + res = run_bild(target) + + if res.returncode == 0: + print("OK") + else: + print("FAIL") + failures += 1 + create_task(target, res, args.parent) + + print(f"\nAudit complete. {failures} failures found.") + if failures > 0: + sys.exit(1) + else: + sys.exit(0) + +if __name__ == '__main__': + main() -- cgit v1.2.3