| #!/usr/bin/env fuchsia-vendored-python |
| # Copyright 2023 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import argparse |
| import difflib |
| import json |
| import pathlib |
| import sys |
| import subprocess |
| from depfile import DepFile |
| |
| |
| def clean_cml(cml_json): |
| for key in cml_json: |
| if isinstance(cml_json[key], list): |
| cml_json[key].sort(key=lambda x: json.dumps(x, sort_keys=True)) |
| |
| |
| def diff(json1, json2, file1_name, file2_name): |
| file1_lines = json.dumps(json1, sort_keys=True, indent=2).splitlines() |
| file2_lines = json.dumps(json2, sort_keys=True, indent=2).splitlines() |
| |
| return difflib.unified_diff( |
| file1_lines, |
| file2_lines, |
| fromfile=file1_name, |
| tofile=file2_name, |
| lineterm="", |
| ) |
| |
| |
| def get_config_values(configc_bin, cvf, component): |
| command = [ |
| configc_bin, |
| "dump-values", |
| "--cvf", |
| str(cvf), |
| "--cm", |
| component, |
| ] |
| |
| output = subprocess.run(command, capture_output=True) |
| stdout, stderr = ( |
| output.stdout.decode("UTF-8"), output.stderr.decode("UTF-8")) |
| if (stderr): |
| raise ValueError(f"Error running configc: {command}\n{stderr}") |
| return stdout |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser( |
| description='Compare two fshost packages, one generated by GN and another' |
| 'by Assembly, and assert they are the same') |
| parser.add_argument('--configc-bin', type=pathlib.Path, required=True) |
| parser.add_argument( |
| '--gn-fshost-component', type=pathlib.Path, required=True) |
| parser.add_argument( |
| '--assembly-fshost-component', type=pathlib.Path, required=True) |
| parser.add_argument( |
| '--gn-fshost-cml', type=argparse.FileType('r'), required=True) |
| parser.add_argument( |
| '--assembly-fshost-cml', type=argparse.FileType('r'), required=True) |
| parser.add_argument('--gn-fshost-cvf', type=pathlib.Path, required=True) |
| parser.add_argument( |
| '--assembly-fshost-cvf', type=pathlib.Path, required=True) |
| parser.add_argument( |
| "--output", |
| type=argparse.FileType('w'), |
| help="A file to write output to.") |
| parser.add_argument( |
| "--depfile", |
| type=argparse.FileType('w'), |
| help="A depfile of read files, this requires the use of --output") |
| |
| output = [] |
| |
| def error(string: str): |
| """output an error string""" |
| print(string, file=sys.stderr) |
| if args.output: |
| output.append(string) |
| |
| args = parser.parse_args() |
| |
| difflines = [] |
| |
| difflines += diff( |
| clean_cml(json.load(args.gn_fshost_cml)), |
| clean_cml(json.load(args.assembly_fshost_cml)), args.gn_fshost_cml.name, |
| args.assembly_fshost_cml.name) |
| |
| gn_fshost_config_values = get_config_values( |
| args.configc_bin, args.gn_fshost_cvf, args.gn_fshost_component) |
| assembly_fshost_config_values = get_config_values( |
| args.configc_bin, args.assembly_fshost_cvf, |
| args.assembly_fshost_component) |
| difflines += diff( |
| gn_fshost_config_values, assembly_fshost_config_values, |
| "gn_structured_config", "assembly_structured_config") |
| |
| output += difflines |
| diffstr = "\n".join(difflines) |
| |
| if args.depfile: |
| if args.output: |
| depfile = DepFile(args.output.name) |
| depfile.update( |
| [ |
| args.gn_fshost_cml.name, args.assembly_fshost_cml.name, |
| args.gn_fshost_component, args.assembly_fshost_component, |
| args.gn_fshost_cvf, args.assembly_fshost_cvf, |
| args.configc_bin |
| ]) |
| depfile.write_to(args.depfile) |
| else: |
| error("Cannot create a depfile without an output file") |
| return -2 |
| |
| if args.output: |
| for line in difflines: |
| print(line, file=args.output) |
| |
| if len(diffstr) != 0: |
| print( |
| "Error: non-empty diff between canonical json" |
| f" representations:\n{diffstr}") |
| return 1 |
| |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |