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