132 lines
4.4 KiB
Python
Executable file
132 lines
4.4 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
#
|
|
# Copyright 2018 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.
|
|
|
|
import argparse
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import zipfile
|
|
|
|
from util import build_utils
|
|
|
|
|
|
def _ParseOptions(args):
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--depfile', help='Path to the depfile to write to.')
|
|
parser.add_argument('--stamp', help='Path to stamp to mark when finished.')
|
|
parser.add_argument('--r8-path', help='Path to the r8.jar to use.')
|
|
parser.add_argument(
|
|
'--input-dex-zip', help='Path to dex files in zip being split.')
|
|
parser.add_argument(
|
|
'--proguard-mapping-file', help='Path to proguard mapping file.')
|
|
parser.add_argument(
|
|
'--feature-name',
|
|
action='append',
|
|
dest='feature_names',
|
|
help='The name of the feature module.')
|
|
parser.add_argument(
|
|
'--feature-jars',
|
|
action='append',
|
|
help='GN list of path to jars which compirse the corresponding feature.')
|
|
parser.add_argument(
|
|
'--dex-dest',
|
|
action='append',
|
|
dest='dex_dests',
|
|
help='Destination for dex file of the corresponding feature.')
|
|
options = parser.parse_args(args)
|
|
|
|
assert len(options.feature_names) == len(options.feature_jars) and len(
|
|
options.feature_names) == len(options.dex_dests)
|
|
options.features = {}
|
|
for i, name in enumerate(options.feature_names):
|
|
options.features[name] = build_utils.ParseGnList(options.feature_jars[i])
|
|
|
|
return options
|
|
|
|
|
|
def _RunDexsplitter(options, output_dir):
|
|
cmd = build_utils.JavaCmd() + [
|
|
'-cp',
|
|
options.r8_path,
|
|
'com.android.tools.r8.dexsplitter.DexSplitter',
|
|
'--output',
|
|
output_dir,
|
|
'--proguard-map',
|
|
options.proguard_mapping_file,
|
|
]
|
|
|
|
for base_jar in options.features['base']:
|
|
cmd += ['--base-jar', base_jar]
|
|
|
|
base_jars_lookup = set(options.features['base'])
|
|
for feature in options.features:
|
|
if feature == 'base':
|
|
continue
|
|
for feature_jar in options.features[feature]:
|
|
if feature_jar not in base_jars_lookup:
|
|
cmd += ['--feature-jar', feature_jar + ':' + feature]
|
|
|
|
with build_utils.TempDir() as temp_dir:
|
|
unzipped_files = build_utils.ExtractAll(options.input_dex_zip, temp_dir)
|
|
for file_name in unzipped_files:
|
|
cmd += ['--input', file_name]
|
|
build_utils.CheckOutput(cmd)
|
|
|
|
|
|
def main(args):
|
|
args = build_utils.ExpandFileArgs(args)
|
|
options = _ParseOptions(args)
|
|
|
|
input_paths = [options.input_dex_zip]
|
|
for feature_jars in options.features.values():
|
|
for feature_jar in feature_jars:
|
|
input_paths.append(feature_jar)
|
|
|
|
with build_utils.TempDir() as dexsplitter_output_dir:
|
|
curr_location_to_dest = []
|
|
if len(options.features) == 1:
|
|
# Don't run dexsplitter since it needs at least 1 feature module.
|
|
curr_location_to_dest.append((options.input_dex_zip,
|
|
options.dex_dests[0]))
|
|
else:
|
|
_RunDexsplitter(options, dexsplitter_output_dir)
|
|
|
|
for i, dest in enumerate(options.dex_dests):
|
|
module_dex_file = os.path.join(dexsplitter_output_dir,
|
|
options.feature_names[i], 'classes.dex')
|
|
if os.path.exists(module_dex_file):
|
|
curr_location_to_dest.append((module_dex_file, dest))
|
|
else:
|
|
module_dex_file += '.jar'
|
|
assert os.path.exists(
|
|
module_dex_file), 'Dexsplitter tool output not found.'
|
|
curr_location_to_dest.append((module_dex_file + '.jar', dest))
|
|
|
|
for curr_location, dest in curr_location_to_dest:
|
|
with build_utils.AtomicOutput(dest) as f:
|
|
if curr_location.endswith('.jar'):
|
|
if dest.endswith('.jar'):
|
|
shutil.copy(curr_location, f.name)
|
|
else:
|
|
with zipfile.ZipFile(curr_location, 'r') as z:
|
|
namelist = z.namelist()
|
|
assert len(namelist) == 1, (
|
|
'Unzipping to single dex file, but not single dex file in ' +
|
|
options.input_dex_zip)
|
|
z.extract(namelist[0], f.name)
|
|
else:
|
|
if dest.endswith('.jar'):
|
|
build_utils.ZipDir(
|
|
f.name, os.path.abspath(os.path.join(curr_location, os.pardir)))
|
|
else:
|
|
shutil.move(curr_location, f.name)
|
|
|
|
build_utils.Touch(options.stamp)
|
|
build_utils.WriteDepfile(options.depfile, options.stamp, inputs=input_paths)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(sys.argv[1:]))
|