Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2016 The Chromium Authors. All rights reserved. | 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Generates an Android Studio project from a GN target.""" | 6 """Generates an Android Studio project from a GN target.""" |
| 7 | 7 |
| 8 import argparse | 8 import argparse |
| 9 import codecs | 9 import codecs |
| 10 import logging | 10 import logging |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 from util import build_utils | 27 from util import build_utils |
| 28 | 28 |
| 29 | 29 |
| 30 _DEFAULT_ANDROID_MANIFEST_PATH = os.path.join( | 30 _DEFAULT_ANDROID_MANIFEST_PATH = os.path.join( |
| 31 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml') | 31 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml') |
| 32 _FILE_DIR = os.path.dirname(__file__) | 32 _FILE_DIR = os.path.dirname(__file__) |
| 33 _JAVA_SUBDIR = 'symlinked-java' | 33 _JAVA_SUBDIR = 'symlinked-java' |
| 34 _SRCJARS_SUBDIR = 'extracted-srcjars' | 34 _SRCJARS_SUBDIR = 'extracted-srcjars' |
| 35 _JNI_LIBS_SUBDIR = 'symlinked-libs' | 35 _JNI_LIBS_SUBDIR = 'symlinked-libs' |
| 36 _ARMEABI_SUBDIR = 'armeabi' | 36 _ARMEABI_SUBDIR = 'armeabi' |
| 37 _RES_SUBDIR = 'extracted-res' | |
| 37 | 38 |
| 38 _DEFAULT_TARGETS = [ | 39 _DEFAULT_TARGETS = [ |
| 39 # TODO(agrieve): Requires alternate android.jar to compile. | 40 # TODO(agrieve): Requires alternate android.jar to compile. |
| 40 # '//android_webview:system_webview_apk', | 41 # '//android_webview:system_webview_apk', |
| 41 '//android_webview/test:android_webview_apk', | 42 '//android_webview/test:android_webview_apk', |
| 42 '//android_webview/test:android_webview_test_apk', | 43 '//android_webview/test:android_webview_test_apk', |
| 43 '//base:base_junit_tests', | 44 '//base:base_junit_tests', |
| 44 '//chrome/android:chrome_junit_tests', | 45 '//chrome/android:chrome_junit_tests', |
| 45 '//chrome/android:chrome_public_apk', | 46 '//chrome/android:chrome_public_apk', |
| 46 '//chrome/android:chrome_public_test_apk', | 47 '//chrome/android:chrome_public_test_apk', |
| 47 '//chrome/android:chrome_sync_shell_apk', | 48 '//chrome/android:chrome_sync_shell_apk', |
| 48 '//chrome/android:chrome_sync_shell_test_apk', | 49 '//chrome/android:chrome_sync_shell_test_apk', |
| 49 '//content/public/android:content_junit_tests', | 50 '//content/public/android:content_junit_tests', |
| 50 '//content/shell/android:content_shell_apk', | 51 '//content/shell/android:content_shell_apk', |
| 51 ] | 52 ] |
| 52 | 53 |
| 53 | 54 |
| 54 def _TemplatePath(name): | 55 def _TemplatePath(name): |
| 55 return os.path.join(_FILE_DIR, '{}.jinja'.format(name)) | 56 return os.path.join(_FILE_DIR, '{}.jinja'.format(name)) |
| 56 | 57 |
| 57 | 58 |
| 58 def _RebasePath(path_or_list, new_cwd=None, old_cwd=None): | 59 def _RebasePath(path_or_list, new_cwd=None, old_cwd=None): |
| 59 """Makes the given path(s) relative to new_cwd, or absolute if not specified. | 60 """Makes the given path(s) relative to new_cwd, or absolute if not specified. |
| 60 | 61 |
| 61 If new_cwd is not specified, absolute paths are returned. | 62 If new_cwd is not specified, absolute paths are returned. |
| 62 If old_cwd is not specified, constants.GetOutDirectory() is assumed. | 63 If old_cwd is not specified, constants.GetOutDirectory() is assumed. |
| 63 """ | 64 """ |
| 65 if not path_or_list: | |
|
agrieve
2017/02/09 15:29:31
The following line says:
if not isinstance(path_o
Peter Wen
2017/02/09 16:42:05
Opps, you're right. Fixed now.
| |
| 66 return [] | |
| 64 if not isinstance(path_or_list, basestring): | 67 if not isinstance(path_or_list, basestring): |
| 65 return [_RebasePath(p, new_cwd, old_cwd) for p in path_or_list] | 68 return [_RebasePath(p, new_cwd, old_cwd) for p in path_or_list] |
| 66 if old_cwd is None: | 69 if old_cwd is None: |
| 67 old_cwd = constants.GetOutDirectory() | 70 old_cwd = constants.GetOutDirectory() |
| 68 old_cwd = os.path.abspath(old_cwd) | 71 old_cwd = os.path.abspath(old_cwd) |
| 69 if new_cwd: | 72 if new_cwd: |
| 70 new_cwd = os.path.abspath(new_cwd) | 73 new_cwd = os.path.abspath(new_cwd) |
| 71 return os.path.relpath(os.path.join(old_cwd, path_or_list), new_cwd) | 74 return os.path.relpath(os.path.join(old_cwd, path_or_list), new_cwd) |
| 72 return os.path.abspath(os.path.join(old_cwd, path_or_list)) | 75 return os.path.abspath(os.path.join(old_cwd, path_or_list)) |
| 73 | 76 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 def DepsInfo(self): | 172 def DepsInfo(self): |
| 170 return self.BuildConfig()['deps_info'] | 173 return self.BuildConfig()['deps_info'] |
| 171 | 174 |
| 172 def Gradle(self): | 175 def Gradle(self): |
| 173 return self.BuildConfig()['gradle'] | 176 return self.BuildConfig()['gradle'] |
| 174 | 177 |
| 175 def GetType(self): | 178 def GetType(self): |
| 176 """Returns the target type from its .build_config.""" | 179 """Returns the target type from its .build_config.""" |
| 177 return self.DepsInfo()['type'] | 180 return self.DepsInfo()['type'] |
| 178 | 181 |
| 182 def ResZips(self): | |
| 183 return self.DepsInfo().get('owned_resources_zips') | |
| 184 | |
| 179 def JavaFiles(self): | 185 def JavaFiles(self): |
| 180 if self._java_files is None: | 186 if self._java_files is None: |
| 181 java_sources_file = self.Gradle().get('java_sources_file') | 187 java_sources_file = self.Gradle().get('java_sources_file') |
| 182 java_files = [] | 188 java_files = [] |
| 183 if java_sources_file: | 189 if java_sources_file: |
| 184 java_sources_file = _RebasePath(java_sources_file) | 190 java_sources_file = _RebasePath(java_sources_file) |
| 185 java_files = build_utils.ReadSourcesList(java_sources_file) | 191 java_files = build_utils.ReadSourcesList(java_sources_file) |
| 186 self._java_files = java_files | 192 self._java_files = java_files |
| 187 return self._java_files | 193 return self._java_files |
| 188 | 194 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 205 | 211 |
| 206 def _GenJavaDirs(self, entry): | 212 def _GenJavaDirs(self, entry): |
| 207 java_dirs = _CreateJavaSourceDir( | 213 java_dirs = _CreateJavaSourceDir( |
| 208 constants.GetOutDirectory(), self.EntryOutputDir(entry), | 214 constants.GetOutDirectory(), self.EntryOutputDir(entry), |
| 209 entry.JavaFiles()) | 215 entry.JavaFiles()) |
| 210 if self.Srcjars(entry): | 216 if self.Srcjars(entry): |
| 211 java_dirs.append( | 217 java_dirs.append( |
| 212 os.path.join(self.EntryOutputDir(entry), _SRCJARS_SUBDIR)) | 218 os.path.join(self.EntryOutputDir(entry), _SRCJARS_SUBDIR)) |
| 213 return java_dirs | 219 return java_dirs |
| 214 | 220 |
| 221 def _GenResDirs(self, entry): | |
| 222 res_dirs = list(entry.DepsInfo().get('owned_resources_dirs', [])) | |
| 223 if entry.ResZips(): | |
| 224 res_dirs.append(os.path.join(self.EntryOutputDir(entry), _RES_SUBDIR)) | |
| 225 return res_dirs | |
| 226 | |
| 215 def _Relativize(self, entry, paths): | 227 def _Relativize(self, entry, paths): |
| 216 return _RebasePath(paths, self.EntryOutputDir(entry)) | 228 return _RebasePath(paths, self.EntryOutputDir(entry)) |
| 217 | 229 |
| 218 def EntryOutputDir(self, entry): | 230 def EntryOutputDir(self, entry): |
| 219 return os.path.join(self.project_dir, entry.GradleSubdir()) | 231 return os.path.join(self.project_dir, entry.GradleSubdir()) |
| 220 | 232 |
| 221 def Srcjars(self, entry): | 233 def Srcjars(self, entry): |
| 222 srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', [])) | 234 srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', [])) |
| 223 if not self.use_gradle_process_resources: | 235 if not self.use_gradle_process_resources: |
| 224 srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars']) | 236 srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars']) |
| 225 return srcjars | 237 return srcjars |
| 226 | 238 |
| 227 def GeneratedInputs(self, entry): | 239 def GeneratedInputs(self, entry): |
| 228 generated_inputs = [] | 240 generated_inputs = [] |
| 229 generated_inputs.extend(self.Srcjars(entry)) | 241 generated_inputs.extend(self.Srcjars(entry)) |
| 242 generated_inputs.extend(_RebasePath(entry.ResZips())) | |
| 230 generated_inputs.extend( | 243 generated_inputs.extend( |
| 231 p for p in entry.JavaFiles() if not p.startswith('..')) | 244 p for p in entry.JavaFiles() if not p.startswith('..')) |
| 232 generated_inputs.extend(entry.Gradle()['dependent_prebuilt_jars']) | 245 generated_inputs.extend(entry.Gradle()['dependent_prebuilt_jars']) |
| 233 return generated_inputs | 246 return generated_inputs |
| 234 | 247 |
| 235 def Generate(self, entry): | 248 def Generate(self, entry): |
| 236 variables = {} | 249 variables = {} |
| 237 android_test_manifest = entry.Gradle().get( | 250 android_test_manifest = entry.Gradle().get( |
| 238 'android_manifest', _DEFAULT_ANDROID_MANIFEST_PATH) | 251 'android_manifest', _DEFAULT_ANDROID_MANIFEST_PATH) |
| 239 variables['android_manifest'] = self._Relativize( | 252 variables['android_manifest'] = self._Relativize( |
| 240 entry, android_test_manifest) | 253 entry, android_test_manifest) |
| 241 variables['java_dirs'] = self._Relativize(entry, self._GenJavaDirs(entry)) | 254 variables['java_dirs'] = self._Relativize(entry, self._GenJavaDirs(entry)) |
| 242 variables['jni_libs'] = self._Relativize(entry, self._GenJniLibs(entry)) | 255 variables['jni_libs'] = self._Relativize(entry, self._GenJniLibs(entry)) |
| 256 variables['res_dirs'] = self._Relativize(entry, self._GenResDirs(entry)) | |
| 243 deps = [_ProjectEntry.FromBuildConfigPath(p) | 257 deps = [_ProjectEntry.FromBuildConfigPath(p) |
| 244 for p in entry.Gradle()['dependent_android_projects']] | 258 for p in entry.Gradle()['dependent_android_projects']] |
| 245 variables['android_project_deps'] = [d.ProjectName() for d in deps] | 259 variables['android_project_deps'] = [d.ProjectName() for d in deps] |
| 246 # TODO(agrieve): Add an option to use interface jars and see if that speeds | 260 # TODO(agrieve): Add an option to use interface jars and see if that speeds |
| 247 # things up at all. | 261 # things up at all. |
| 248 variables['prebuilts'] = self._Relativize( | 262 variables['prebuilts'] = self._Relativize( |
| 249 entry, entry.Gradle()['dependent_prebuilt_jars']) | 263 entry, entry.Gradle()['dependent_prebuilt_jars']) |
| 250 deps = [_ProjectEntry.FromBuildConfigPath(p) | 264 deps = [_ProjectEntry.FromBuildConfigPath(p) |
| 251 for p in entry.Gradle()['dependent_java_projects']] | 265 for p in entry.Gradle()['dependent_java_projects']] |
| 252 variables['java_project_deps'] = [d.ProjectName() for d in deps] | 266 variables['java_project_deps'] = [d.ProjectName() for d in deps] |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 422 lines.append('') | 436 lines.append('') |
| 423 | 437 |
| 424 for entry in project_entries: | 438 for entry in project_entries: |
| 425 # Example target: android_webview:android_webview_java__build_config | 439 # Example target: android_webview:android_webview_java__build_config |
| 426 lines.append('include ":%s"' % entry.ProjectName()) | 440 lines.append('include ":%s"' % entry.ProjectName()) |
| 427 lines.append('project(":%s").projectDir = new File(settingsDir, "%s")' % | 441 lines.append('project(":%s").projectDir = new File(settingsDir, "%s")' % |
| 428 (entry.ProjectName(), entry.GradleSubdir())) | 442 (entry.ProjectName(), entry.GradleSubdir())) |
| 429 return '\n'.join(lines) | 443 return '\n'.join(lines) |
| 430 | 444 |
| 431 | 445 |
| 432 def _ExtractSrcjars(entry_output_dir, srcjar_tuples): | 446 def _ExtractFile(zip_path, extracted_path): |
| 447 logging.info('Extracting %s to %s', zip_path, extracted_path) | |
| 448 with zipfile.ZipFile(zip_path) as z: | |
| 449 z.extractall(extracted_path) | |
| 450 | |
| 451 | |
| 452 def _ExtractZips(entry_output_dir, zip_tuples): | |
| 433 """Extracts all srcjars to the directory given by the tuples.""" | 453 """Extracts all srcjars to the directory given by the tuples.""" |
| 434 extracted_paths = set(s[1] for s in srcjar_tuples) | 454 extracted_paths = set(s[1] for s in zip_tuples) |
| 435 for extracted_path in extracted_paths: | 455 for extracted_path in extracted_paths: |
| 436 assert _IsSubpathOf(extracted_path, entry_output_dir) | 456 assert _IsSubpathOf(extracted_path, entry_output_dir) |
| 437 shutil.rmtree(extracted_path, True) | 457 shutil.rmtree(extracted_path, True) |
| 438 | 458 |
| 439 for srcjar_path, extracted_path in srcjar_tuples: | 459 for zip_path, extracted_path in zip_tuples: |
| 440 logging.info('Extracting %s to %s', srcjar_path, extracted_path) | 460 _ExtractFile(zip_path, extracted_path) |
| 441 with zipfile.ZipFile(srcjar_path) as z: | |
| 442 z.extractall(extracted_path) | |
| 443 | 461 |
| 444 | 462 |
| 445 def _FindAllProjectEntries(main_entries): | 463 def _FindAllProjectEntries(main_entries): |
| 446 """Returns the list of all _ProjectEntry instances given the root project.""" | 464 """Returns the list of all _ProjectEntry instances given the root project.""" |
| 447 found = set() | 465 found = set() |
| 448 to_scan = list(main_entries) | 466 to_scan = list(main_entries) |
| 449 while to_scan: | 467 while to_scan: |
| 450 cur_entry = to_scan.pop() | 468 cur_entry = to_scan.pop() |
| 451 if cur_entry in found: | 469 if cur_entry in found: |
| 452 continue | 470 continue |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 547 | 565 |
| 548 all_entries = _FindAllProjectEntries(main_entries) | 566 all_entries = _FindAllProjectEntries(main_entries) |
| 549 logging.info('Found %d dependent build_config targets.', len(all_entries)) | 567 logging.info('Found %d dependent build_config targets.', len(all_entries)) |
| 550 entries = _CombineTestEntries(all_entries) | 568 entries = _CombineTestEntries(all_entries) |
| 551 logging.info('Creating %d projects for targets.', len(entries)) | 569 logging.info('Creating %d projects for targets.', len(entries)) |
| 552 | 570 |
| 553 logging.warning('Writing .gradle files...') | 571 logging.warning('Writing .gradle files...') |
| 554 jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR) | 572 jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR) |
| 555 build_vars = _ReadBuildVars(output_dir) | 573 build_vars = _ReadBuildVars(output_dir) |
| 556 project_entries = [] | 574 project_entries = [] |
| 557 srcjar_tuples = [] | 575 zip_tuples = [] |
| 558 generated_inputs = [] | 576 generated_inputs = [] |
| 559 for entry in entries: | 577 for entry in entries: |
| 560 if entry.GetType() not in ('android_apk', 'java_library', 'java_binary'): | 578 if entry.GetType() not in ('android_apk', 'java_library', 'java_binary'): |
| 561 continue | 579 continue |
| 562 | 580 |
| 563 data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor) | 581 data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor) |
| 564 if data: | 582 if data: |
| 565 project_entries.append(entry) | 583 project_entries.append(entry) |
| 566 # Build all paths references by .gradle that exist within output_dir. | 584 # Build all paths references by .gradle that exist within output_dir. |
| 567 generated_inputs.extend(generator.GeneratedInputs(entry)) | 585 generated_inputs.extend(generator.GeneratedInputs(entry)) |
| 568 srcjar_tuples.extend( | 586 zip_tuples.extend( |
| 569 (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR)) | 587 (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR)) |
| 570 for s in generator.Srcjars(entry)) | 588 for s in generator.Srcjars(entry)) |
| 589 zip_tuples.extend( | |
| 590 (s, os.path.join(generator.EntryOutputDir(entry), _RES_SUBDIR)) | |
| 591 for s in _RebasePath(entry.ResZips())) | |
| 571 _WriteFile( | 592 _WriteFile( |
| 572 os.path.join(generator.EntryOutputDir(entry), 'build.gradle'), data) | 593 os.path.join(generator.EntryOutputDir(entry), 'build.gradle'), data) |
| 573 | 594 |
| 574 _WriteFile(os.path.join(generator.project_dir, 'build.gradle'), | 595 _WriteFile(os.path.join(generator.project_dir, 'build.gradle'), |
| 575 _GenerateRootGradle(jinja_processor)) | 596 _GenerateRootGradle(jinja_processor)) |
| 576 | 597 |
| 577 _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'), | 598 _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'), |
| 578 _GenerateSettingsGradle(project_entries)) | 599 _GenerateSettingsGradle(project_entries)) |
| 579 | 600 |
| 580 sdk_path = _RebasePath(build_vars['android_sdk_root']) | 601 sdk_path = _RebasePath(build_vars['android_sdk_root']) |
| 581 _WriteFile(os.path.join(generator.project_dir, 'local.properties'), | 602 _WriteFile(os.path.join(generator.project_dir, 'local.properties'), |
| 582 _GenerateLocalProperties(sdk_path)) | 603 _GenerateLocalProperties(sdk_path)) |
| 583 | 604 |
| 584 if generated_inputs: | 605 if generated_inputs: |
| 585 logging.warning('Building generated source files...') | 606 logging.warning('Building generated source files...') |
| 586 targets = _RebasePath(generated_inputs, output_dir) | 607 targets = _RebasePath(generated_inputs, output_dir) |
| 587 _RunNinja(output_dir, targets) | 608 _RunNinja(output_dir, targets) |
| 588 | 609 |
| 589 if srcjar_tuples: | 610 if zip_tuples: |
| 590 _ExtractSrcjars(generator.project_dir, srcjar_tuples) | 611 _ExtractZips(generator.project_dir, zip_tuples) |
| 591 | 612 |
| 592 logging.warning('Project created! (%d subprojects)', len(project_entries)) | 613 logging.warning('Project created! (%d subprojects)', len(project_entries)) |
| 593 logging.warning('Generated projects work best with Android Studio 2.2') | 614 logging.warning('Generated projects work best with Android Studio 2.2') |
| 594 logging.warning('For more tips: https://chromium.googlesource.com/chromium' | 615 logging.warning('For more tips: https://chromium.googlesource.com/chromium' |
| 595 '/src.git/+/master/docs/android_studio.md') | 616 '/src.git/+/master/docs/android_studio.md') |
| 596 | 617 |
| 597 | 618 |
| 598 if __name__ == '__main__': | 619 if __name__ == '__main__': |
| 599 main() | 620 main() |
| OLD | NEW |