Index: build/android/gradle/generate_gradle.py |
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py |
index 3c08114cfe43ddddd14f35c4908cab32690f1953..268650061d8d78952d66670924c07554fe9d5d62 100755 |
--- a/build/android/gradle/generate_gradle.py |
+++ b/build/android/gradle/generate_gradle.py |
@@ -115,13 +115,15 @@ def _QueryForAllGnTargets(output_dir): |
class _ProjectEntry(object): |
- """Helper class for various path transformations.""" |
+ """Helper class for project entries.""" |
def __init__(self, gn_target): |
assert gn_target.startswith('//'), gn_target |
if ':' not in gn_target: |
gn_target = '%s:%s' % (gn_target, os.path.basename(gn_target)) |
self._gn_target = gn_target |
self._build_config = None |
+ self._java_files = None |
+ self.android_test_entry = None |
@classmethod |
def FromBuildConfigPath(cls, path): |
@@ -164,9 +166,91 @@ class _ProjectEntry(object): |
self._build_config = build_utils.ReadJson(_RebasePath(path)) |
return self._build_config |
+ def DepsInfo(self): |
+ return self.BuildConfig()['deps_info'] |
+ |
+ def Gradle(self): |
+ return self.BuildConfig()['gradle'] |
+ |
def GetType(self): |
"""Returns the target type from its .build_config.""" |
- return self.BuildConfig()['deps_info']['type'] |
+ return self.DepsInfo()['type'] |
+ |
+ def JavaFiles(self): |
+ if self._java_files is None: |
+ java_sources_file = self.Gradle().get('java_sources_file') |
+ java_files = [] |
+ if java_sources_file: |
+ java_sources_file = _RebasePath(java_sources_file) |
+ java_files = build_utils.ReadSourcesList(java_sources_file) |
+ self._java_files = java_files |
+ return self._java_files |
+ |
+ |
+class _ProjectContextGenerator(object): |
+ """Helper class to generate gradle build files""" |
+ def __init__(self, project_dir, use_gradle_process_resources): |
+ self.project_dir = project_dir |
+ self.use_gradle_process_resources = use_gradle_process_resources |
+ |
+ def _GenJniLibs(self, entry): |
+ native_section = entry.BuildConfig().get('native') |
+ if native_section: |
+ jni_libs = _CreateJniLibsDir( |
+ constants.GetOutDirectory(), self.EntryOutputDir(entry), |
+ native_section.get('libraries')) |
+ else: |
+ jni_libs = [] |
+ return jni_libs |
+ |
+ def _GenJavaDirs(self, entry): |
+ java_dirs = _CreateJavaSourceDir( |
+ constants.GetOutDirectory(), self.EntryOutputDir(entry), |
+ entry.JavaFiles()) |
+ if self.Srcjars(entry): |
+ java_dirs.append( |
+ os.path.join(self.EntryOutputDir(entry), _SRCJARS_SUBDIR)) |
+ return java_dirs |
+ |
+ def _Relativize(self, entry, paths): |
+ return _RebasePath(paths, self.EntryOutputDir(entry)) |
+ |
+ def EntryOutputDir(self, entry): |
+ return os.path.join(self.project_dir, entry.GradleSubdir()) |
+ |
+ def Srcjars(self, entry): |
+ srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', [])) |
+ if not self.use_gradle_process_resources: |
+ srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars']) |
+ return srcjars |
+ |
+ def GeneratedInputs(self, entry): |
+ generated_inputs = [] |
+ generated_inputs.extend(self.Srcjars(entry)) |
+ generated_inputs.extend( |
+ p for p in entry.JavaFiles() if not p.startswith('..')) |
+ generated_inputs.extend(entry.Gradle()['dependent_prebuilt_jars']) |
+ return generated_inputs |
+ |
+ def Generate(self, entry): |
+ variables = {} |
+ android_test_manifest = entry.Gradle().get( |
+ 'android_manifest', _DEFAULT_ANDROID_MANIFEST_PATH) |
+ variables['android_manifest'] = self._Relativize( |
+ entry, android_test_manifest) |
+ variables['java_dirs'] = self._Relativize(entry, self._GenJavaDirs(entry)) |
+ variables['jni_libs'] = self._Relativize(entry, self._GenJniLibs(entry)) |
+ deps = [_ProjectEntry.FromBuildConfigPath(p) |
+ for p in entry.Gradle()['dependent_android_projects']] |
+ variables['android_project_deps'] = [d.ProjectName() for d in deps] |
+ # TODO(agrieve): Add an option to use interface jars and see if that speeds |
+ # things up at all. |
+ variables['prebuilts'] = self._Relativize( |
+ entry, entry.Gradle()['dependent_prebuilt_jars']) |
+ deps = [_ProjectEntry.FromBuildConfigPath(p) |
+ for p in entry.Gradle()['dependent_java_projects']] |
+ variables['java_project_deps'] = [d.ProjectName() for d in deps] |
+ return variables |
def _ComputeJavaSourceDirs(java_files): |
@@ -278,12 +362,10 @@ def _GenerateLocalProperties(sdk_dir): |
'']) |
-def _GenerateGradleFile(build_config, build_vars, java_dirs, jni_libs, |
- relativize, use_gradle_process_resources, |
- jinja_processor): |
+def _GenerateGradleFile(entry, generator, build_vars, jinja_processor): |
"""Returns the data for a project's build.gradle.""" |
- deps_info = build_config['deps_info'] |
- gradle = build_config['gradle'] |
+ deps_info = entry.DepsInfo() |
+ gradle = entry.Gradle() |
variables = { |
'sourceSetName': 'main', |
@@ -294,8 +376,7 @@ def _GenerateGradleFile(build_config, build_vars, java_dirs, jni_libs, |
elif deps_info['type'] == 'java_library': |
if deps_info['is_prebuilt'] or deps_info['gradle_treat_as_prebuilt']: |
return None |
- |
- if deps_info['requires_android']: |
+ elif deps_info['requires_android']: |
target_type = 'android_library' |
else: |
target_type = 'java_library' |
@@ -312,25 +393,15 @@ def _GenerateGradleFile(build_config, build_vars, java_dirs, jni_libs, |
variables['target_name'] = os.path.splitext(deps_info['name'])[0] |
variables['template_type'] = target_type |
- variables['use_gradle_process_resources'] = use_gradle_process_resources |
+ variables['use_gradle_process_resources'] = ( |
+ generator.use_gradle_process_resources) |
variables['build_tools_version'] = ( |
build_vars['android_sdk_build_tools_version']) |
variables['compile_sdk_version'] = build_vars['android_sdk_version'] |
- android_manifest = gradle.get('android_manifest', |
- _DEFAULT_ANDROID_MANIFEST_PATH) |
- variables['android_manifest'] = relativize(android_manifest) |
- variables['java_dirs'] = relativize(java_dirs) |
- variables['jni_libs'] = relativize(jni_libs) |
- # TODO(agrieve): Add an option to use interface jars and see if that speeds |
- # things up at all. |
- variables['prebuilts'] = relativize(gradle['dependent_prebuilt_jars']) |
- deps = [_ProjectEntry.FromBuildConfigPath(p) |
- for p in gradle['dependent_android_projects']] |
- |
- variables['android_project_deps'] = [d.ProjectName() for d in deps] |
- deps = [_ProjectEntry.FromBuildConfigPath(p) |
- for p in gradle['dependent_java_projects']] |
- variables['java_project_deps'] = [d.ProjectName() for d in deps] |
+ variables['main'] = generator.Generate(entry) |
+ if entry.android_test_entry: |
+ variables['android_test'] = generator.Generate( |
+ entry.android_test_entry) |
return jinja_processor.Render( |
_TemplatePath(target_type.split('_')[0]), variables) |
@@ -380,16 +451,44 @@ def _FindAllProjectEntries(main_entries): |
if cur_entry in found: |
continue |
found.add(cur_entry) |
- build_config = cur_entry.BuildConfig() |
- sub_config_paths = build_config['deps_info']['deps_configs'] |
+ sub_config_paths = cur_entry.DepsInfo()['deps_configs'] |
to_scan.extend( |
_ProjectEntry.FromBuildConfigPath(p) for p in sub_config_paths) |
return list(found) |
+def _CombineTestEntries(entries): |
+ """Combines test apks into the androidTest source set of their target. |
+ |
+ - Speeds up android studio |
+ - Adds proper dependency between test and apk_under_test |
+ - Doesn't work for junit yet due to resulting circular dependencies |
+ - e.g. base_junit_tests > base_junit_test_support > base_java |
+ """ |
+ combined_entries = [] |
+ android_test_entries = {} |
+ for entry in entries: |
+ target_name = entry.GnTarget() |
+ if (target_name.endswith('_test_apk__apk') and |
+ 'apk_under_test' in entry.Gradle()): |
+ apk_name = entry.Gradle()['apk_under_test'] |
+ android_test_entries[apk_name] = entry |
+ else: |
+ combined_entries.append(entry) |
+ for entry in combined_entries: |
+ target_name = entry.DepsInfo()['name'] |
+ if target_name in android_test_entries: |
+ entry.android_test_entry = android_test_entries[target_name] |
+ del android_test_entries[target_name] |
+ # Add unmatched test entries as individual targets. |
+ combined_entries.extend(android_test_entries.values()) |
+ return combined_entries |
+ |
+ |
def main(): |
parser = argparse.ArgumentParser() |
parser.add_argument('--output-directory', |
+ default='out/Debug', |
help='Path to the root build directory.') |
parser.add_argument('-v', |
'--verbose', |
@@ -419,20 +518,21 @@ def main(): |
devil_chromium.Initialize(output_directory=output_dir) |
run_tests_helper.SetLogLevel(args.verbose_count) |
- gradle_output_dir = os.path.abspath( |
+ _gradle_output_dir = os.path.abspath( |
args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir)) |
- logging.warning('Creating project at: %s', gradle_output_dir) |
+ generator = _ProjectContextGenerator( |
+ _gradle_output_dir, args.use_gradle_process_resources) |
+ logging.warning('Creating project at: %s', generator.project_dir) |
if args.all: |
# Run GN gen if necessary (faster than running "gn gen" in the no-op case). |
- _RunNinja(output_dir, ['build.ninja']) |
+ _RunNinja(constants.GetOutDirectory(), ['build.ninja']) |
# Query ninja for all __build_config targets. |
targets = _QueryForAllGnTargets(output_dir) |
else: |
targets = args.targets or _DEFAULT_TARGETS |
- # TODO(agrieve): See if it makes sense to utilize Gradle's test constructs |
- # for our instrumentation tests. |
targets = [re.sub(r'_test_apk$', '_test_apk__apk', t) for t in targets] |
+ # TODO(wnwen): Utilize Gradle's test constructs for our junit tests? |
targets = [re.sub(r'_junit_tests$', '_junit_tests__java_binary', t) |
for t in targets] |
@@ -448,6 +548,8 @@ def main(): |
all_entries = _FindAllProjectEntries(main_entries) |
logging.info('Found %d dependent build_config targets.', len(all_entries)) |
+ entries = _CombineTestEntries(all_entries) |
+ logging.info('Creating %d projects for targets.', len(entries)) |
logging.warning('Writing .gradle files...') |
jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR) |
@@ -455,57 +557,29 @@ def main(): |
project_entries = [] |
srcjar_tuples = [] |
generated_inputs = [] |
- for entry in all_entries: |
+ for entry in entries: |
if entry.GetType() not in ('android_apk', 'java_library', 'java_binary'): |
continue |
- entry_output_dir = os.path.join(gradle_output_dir, entry.GradleSubdir()) |
- relativize = lambda x, d=entry_output_dir: _RebasePath(x, d) |
- build_config = entry.BuildConfig() |
- |
- srcjars = _RebasePath(build_config['gradle'].get('bundled_srcjars', [])) |
- if not args.use_gradle_process_resources: |
- srcjars += _RebasePath(build_config['javac']['srcjars']) |
- |
- java_sources_file = build_config['gradle'].get('java_sources_file') |
- java_files = [] |
- if java_sources_file: |
- java_sources_file = _RebasePath(java_sources_file) |
- java_files = build_utils.ReadSourcesList(java_sources_file) |
- |
- java_dirs = _CreateJavaSourceDir(output_dir, entry_output_dir, java_files) |
- if srcjars: |
- java_dirs.append(os.path.join(entry_output_dir, _SRCJARS_SUBDIR)) |
- |
- native_section = build_config.get('native') |
- if native_section: |
- jni_libs = _CreateJniLibsDir( |
- output_dir, entry_output_dir, native_section.get('libraries')) |
- else: |
- jni_libs = [] |
- |
- data = _GenerateGradleFile(build_config, build_vars, java_dirs, jni_libs, |
- relativize, args.use_gradle_process_resources, |
- jinja_processor) |
+ data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor) |
if data: |
project_entries.append(entry) |
# Build all paths references by .gradle that exist within output_dir. |
- generated_inputs.extend(srcjars) |
- generated_inputs.extend(p for p in java_files if not p.startswith('..')) |
- generated_inputs.extend(build_config['gradle']['dependent_prebuilt_jars']) |
- |
+ generated_inputs.extend(generator.GeneratedInputs(entry)) |
srcjar_tuples.extend( |
- (s, os.path.join(entry_output_dir, _SRCJARS_SUBDIR)) for s in srcjars) |
- _WriteFile(os.path.join(entry_output_dir, 'build.gradle'), data) |
+ (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR)) |
+ for s in generator.Srcjars(entry)) |
+ _WriteFile( |
+ os.path.join(generator.EntryOutputDir(entry), 'build.gradle'), data) |
- _WriteFile(os.path.join(gradle_output_dir, 'build.gradle'), |
+ _WriteFile(os.path.join(generator.project_dir, 'build.gradle'), |
_GenerateRootGradle(jinja_processor)) |
- _WriteFile(os.path.join(gradle_output_dir, 'settings.gradle'), |
+ _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'), |
_GenerateSettingsGradle(project_entries)) |
sdk_path = _RebasePath(build_vars['android_sdk_root']) |
- _WriteFile(os.path.join(gradle_output_dir, 'local.properties'), |
+ _WriteFile(os.path.join(generator.project_dir, 'local.properties'), |
_GenerateLocalProperties(sdk_path)) |
if generated_inputs: |
@@ -514,7 +588,7 @@ def main(): |
_RunNinja(output_dir, targets) |
if srcjar_tuples: |
- _ExtractSrcjars(gradle_output_dir, srcjar_tuples) |
+ _ExtractSrcjars(generator.project_dir, srcjar_tuples) |
logging.warning('Project created! (%d subprojects)', len(project_entries)) |
logging.warning('Generated projects work best with Android Studio 2.2') |