1#!/usr/bin/env python 2 3# Copyright 2017 The Chromium Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Merges dependency Android manifests into a root manifest.""" 8 9import argparse 10import contextlib 11import os 12import sys 13import tempfile 14import xml.etree.ElementTree as ElementTree 15 16from util import build_utils 17from util import manifest_utils 18 19_MANIFEST_MERGER_MAIN_CLASS = 'com.android.manifmerger.Merger' 20_MANIFEST_MERGER_JARS = [ 21 os.path.join('build-system', 'manifest-merger.jar'), 22 os.path.join('common', 'common.jar'), 23 os.path.join('sdk-common', 'sdk-common.jar'), 24 os.path.join('sdklib', 'sdklib.jar'), 25 os.path.join('external', 'com', 'google', 'guava', 'guava', '27.1-jre', 26 'guava-27.1-jre.jar'), 27 os.path.join('external', 'kotlin-plugin-ij', 'Kotlin', 'kotlinc', 'lib', 28 'kotlin-stdlib.jar'), 29 os.path.join('external', 'com', 'google', 'code', 'gson', 'gson', '2.8.5', 30 'gson-2.8.5.jar'), 31] 32 33 34@contextlib.contextmanager 35def _ProcessManifest(manifest_path, min_sdk_version, target_sdk_version, 36 max_sdk_version, manifest_package): 37 """Patches an Android manifest's package and performs assertions to ensure 38 correctness for the manifest. 39 """ 40 doc, manifest, _ = manifest_utils.ParseManifest(manifest_path) 41 manifest_utils.AssertUsesSdk(manifest, min_sdk_version, target_sdk_version, 42 max_sdk_version) 43 assert manifest_utils.GetPackage(manifest) or manifest_package, \ 44 'Must set manifest package in GN or in AndroidManifest.xml' 45 manifest_utils.AssertPackage(manifest, manifest_package) 46 if manifest_package: 47 manifest.set('package', manifest_package) 48 tmp_prefix = os.path.basename(manifest_path) 49 with tempfile.NamedTemporaryFile(prefix=tmp_prefix) as patched_manifest: 50 manifest_utils.SaveManifest(doc, patched_manifest.name) 51 yield patched_manifest.name, manifest_utils.GetPackage(manifest) 52 53 54def _BuildManifestMergerClasspath(android_sdk_cmdline_tools): 55 return ':'.join([ 56 os.path.join(android_sdk_cmdline_tools, 'lib', jar) 57 for jar in _MANIFEST_MERGER_JARS 58 ]) 59 60 61def main(argv): 62 argv = build_utils.ExpandFileArgs(argv) 63 parser = argparse.ArgumentParser(description=__doc__) 64 build_utils.AddDepfileOption(parser) 65 parser.add_argument( 66 '--android-sdk-cmdline-tools', 67 help='Path to SDK\'s cmdline-tools folder.', 68 required=True) 69 parser.add_argument('--root-manifest', 70 help='Root manifest which to merge into', 71 required=True) 72 parser.add_argument('--output', help='Output manifest path', required=True) 73 parser.add_argument('--extras', 74 help='GN list of additional manifest to merge') 75 parser.add_argument( 76 '--min-sdk-version', 77 required=True, 78 help='android:minSdkVersion for merging.') 79 parser.add_argument( 80 '--target-sdk-version', 81 required=True, 82 help='android:targetSdkVersion for merging.') 83 parser.add_argument( 84 '--max-sdk-version', help='android:maxSdkVersion for merging.') 85 parser.add_argument( 86 '--manifest-package', 87 help='Package name of the merged AndroidManifest.xml.') 88 args = parser.parse_args(argv) 89 90 classpath = _BuildManifestMergerClasspath(args.android_sdk_cmdline_tools) 91 92 with build_utils.AtomicOutput(args.output) as output: 93 cmd = [ 94 build_utils.JAVA_PATH, 95 '-cp', 96 classpath, 97 _MANIFEST_MERGER_MAIN_CLASS, 98 '--out', 99 output.name, 100 '--property', 101 'MIN_SDK_VERSION=' + args.min_sdk_version, 102 '--property', 103 'TARGET_SDK_VERSION=' + args.target_sdk_version, 104 ] 105 106 if args.max_sdk_version: 107 cmd += [ 108 '--property', 109 'MAX_SDK_VERSION=' + args.max_sdk_version, 110 ] 111 112 extras = build_utils.ParseGnList(args.extras) 113 if extras: 114 cmd += ['--libs', ':'.join(extras)] 115 116 with _ProcessManifest(args.root_manifest, args.min_sdk_version, 117 args.target_sdk_version, args.max_sdk_version, 118 args.manifest_package) as tup: 119 root_manifest, package = tup 120 cmd += [ 121 '--main', 122 root_manifest, 123 '--property', 124 'PACKAGE=' + package, 125 ] 126 build_utils.CheckOutput(cmd, 127 # https://issuetracker.google.com/issues/63514300: 128 # The merger doesn't set a nonzero exit code for failures. 129 fail_func=lambda returncode, stderr: returncode != 0 or 130 build_utils.IsTimeStale(output.name, [root_manifest] + extras)) 131 132 # Check for correct output. 133 _, manifest, _ = manifest_utils.ParseManifest(output.name) 134 manifest_utils.AssertUsesSdk(manifest, args.min_sdk_version, 135 args.target_sdk_version) 136 manifest_utils.AssertPackage(manifest, package) 137 138 if args.depfile: 139 inputs = extras + classpath.split(':') 140 build_utils.WriteDepfile(args.depfile, args.output, inputs=inputs, 141 add_pydeps=False) 142 143 144if __name__ == '__main__': 145 main(sys.argv[1:]) 146