From 6b98f0ed0d909575d5d31c790ea222cee0828fa6 Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Sat, 7 Sep 2024 19:52:23 +0200 Subject: [PATCH] Test 2 --- SConstruct | 2 ++ methods.py | 70 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/SConstruct b/SConstruct index 5c1ccd244923..52a130ad8bd8 100644 --- a/SConstruct +++ b/SConstruct @@ -1124,3 +1124,5 @@ def purge_flaky_files(): atexit.register(purge_flaky_files) + +methods.clean_cache(env) diff --git a/methods.py b/methods.py index a9ca9e05cff7..51f1d52d892b 100644 --- a/methods.py +++ b/methods.py @@ -892,7 +892,6 @@ def show_progress(env): # Has its own progress/tracking tool that clashes with ours return - import atexit import sys from SCons.Script import AlwaysBuild, Command, Progress @@ -921,7 +920,6 @@ def __init__(self, path=None, limit=1073741824, half_life=43200): self.convert_size(limit), self.convert_size(self.get_size(path)) ) ) - # self.delete(self.file_list()) def __call__(self, node, *args, **kw): nonlocal node_count, node_count_max, node_count_interval, node_count_fname, show_progress @@ -946,7 +944,7 @@ def delete(self, files): screen.write("\rPurging %d %s from cache...\n" % (len(files), len(files) > 1 and "files" or "file")) [os.remove(f) for f in files] - def file_list(self, limit_mult=1.0): + def file_list(self): if self.path is None: # Nothing to do return [] @@ -969,7 +967,7 @@ def file_list(self, limit_mult=1.0): sum, mark = 0, None for i, x in enumerate(file_stat): sum += x[1] - if sum > self.limit * limit_mult: + if sum > self.limit: mark = i break if mark is None: @@ -999,7 +997,6 @@ def progress_finish(target, source, env): try: with open(node_count_fname, "w", encoding="utf-8", newline="\n") as f: f.write("%d\n" % node_count) - progressor.delete(progressor.file_list(1.1)) except Exception: pass @@ -1019,13 +1016,72 @@ def progress_finish(target, source, env): progress_finish_command = Command("progress_finish", [], progress_finish) AlwaysBuild(progress_finish_command) + +def clean_cache(env): + import atexit + import time + + class cache_clean: + def __init__(self, path=None, limit=1073741824): + self.path = path + self.limit = limit + + def clean(self): + self.delete(self.file_list()) + + def delete(self, files): + if len(files) == 0: + return + if env["verbose"]: + # Utter something + print("Purging %d %s from cache..." % (len(files), len(files) > 1 and "files" or "file")) + [os.remove(f) for f in files] + + def file_list(self): + if self.path is None: + # Nothing to do + return [] + # Gather a list of (filename, (size, atime)) within the + # cache directory + file_stat = [(x, os.stat(x)[6:8]) for x in glob.glob(os.path.join(self.path, "*", "*"))] + if file_stat == []: + # Nothing to do + return [] + # Weight the cache files by size (assumed to be roughly + # proportional to the recompilation time) times an exponential + # decay since the ctime, and return a list with the entries + # (filename, size, weight). + current_time = time.time() + file_stat = [(x[0], x[1][0], (current_time - x[1][1])) for x in file_stat] + # Sort by the most recently accessed files (most sensible to keep) first + file_stat.sort(key=lambda x: x[2]) + # Search for the first entry where the storage limit is + # reached + sum, mark = 0, None + for i, x in enumerate(file_stat): + sum += x[1] + if sum > self.limit: + mark = i + break + if mark is None: + return [] + else: + return [x[0] for x in file_stat[mark:]] + def progress_finally(): - nonlocal node_count, progressor + nonlocal cleaner try: - progressor.delete(progressor.file_list()) + cleaner.clean() + print("Final") except Exception: pass + cache_directory = os.environ.get("SCONS_CACHE") + # Simple cache pruning, attached to SCons' progress callback. Trim the + # cache directory to a size not larger than cache_limit. + cache_limit = float(os.getenv("SCONS_CACHE_LIMIT", 1024)) * 1024 * 1024 + cleaner = cache_clean(cache_directory, cache_limit) + atexit.register(progress_finally)