Peter Kotwicz | 4e476d7d | 2021-06-29 14:25:05 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Avi Drissman | 73a09d1 | 2022-09-08 20:33:38 | [diff] [blame] | 2 | # Copyright 2020 The Chromium Authors |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | # Lint as: python3 |
| 7 | """Prints out available java targets. |
| 8 | |
| 9 | Examples: |
| 10 | # List GN target for bundles: |
Peter Wen | a57817c | 2020-07-27 17:47:52 | [diff] [blame] | 11 | build/android/list_java_targets.py -C out/Default --type android_app_bundle \ |
| 12 | --gn-labels |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 13 | |
| 14 | # List all android targets with types: |
Peter Wen | a57817c | 2020-07-27 17:47:52 | [diff] [blame] | 15 | build/android/list_java_targets.py -C out/Default --print-types |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 16 | |
| 17 | # Build all apk targets: |
Peter Wen | a57817c | 2020-07-27 17:47:52 | [diff] [blame] | 18 | build/android/list_java_targets.py -C out/Default --type android_apk | xargs \ |
| 19 | autoninja -C out/Default |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 20 | |
| 21 | # Show how many of each target type exist: |
Peter Wen | a57817c | 2020-07-27 17:47:52 | [diff] [blame] | 22 | build/android/list_java_targets.py -C out/Default --stats |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 23 | |
| 24 | """ |
| 25 | |
| 26 | import argparse |
| 27 | import collections |
| 28 | import json |
| 29 | import logging |
| 30 | import os |
Andrew Grieve | 911128a | 2023-07-10 19:06:42 | [diff] [blame] | 31 | import shlex |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 32 | import subprocess |
| 33 | import sys |
| 34 | |
| 35 | _SRC_ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', |
| 36 | '..')) |
Andrew Grieve | 911128a | 2023-07-10 19:06:42 | [diff] [blame] | 37 | sys.path.append(os.path.join(_SRC_ROOT, 'build')) |
| 38 | import gn_helpers |
| 39 | |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 40 | sys.path.append(os.path.join(_SRC_ROOT, 'build', 'android')) |
| 41 | from pylib import constants |
| 42 | |
| 43 | _VALID_TYPES = ( |
| 44 | 'android_apk', |
| 45 | 'android_app_bundle', |
| 46 | 'android_app_bundle_module', |
| 47 | 'android_assets', |
| 48 | 'android_resources', |
| 49 | 'dist_aar', |
| 50 | 'dist_jar', |
| 51 | 'group', |
| 52 | 'java_annotation_processor', |
| 53 | 'java_binary', |
| 54 | 'java_library', |
Andrew Grieve | 4b737679 | 2022-06-30 20:00:03 | [diff] [blame] | 55 | 'robolectric_binary', |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 56 | 'system_java_library', |
| 57 | ) |
| 58 | |
| 59 | |
Andrew Grieve | 911128a | 2023-07-10 19:06:42 | [diff] [blame] | 60 | def _compile(output_dir, args, quiet=False): |
| 61 | cmd = gn_helpers.CreateBuildCommand(output_dir) + args |
| 62 | logging.info('Running: %s', shlex.join(cmd)) |
Peter Wen | 6754d96 | 2022-08-29 17:48:41 | [diff] [blame] | 63 | if quiet: |
| 64 | subprocess.run(cmd, check=True, capture_output=True) |
| 65 | else: |
| 66 | subprocess.run(cmd, check=True, stdout=sys.stderr) |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 67 | |
| 68 | |
| 69 | def _query_for_build_config_targets(output_dir): |
| 70 | # Query ninja rather than GN since it's faster. |
Fumitoshi Ukai | fa23bad2 | 2025-04-14 13:57:56 | [diff] [blame] | 71 | cmd = [ |
| 72 | os.path.join(_SRC_ROOT, 'third_party', 'siso', 'cipd', 'siso'), 'query', |
| 73 | 'targets', '-C', output_dir |
| 74 | ] |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 75 | logging.info('Running: %r', cmd) |
Andrew Grieve | 068c6f07 | 2025-04-08 19:09:39 | [diff] [blame] | 76 | try: |
Fumitoshi Ukai | fa23bad2 | 2025-04-14 13:57:56 | [diff] [blame] | 77 | query_output = subprocess.run(cmd, |
Andrew Grieve | 068c6f07 | 2025-04-08 19:09:39 | [diff] [blame] | 78 | check=True, |
| 79 | capture_output=True, |
| 80 | encoding='ascii').stdout |
| 81 | except subprocess.CalledProcessError as e: |
| 82 | sys.stderr.write('Command output:\n' + e.stdout + e.stderr) |
| 83 | raise |
| 84 | |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 85 | ret = [] |
| 86 | SUFFIX = '__build_config_crbug_908819' |
| 87 | SUFFIX_LEN = len(SUFFIX) |
Fumitoshi Ukai | fa23bad2 | 2025-04-14 13:57:56 | [diff] [blame] | 88 | for line in query_output.splitlines(): |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 89 | ninja_target = line.rsplit(':', 1)[0] |
| 90 | # Ignore root aliases by ensuring a : exists. |
| 91 | if ':' in ninja_target and ninja_target.endswith(SUFFIX): |
Peter Wen | a57817c | 2020-07-27 17:47:52 | [diff] [blame] | 92 | ret.append(f'//{ninja_target[:-SUFFIX_LEN]}') |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 93 | return ret |
| 94 | |
| 95 | |
Peter Wen | 73d007e | 2022-12-05 17:54:59 | [diff] [blame] | 96 | def _query_json(*, json_dict: dict, query: str, path: str): |
| 97 | """Traverses through the json dictionary according to the query. |
| 98 | |
| 99 | If at any point a key does not exist, return the empty string, but raise an |
| 100 | error if a key exists but is the wrong type. |
| 101 | |
| 102 | This is roughly equivalent to returning |
| 103 | json_dict[queries[0]]?[queries[1]]?...[queries[N]]? where the ? means that if |
| 104 | the key doesn't exist, the empty string is returned. |
| 105 | |
| 106 | Example: |
| 107 | Given json_dict = {'a': {'b': 'c'}} |
| 108 | - If queries = ['a', 'b'] |
| 109 | Return: 'c' |
| 110 | - If queries = ['a', 'd'] |
| 111 | Return '' |
| 112 | - If queries = ['x'] |
| 113 | Return '' |
| 114 | - If queries = ['a', 'b', 'x'] |
| 115 | Raise an error since json_dict['a']['b'] is the string 'c' instead of an |
| 116 | expected dict that can be indexed into. |
| 117 | |
| 118 | Returns the final result after exhausting all the queries. |
| 119 | """ |
| 120 | queries = query.split('.') |
| 121 | value = json_dict |
| 122 | try: |
| 123 | for key in queries: |
| 124 | value = value.get(key) |
| 125 | if value is None: |
| 126 | return '' |
| 127 | except AttributeError as e: |
| 128 | raise Exception( |
| 129 | f'Failed when attempting to get {queries} from {path}') from e |
| 130 | return value |
| 131 | |
| 132 | |
Yoshisato Yanagisawa | 9f47779 | 2021-12-09 00:00:25 | [diff] [blame] | 133 | class _TargetEntry: |
Peter Wen | 73d007e | 2022-12-05 17:54:59 | [diff] [blame] | 134 | |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 135 | def __init__(self, gn_target): |
Peter Wen | a57817c | 2020-07-27 17:47:52 | [diff] [blame] | 136 | assert gn_target.startswith('//'), f'{gn_target} does not start with //' |
| 137 | assert ':' in gn_target, f'Non-root {gn_target} required' |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 138 | self.gn_target = gn_target |
| 139 | self._build_config = None |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 140 | |
| 141 | @property |
| 142 | def ninja_target(self): |
| 143 | return self.gn_target[2:] |
| 144 | |
| 145 | @property |
| 146 | def ninja_build_config_target(self): |
| 147 | return self.ninja_target + '__build_config_crbug_908819' |
| 148 | |
Henrique Nakashima | 5f306229 | 2021-03-25 21:55:45 | [diff] [blame] | 149 | @property |
| 150 | def build_config_path(self): |
Peter Wen | d9e1d00 | 2021-07-12 15:36:42 | [diff] [blame] | 151 | """Returns the filepath of the project's .build_config.json.""" |
Henrique Nakashima | 5f306229 | 2021-03-25 21:55:45 | [diff] [blame] | 152 | ninja_target = self.ninja_target |
| 153 | # Support targets at the root level. e.g. //:foo |
| 154 | if ninja_target[0] == ':': |
| 155 | ninja_target = ninja_target[1:] |
Peter Wen | d9e1d00 | 2021-07-12 15:36:42 | [diff] [blame] | 156 | subpath = ninja_target.replace(':', os.path.sep) + '.build_config.json' |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 157 | return os.path.relpath( |
| 158 | os.path.join(constants.GetOutDirectory(), 'gen', subpath)) |
Henrique Nakashima | 5f306229 | 2021-03-25 21:55:45 | [diff] [blame] | 159 | |
Andrew Grieve | 7d34dfa | 2025-04-28 20:15:37 | [diff] [blame] | 160 | @property |
| 161 | def params_path(self): |
| 162 | """Returns the filepath of the project's .params.json.""" |
| 163 | return self.build_config_path.replace('.build_config.json', '.params.json') |
| 164 | |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 165 | def build_config(self): |
Peter Wen | d9e1d00 | 2021-07-12 15:36:42 | [diff] [blame] | 166 | """Reads and returns the project's .build_config.json JSON.""" |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 167 | if not self._build_config: |
Andrew Grieve | 7d34dfa | 2025-04-28 20:15:37 | [diff] [blame] | 168 | with open(self.params_path) as f: |
| 169 | config = json.load(f) |
| 170 | with open(self.build_config_path) as f: |
| 171 | config.update(json.load(f)) |
| 172 | self._build_config = config |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 173 | return self._build_config |
| 174 | |
| 175 | def get_type(self): |
Peter Wen | d9e1d00 | 2021-07-12 15:36:42 | [diff] [blame] | 176 | """Returns the target type from its .build_config.json.""" |
Andrew Grieve | 7d34dfa | 2025-04-28 20:15:37 | [diff] [blame] | 177 | return self.build_config()['type'] |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 178 | |
Andrew Grieve | c5e15d1b | 2020-12-04 18:13:02 | [diff] [blame] | 179 | def proguard_enabled(self): |
| 180 | """Returns whether proguard runs for this target.""" |
| 181 | # Modules set proguard_enabled, but the proguarding happens only once at the |
| 182 | # bundle level. |
| 183 | if self.get_type() == 'android_app_bundle_module': |
| 184 | return False |
Andrew Grieve | 7d34dfa | 2025-04-28 20:15:37 | [diff] [blame] | 185 | return self.build_config().get('proguard_enabled', False) |
Andrew Grieve | c5e15d1b | 2020-12-04 18:13:02 | [diff] [blame] | 186 | |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 187 | |
| 188 | def main(): |
| 189 | parser = argparse.ArgumentParser( |
| 190 | description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) |
Peter Wen | a57817c | 2020-07-27 17:47:52 | [diff] [blame] | 191 | parser.add_argument('-C', |
| 192 | '--output-directory', |
| 193 | help='If outdir is not provided, will attempt to guess.') |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 194 | parser.add_argument('--gn-labels', |
| 195 | action='store_true', |
| 196 | help='Print GN labels rather than ninja targets') |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 197 | parser.add_argument('--omit-targets', |
| 198 | action='store_true', |
| 199 | help='Do not print the target / gn label') |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 200 | parser.add_argument( |
| 201 | '--nested', |
| 202 | action='store_true', |
| 203 | help='Do not convert nested targets to their top-level equivalents. ' |
| 204 | 'E.g. Without this, foo_test__apk -> foo_test') |
| 205 | parser.add_argument('--print-types', |
| 206 | action='store_true', |
| 207 | help='Print type of each target') |
Peter Wen | d9e1d00 | 2021-07-12 15:36:42 | [diff] [blame] | 208 | parser.add_argument( |
| 209 | '--print-build-config-paths', |
| 210 | action='store_true', |
| 211 | help='Print path to the .build_config.json of each target') |
Andrew Grieve | 7d34dfa | 2025-04-28 20:15:37 | [diff] [blame] | 212 | parser.add_argument('--print-params-paths', |
| 213 | action='store_true', |
| 214 | help='Print path to the .params.json of each target') |
Andrew Grieve | c5e15d1b | 2020-12-04 18:13:02 | [diff] [blame] | 215 | parser.add_argument('--build', |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 216 | action='store_true', |
Peter Wen | d9e1d00 | 2021-07-12 15:36:42 | [diff] [blame] | 217 | help='Build all .build_config.json files.') |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 218 | parser.add_argument('--type', |
| 219 | action='append', |
| 220 | help='Restrict to targets of given type', |
| 221 | choices=_VALID_TYPES) |
| 222 | parser.add_argument('--stats', |
| 223 | action='store_true', |
| 224 | help='Print counts of each target type.') |
Andrew Grieve | c5e15d1b | 2020-12-04 18:13:02 | [diff] [blame] | 225 | parser.add_argument('--proguard-enabled', |
| 226 | action='store_true', |
Peter Wen | 73d007e | 2022-12-05 17:54:59 | [diff] [blame] | 227 | help='Restrict to targets that have proguard enabled.') |
| 228 | parser.add_argument('--query', |
| 229 | help='A dot separated string specifying a query for a ' |
| 230 | 'build config json value of each target. Example: Use ' |
Andrew Grieve | 7d34dfa | 2025-04-28 20:15:37 | [diff] [blame] | 231 | '--query unprocessed_jar_path to show a list ' |
| 232 | 'of all targets that have a non-empty ' |
| 233 | '"unprocessed_jar_path" value in that dict.') |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 234 | parser.add_argument('-v', '--verbose', default=0, action='count') |
Peter Wen | 6754d96 | 2022-08-29 17:48:41 | [diff] [blame] | 235 | parser.add_argument('-q', '--quiet', default=0, action='count') |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 236 | args = parser.parse_args() |
| 237 | |
Andrew Grieve | c5e15d1b | 2020-12-04 18:13:02 | [diff] [blame] | 238 | args.build |= bool(args.type or args.proguard_enabled or args.print_types |
Peter Wen | 73d007e | 2022-12-05 17:54:59 | [diff] [blame] | 239 | or args.stats or args.query) |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 240 | |
Peter Wen | 6754d96 | 2022-08-29 17:48:41 | [diff] [blame] | 241 | logging.basicConfig(level=logging.WARNING + 10 * (args.quiet - args.verbose), |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 242 | format='%(levelname).1s %(relativeCreated)6d %(message)s') |
| 243 | |
| 244 | if args.output_directory: |
| 245 | constants.SetOutputDirectory(args.output_directory) |
| 246 | constants.CheckOutputDirectory() |
| 247 | output_dir = constants.GetOutDirectory() |
| 248 | |
Andrew Grieve | 4281bf3 | 2025-01-14 02:29:33 | [diff] [blame] | 249 | if args.build: |
| 250 | _compile(output_dir, ['build.ninja']) |
| 251 | |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 252 | # Query ninja for all __build_config_crbug_908819 targets. |
| 253 | targets = _query_for_build_config_targets(output_dir) |
| 254 | entries = [_TargetEntry(t) for t in targets] |
| 255 | |
Andrew Grieve | 4281bf3 | 2025-01-14 02:29:33 | [diff] [blame] | 256 | if not entries: |
| 257 | logging.warning('No targets found. Run with --build') |
| 258 | sys.exit(1) |
| 259 | |
Andrew Grieve | c5e15d1b | 2020-12-04 18:13:02 | [diff] [blame] | 260 | if args.build: |
Peter Wen | d9e1d00 | 2021-07-12 15:36:42 | [diff] [blame] | 261 | logging.warning('Building %d .build_config.json files...', len(entries)) |
Andrew Grieve | 911128a | 2023-07-10 19:06:42 | [diff] [blame] | 262 | _compile(output_dir, [e.ninja_build_config_target for e in entries], |
| 263 | quiet=args.quiet) |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 264 | |
| 265 | if args.type: |
| 266 | entries = [e for e in entries if e.get_type() in args.type] |
| 267 | |
Andrew Grieve | c5e15d1b | 2020-12-04 18:13:02 | [diff] [blame] | 268 | if args.proguard_enabled: |
| 269 | entries = [e for e in entries if e.proguard_enabled()] |
| 270 | |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 271 | if args.stats: |
| 272 | counts = collections.Counter(e.get_type() for e in entries) |
| 273 | for entry_type, count in sorted(counts.items()): |
Peter Wen | a57817c | 2020-07-27 17:47:52 | [diff] [blame] | 274 | print(f'{entry_type}: {count}') |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 275 | else: |
| 276 | for e in entries: |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 277 | if args.omit_targets: |
| 278 | target_part = '' |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 279 | else: |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 280 | if args.gn_labels: |
| 281 | target_part = e.gn_target |
| 282 | else: |
| 283 | target_part = e.ninja_target |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 284 | |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 285 | # Convert to top-level target |
| 286 | if not args.nested: |
| 287 | target_part = target_part.replace('__test_apk', |
| 288 | '').replace('__apk', '') |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 289 | |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 290 | type_part = '' |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 291 | if args.print_types: |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 292 | type_part = e.get_type() |
Henrique Nakashima | 5f306229 | 2021-03-25 21:55:45 | [diff] [blame] | 293 | elif args.print_build_config_paths: |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 294 | type_part = e.build_config_path |
Andrew Grieve | 7d34dfa | 2025-04-28 20:15:37 | [diff] [blame] | 295 | elif args.print_params_paths: |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 296 | type_part = e.params_path |
Peter Wen | 73d007e | 2022-12-05 17:54:59 | [diff] [blame] | 297 | elif args.query: |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 298 | type_part = _query_json(json_dict=e.build_config(), |
| 299 | query=args.query, |
| 300 | path=e.build_config_path) |
| 301 | if not type_part: |
Peter Wen | 73d007e | 2022-12-05 17:54:59 | [diff] [blame] | 302 | continue |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 303 | |
Andrew Grieve | 8def398 | 2025-06-09 15:47:13 | [diff] [blame] | 304 | if target_part and type_part: |
| 305 | print(f'{target_part}: {type_part}') |
| 306 | elif target_part or type_part: |
| 307 | print(target_part or type_part) |
Andrew Grieve | e95e8e28 | 2020-07-14 01:27:13 | [diff] [blame] | 308 | |
| 309 | |
| 310 | if __name__ == '__main__': |
| 311 | main() |