blob: b747d709a8762bcf81e23ddbbf6a4ec4a2c4ce97 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import ctypes
import os
import re
import subprocess
import sys
import typing
# Import the UKM codegen library for its hashing function, which is the same
# hashing function as used for flag names.
# TODO(crbug.com/1371214) Move `codegen.HashName()` somewhere common so we don't
# depend on 'ukm'.
sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'ukm'))
import codegen
sys.path.append(
os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir,
os.pardir, 'python', 'google'))
import path_utils
import pretty_print
def get_entries_from_unit_test(outdir: str) -> typing.List[str]:
"""Returns `<int>` entries reported missing by the 'CheckHistograms' unittest.
"""
subprocess.run(['autoninja', '-C', outdir, 'unit_tests'])
run_test_command = subprocess.run([
os.path.join(outdir, 'unit_tests'),
'--gtest_filter=AboutFlagsHistogramTest.CheckHistograms'
],
capture_output=True,
text=True)
return re.findall('<int [^>]*>', run_test_command.stdout)
def get_entries_from_feature_string(feature: str) -> typing.List[str]:
"""Generates entries for `feature`."""
entries = []
for suffix in ['disabled', 'enabled']:
label = f'{feature}:{suffix}'
value_64 = codegen.HashName(label)
value_32 = ctypes.c_int32(value_64).value
entries.append(f'<int value="{value_32}" label="{label}"/>')
return entries
def add_entries_to_xml(enums_xml: str, entries: typing.List[str]) -> str:
"""Adds each of `entries` to `enums_xml` and pretty prints it."""
# Only add entries not already present.
entries = [entry for entry in entries if enums_xml.find(entry) == -1]
if entries:
find_text = '<enum name="LoginCustomFlags">'
find_index = enums_xml.find(find_text)
if find_index == -1:
raise Exception(f'Missing {find_text} in enums.xml.')
find_index += len(find_text)
enums_xml = (enums_xml[:find_index] + ' '.join(entries) +
enums_xml[find_index:])
return pretty_print.PrettyPrintEnums(enums_xml)
def main():
"""Generates and formats flag enums.
Args:
outdir: (Optional) The build output directory, defaults to out/Default.
feature: (Optional) The feature associated with the flag added. If omitted,
will determine it by building and running `unit_tests
AboutFlagsHistogramTest.CheckHistograms`. If provided, there's no use also
providing `outdir`, as nothing needs to be built.
Example usage:
generate_flag_enums.py
generate_flag_enums.py out/Default
generate_flag_enums.py --feature MyFeatureString
"""
parser = argparse.ArgumentParser()
parser.add_argument(
'outdir',
nargs='?',
default='out/Default',
help='(Optional) The build output directory, defaults to out/Default.')
parser.add_argument(
'--feature',
help="(Optional) The feature associated with the flag added. If omitted, "
"will determine it by building and running `unit_tests "
"AboutFlagsHistogramTest.CheckHistograms`. If provided, there's no use "
"also providing `outdir`, as nothing needs to be built.")
args = parser.parse_args()
entries = get_entries_from_feature_string(args.feature) \
if args.feature else get_entries_from_unit_test(args.outdir)
if not entries:
print("No missing enum entries found.")
return
xml_dir = path_utils.ScriptDir()
xml_path = os.path.join(xml_dir, 'enums.xml')
# Add any missing flag entries to enums.xml.
with open(xml_path, 'r+') as fd:
enums_xml = fd.read()
enums_xml = add_entries_to_xml(enums_xml, entries)
# Write back the entries to enums.xml.
fd.seek(0)
fd.write(enums_xml)
# Print any changes.
subprocess.run(['git', 'diff', xml_path])
if __name__ == '__main__':
main()