diff --git a/build.sh b/build.sh index f69905b..777b406 100755 --- a/build.sh +++ b/build.sh @@ -6,11 +6,11 @@ set -ev export PATH=$PATH:~/.cargo/bin:$GOROOT/bin run_from_diff() { - echo "$1" | grep "day-" | cut -d "/" -f1 | cut -d "-" -f2 | sort | uniq | xargs -I{} ./aoc run -fntd {} + echo "$1" | grep "day-" | cut -d "/" -f1 | cut -d "-" -f2 | sort | uniq | xargs -I{} ./aoc run --timeout 1 -fntd {} } run_from_inputs() { - for day in $1; do echo "$day"; done | sort | uniq | xargs -I{} ./aoc run -fntd {} + for day in $1; do echo "$day"; done | sort | uniq | xargs -I{} ./aoc run --timeout 1 -fntd {} } # Note: we cannot use "git branch --show-current" as GitHub rewrites the history in actions diff --git a/day-18/part-2/th-ch.py b/day-18/part-2/th-ch._py similarity index 100% rename from day-18/part-2/th-ch.py rename to day-18/part-2/th-ch._py diff --git a/leaderboard.sh b/leaderboard.sh index 04c125f..fd5b98a 100755 --- a/leaderboard.sh +++ b/leaderboard.sh @@ -5,7 +5,7 @@ set -ev # source $HOME/.cargo/env export PATH=$PATH:~/.cargo/bin:$GOROOT/bin -./aoc run --all +./aoc run --all --timeout 1 # Upload the content of leaderboard to the web. netlify deploy --prod --site cs-advent-of-code-2024 -d leaderboard --auth $NETLIFY_AUTH diff --git a/tool/AOC.py b/tool/AOC.py index 7819b8f..1a4bf45 100644 --- a/tool/AOC.py +++ b/tool/AOC.py @@ -100,6 +100,12 @@ def run(argv: list[str]) -> None: action="store_true", default=False, ) + parser.add_argument( + "--timeout", + help="max duration per script in seconds (default to 1s)", + default=0, + type=int + ) args = parser.parse_args(argv) @@ -115,6 +121,7 @@ def run(argv: list[str]) -> None: args.restricted, args.expand, args.times, + args.timeout, ) @staticmethod diff --git a/tool/run.py b/tool/run.py index a07473c..905bb74 100644 --- a/tool/run.py +++ b/tool/run.py @@ -2,6 +2,7 @@ import sys import time +import signal from collections import defaultdict from typing import Mapping @@ -19,11 +20,19 @@ class DifferentAnswersException(Exception): pass - class UnexpectedDebugLinesException(Exception): pass +class TooLongException(Exception): + pass + +def maxDurationHandler(signum, frame): + raise TooLongException("Submission ran for too long") + +signal.signal(signal.SIGALRM, maxDurationHandler) + + def run( days: list[int] | None, parts: list[int] | None, @@ -36,6 +45,7 @@ def run( restricted: bool, expand: bool, print_time_dist: bool, + timeout: int, ) -> None: problems = discovery.get_problems(days, parts, all_days_parts) printed_day_header: set[int] = set() @@ -63,18 +73,22 @@ def run( if restricted and input.author != submission.author.split(".")[0]: continue try: + # Start timeout timer + # if it's 0 (default, will be a no-op) + signal.alarm(timeout) result = run_submission( problem, submission, input, previous, no_debug ) + signal.alarm(0) # Stop the timer results_by_author[submission.author].append(result) results_by_input[input.author].append(result) previous = result except (DifferentAnswersException, UnexpectedDebugLinesException) as e: - errors.append( - f"{BColor.RED}ERROR: {e}{BColor.ENDC}".format( - BColor.RED, e, BColor.ENDC - ) - ) + errors.append(f"{BColor.RED}ERROR: {e}{BColor.ENDC}") + except TooLongException: + errors.append(f"{BColor.RED}[{submission.author}] day-{submission.problem.day}/part-{submission.problem.part} ({submission.language}){BColor.ENDC}: Maximum of {timeout}s reached (on input {BColor.BLUE}{input.author}{BColor.ENDC})") + finally: + signal.alarm(0) # Stop the timer just in case for submission in submissions: if submission.runnable is not None: