summaryrefslogtreecommitdiff
path: root/build/android/gyp/unused_resources.py
blob: 6e49560e019fed769691957a8ab6da69f6358ab9 (plain)
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
#!/usr/bin/env python3
# encoding: utf-8
# Copyright 2021 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 os
import sys

sys.path.insert(
    0, os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)))
from util import build_utils
from util import resource_utils


def _FilterUnusedResources(r_text_in, r_text_out, unused_resources_config):
  removed_resources = set()
  with open(unused_resources_config, encoding='utf-8') as output_config:
    for line in output_config:
      # example line: attr/line_height#remove
      resource = line.split('#')[0]
      resource_type, resource_name = resource.split('/')
      removed_resources.add((resource_type, resource_name))
  kept_lines = []
  with open(r_text_in, encoding='utf-8') as infile:
    for line in infile:
      # example line: int attr line_height 0x7f0014ee
      resource_type, resource_name = line.split(' ')[1:3]
      if (resource_type, resource_name) not in removed_resources:
        kept_lines.append(line)

  with open(r_text_out, 'w', encoding='utf-8') as out_file:
    out_file.writelines(kept_lines)


def main(args):
  parser = argparse.ArgumentParser()

  build_utils.AddDepfileOption(parser)
  parser.add_argument('--script',
                      required=True,
                      help='Path to the unused resources detector script.')
  parser.add_argument(
      '--dependencies-res-zips',
      required=True,
      action='append',
      help='Resources zip archives to investigate for unused resources.')
  parser.add_argument('--dexes',
                      action='append',
                      required=True,
                      help='Path to dex file, or zip with dex files.')
  parser.add_argument(
      '--proguard-mapping',
      help='Path to proguard mapping file for the optimized dex.')
  parser.add_argument('--r-text-in', required=True, help='Path to input R.txt')
  parser.add_argument(
      '--r-text-out',
      help='Path to output R.txt with unused resources removed.')
  parser.add_argument('--android-manifests',
                      action='append',
                      required=True,
                      help='Path to AndroidManifest')
  parser.add_argument('--output-config',
                      required=True,
                      help='Path to output the aapt2 config to.')
  args = build_utils.ExpandFileArgs(args)
  options = parser.parse_args(args)
  options.dependencies_res_zips = (build_utils.ParseGnList(
      options.dependencies_res_zips))

  # in case of no resources, short circuit early.
  if not options.dependencies_res_zips:
    build_utils.Touch(options.output_config)
    return

  with build_utils.TempDir() as temp_dir:
    dep_subdirs = []
    for dependency_res_zip in options.dependencies_res_zips:
      dep_subdirs += resource_utils.ExtractDeps([dependency_res_zip], temp_dir)

    cmd = [
        options.script,
        '--rtxts',
        options.r_text_in,
        '--manifests',
        ':'.join(options.android_manifests),
        '--resourceDirs',
        ':'.join(dep_subdirs),
        '--dexes',
        ':'.join(options.dexes),
        '--outputConfig',
        options.output_config,
    ]
    if options.proguard_mapping:
      cmd += [
          '--mapping',
          options.proguard_mapping,
      ]
    build_utils.CheckOutput(cmd)

  if options.r_text_out:
    _FilterUnusedResources(options.r_text_in, options.r_text_out,
                           options.output_config)

  if options.depfile:
    depfile_deps = (options.dependencies_res_zips + options.android_manifests +
                    options.dexes) + [options.r_text_in]
    if options.proguard_mapping:
      depfile_deps.append(options.proguard_mapping)
    build_utils.WriteDepfile(options.depfile, options.output_config,
                             depfile_deps)


if __name__ == '__main__':
  main(sys.argv[1:])