summaryrefslogtreecommitdiff
path: root/Omni/Bild
diff options
context:
space:
mode:
authorOmni Worker <bot@omni.agent>2025-11-22 06:39:54 -0500
committerOmni Worker <bot@omni.agent>2025-11-22 06:39:54 -0500
commit242903ce18b3a85f45db1888f8944ab036d5df23 (patch)
tree07fd8fcbc3e22101836779b9d4e297ffe425854d /Omni/Bild
parent6f4b2c97a24967508f3970b46999052fd1f44e67 (diff)
feat: implement t-rWcmRMaWX.4
Diffstat (limited to 'Omni/Bild')
-rwxr-xr-xOmni/Bild/audit.sh143
1 files changed, 143 insertions, 0 deletions
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()