From e8094340a351f462c06897584c0ccc1084a0d511 Mon Sep 17 00:00:00 2001 From: Fennelfoxxo Date: Tue, 8 Apr 2025 05:11:01 -0700 Subject: [PATCH] Build: Add output file diffing to config_gen.py Currently, whenever CMake is reconfigured, config_gen.py will always regenerate the output config header and json, forcing a timestamp update and a rebuild. This change adds a --skip-unchanged option which skips writing to the output file if the write would not change the file's contents. The default is off to avoid breaking builds that rely on the existing behavior of always overwriting. Signed-off-by: James Martin --- tools/config_gen.py | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/tools/config_gen.py b/tools/config_gen.py index 76e09e750..b72130d9e 100644 --- a/tools/config_gen.py +++ b/tools/config_gen.py @@ -21,12 +21,19 @@ def main(): default=sys.stdin, help="Input YAML file.", ) + parser.add_argument( + "--skip-unchanged", + dest="skip_unchanged", + action="store_true", + help="Only write output file if new content is different" + ) parser.add_argument( "--write-c", metavar="OUT_FILE", dest="out_file_c", nargs="?", - type=argparse.FileType("w"), + # Use a+ mode to open in read/write mode without truncating existing contents + type=argparse.FileType("a+"), const=sys.stdout, default=None, help="Output C header file.", @@ -36,25 +43,25 @@ def main(): metavar="OUT_FILE", dest="out_file_json", nargs="?", - type=argparse.FileType("w"), + type=argparse.FileType("a+"), const=sys.stdout, default=None, help="Output JSON file.", ) args = parser.parse_args() generate(args.in_file_yaml, out_file_c=args.out_file_c, - out_file_json=args.out_file_json) + out_file_json=args.out_file_json, skip_unchanged=args.skip_unchanged) -def generate(in_file_yaml, out_file_c=None, out_file_json=None): +def generate(in_file_yaml, out_file_c=None, out_file_json=None, skip_unchanged=False): config = yaml.safe_load(in_file_yaml) if out_file_c is not None: - generate_c(config, out_file_c) + generate_c(config, out_file_c, skip_unchanged) if out_file_json is not None: - generate_json(config, out_file_json) + generate_json(config, out_file_json, skip_unchanged) -def generate_c(config, out_file): +def generate_c(config, out_file, skip_unchanged): header_contents = "#pragma once\n\n" for key, value in config.items(): @@ -76,11 +83,24 @@ def generate_c(config, out_file): header_contents += f"{entry}\n" - out_file.write(header_contents) + write_file_lazy(out_file, header_contents, skip_unchanged) -def generate_json(config, out_file): - json.dump(config, out_file, indent=4) +def generate_json(config, out_file, skip_unchanged): + json_contents = json.dumps(config, indent=4) + write_file_lazy(out_file, json_contents, skip_unchanged) + + +def write_file_lazy(out_file, content, skip_unchanged): + if out_file == sys.stdout: + out_file.write(content) + return + + out_file.seek(0) + if not skip_unchanged or out_file.read() != content: + out_file.seek(0) + out_file.truncate() + out_file.write(content) if __name__ == "__main__":