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 |