#!/usr/bin/env python3 # # Copyright 2017 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Creates an Android .aar file.""" import argparse import os import posixpath import shutil import sys import tempfile import zipfile import filter_zip from util import build_utils _ANDROID_BUILD_DIR = os.path.dirname(os.path.dirname(__file__)) def _MergeRTxt(r_paths, include_globs): """Merging the given R.txt files and returns them as a string.""" all_lines = set() for r_path in r_paths: if include_globs and not build_utils.MatchesGlob(r_path, include_globs): continue with open(r_path) as f: all_lines.update(f.readlines()) return ''.join(sorted(all_lines)) def _MergeProguardConfigs(proguard_configs): """Merging the given proguard config files and returns them as a string.""" ret = [] for config in proguard_configs: ret.append('# FROM: {}'.format(config)) with open(config) as f: ret.append(f.read()) return '\n'.join(ret) def _AddResources(aar_zip, resource_zips, include_globs): """Adds all resource zips to the given aar_zip. Ensures all res/values/* files have unique names by prefixing them. """ for i, path in enumerate(resource_zips): if include_globs and not build_utils.MatchesGlob(path, include_globs): continue with zipfile.ZipFile(path) as res_zip: for info in res_zip.infolist(): data = res_zip.read(info) dirname, basename = posixpath.split(info.filename) if 'values' in dirname: root, ext = os.path.splitext(basename) basename = '{}_{}{}'.format(root, i, ext) info.filename = posixpath.join(dirname, basename) info.filename = posixpath.join('res', info.filename) aar_zip.writestr(info, data) def main(args): args = build_utils.ExpandFileArgs(args) parser = argparse.ArgumentParser() build_utils.AddDepfileOption(parser) parser.add_argument('--output', required=True, help='Path to output aar.') parser.add_argument('--jars', required=True, help='GN list of jar inputs.') parser.add_argument('--dependencies-res-zips', required=True, help='GN list of resource zips') parser.add_argument('--r-text-files', required=True, help='GN list of R.txt files to merge') parser.add_argument('--proguard-configs', required=True, help='GN list of ProGuard flag files to merge.') parser.add_argument( '--android-manifest', help='Path to AndroidManifest.xml to include.', default=os.path.join(_ANDROID_BUILD_DIR, 'AndroidManifest.xml')) parser.add_argument('--native-libraries', default='', help='GN list of native libraries. If non-empty then ' 'ABI must be specified.') parser.add_argument('--abi', help='ABI (e.g. armeabi-v7a) for native libraries.') parser.add_argument( '--jar-excluded-globs', help='GN-list of globs for paths to exclude in jar.') parser.add_argument( '--jar-included-globs', help='GN-list of globs for paths to include in jar.') parser.add_argument( '--resource-included-globs', help='GN-list of globs for paths to include in R.txt and resources zips.') options = parser.parse_args(args) if options.native_libraries and not options.abi: parser.error('You must provide --abi if you have native libs') options.jars = build_utils.ParseGnList(options.jars) options.dependencies_res_zips = build_utils.ParseGnList( options.dependencies_res_zips) options.r_text_files = build_utils.ParseGnList(options.r_text_files) options.proguard_configs = build_utils.ParseGnList(options.proguard_configs) options.native_libraries = build_utils.ParseGnList(options.native_libraries) options.jar_excluded_globs = build_utils.ParseGnList( options.jar_excluded_globs) options.jar_included_globs = build_utils.ParseGnList( options.jar_included_globs) options.resource_included_globs = build_utils.ParseGnList( options.resource_included_globs) with tempfile.NamedTemporaryFile(delete=False) as staging_file: try: with zipfile.ZipFile(staging_file.name, 'w') as z: build_utils.AddToZipHermetic( z, 'AndroidManifest.xml', src_path=options.android_manifest) path_transform = filter_zip.CreatePathTransform( options.jar_excluded_globs, options.jar_included_globs) with tempfile.NamedTemporaryFile() as jar_file: build_utils.MergeZips( jar_file.name, options.jars, path_transform=path_transform) build_utils.AddToZipHermetic(z, 'classes.jar', src_path=jar_file.name) build_utils.AddToZipHermetic( z, 'R.txt', data=_MergeRTxt(options.r_text_files, options.resource_included_globs)) build_utils.AddToZipHermetic(z, 'public.txt', data='') if options.proguard_configs: build_utils.AddToZipHermetic( z, 'proguard.txt', data=_MergeProguardConfigs(options.proguard_configs)) _AddResources(z, options.dependencies_res_zips, options.resource_included_globs) for native_library in options.native_libraries: libname = os.path.basename(native_library) build_utils.AddToZipHermetic( z, os.path.join('jni', options.abi, libname), src_path=native_library) except: os.unlink(staging_file.name) raise shutil.move(staging_file.name, options.output) if options.depfile: all_inputs = (options.jars + options.dependencies_res_zips + options.r_text_files + options.proguard_configs) build_utils.WriteDepfile(options.depfile, options.output, all_inputs) if __name__ == '__main__': main(sys.argv[1:])