xref: /aosp_15_r20/external/cronet/build/android/gyp/prepare_resources.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6777b538SAndroid Build Coastguard Worker#
3*6777b538SAndroid Build Coastguard Worker# Copyright 2012 The Chromium Authors
4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file.
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker"""Process Android resource directories to generate .resources.zip and R.txt
8*6777b538SAndroid Build Coastguard Workerfiles."""
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Workerimport argparse
11*6777b538SAndroid Build Coastguard Workerimport os
12*6777b538SAndroid Build Coastguard Workerimport shutil
13*6777b538SAndroid Build Coastguard Workerimport sys
14*6777b538SAndroid Build Coastguard Workerimport zipfile
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Workerfrom util import build_utils
17*6777b538SAndroid Build Coastguard Workerfrom util import jar_info_utils
18*6777b538SAndroid Build Coastguard Workerfrom util import md5_check
19*6777b538SAndroid Build Coastguard Workerfrom util import resources_parser
20*6777b538SAndroid Build Coastguard Workerfrom util import resource_utils
21*6777b538SAndroid Build Coastguard Workerimport action_helpers  # build_utils adds //build to sys.path.
22*6777b538SAndroid Build Coastguard Workerimport zip_helpers
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Workerdef _ParseArgs(args):
26*6777b538SAndroid Build Coastguard Worker  """Parses command line options.
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker  Returns:
29*6777b538SAndroid Build Coastguard Worker    An options object as from argparse.ArgumentParser.parse_args()
30*6777b538SAndroid Build Coastguard Worker  """
31*6777b538SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(description=__doc__)
32*6777b538SAndroid Build Coastguard Worker  action_helpers.add_depfile_arg(parser)
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--res-sources-path',
35*6777b538SAndroid Build Coastguard Worker                      required=True,
36*6777b538SAndroid Build Coastguard Worker                      help='Path to a list of input resources for this target.')
37*6777b538SAndroid Build Coastguard Worker
38*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
39*6777b538SAndroid Build Coastguard Worker      '--r-text-in',
40*6777b538SAndroid Build Coastguard Worker      help='Path to pre-existing R.txt. Its resource IDs override those found '
41*6777b538SAndroid Build Coastguard Worker      'in the generated R.txt when generating R.java.')
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
44*6777b538SAndroid Build Coastguard Worker      '--allow-missing-resources',
45*6777b538SAndroid Build Coastguard Worker      action='store_true',
46*6777b538SAndroid Build Coastguard Worker      help='Do not fail if some resources exist in the res/ dir but are not '
47*6777b538SAndroid Build Coastguard Worker      'listed in the sources.')
48*6777b538SAndroid Build Coastguard Worker
49*6777b538SAndroid Build Coastguard Worker  parser.add_argument(
50*6777b538SAndroid Build Coastguard Worker      '--resource-zip-out',
51*6777b538SAndroid Build Coastguard Worker      help='Path to a zip archive containing all resources from '
52*6777b538SAndroid Build Coastguard Worker      '--resource-dirs, merged into a single directory tree.')
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--r-text-out',
55*6777b538SAndroid Build Coastguard Worker                      help='Path to store the generated R.txt file.')
56*6777b538SAndroid Build Coastguard Worker
57*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--strip-drawables',
58*6777b538SAndroid Build Coastguard Worker                      action="store_true",
59*6777b538SAndroid Build Coastguard Worker                      help='Remove drawables from the resources.')
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard Worker  options = parser.parse_args(args)
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker  with open(options.res_sources_path) as f:
64*6777b538SAndroid Build Coastguard Worker    options.sources = f.read().splitlines()
65*6777b538SAndroid Build Coastguard Worker  options.resource_dirs = resource_utils.DeduceResourceDirsFromFileList(
66*6777b538SAndroid Build Coastguard Worker      options.sources)
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker  return options
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Workerdef _CheckAllFilesListed(resource_files, resource_dirs):
72*6777b538SAndroid Build Coastguard Worker  resource_files = set(resource_files)
73*6777b538SAndroid Build Coastguard Worker  missing_files = []
74*6777b538SAndroid Build Coastguard Worker  for path, _ in resource_utils.IterResourceFilesInDirectories(resource_dirs):
75*6777b538SAndroid Build Coastguard Worker    if path not in resource_files:
76*6777b538SAndroid Build Coastguard Worker      missing_files.append(path)
77*6777b538SAndroid Build Coastguard Worker
78*6777b538SAndroid Build Coastguard Worker  if missing_files:
79*6777b538SAndroid Build Coastguard Worker    sys.stderr.write('Error: Found files not listed in the sources list of '
80*6777b538SAndroid Build Coastguard Worker                     'the BUILD.gn target:\n')
81*6777b538SAndroid Build Coastguard Worker    for path in missing_files:
82*6777b538SAndroid Build Coastguard Worker      sys.stderr.write('{}\n'.format(path))
83*6777b538SAndroid Build Coastguard Worker    sys.exit(1)
84*6777b538SAndroid Build Coastguard Worker
85*6777b538SAndroid Build Coastguard Worker
86*6777b538SAndroid Build Coastguard Workerdef _ZipResources(resource_dirs, zip_path, ignore_pattern):
87*6777b538SAndroid Build Coastguard Worker  # ignore_pattern is a string of ':' delimited list of globs used to ignore
88*6777b538SAndroid Build Coastguard Worker  # files that should not be part of the final resource zip.
89*6777b538SAndroid Build Coastguard Worker  files_to_zip = []
90*6777b538SAndroid Build Coastguard Worker  path_info = resource_utils.ResourceInfoFile()
91*6777b538SAndroid Build Coastguard Worker  for index, resource_dir in enumerate(resource_dirs):
92*6777b538SAndroid Build Coastguard Worker    attributed_aar = None
93*6777b538SAndroid Build Coastguard Worker    if not resource_dir.startswith('..'):
94*6777b538SAndroid Build Coastguard Worker      aar_source_info_path = os.path.join(
95*6777b538SAndroid Build Coastguard Worker          os.path.dirname(resource_dir), 'source.info')
96*6777b538SAndroid Build Coastguard Worker      if os.path.exists(aar_source_info_path):
97*6777b538SAndroid Build Coastguard Worker        attributed_aar = jar_info_utils.ReadAarSourceInfo(aar_source_info_path)
98*6777b538SAndroid Build Coastguard Worker
99*6777b538SAndroid Build Coastguard Worker    for path, archive_path in resource_utils.IterResourceFilesInDirectories(
100*6777b538SAndroid Build Coastguard Worker        [resource_dir], ignore_pattern):
101*6777b538SAndroid Build Coastguard Worker      attributed_path = path
102*6777b538SAndroid Build Coastguard Worker      if attributed_aar:
103*6777b538SAndroid Build Coastguard Worker        attributed_path = os.path.join(attributed_aar, 'res',
104*6777b538SAndroid Build Coastguard Worker                                       path[len(resource_dir) + 1:])
105*6777b538SAndroid Build Coastguard Worker      # Use the non-prefixed archive_path in the .info file.
106*6777b538SAndroid Build Coastguard Worker      path_info.AddMapping(archive_path, attributed_path)
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker      resource_dir_name = os.path.basename(resource_dir)
109*6777b538SAndroid Build Coastguard Worker      archive_path = '{}_{}/{}'.format(index, resource_dir_name, archive_path)
110*6777b538SAndroid Build Coastguard Worker      files_to_zip.append((archive_path, path))
111*6777b538SAndroid Build Coastguard Worker
112*6777b538SAndroid Build Coastguard Worker  path_info.Write(zip_path + '.info')
113*6777b538SAndroid Build Coastguard Worker
114*6777b538SAndroid Build Coastguard Worker  with zipfile.ZipFile(zip_path, 'w') as z:
115*6777b538SAndroid Build Coastguard Worker    # This magic comment signals to resource_utils.ExtractDeps that this zip is
116*6777b538SAndroid Build Coastguard Worker    # not just the contents of a single res dir, without the encapsulating res/
117*6777b538SAndroid Build Coastguard Worker    # (like the outputs of android_generated_resources targets), but instead has
118*6777b538SAndroid Build Coastguard Worker    # the contents of possibly multiple res/ dirs each within an encapsulating
119*6777b538SAndroid Build Coastguard Worker    # directory within the zip.
120*6777b538SAndroid Build Coastguard Worker    z.comment = resource_utils.MULTIPLE_RES_MAGIC_STRING
121*6777b538SAndroid Build Coastguard Worker    zip_helpers.add_files_to_zip(files_to_zip, z)
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker
124*6777b538SAndroid Build Coastguard Workerdef _GenerateRTxt(options, r_txt_path):
125*6777b538SAndroid Build Coastguard Worker  """Generate R.txt file.
126*6777b538SAndroid Build Coastguard Worker
127*6777b538SAndroid Build Coastguard Worker  Args:
128*6777b538SAndroid Build Coastguard Worker    options: The command-line options tuple.
129*6777b538SAndroid Build Coastguard Worker    r_txt_path: Locates where the R.txt file goes.
130*6777b538SAndroid Build Coastguard Worker  """
131*6777b538SAndroid Build Coastguard Worker  ignore_pattern = resource_utils.AAPT_IGNORE_PATTERN
132*6777b538SAndroid Build Coastguard Worker  if options.strip_drawables:
133*6777b538SAndroid Build Coastguard Worker    ignore_pattern += ':*drawable*'
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker  resources_parser.RTxtGenerator(options.resource_dirs,
136*6777b538SAndroid Build Coastguard Worker                                 ignore_pattern).WriteRTxtFile(r_txt_path)
137*6777b538SAndroid Build Coastguard Worker
138*6777b538SAndroid Build Coastguard Worker
139*6777b538SAndroid Build Coastguard Workerdef _OnStaleMd5(options):
140*6777b538SAndroid Build Coastguard Worker  with resource_utils.BuildContext() as build:
141*6777b538SAndroid Build Coastguard Worker    if options.sources and not options.allow_missing_resources:
142*6777b538SAndroid Build Coastguard Worker      _CheckAllFilesListed(options.sources, options.resource_dirs)
143*6777b538SAndroid Build Coastguard Worker    if options.r_text_in:
144*6777b538SAndroid Build Coastguard Worker      r_txt_path = options.r_text_in
145*6777b538SAndroid Build Coastguard Worker    else:
146*6777b538SAndroid Build Coastguard Worker      _GenerateRTxt(options, build.r_txt_path)
147*6777b538SAndroid Build Coastguard Worker      r_txt_path = build.r_txt_path
148*6777b538SAndroid Build Coastguard Worker
149*6777b538SAndroid Build Coastguard Worker    if options.r_text_out:
150*6777b538SAndroid Build Coastguard Worker      shutil.copyfile(r_txt_path, options.r_text_out)
151*6777b538SAndroid Build Coastguard Worker
152*6777b538SAndroid Build Coastguard Worker    if options.resource_zip_out:
153*6777b538SAndroid Build Coastguard Worker      ignore_pattern = resource_utils.AAPT_IGNORE_PATTERN
154*6777b538SAndroid Build Coastguard Worker      if options.strip_drawables:
155*6777b538SAndroid Build Coastguard Worker        ignore_pattern += ':*drawable*'
156*6777b538SAndroid Build Coastguard Worker      _ZipResources(options.resource_dirs, options.resource_zip_out,
157*6777b538SAndroid Build Coastguard Worker                    ignore_pattern)
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker
160*6777b538SAndroid Build Coastguard Workerdef main(args):
161*6777b538SAndroid Build Coastguard Worker  args = build_utils.ExpandFileArgs(args)
162*6777b538SAndroid Build Coastguard Worker  options = _ParseArgs(args)
163*6777b538SAndroid Build Coastguard Worker
164*6777b538SAndroid Build Coastguard Worker  # Order of these must match order specified in GN so that the correct one
165*6777b538SAndroid Build Coastguard Worker  # appears first in the depfile.
166*6777b538SAndroid Build Coastguard Worker  output_paths = [
167*6777b538SAndroid Build Coastguard Worker      options.resource_zip_out,
168*6777b538SAndroid Build Coastguard Worker      options.resource_zip_out + '.info',
169*6777b538SAndroid Build Coastguard Worker      options.r_text_out,
170*6777b538SAndroid Build Coastguard Worker  ]
171*6777b538SAndroid Build Coastguard Worker
172*6777b538SAndroid Build Coastguard Worker  input_paths = [options.res_sources_path]
173*6777b538SAndroid Build Coastguard Worker  if options.r_text_in:
174*6777b538SAndroid Build Coastguard Worker    input_paths += [options.r_text_in]
175*6777b538SAndroid Build Coastguard Worker
176*6777b538SAndroid Build Coastguard Worker  # Resource files aren't explicitly listed in GN. Listing them in the depfile
177*6777b538SAndroid Build Coastguard Worker  # ensures the target will be marked stale when resource files are removed.
178*6777b538SAndroid Build Coastguard Worker  depfile_deps = []
179*6777b538SAndroid Build Coastguard Worker  resource_names = []
180*6777b538SAndroid Build Coastguard Worker  for resource_dir in options.resource_dirs:
181*6777b538SAndroid Build Coastguard Worker    for resource_file in build_utils.FindInDirectory(resource_dir, '*'):
182*6777b538SAndroid Build Coastguard Worker      # Don't list the empty .keep file in depfile. Since it doesn't end up
183*6777b538SAndroid Build Coastguard Worker      # included in the .zip, it can lead to -w 'dupbuild=err' ninja errors
184*6777b538SAndroid Build Coastguard Worker      # if ever moved.
185*6777b538SAndroid Build Coastguard Worker      if not resource_file.endswith(os.path.join('empty', '.keep')):
186*6777b538SAndroid Build Coastguard Worker        input_paths.append(resource_file)
187*6777b538SAndroid Build Coastguard Worker        depfile_deps.append(resource_file)
188*6777b538SAndroid Build Coastguard Worker      resource_names.append(os.path.relpath(resource_file, resource_dir))
189*6777b538SAndroid Build Coastguard Worker
190*6777b538SAndroid Build Coastguard Worker  # Resource filenames matter to the output, so add them to strings as well.
191*6777b538SAndroid Build Coastguard Worker  # This matters if a file is renamed but not changed (http://crbug.com/597126).
192*6777b538SAndroid Build Coastguard Worker  input_strings = sorted(resource_names) + [
193*6777b538SAndroid Build Coastguard Worker      options.strip_drawables,
194*6777b538SAndroid Build Coastguard Worker  ]
195*6777b538SAndroid Build Coastguard Worker
196*6777b538SAndroid Build Coastguard Worker  # Since android_resources targets like *__all_dfm_resources depend on java
197*6777b538SAndroid Build Coastguard Worker  # targets that they do not need (in reality it only needs the transitive
198*6777b538SAndroid Build Coastguard Worker  # resource targets that those java targets depend on), md5_check is used to
199*6777b538SAndroid Build Coastguard Worker  # prevent outputs from being re-written when real inputs have not changed.
200*6777b538SAndroid Build Coastguard Worker  md5_check.CallAndWriteDepfileIfStale(lambda: _OnStaleMd5(options),
201*6777b538SAndroid Build Coastguard Worker                                       options,
202*6777b538SAndroid Build Coastguard Worker                                       input_paths=input_paths,
203*6777b538SAndroid Build Coastguard Worker                                       input_strings=input_strings,
204*6777b538SAndroid Build Coastguard Worker                                       output_paths=output_paths,
205*6777b538SAndroid Build Coastguard Worker                                       depfile_deps=depfile_deps)
206*6777b538SAndroid Build Coastguard Worker
207*6777b538SAndroid Build Coastguard Worker
208*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__':
209*6777b538SAndroid Build Coastguard Worker  main(sys.argv[1:])
210