xref: /aosp_15_r20/external/autotest/metadata/utils/extract_configs.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Lint as: python3
2*9c5db199SXin Li# Copyright 2020 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Liimport ast
7*9c5db199SXin Liimport collections
8*9c5db199SXin Liimport glob
9*9c5db199SXin Liimport logging
10*9c5db199SXin Liimport os
11*9c5db199SXin Liimport shutil
12*9c5db199SXin Lifrom typing import Generator, List, DefaultDict, NoReturn, Optional, Tuple
13*9c5db199SXin Li
14*9c5db199SXin Liimport control_files
15*9c5db199SXin Li
16*9c5db199SXin Li_ROOT_DIR = os.path.realpath(
17*9c5db199SXin Li    os.path.join(os.path.realpath(__file__), '../../..'))
18*9c5db199SXin Li_METADATA_DIR = os.path.join(_ROOT_DIR, 'metadata')
19*9c5db199SXin Li_CATEGORY_DEFS_DIR = os.path.join(_METADATA_DIR, 'tests')
20*9c5db199SXin Li_CATEGORY_DEFS_PACKAGE = '//metadata/tests'
21*9c5db199SXin Li_ALL_TESTS_FILE = os.path.join(_METADATA_DIR, 'tests.star')
22*9c5db199SXin Li
23*9c5db199SXin Li
24*9c5db199SXin Liclass ExtractionError(Exception):
25*9c5db199SXin Li  """Generic error from this package."""
26*9c5db199SXin Li
27*9c5db199SXin Li
28*9c5db199SXin Lidef main():
29*9c5db199SXin Li  """Extract starlark metadata for all tests in this project.
30*9c5db199SXin Li
31*9c5db199SXin Li  This script generates the starlark config files by parsing control files.
32*9c5db199SXin Li  The intent is to backfill majority of the required starlark configs this way,
33*9c5db199SXin Li  followed by hand-editing.
34*9c5db199SXin Li  """
35*9c5db199SXin Li  logging.basicConfig(level=logging.INFO)
36*9c5db199SXin Li  controls = control_files.load_all()
37*9c5db199SXin Li  logging.info('Loaded %d control files', len(controls))
38*9c5db199SXin Li  categorized = dict(_categorize_control_files(controls))
39*9c5db199SXin Li  logging.info('Categorized control files into %d categories', len(categorized))
40*9c5db199SXin Li
41*9c5db199SXin Li  _delete_existing_defs()
42*9c5db199SXin Li  for category, control in categorized.items():
43*9c5db199SXin Li    with open(_category_def_file(category), 'w') as f:
44*9c5db199SXin Li      f.write(_generate_category_def(control))
45*9c5db199SXin Li  logging.info('Wrote starlark files to %s', _CATEGORY_DEFS_DIR)
46*9c5db199SXin Li  with open(_ALL_TESTS_FILE, 'w') as f:
47*9c5db199SXin Li    f.write(_generate_all_tests_def(categorized.keys()))
48*9c5db199SXin Li  logging.info('Included all categories in %s', _ALL_TESTS_FILE)
49*9c5db199SXin Li
50*9c5db199SXin Li
51*9c5db199SXin Lidef _delete_existing_defs() -> NoReturn:
52*9c5db199SXin Li  if os.path.exists(_CATEGORY_DEFS_DIR):
53*9c5db199SXin Li    shutil.rmtree(_CATEGORY_DEFS_DIR)
54*9c5db199SXin Li    os.mkdir(_CATEGORY_DEFS_DIR)
55*9c5db199SXin Li  if os.path.exists(_ALL_TESTS_FILE):
56*9c5db199SXin Li    os.unlink(_ALL_TESTS_FILE)
57*9c5db199SXin Li
58*9c5db199SXin Li
59*9c5db199SXin Lidef _categorize_control_files(controls: List[control_files.Control]
60*9c5db199SXin Li                             ) -> DefaultDict[str, control_files.Control]:
61*9c5db199SXin Li  categorized = collections.defaultdict(list)
62*9c5db199SXin Li  for c in controls:
63*9c5db199SXin Li    categorized[c.category].append(c)
64*9c5db199SXin Li  if 'uncategorized' in categorized:
65*9c5db199SXin Li    raise ExtractionError('"uncategorized" is reserved')
66*9c5db199SXin Li  if '' in categorized:
67*9c5db199SXin Li    categorized['uncategorized'] = categorized['']
68*9c5db199SXin Li    del categorized['']
69*9c5db199SXin Li  return categorized
70*9c5db199SXin Li
71*9c5db199SXin Li
72*9c5db199SXin Lidef _category_def_file(category: str) -> str:
73*9c5db199SXin Li  return os.path.join(_CATEGORY_DEFS_DIR, '%s.star' % category)
74*9c5db199SXin Li
75*9c5db199SXin Li
76*9c5db199SXin Li_CATEGORY_TEMPLATE = """
77*9c5db199SXin Li# Copyright 2020 The Chromium OS Authors. All rights reserved.
78*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
79*9c5db199SXin Li# found in the LICENSE file.
80*9c5db199SXin Li
81*9c5db199SXin Li# !!! GENERATED FILE. DO NOT EDIT !!!
82*9c5db199SXin Li
83*9c5db199SXin Liload('//metadata/test_common.star', 'test_common')
84*9c5db199SXin Li
85*9c5db199SXin Lidef define_tests():
86*9c5db199SXin Li    return [%(test_list)s
87*9c5db199SXin Li    ]
88*9c5db199SXin Li"""
89*9c5db199SXin Li
90*9c5db199SXin Li_TEST_TEMPLATE = """
91*9c5db199SXin Li        test_common.define_test(
92*9c5db199SXin Li            %(name)s,
93*9c5db199SXin Li            suites = %(suites)s,
94*9c5db199SXin Li            main_package = %(main_package)s,
95*9c5db199SXin Li        )"""
96*9c5db199SXin Li
97*9c5db199SXin Li
98*9c5db199SXin Lidef _generate_category_def(controls: List[control_files.Control]) -> str:
99*9c5db199SXin Li  controls = sorted(controls, key=lambda c: c.name)
100*9c5db199SXin Li  test_list = ','.join([
101*9c5db199SXin Li      _TEST_TEMPLATE % {
102*9c5db199SXin Li          'name': "'%s/%s'" % (c.category, c.name),
103*9c5db199SXin Li          'suites': sorted(c.suites),
104*9c5db199SXin Li          'main_package': "'%s'" % c.main_package,
105*9c5db199SXin Li      } for c in controls
106*9c5db199SXin Li  ])
107*9c5db199SXin Li  return _CATEGORY_TEMPLATE % {'test_list': test_list}
108*9c5db199SXin Li
109*9c5db199SXin Li
110*9c5db199SXin Li_ALL_CATEGORIES_TEMPLATE = """
111*9c5db199SXin Li# Copyright 2020 The Chromium OS Authors. All rights reserved.
112*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
113*9c5db199SXin Li# found in the LICENSE file.
114*9c5db199SXin Li
115*9c5db199SXin Li# !!! GENERATED FILE. DO NOT EDIT !!!
116*9c5db199SXin Li
117*9c5db199SXin Li%(load_inclusions)s
118*9c5db199SXin Li
119*9c5db199SXin Lidef define_tests():
120*9c5db199SXin Li    tests = []
121*9c5db199SXin Li    %(append_inclusions)s
122*9c5db199SXin Li    return tests
123*9c5db199SXin Li"""
124*9c5db199SXin Li
125*9c5db199SXin Li_LOAD_CATEGORY_TEMPLATE = """
126*9c5db199SXin Liload('%(path)s', define_%(name)s = 'define_tests')"""
127*9c5db199SXin Li
128*9c5db199SXin Li_APPEND_CATEGORY_TEMPLATE = """
129*9c5db199SXin Li    tests += define_%(name)s()"""
130*9c5db199SXin Li
131*9c5db199SXin Li
132*9c5db199SXin Lidef _generate_all_tests_def(categories: List[str]) -> str:
133*9c5db199SXin Li  load_inclusions = [
134*9c5db199SXin Li      _LOAD_CATEGORY_TEMPLATE % {
135*9c5db199SXin Li          'name': c,
136*9c5db199SXin Li          'path': '%s/%s.star' % (_CATEGORY_DEFS_PACKAGE, c),
137*9c5db199SXin Li      } for c in categories
138*9c5db199SXin Li  ]
139*9c5db199SXin Li  append_inclusions = [
140*9c5db199SXin Li      _APPEND_CATEGORY_TEMPLATE % {
141*9c5db199SXin Li          'name': c
142*9c5db199SXin Li      } for c in categories
143*9c5db199SXin Li  ]
144*9c5db199SXin Li  return _ALL_CATEGORIES_TEMPLATE % {
145*9c5db199SXin Li      'load_inclusions': ''.join(load_inclusions),
146*9c5db199SXin Li      'append_inclusions': ''.join(append_inclusions),
147*9c5db199SXin Li  }
148*9c5db199SXin Li
149*9c5db199SXin Li
150*9c5db199SXin Liif __name__ == '__main__':
151*9c5db199SXin Li  main()
152