pymake

A build system based on Build Systems à la Carte
git clone https://git.grace.moe/pymake
Log | Files | Refs | README

commit 9379a82f3e413a41335a642081018fb08a9348f7
parent fb9a6fe690ec46a2a4c8f872c6a6b2840c2296d4
Author: gracefu <81774659+gracefuu@users.noreply.github.com>
Date:   Sun, 20 Apr 2025 08:01:30 +0800

Refactor the rerun_if_changed based build system into its own file

Diffstat:
Amake3.py | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtar-sketch/a.txt | 2+-
Mtar-sketch/tar2.py | 118++++---------------------------------------------------------------------------
3 files changed, 143 insertions(+), 113 deletions(-)

diff --git a/make3.py b/make3.py @@ -0,0 +1,136 @@ +import contextvars +import functools +import inspect +import pickle +from typing import Any + +rerun_db_var: contextvars.ContextVar[dict] = contextvars.ContextVar("rerun_db") +rerun_changes_var: contextvars.ContextVar[list[tuple[str, Any]]] = ( + contextvars.ContextVar("rerun_changes") +) +rerun_globals_var: contextvars.ContextVar[dict[str, Any]] = contextvars.ContextVar( + "rerun_globals" +) +rerun_locals_var: contextvars.ContextVar[dict[str, Any]] = contextvars.ContextVar( + "rerun_locals" +) + + +def with_rerun_context( + rerun_changes, rerun_globals, rerun_locals, f, /, *args, **kwargs +): + rerun_changes_var.set(rerun_changes) + rerun_globals_var.set(rerun_globals) + rerun_locals_var.set(rerun_locals) + return f(*args, **kwargs) + + +class UseEval: ... + + +def rerun_if_changed(f_str, current_value: Any = UseEval): + rerun_changes_var.get().append( + ( + f_str, + ( + eval( + f_str, + globals=rerun_globals_var.get(), + locals=rerun_locals_var.get(), + ) + if current_value == UseEval + else current_value + ), + ) + ) + + +def rerun_if(f_str): + return rerun_if_changed(f"bool({f_str})", False) + + +def cache_conditionally( + keys_fn=lambda *args, **kwargs: (args, tuple(sorted(kwargs.items()))), + store_fn=lambda result, /, *_, **__: result, + load_fn=lambda cached_result, /, *_, **__: cached_result, +): + def decorator(fn): + signature = inspect.signature(fn) + + @functools.wraps(fn) + def wrapped(*args, **kwargs): + db = rerun_db_var.get() + keys = keys_fn(*args, **kwargs) + bound_args = signature.bind(*args, **kwargs) + bound_args.apply_defaults() + rerun_locals = bound_args.arguments + if ("track", "result", fn.__qualname__, keys) in db: + if ("track", "rerun_changes", fn.__qualname__, keys) not in db: + old_rerun_changes = [] + db[("track", "rerun_changes", fn.__qualname__, keys)] = ( + old_rerun_changes + ) + else: + old_rerun_changes = db[ + ("track", "rerun_changes", fn.__qualname__, keys) + ] + for expr, old_val in old_rerun_changes: + try: + res = eval(expr, globals=fn.__globals__, locals=rerun_locals) + if res != old_val: + break + except BaseException: + break + else: + return load_fn( + db[("track", "result", fn.__qualname__, keys)], *args, **kwargs + ) + + context = contextvars.copy_context() + rerun_changes = [] + result = context.run( + with_rerun_context, + rerun_changes, + fn.__globals__, + rerun_locals, + fn, + *args, + **kwargs, + ) + db[("track", "rerun_changes", fn.__qualname__, keys)] = rerun_changes + db[("track", "result", fn.__qualname__, keys)] = store_fn( + result, *args, **kwargs + ) + return result + + return wrapped + + return decorator + + +class Rerunner: + def __init__(self, db_filename=b".makedb", db_file=None): + if db_file: + self.db_file = db_file + else: + self.db_file = open(db_filename, "a+b") + self.db_file.seek(0) + + def __enter__(self): + self.db_file.__enter__() + try: + self.db = pickle.load(self.db_file) + except pickle.PickleError: + self.db = dict() + except EOFError: + self.db = dict() + self.var_tok = rerun_db_var.set(self.db) + return self + + def __exit__(self, ty, exc, tb): + rerun_db_var.reset(self.var_tok) + if exc is None: + self.db_file.seek(0) + self.db_file.truncate(0) + pickle.dump(self.db, self.db_file) + self.db_file.__exit__(ty, exc, tb) diff --git a/tar-sketch/a.txt b/tar-sketch/a.txt @@ -1 +1 @@ -Sun Apr 20 07:16:53 AM +08 2025 +Sun Apr 20 08:02:47 AM +08 2025 diff --git a/tar-sketch/tar2.py b/tar-sketch/tar2.py @@ -1,117 +1,13 @@ -import contextvars -import functools -import inspect -import pickle -from typing import Any - -db: dict = dict() - -try: - with open(b".makedb", "rb") as f: - db = pickle.load(f) -except BaseException as e: - pass - - -def get_or_set(d, k, v): - if k in d: - return d[k] - d[k] = v - return v - - -rerun_changes_var: contextvars.ContextVar[list[tuple[str, Any]]] = ( - contextvars.ContextVar("rerun_changes") -) -rerun_locals_var: contextvars.ContextVar[dict[str, Any]] = contextvars.ContextVar( - "rerun_locals" -) - - -def with_rerun_context(rerun_changes, rerun_locals, f, /, *args, **kwargs): - rerun_changes_var.set(rerun_changes) - rerun_locals_var.set(rerun_locals) - return f(*args, **kwargs) - - -class UseEval: - pass - - -class UseCaller: - pass - - -def rerun_if_changed(f_str, current_value: Any = UseEval): - rerun_changes_var.get().append( - ( - f_str, - ( - eval(f_str, locals=rerun_locals_var.get()) - if current_value == UseEval - else current_value - ), - ) - ) - - -def rerun_if(f_str): - return rerun_if_changed(f"bool({f_str})", False) - - -def cache_conditionally( - keys_fn=lambda *args, **kwargs: (args, tuple(sorted(kwargs.items()))), - store_fn=lambda cached_result, /, *_, **__: cached_result, - load_fn=lambda cached_result, /, *_, **__: cached_result, -): - def decorator(fn): - signature = inspect.signature(fn) - - @functools.wraps(fn) - def wrapped(*args, **kwargs): - keys = keys_fn(*args, **kwargs) - bound_args = signature.bind(*args, **kwargs) - bound_args.apply_defaults() - rerun_locals = bound_args.arguments - if ("track", "result", fn.__qualname__, keys) in db: - old_rerun_changes = get_or_set( - db, ("track", "rerun_changes", fn.__qualname__, keys), [] - ) - for expr, old_val in old_rerun_changes: - try: - res = eval(expr, locals=rerun_locals) - if res != old_val: - break - except: - break - else: - return load_fn( - db[("track", "result", fn.__qualname__, keys)], *args, **kwargs - ) - - context = contextvars.copy_context() - rerun_changes = [] - result = context.run( - with_rerun_context, rerun_changes, rerun_locals, fn, *args, **kwargs - ) - db[("track", "rerun_changes", fn.__qualname__, keys)] = rerun_changes - db[("track", "result", fn.__qualname__, keys)] = store_fn( - result, *args, **kwargs - ) - return result - - return wrapped - - return decorator +import sys +sys.path.append("..") +from make3 import cache_conditionally, rerun_if_changed, Rerunner +from io import BufferedReader import hashlib import os import subprocess -from io import BufferedReader - - file_modtime = lambda f: os.stat(f.fileno()).st_mtime_ns @@ -146,7 +42,5 @@ def tar(manifest=b"manifest", output=b"archive.tar.gz"): rerun_if_changed(f"file_hash({repr(output)})") -tar() - -with open(b".makedb", "wb") as f: - pickle.dump(db, f) +with Rerunner(): + tar()