1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
#!/usr/bin/env python3
# Copyright 2025 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Compares the structure / alignment of .grd files.
This takes as inputs two .grd files and checks that they contain the same nodes
and define the same resources with the same names.
Writes a stamp file if this is the case, or removes the stamp file and prints
an error message, otherwise.
"""
import argparse
import os
import xml.etree.ElementTree as ET
EXACT_TAGS = {'grit', 'outputs', 'output', 'emit', 'release', 'if'}
RESOURCE_TAGS = {'include', 'message'}
IGNORE = {'ph', 'includes', 'messages', 'ex'}
def compare_exact(a, b):
if len(a.attrib) != len(b.attrib):
return f'Attribute count mismatch: {len(a.attrib)} vs {len(b.attrib)}'
for key in a.attrib:
va = a.attrib[key]
vb = b.attrib[key]
if va != vb:
return f'Attribute mismatch for \'{key}\': {va} vs {vb}'
return 0
def compare_resource(a, b):
na = a.attrib['name']
nb = b.attrib['name']
if na != nb:
return f'Resource name mismatch: {na} vs {nb}'
return 0
def compare(a, b):
if a.tag != b.tag:
return f'Tag name mismatch: {a.tag} vs {b.tag}'
if a.tag in EXACT_TAGS:
result = compare_exact(a, b)
if result != 0:
return result
elif a.tag in RESOURCE_TAGS:
result = compare_resource(a, b)
if result != 0:
return result
else:
if a.tag not in IGNORE:
return f'Unexpected tag: {a.tag}'
ca = list(a)
cb = list(b)
if len(ca) != len(cb):
return f'Child count mismatch: {len(ca)} vs {len(cb)}'
for i in range(len(ca)):
result = compare(ca[i], cb[i])
if result != 0:
return result
return 0
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description=__doc__.strip().splitlines()[0],
epilog=' '.join(__doc__.strip().splitlines()[1:]))
parser.add_argument('--stamp', help='The check file to output')
parser.add_argument('lhs', help='The first .grd file')
parser.add_argument('rhs', help='The second .grd file')
args = parser.parse_args()
a = ET.parse(args.lhs)
b = ET.parse(args.rhs)
result = compare(a.getroot(), b.getroot())
# Always delete the stamp to create with a new timestamp.
if os.path.exists(args.stamp):
os.remove(args.stamp)
if result != 0:
print(result)
else:
with open(args.stamp, 'a') as _:
pass
|