From 6469bfc900147925ec24270898c6639991cd2c24 Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 12 May 2025 03:19:58 +0800 Subject: [PATCH 1/2] retry file move in case first time fails This is necessary under Windows because Microsoft Antivirus will lock directories while they are scanned. A retry will give the AV some time to run and unlock the directory. --- util/ipgen/renderer.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/util/ipgen/renderer.py b/util/ipgen/renderer.py index 32ee564bbec..95a6e33bd38 100644 --- a/util/ipgen/renderer.py +++ b/util/ipgen/renderer.py @@ -276,12 +276,17 @@ def _refresh_directory(self, staging_dir: Path, output_dir: Path, f'{output_dir_existing_bak}.') raise TemplateRenderError(msg).with_traceback(e.__traceback__) - try: - os.rename(staging_dir, output_dir) - except OSError as e: - msg = (f'Cannot move staging directory {staging_dir} to ' - f'{output_dir}.') - raise TemplateRenderError(msg).with_traceback(e.__traceback__) + for _ in range(5): + try: + os.rename(staging_dir, output_dir) + break + except PermissionError: + # give time for windows antivirus to run so the directory isn't locked + time.sleep(0.2) + except OSError as e: + msg = (f'Cannot move staging directory {staging_dir} to ' + f'{output_dir}.') + raise TemplateRenderError(msg).with_traceback(e.__traceback__) if do_overwrite: try: From e75443269bc937ed91597b5185b3961c5cca1b0a Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 12 May 2025 03:21:16 +0800 Subject: [PATCH 2/2] add a convenience routine to clear cached staging files When topgen crashes it leaves a lot of .~ staging files around, which if they exist on a future run causes the script to fail. --clear-cache argument goes through and cleans these up, which saves some effort on debug. This argument is false by default. --- util/topgen.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/util/topgen.py b/util/topgen.py index d8db3e4cd52..b67a93c1822 100755 --- a/util/topgen.py +++ b/util/topgen.py @@ -1521,6 +1521,10 @@ def main(): default=False, action="store_true", help="Only return the list of blocks and exit.") + parser.add_argument("--clear-cache", + default=False, + action="store_true", + help = "Clear any temporary files") args = parser.parse_args() @@ -1528,6 +1532,17 @@ def main(): if args.top_ral: args.no_top = True + if args.clear_cache: + for path in Path.cwd().rglob('*'): + if path.name.startswith('.~'): + try: + if path.is_file() or path.is_symlink(): + path.unlink() + elif path.is_dir(): + shutil.rmtree(path) + except Exception as e: + print(f"Failed to remove {path}: {e}") + if (args.no_top or args.no_xbar or args.no_plic) and (args.top_only or args.xbar_only or args.plic_only or args.alert_handler_only):