blob: ffaa54313b6de85bfbfc3109bba42c866d638553 [file] [log] [blame]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2022 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 json
import sys
# Removes |prefix| from |line|.
# A removeprefix() function is not available until 3.9.
def removeprefix(line, prefix):
if line.startswith(prefix):
return line[len(prefix) :]
return line
# Create new dict/lists containers that are hashable, but first remove any
# |prefixes| from nested strings.
def make_hashable(item, prefixes):
if isinstance(item, dict):
item = hashabledict(item, prefixes)
elif isinstance(item, list):
item = hashablelist(item, prefixes)
elif isinstance(item, str):
for prefix in prefixes:
item = removeprefix(item, prefix)
return item
# A list that is hashable so it can be added to a set.
class hashablelist(list):
def __init__(self, list, prefixes):
for v in list:
self.append(make_hashable(v, prefixes))
def __hash__(self):
return hash(tuple(sorted(self)))
def __eq__(self, other):
return sorted(self) == sorted(other)
# A dictionary that is hashable so it can be added to a set.
class hashabledict(dict):
def __init__(self, dict, prefixes):
for k, v in dict.items():
self[k] = make_hashable(v, prefixes)
def __hash__(self):
return hash(tuple(sorted(self.items())))
# Loads a set of items from a json file and optionally, uses |key| to get the list.
# Any |prefixes| will be stripped from strings in each item.
def load_set_from_json(log, key, prefixes):
items = json.load(log)
if key:
items = items.get(key, [])
return set(make_hashable(i, prefixes) for i in items)
def main():
parser = argparse.ArgumentParser(
description="Compare two json lists generated by different assembly invocations"
"and assert that they are functionally equivalent"
)
parser.add_argument(
"--reference", type=argparse.FileType("r"), required=True
)
parser.add_argument(
"--comparison", type=argparse.FileType("r"), required=True
)
parser.add_argument("--stamp", type=argparse.FileType("w"), required=True)
parser.add_argument("--strip-prefix", nargs="*")
parser.add_argument("--list-key", type=str)
args = parser.parse_args()
reference = load_set_from_json(
args.reference, args.list_key, args.strip_prefix
)
comparison = load_set_from_json(
args.comparison, args.list_key, args.strip_prefix
)
# Checks for missing commands.
missing = reference.difference(comparison)
extra = comparison.difference(reference)
if missing:
print("Items in the reference were missing from the comparison")
for cmd in missing:
print("Missing: " + str(cmd))
if extra:
print("Items in the comparison were not found in the reference")
for cmd in extra:
print("Extra: " + str(cmd))
if missing or extra:
return len(missing) + len(extra)
# Writes an empty file because GN requires targets to have an output.
with args.stamp as stamp:
stamp.write("")
return 0
if __name__ == "__main__":
sys.exit(main())