| 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 glob | |
| 11 import logging | 10 import logging |
| 12 import os | 11 import os |
| 13 import re | 12 import re |
| 14 import shutil | 13 import shutil |
| 15 import subprocess | 14 import subprocess |
| 16 import sys | 15 import sys |
| 17 import zipfile | 16 import zipfile |
| 18 | 17 |
| 19 _BUILD_ANDROID = os.path.join(os.path.dirname(__file__), os.pardir) | 18 _BUILD_ANDROID = os.path.join(os.path.dirname(__file__), os.pardir) |
| 20 sys.path.append(_BUILD_ANDROID) | 19 sys.path.append(_BUILD_ANDROID) |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 libraries += entry.BuildConfig().get('native', {}).get('libraries', []) | 251 libraries += entry.BuildConfig().get('native', {}).get('libraries', []) |
| 253 if libraries: | 252 if libraries: |
| 254 return _CreateJniLibsDir(constants.GetOutDirectory(), | 253 return _CreateJniLibsDir(constants.GetOutDirectory(), |
| 255 self.EntryOutputDir(root_entry), libraries) | 254 self.EntryOutputDir(root_entry), libraries) |
| 256 return [] | 255 return [] |
| 257 | 256 |
| 258 def _GenJavaDirs(self, root_entry): | 257 def _GenJavaDirs(self, root_entry): |
| 259 java_files = [] | 258 java_files = [] |
| 260 for entry in self._GetEntries(root_entry): | 259 for entry in self._GetEntries(root_entry): |
| 261 java_files += entry.JavaFiles() | 260 java_files += entry.JavaFiles() |
| 262 java_dirs, excludes = _ComputeJavaSourceDirsAndExcludes( | 261 java_dirs, single_files = _ComputeJavaSourceDirsAndFiles( |
| 263 constants.GetOutDirectory(), java_files) | 262 constants.GetOutDirectory(), java_files) |
| 264 return java_dirs, excludes | 263 return java_dirs, single_files |
| 265 | 264 |
| 266 def _GenCustomManifest(self, entry): | 265 def _GenCustomManifest(self, entry): |
| 267 """Returns the path to the generated AndroidManifest.xml. | 266 """Returns the path to the generated AndroidManifest.xml. |
| 268 | 267 |
| 269 Gradle uses package id from manifest when generating R.class. So, we need | 268 Gradle uses package id from manifest when generating R.class. So, we need |
| 270 to generate a custom manifest if we let gradle process resources. We cannot | 269 to generate a custom manifest if we let gradle process resources. We cannot |
| 271 simply set android.defaultConfig.applicationId because it is not supported | 270 simply set android.defaultConfig.applicationId because it is not supported |
| 272 for library targets.""" | 271 for library targets.""" |
| 273 resource_packages = entry.Javac().get('resource_packages') | 272 resource_packages = entry.Javac().get('resource_packages') |
| 274 if not resource_packages: | 273 if not resource_packages: |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 generated_inputs.update(self.AllSrcjars(root_entry)) | 325 generated_inputs.update(self.AllSrcjars(root_entry)) |
| 327 for entry in self._GetEntries(root_entry): | 326 for entry in self._GetEntries(root_entry): |
| 328 generated_inputs.update(entry.GeneratedJavaFiles()) | 327 generated_inputs.update(entry.GeneratedJavaFiles()) |
| 329 generated_inputs.update(entry.PrebuiltJars()) | 328 generated_inputs.update(entry.PrebuiltJars()) |
| 330 return set(generated_inputs) | 329 return set(generated_inputs) |
| 331 | 330 |
| 332 def Generate(self, root_entry): | 331 def Generate(self, root_entry): |
| 333 # TODO(agrieve): Add an option to use interface jars and see if that speeds | 332 # TODO(agrieve): Add an option to use interface jars and see if that speeds |
| 334 # things up at all. | 333 # things up at all. |
| 335 variables = {} | 334 variables = {} |
| 336 java_dirs, excludes = self._GenJavaDirs(root_entry) | 335 java_dirs, java_files = self._GenJavaDirs(root_entry) |
| 337 java_dirs.sort() | 336 java_dirs.sort() |
| 338 variables['java_dirs'] = self._Relativize(root_entry, java_dirs) | 337 variables['java_dirs'] = self._Relativize(root_entry, java_dirs) |
| 339 variables['java_dirs'].append(_SRCJARS_SUBDIR) | 338 variables['java_dirs'].append(_SRCJARS_SUBDIR) |
| 340 variables['java_excludes'] = excludes | 339 variables['java_files'] = self._Relativize(root_entry, java_files) |
| 341 variables['jni_libs'] = self._Relativize( | 340 variables['jni_libs'] = self._Relativize( |
| 342 root_entry, set(self._GenJniLibs(root_entry))) | 341 root_entry, set(self._GenJniLibs(root_entry))) |
| 343 variables['prebuilts'] = [ | 342 variables['prebuilts'] = [ |
| 344 p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()] | 343 p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()] |
| 345 variables['res_dirs'] = [ | 344 variables['res_dirs'] = [ |
| 346 p for e in self._GetEntries(root_entry) for p in e.ResDirs()] | 345 p for e in self._GetEntries(root_entry) for p in e.ResDirs()] |
| 347 for entry in self._GetEntries(root_entry): | 346 for entry in self._GetEntries(root_entry): |
| 348 variables['prebuilts'] += entry.PrebuiltJars() | 347 variables['prebuilts'] += entry.PrebuiltJars() |
| 349 variables['res_dirs'] += entry.ResDirs() | 348 variables['res_dirs'] += entry.ResDirs() |
| 350 variables['prebuilts'] = self._Relativize( | 349 variables['prebuilts'] = self._Relativize( |
| (...skipping 30 matching lines...) Expand all Loading... |
| 381 break | 380 break |
| 382 if basename in ('javax', 'org', 'com'): | 381 if basename in ('javax', 'org', 'com'): |
| 383 path_root = os.path.dirname(path_root) | 382 path_root = os.path.dirname(path_root) |
| 384 break | 383 break |
| 385 if path_root not in found_roots: | 384 if path_root not in found_roots: |
| 386 found_roots[path_root] = [] | 385 found_roots[path_root] = [] |
| 387 found_roots[path_root].append(path) | 386 found_roots[path_root].append(path) |
| 388 return found_roots | 387 return found_roots |
| 389 | 388 |
| 390 | 389 |
| 391 def _ComputeExcludeFilters(wanted_files, unwanted_files, parent_dir): | 390 def _ComputeJavaSourceDirsAndFiles(output_dir, java_files): |
| 392 """Returns exclude patters to exclude unwanted files but keep wanted files. | 391 """Computes the list of java source directories and single files. |
| 393 | |
| 394 - Shortens exclude list by globbing if possible. | |
| 395 - Exclude patterns are relative paths from the parent directory. | |
| 396 """ | |
| 397 excludes = [] | |
| 398 files_to_include = set(wanted_files) | |
| 399 files_to_exclude = set(unwanted_files) | |
| 400 while files_to_exclude: | |
| 401 unwanted_file = files_to_exclude.pop() | |
| 402 target_exclude = os.path.join( | |
| 403 os.path.dirname(unwanted_file), '*.java') | |
| 404 found_files = set(glob.glob(target_exclude)) | |
| 405 valid_files = found_files & files_to_include | |
| 406 if valid_files: | |
| 407 excludes.append(os.path.relpath(unwanted_file, parent_dir)) | |
| 408 else: | |
| 409 excludes.append(os.path.relpath(target_exclude, parent_dir)) | |
| 410 files_to_exclude -= found_files | |
| 411 return excludes | |
| 412 | |
| 413 | |
| 414 def _ComputeJavaSourceDirsAndExcludes(output_dir, java_files): | |
| 415 """Computes the list of java source directories and exclude patterns. | |
| 416 | 392 |
| 417 1. Computes the root java source directories from the list of files. | 393 1. Computes the root java source directories from the list of files. |
| 418 2. Compute exclude patterns that exclude all extra files only. | 394 2. Compute single files that are not included in full directories. |
| 419 3. Returns the list of java source directories and exclude patterns. | 395 3. Returns the list of java source directories and single files. |
| 420 """ | 396 """ |
| 421 java_dirs = [] | 397 java_dirs = [] |
| 422 excludes = [] | 398 single_files = set() |
| 423 if java_files: | 399 if java_files: |
| 424 java_files = _RebasePath(java_files) | 400 java_files = _RebasePath(java_files) |
| 425 computed_dirs = _ComputeJavaSourceDirs(java_files) | 401 computed_dirs = _ComputeJavaSourceDirs(java_files) |
| 426 java_dirs = computed_dirs.keys() | |
| 427 all_found_java_files = set() | 402 all_found_java_files = set() |
| 428 | 403 |
| 429 for directory, files in computed_dirs.iteritems(): | 404 for directory, files in computed_dirs.iteritems(): |
| 430 found_java_files = build_utils.FindInDirectory(directory, '*.java') | 405 found_java_files = build_utils.FindInDirectory(directory, '*.java') |
| 431 all_found_java_files.update(found_java_files) | 406 all_found_java_files.update(found_java_files) |
| 432 unwanted_java_files = set(found_java_files) - set(files) | 407 unwanted_java_files = set(found_java_files) - set(files) |
| 433 if unwanted_java_files: | 408 if unwanted_java_files: |
| 434 logging.debug('Directory requires excludes: %s', directory) | 409 logging.debug('Directory requires single files: %s', directory) |
| 435 excludes.extend( | 410 single_files.update(files) |
| 436 _ComputeExcludeFilters(files, unwanted_java_files, directory)) | 411 else: |
| 412 java_dirs.append(directory) |
| 437 | 413 |
| 438 missing_java_files = set(java_files) - all_found_java_files | 414 missing_java_files = set(java_files) - all_found_java_files |
| 439 # Warn only about non-generated files that are missing. | 415 # Warn only about non-generated files that are missing. |
| 440 missing_java_files = [p for p in missing_java_files | 416 missing_java_files = [p for p in missing_java_files |
| 441 if not p.startswith(output_dir)] | 417 if not p.startswith(output_dir)] |
| 442 if missing_java_files: | 418 if missing_java_files: |
| 443 logging.warning( | 419 logging.error( |
| 444 'Some java files were not found: %s', missing_java_files) | 420 'Some java files were not found: %s', missing_java_files) |
| 445 | 421 |
| 446 return java_dirs, excludes | 422 return java_dirs, list(single_files) |
| 447 | 423 |
| 448 | 424 |
| 449 def _CreateRelativeSymlink(target_path, link_path): | 425 def _CreateRelativeSymlink(target_path, link_path): |
| 450 link_dir = os.path.dirname(link_path) | 426 link_dir = os.path.dirname(link_path) |
| 451 relpath = os.path.relpath(target_path, link_dir) | 427 relpath = os.path.relpath(target_path, link_dir) |
| 452 logging.debug('Creating symlink %s -> %s', link_path, relpath) | 428 logging.debug('Creating symlink %s -> %s', link_path, relpath) |
| 453 os.symlink(relpath, link_path) | 429 os.symlink(relpath, link_path) |
| 454 | 430 |
| 455 | 431 |
| 456 def _CreateJniLibsDir(output_dir, entry_output_dir, so_files): | 432 def _CreateJniLibsDir(output_dir, entry_output_dir, so_files): |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 return None | 488 return None |
| 513 | 489 |
| 514 variables['target_name'] = os.path.splitext(deps_info['name'])[0] | 490 variables['target_name'] = os.path.splitext(deps_info['name'])[0] |
| 515 variables['template_type'] = target_type | 491 variables['template_type'] = target_type |
| 516 variables['use_gradle_process_resources'] = ( | 492 variables['use_gradle_process_resources'] = ( |
| 517 generator.use_gradle_process_resources) | 493 generator.use_gradle_process_resources) |
| 518 source_properties = _ReadPropertiesFile( | 494 source_properties = _ReadPropertiesFile( |
| 519 _RebasePath(os.path.join(build_vars['android_sdk_build_tools'], | 495 _RebasePath(os.path.join(build_vars['android_sdk_build_tools'], |
| 520 'source.properties'))) | 496 'source.properties'))) |
| 521 variables['build_tools_version'] = source_properties['Pkg.Revision'] | 497 variables['build_tools_version'] = source_properties['Pkg.Revision'] |
| 498 # TODO(wnwen): Remove this line once http://crbug.com/688263 is fixed. |
| 499 variables['build_tools_version'] = '25.0.0' |
| 522 variables['compile_sdk_version'] = ( | 500 variables['compile_sdk_version'] = ( |
| 523 'android-%s' % build_vars['android_sdk_version']) | 501 'android-%s' % build_vars['android_sdk_version']) |
| 524 variables['main'] = generator.Generate(entry) | 502 variables['main'] = generator.Generate(entry) |
| 525 bootclasspath = gradle.get('bootclasspath') | 503 bootclasspath = gradle.get('bootclasspath') |
| 526 if bootclasspath: | 504 if bootclasspath: |
| 527 # Must use absolute path here. | 505 # Must use absolute path here. |
| 528 variables['bootclasspath'] = _RebasePath(bootclasspath) | 506 variables['bootclasspath'] = _RebasePath(bootclasspath) |
| 529 if entry.android_test_entry: | 507 if entry.android_test_entry: |
| 530 variables['android_test'] = generator.Generate( | 508 variables['android_test'] = generator.Generate( |
| 531 entry.android_test_entry) | 509 entry.android_test_entry) |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 | 709 |
| 732 if generated_inputs: | 710 if generated_inputs: |
| 733 logging.warning('Building generated source files...') | 711 logging.warning('Building generated source files...') |
| 734 targets = _RebasePath(generated_inputs, output_dir) | 712 targets = _RebasePath(generated_inputs, output_dir) |
| 735 _RunNinja(output_dir, targets) | 713 _RunNinja(output_dir, targets) |
| 736 | 714 |
| 737 if zip_tuples: | 715 if zip_tuples: |
| 738 _ExtractZips(generator.project_dir, zip_tuples) | 716 _ExtractZips(generator.project_dir, zip_tuples) |
| 739 | 717 |
| 740 logging.warning('Project created! (%d subprojects)', len(project_entries)) | 718 logging.warning('Project created! (%d subprojects)', len(project_entries)) |
| 741 logging.warning('Generated projects work best with Android Studio 2.2') | 719 logging.warning('Generated projects are targeting Android Studio 2.3') |
| 742 logging.warning('For more tips: https://chromium.googlesource.com/chromium' | 720 logging.warning('For more tips: https://chromium.googlesource.com/chromium' |
| 743 '/src.git/+/master/docs/android_studio.md') | 721 '/src.git/+/master/docs/android_studio.md') |
| 744 | 722 |
| 745 | 723 |
| 746 if __name__ == '__main__': | 724 if __name__ == '__main__': |
| 747 main() | 725 main() |
| OLD | NEW |