File: generate_flag_enums.py

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (120 lines) | stat: -rwxr-xr-x 4,031 bytes parent folder | download | duplicates (2)
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/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()