xref: /aosp_15_r20/external/angle/build/android/gyp/unused_resources.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1#!/usr/bin/env python3
2# encoding: utf-8
3# Copyright 2021 The Chromium Authors
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import argparse
8import os
9import pathlib
10import sys
11
12from util import build_utils
13from util import resource_utils
14import action_helpers  # build_utils adds //build to sys.path.
15
16
17def _FilterUnusedResources(r_text_in, r_text_out, unused_resources_config):
18  removed_resources = set()
19  with open(unused_resources_config, encoding='utf-8') as output_config:
20    for line in output_config:
21      # example line: attr/line_height#remove
22      resource = line.split('#')[0]
23      resource_type, resource_name = resource.split('/')
24      removed_resources.add((resource_type, resource_name))
25  kept_lines = []
26  with open(r_text_in, encoding='utf-8') as infile:
27    for line in infile:
28      # example line: int attr line_height 0x7f0014ee
29      resource_type, resource_name = line.split(' ')[1:3]
30      if (resource_type, resource_name) not in removed_resources:
31        kept_lines.append(line)
32
33  with open(r_text_out, 'w', encoding='utf-8') as out_file:
34    out_file.writelines(kept_lines)
35
36
37def _WritePaths(dest_path, lines):
38  pathlib.Path(dest_path).write_text('\n'.join(lines) + '\n')
39
40
41def main(args):
42  parser = argparse.ArgumentParser()
43
44  action_helpers.add_depfile_arg(parser)
45  parser.add_argument('--script',
46                      required=True,
47                      help='Path to the unused resources detector script.')
48  parser.add_argument(
49      '--dependencies-res-zips',
50      required=True,
51      action='append',
52      help='Resources zip archives to investigate for unused resources.')
53  parser.add_argument('--dexes',
54                      action='append',
55                      required=True,
56                      help='Path to dex file, or zip with dex files.')
57  parser.add_argument(
58      '--proguard-mapping',
59      help='Path to proguard mapping file for the optimized dex.')
60  parser.add_argument('--r-text-in', required=True, help='Path to input R.txt')
61  parser.add_argument(
62      '--r-text-out',
63      help='Path to output R.txt with unused resources removed.')
64  parser.add_argument('--android-manifests',
65                      action='append',
66                      required=True,
67                      help='Path to AndroidManifest')
68  parser.add_argument('--output-config',
69                      required=True,
70                      help='Path to output the aapt2 config to.')
71  args = build_utils.ExpandFileArgs(args)
72  options = parser.parse_args(args)
73  options.dependencies_res_zips = (action_helpers.parse_gn_list(
74      options.dependencies_res_zips))
75
76  # in case of no resources, short circuit early.
77  if not options.dependencies_res_zips:
78    build_utils.Touch(options.output_config)
79    return
80
81  with build_utils.TempDir() as temp_dir:
82    dep_subdirs = []
83    for dependency_res_zip in options.dependencies_res_zips:
84      dep_subdirs += resource_utils.ExtractDeps([dependency_res_zip], temp_dir)
85
86    # Use files for paths to avoid command line getting too long.
87    # https://crbug.com/362019371
88    manifests_file = os.path.join(temp_dir, 'manifests-inputs.txt')
89    resources_file = os.path.join(temp_dir, 'resources-inputs.txt')
90    dexes_file = os.path.join(temp_dir, 'dexes-inputs.txt')
91
92    _WritePaths(manifests_file, options.android_manifests)
93    _WritePaths(resources_file, dep_subdirs)
94    _WritePaths(dexes_file, options.dexes)
95
96    cmd = [
97        options.script,
98        '--rtxts',
99        options.r_text_in,
100        '--manifests',
101        manifests_file,
102        '--resourceDirs',
103        resources_file,
104        '--dexes',
105        dexes_file,
106        '--outputConfig',
107        options.output_config,
108    ]
109    if options.proguard_mapping:
110      cmd += [
111          '--mapping',
112          options.proguard_mapping,
113      ]
114    build_utils.CheckOutput(cmd)
115
116  if options.r_text_out:
117    _FilterUnusedResources(options.r_text_in, options.r_text_out,
118                           options.output_config)
119
120  if options.depfile:
121    depfile_deps = (options.dependencies_res_zips + options.android_manifests +
122                    options.dexes) + [options.r_text_in]
123    if options.proguard_mapping:
124      depfile_deps.append(options.proguard_mapping)
125    action_helpers.write_depfile(options.depfile, options.output_config,
126                                 depfile_deps)
127
128
129if __name__ == '__main__':
130  main(sys.argv[1:])
131