• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright 2017 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
7"""Creates an Android .aar file."""
8
9import argparse
10import os
11import posixpath
12import shutil
13import sys
14import tempfile
15import zipfile
16
17import filter_zip
18from util import build_utils
19import action_helpers  # build_utils adds //build to sys.path.
20import zip_helpers
21
22
23_ANDROID_BUILD_DIR = os.path.dirname(os.path.dirname(__file__))
24
25
26def _MergeRTxt(r_paths, include_globs, exclude_globs):
27  """Merging the given R.txt files and returns them as a string."""
28  all_lines = set()
29  for r_path in r_paths:
30    if include_globs and not build_utils.MatchesGlob(r_path, include_globs) or \
31       exclude_globs and build_utils.MatchesGlob(r_path, exclude_globs):
32      continue
33    with open(r_path) as f:
34      all_lines.update(f.readlines())
35  return ''.join(sorted(all_lines))
36
37
38def _MergeProguardConfigs(proguard_configs):
39  """Merging the given proguard config files and returns them as a string."""
40  ret = []
41  for config in proguard_configs:
42    ret.append('# FROM: {}'.format(config))
43    with open(config) as f:
44      ret.append(f.read())
45  return '\n'.join(ret)
46
47
48def _AddResources(aar_zip, resource_zips, include_globs, exclude_globs):
49  """Adds all resource zips to the given aar_zip.
50
51  Ensures all res/values/* files have unique names by prefixing them.
52  """
53  for i, path in enumerate(resource_zips):
54    if include_globs and not build_utils.MatchesGlob(path, include_globs) or \
55       exclude_globs and build_utils.MatchesGlob(path, exclude_globs):
56      continue
57    with zipfile.ZipFile(path) as res_zip:
58      for info in res_zip.infolist():
59        data = res_zip.read(info)
60        dirname, basename = posixpath.split(info.filename)
61        if 'values' in dirname:
62          root, ext = os.path.splitext(basename)
63          basename = '{}_{}{}'.format(root, i, ext)
64          info.filename = posixpath.join(dirname, basename)
65        info.filename = posixpath.join('res', info.filename)
66        aar_zip.writestr(info, data)
67
68
69def main(args):
70  args = build_utils.ExpandFileArgs(args)
71  parser = argparse.ArgumentParser()
72  action_helpers.add_depfile_arg(parser)
73  parser.add_argument('--output', required=True, help='Path to output aar.')
74  parser.add_argument('--jars', required=True, help='GN list of jar inputs.')
75  parser.add_argument('--dependencies-res-zips', required=True,
76                      help='GN list of resource zips')
77  parser.add_argument('--r-text-files', required=True,
78                      help='GN list of R.txt files to merge')
79  parser.add_argument('--proguard-configs', required=True,
80                      help='GN list of ProGuard flag files to merge.')
81  parser.add_argument(
82      '--android-manifest',
83      help='Path to AndroidManifest.xml to include.',
84      default=os.path.join(_ANDROID_BUILD_DIR, 'AndroidManifest.xml'))
85  parser.add_argument('--native-libraries', default='',
86                      help='GN list of native libraries. If non-empty then '
87                      'ABI must be specified.')
88  parser.add_argument('--abi',
89                      help='ABI (e.g. armeabi-v7a) for native libraries.')
90  parser.add_argument(
91      '--jar-excluded-globs',
92      help='GN-list of globs for paths to exclude in jar.')
93  parser.add_argument(
94      '--jar-included-globs',
95      help='GN-list of globs for paths to include in jar.')
96  parser.add_argument(
97      '--resource-included-globs',
98      help='GN-list of globs for paths to include in R.txt and resources zips.')
99  parser.add_argument(
100      '--resource-excluded-globs',
101      help='GN-list of globs for paths to exclude in R.txt and resources zips.')
102
103  options = parser.parse_args(args)
104
105  if options.native_libraries and not options.abi:
106    parser.error('You must provide --abi if you have native libs')
107
108  options.jars = action_helpers.parse_gn_list(options.jars)
109  options.dependencies_res_zips = action_helpers.parse_gn_list(
110      options.dependencies_res_zips)
111  options.r_text_files = action_helpers.parse_gn_list(options.r_text_files)
112  options.proguard_configs = action_helpers.parse_gn_list(
113      options.proguard_configs)
114  options.native_libraries = action_helpers.parse_gn_list(
115      options.native_libraries)
116  options.jar_excluded_globs = action_helpers.parse_gn_list(
117      options.jar_excluded_globs)
118  options.jar_included_globs = action_helpers.parse_gn_list(
119      options.jar_included_globs)
120  options.resource_included_globs = action_helpers.parse_gn_list(
121      options.resource_included_globs)
122  options.resource_excluded_globs = action_helpers.parse_gn_list(
123      options.resource_excluded_globs)
124
125  with tempfile.NamedTemporaryFile(delete=False) as staging_file:
126    try:
127      with zipfile.ZipFile(staging_file.name, 'w') as z:
128        zip_helpers.add_to_zip_hermetic(z,
129                                        'AndroidManifest.xml',
130                                        src_path=options.android_manifest)
131
132        path_transform = filter_zip.CreatePathTransform(
133            options.jar_excluded_globs, options.jar_included_globs)
134        with tempfile.NamedTemporaryFile() as jar_file:
135          zip_helpers.merge_zips(jar_file.name,
136                                 options.jars,
137                                 path_transform=path_transform)
138          zip_helpers.add_to_zip_hermetic(z,
139                                          'classes.jar',
140                                          src_path=jar_file.name)
141        zip_helpers.add_to_zip_hermetic(z,
142                                        'R.txt',
143                                        data=_MergeRTxt(
144                                            options.r_text_files,
145                                            options.resource_included_globs,
146                                            options.resource_excluded_globs))
147        zip_helpers.add_to_zip_hermetic(z, 'public.txt', data='')
148
149        if options.proguard_configs:
150          zip_helpers.add_to_zip_hermetic(z,
151                                          'proguard.txt',
152                                          data=_MergeProguardConfigs(
153                                              options.proguard_configs))
154
155        _AddResources(z, options.dependencies_res_zips,
156                      options.resource_included_globs,
157                      options.resource_excluded_globs)
158
159        for native_library in options.native_libraries:
160          libname = os.path.basename(native_library)
161          zip_helpers.add_to_zip_hermetic(z,
162                                          os.path.join('jni', options.abi,
163                                                       libname),
164                                          src_path=native_library)
165    except:
166      os.unlink(staging_file.name)
167      raise
168    shutil.move(staging_file.name, options.output)
169
170  if options.depfile:
171    all_inputs = (options.jars + options.dependencies_res_zips +
172                  options.r_text_files + options.proguard_configs)
173    action_helpers.write_depfile(options.depfile, options.output, all_inputs)
174
175
176if __name__ == '__main__':
177  main(sys.argv[1:])
178