blob: 61840bf6a1ae2d9ff6126daf19d28592671d5872 [file] [log] [blame]
#!/usr/bin/env python
# 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.
"""Merges dependency Android manifests into a root manifest."""
import argparse
import contextlib
import os
import sys
import tempfile
import xml.etree.ElementTree as ElementTree
from util import build_utils
from util import manifest_utils
# Tools library directory - relative to Android SDK root
_SDK_TOOLS_LIB_DIR = os.path.join('tools', 'lib')
_MANIFEST_MERGER_MAIN_CLASS = 'com.android.manifmerger.Merger'
_MANIFEST_MERGER_JARS = [
'common{suffix}.jar',
'manifest-merger{suffix}.jar',
'sdk-common{suffix}.jar',
'sdklib{suffix}.jar',
]
@contextlib.contextmanager
def _ProcessManifest(manifest_path, min_sdk_version, target_sdk_version,
max_sdk_version, manifest_package):
"""Patches an Android manifest to always include the 'tools' namespace
declaration, as it is not propagated by the manifest merger from the SDK.
See https://issuetracker.google.com/issues/63411481
"""
doc, manifest, _ = manifest_utils.ParseManifest(manifest_path)
manifest_utils.AssertUsesSdk(manifest, min_sdk_version, target_sdk_version,
max_sdk_version)
assert manifest_utils.GetPackage(manifest) or manifest_package, \
'Must set manifest package in GN or in AndroidManifest.xml'
manifest_utils.AssertPackage(manifest, manifest_package)
if manifest_package:
manifest.set('package', manifest_package)
tmp_prefix = os.path.basename(manifest_path)
with tempfile.NamedTemporaryFile(prefix=tmp_prefix) as patched_manifest:
manifest_utils.SaveManifest(doc, patched_manifest.name)
yield patched_manifest.name, manifest_utils.GetPackage(manifest)
def _BuildManifestMergerClasspath(build_vars):
return ':'.join([
os.path.join(
build_vars['android_sdk_root'], _SDK_TOOLS_LIB_DIR,
jar.format(suffix=build_vars['android_sdk_tools_version_suffix']))
for jar in _MANIFEST_MERGER_JARS
])
def main(argv):
argv = build_utils.ExpandFileArgs(argv)
parser = argparse.ArgumentParser(description=__doc__)
build_utils.AddDepfileOption(parser)
parser.add_argument('--build-vars',
help='Path to GN build vars file',
required=True)
parser.add_argument('--root-manifest',
help='Root manifest which to merge into',
required=True)
parser.add_argument('--output', help='Output manifest path', required=True)
parser.add_argument('--extras',
help='GN list of additional manifest to merge')
parser.add_argument(
'--min-sdk-version',
required=True,
help='android:minSdkVersion for merging.')
parser.add_argument(
'--target-sdk-version',
required=True,
help='android:targetSdkVersion for merging.')
parser.add_argument(
'--max-sdk-version', help='android:maxSdkVersion for merging.')
parser.add_argument(
'--manifest-package',
help='Package name of the merged AndroidManifest.xml.')
args = parser.parse_args(argv)
classpath = _BuildManifestMergerClasspath(
build_utils.ReadBuildVars(args.build_vars))
with build_utils.AtomicOutput(args.output) as output:
cmd = [
build_utils.JAVA_PATH,
'-cp',
classpath,
_MANIFEST_MERGER_MAIN_CLASS,
'--out',
output.name,
'--property',
'MIN_SDK_VERSION=' + args.min_sdk_version,
'--property',
'TARGET_SDK_VERSION=' + args.target_sdk_version,
]
if args.max_sdk_version:
cmd += [
'--property',
'MAX_SDK_VERSION=' + args.max_sdk_version,
]
extras = build_utils.ParseGnList(args.extras)
if extras:
cmd += ['--libs', ':'.join(extras)]
with _ProcessManifest(args.root_manifest, args.min_sdk_version,
args.target_sdk_version, args.max_sdk_version,
args.manifest_package) as tup:
root_manifest, package = tup
cmd += [
'--main',
root_manifest,
'--property',
'PACKAGE=' + package,
]
build_utils.CheckOutput(cmd,
# https://issuetracker.google.com/issues/63514300:
# The merger doesn't set a nonzero exit code for failures.
fail_func=lambda returncode, stderr: returncode != 0 or
build_utils.IsTimeStale(output.name, [root_manifest] + extras))
# Check for correct output.
_, manifest, _ = manifest_utils.ParseManifest(output.name)
manifest_utils.AssertUsesSdk(manifest, args.min_sdk_version,
args.target_sdk_version)
manifest_utils.AssertPackage(manifest, package)
if args.depfile:
inputs = extras + classpath.split(':')
build_utils.WriteDepfile(args.depfile, args.output, inputs=inputs,
add_pydeps=False)
if __name__ == '__main__':
main(sys.argv[1:])