"""Runs one command and appends an execution record to results/experiment-log.jsonl. usage: python3 code/tools/logrun.py NAME [--log results/NAME.log] -- CMD ARG... The record has the fields required by the AutoScholar artifact contract: name, command, startedAt, endedAt, exitCode (plus durationSeconds, log path, cwd and worker). Output of the command is passed through to stdout/stderr and, if --log is given, also appended to that file. The exit code of the command is propagated so that `set -e` scripts stop on failure. Nothing is ever logged as successful unless the child process really exited with status 0. """ import datetime import json import os import subprocess import sys ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) LOG = os.environ.get("AUTOSCHOLAR_EXPLOG") or os.path.join(ROOT, "results", "experiment-log.jsonl") def utc(): return datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds") def main(argv): name = argv[0] log = None i = 1 if argv[i] == "--log": log = argv[i + 1] i += 2 assert argv[i] == "--", "usage: logrun.py NAME [--log FILE] -- CMD..." cmd = argv[i + 1:] os.chdir(ROOT) started = utc() t0 = datetime.datetime.now() lf = open(log, "a") if log else None proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) for line in proc.stdout: sys.stdout.write(line) sys.stdout.flush() if lf: lf.write(line) lf.flush() code = proc.wait() if lf: lf.close() ended = utc() rec = {"name": name, "command": " ".join(cmd), "startedAt": started, "endedAt": ended, "exitCode": code, "durationSeconds": round((datetime.datetime.now() - t0).total_seconds(), 3), "ok": code == 0, "cwd": ".", "log": log, "worker": os.environ.get("AUTOSCHOLAR_WORKER", "M4M64c")} with open(LOG, "a") as f: f.write(json.dumps(rec, sort_keys=True) + "\n") sys.exit(code) if __name__ == "__main__": main(sys.argv[1:])