1212from operator import itemgetter
1313from pathlib import Path
1414from zlib import crc32
15+ from datetime import timedelta
16+
1517
1618RED = "\033 [91m"
1719GREEN = "\033 [92m"
2628FEINT = "\033 [2m"
2729ITALIC = "\033 [3m"
2830BLINK = "\033 [6m"
31+ CLEAR_EOL = "\033 [0K"
2932
3033LANGUAGES = {
3134 "Python" : "{year}/day{day}/day{day}.py" ,
3639
3740
3841def get_cache ():
42+ """Retrieve the cache instance from memory or load it from disk."""
3943 cache = globals ().get ("_cache" )
4044 if cache is None :
4145 cache_file = Path (__file__ ).parent .parent / "data" / "cache.json"
@@ -58,14 +62,22 @@ def save_cache():
5862 print (f"{ FEINT } { ITALIC } cache commited{ RESET } " )
5963
6064
61- def check_cache (key , timestamp : Path ):
65+ def check_cache (key , file_timestamp : Path ):
6266 cache = get_cache ()
6367 key = str (key )
6468 e = cache .get (key , None )
6569 if e :
66- timestamp = timestamp .stat ().st_mtime_ns
70+ timestamp = file_timestamp .stat ().st_mtime_ns
6771 if e ["timestamp" ] == timestamp :
6872 return e
73+ else :
74+ seconds = round ((timestamp - e ["timestamp" ]) / 1000000000 )
75+ delta = timedelta (seconds = seconds )
76+
77+ print (f"{ FEINT } { ITALIC } entry { key } is out of date for { delta } { RESET } " , end = "\r " )
78+
79+ else :
80+ print (f"{ FEINT } { ITALIC } missing cache for { key } { RESET } " , end = "\r " )
6981
7082
7183def update_cache (key , timestamp : Path , elapsed , status , answers ):
@@ -97,8 +109,6 @@ def run(key: str, prog: Path, file: Path, solution: t.List, refresh: bool):
97109 else :
98110 in_cache = False
99111
100- print (f"{ FEINT } { ITALIC } missing cache for { key } { RESET } " , end = "\r " )
101-
102112 start = time .time_ns ()
103113 out = subprocess .run ([prog , file .absolute ()], cwd = prog .parent , stdout = subprocess .PIPE )
104114 elapsed = time .time_ns () - start
@@ -149,16 +159,16 @@ def build_all():
149159 continue
150160 m = year / "Cargo.toml"
151161 if year .is_dir () and m .is_file ():
152- print (f"{ FEINT } { ITALIC } cargo build { m } { RESET } " , end = " \033 [0K \r " )
162+ print (f"{ FEINT } { ITALIC } cargo build { m } { RESET } " , end = f" { CLEAR_EOL } \r " )
153163 subprocess .check_call (["cargo" , "build" , "--manifest-path" , m , "--release" , "--quiet" ])
154164
155165 for day in range (1 , 26 ):
156166 src = year / f"day{ day } " / f"day{ day } .c"
157- print (f"{ FEINT } { ITALIC } compile { src } { RESET } " , end = " \033 [0K \r " )
167+ print (f"{ FEINT } { ITALIC } compile { src } { RESET } " , end = f" { CLEAR_EOL } \r " )
158168 make (year , src , f"day{ day } _c" , "cc -std=c11" )
159169
160170 src = year / f"day{ day } " / f"day{ day } .cpp"
161- print (f"{ FEINT } { ITALIC } compile { src } { RESET } " , end = " \033 [0K \r " )
171+ print (f"{ FEINT } { ITALIC } compile { src } { RESET } " , end = f" { CLEAR_EOL } \r " )
162172 make (year , src , f"day{ day } _cpp" , "c++ -std=c++17" )
163173
164174
@@ -190,15 +200,17 @@ def load_data():
190200 return inputs , solutions
191201
192202
193- def run_day (year : int , day : int , mday : str , inputs : t .Dict , sols : t .Dict , problems : t .Set , filter_lang , refresh ):
203+ def run_day (
204+ year : int , day : int , mday : str , day_inputs : t .Dict , day_sols : t .Dict , problems : t .Set , filter_lang , refresh
205+ ):
194206 elapsed = defaultdict (list )
195207
196208 first = True
197209
198210 day_suffix = mday .removeprefix (str (day ))
199211 name_max_len = 16 - len (day_suffix )
200212
201- for crc , file in inputs [ year , day ] .items ():
213+ for crc , file in sorted ( day_inputs .items (), key = itemgetter ( 1 ) ):
202214 input_name = file .parent .parent .name .removeprefix ("tmp-" )[:16 ]
203215 prefix = f"[{ year } -{ day :02d} { day_suffix } ] { input_name [:name_max_len ]:<{name_max_len }} "
204216
@@ -221,19 +233,20 @@ def run_day(year: int, day: int, mday: str, inputs: t.Dict, sols: t.Dict, proble
221233 first = False
222234 subprocess .call ([prog , "--help" ], stdout = subprocess .DEVNULL )
223235
224- e = run (key , prog , file , sols [ year , day ] .get (crc ), refresh )
236+ e = run (key , prog , file , day_sols .get (crc ), refresh )
225237
226238 if not e :
227239 continue
228240
229- if e ["status" ] in [ "unknown" , "fail" ] :
241+ if e ["status" ] != "ok" :
230242 info = f" { file } "
231243 else :
232244 info = ""
233245
234246 status_color = {"fail" : MAGENTA , "unknown" : GRAY , "error" : RED , "ok" : GREEN }[e ["status" ]]
235247
236248 line = (
249+ f"\r { RESET } { CLEAR_EOL } "
237250 f"{ prefix } "
238251 f" { YELLOW } { lang :<7} { RESET } :"
239252 f" { status_color } { e ['status' ]:7} { RESET } "
@@ -244,7 +257,7 @@ def run_day(year: int, day: int, mday: str, inputs: t.Dict, sols: t.Dict, proble
244257 )
245258 print (line )
246259
247- if e ["status" ] == "fail" :
260+ if e ["status" ] == "fail" or e [ "status" ] == "error" :
248261 problems .append (line )
249262
250263 if not e ["cache" ] and e ["elapsed" ] / 1e9 > 5 :
@@ -298,7 +311,9 @@ def main():
298311 for mday in list (Path (f"{ year } " ).glob (f"day{ day } " )) + list (Path (f"{ year } " ).glob (f"day{ day } _*" )):
299312 mday = mday .name .removeprefix ("day" )
300313
301- elapsed , nb_samples = run_day (year , day , mday , inputs , sols , problems , args .language , args .refresh )
314+ elapsed , nb_samples = run_day (
315+ year , day , mday , inputs [year , day ], sols [year , day ], problems , args .language , args .refresh
316+ )
302317 save_cache ()
303318
304319 if elapsed :
0 commit comments