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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
325 generated_inputs.update(self.AllSrcjars(root_entry)) | 324 generated_inputs.update(self.AllSrcjars(root_entry)) |
326 for entry in self._GetEntries(root_entry): | 325 for entry in self._GetEntries(root_entry): |
327 generated_inputs.update(entry.GeneratedJavaFiles()) | 326 generated_inputs.update(entry.GeneratedJavaFiles()) |
328 generated_inputs.update(entry.PrebuiltJars()) | 327 generated_inputs.update(entry.PrebuiltJars()) |
329 return set(generated_inputs) | 328 return set(generated_inputs) |
330 | 329 |
331 def Generate(self, root_entry): | 330 def Generate(self, root_entry): |
332 # TODO(agrieve): Add an option to use interface jars and see if that speeds | 331 # TODO(agrieve): Add an option to use interface jars and see if that speeds |
333 # things up at all. | 332 # things up at all. |
334 variables = {} | 333 variables = {} |
335 java_dirs, excludes = self._GenJavaDirs(root_entry) | 334 java_dirs, java_files = self._GenJavaDirs(root_entry) |
336 java_dirs.sort() | 335 java_dirs.sort() |
337 variables['java_dirs'] = self._Relativize(root_entry, java_dirs) | 336 variables['java_dirs'] = self._Relativize(root_entry, java_dirs) |
338 variables['java_dirs'].append(_SRCJARS_SUBDIR) | 337 variables['java_dirs'].append(_SRCJARS_SUBDIR) |
339 variables['java_excludes'] = excludes | 338 variables['java_files'] = self._Relativize(root_entry, java_files) |
340 variables['jni_libs'] = self._Relativize( | 339 variables['jni_libs'] = self._Relativize( |
341 root_entry, set(self._GenJniLibs(root_entry))) | 340 root_entry, set(self._GenJniLibs(root_entry))) |
342 variables['prebuilts'] = [ | 341 variables['prebuilts'] = [ |
343 p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()] | 342 p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()] |
344 variables['res_dirs'] = [ | 343 variables['res_dirs'] = [ |
345 p for e in self._GetEntries(root_entry) for p in e.ResDirs()] | 344 p for e in self._GetEntries(root_entry) for p in e.ResDirs()] |
346 for entry in self._GetEntries(root_entry): | 345 for entry in self._GetEntries(root_entry): |
347 variables['prebuilts'] += entry.PrebuiltJars() | 346 variables['prebuilts'] += entry.PrebuiltJars() |
348 variables['res_dirs'] += entry.ResDirs() | 347 variables['res_dirs'] += entry.ResDirs() |
349 variables['prebuilts'] = self._Relativize( | 348 variables['prebuilts'] = self._Relativize( |
(...skipping 30 matching lines...) Expand all Loading... | |
380 break | 379 break |
381 if basename in ('javax', 'org', 'com'): | 380 if basename in ('javax', 'org', 'com'): |
382 path_root = os.path.dirname(path_root) | 381 path_root = os.path.dirname(path_root) |
383 break | 382 break |
384 if path_root not in found_roots: | 383 if path_root not in found_roots: |
385 found_roots[path_root] = [] | 384 found_roots[path_root] = [] |
386 found_roots[path_root].append(path) | 385 found_roots[path_root].append(path) |
387 return found_roots | 386 return found_roots |
388 | 387 |
389 | 388 |
390 def _ComputeExcludeFilters(wanted_files, unwanted_files, parent_dir): | 389 def _ComputeJavaSourceDirsAndFiles(output_dir, java_files): |
391 """Returns exclude patters to exclude unwanted files but keep wanted files. | 390 """Computes the list of java source directories and single files. |
392 | |
393 - Shortens exclude list by globbing if possible. | |
394 - Exclude patterns are relative paths from the parent directory. | |
395 """ | |
396 excludes = [] | |
397 files_to_include = set(wanted_files) | |
398 files_to_exclude = set(unwanted_files) | |
399 while files_to_exclude: | |
400 unwanted_file = files_to_exclude.pop() | |
401 target_exclude = os.path.join( | |
402 os.path.dirname(unwanted_file), '*.java') | |
403 found_files = set(glob.glob(target_exclude)) | |
404 valid_files = found_files & files_to_include | |
405 if valid_files: | |
406 excludes.append(os.path.relpath(unwanted_file, parent_dir)) | |
407 else: | |
408 excludes.append(os.path.relpath(target_exclude, parent_dir)) | |
409 files_to_exclude -= found_files | |
410 return excludes | |
411 | |
412 | |
413 def _ComputeJavaSourceDirsAndExcludes(output_dir, java_files): | |
414 """Computes the list of java source directories and exclude patterns. | |
415 | 391 |
416 1. Computes the root java source directories from the list of files. | 392 1. Computes the root java source directories from the list of files. |
417 2. Compute exclude patterns that exclude all extra files only. | 393 2. Compute single files that are not included in full directories. |
418 3. Returns the list of java source directories and exclude patterns. | 394 3. Returns the list of java source directories and single files. |
419 """ | 395 """ |
420 java_dirs = [] | 396 java_dirs = [] |
421 excludes = [] | 397 single_files = set() |
422 if java_files: | 398 if java_files: |
423 java_files = _RebasePath(java_files) | 399 java_files = _RebasePath(java_files) |
424 computed_dirs = _ComputeJavaSourceDirs(java_files) | 400 computed_dirs = _ComputeJavaSourceDirs(java_files) |
425 java_dirs = computed_dirs.keys() | |
426 all_found_java_files = set() | 401 all_found_java_files = set() |
427 | 402 |
428 for directory, files in computed_dirs.iteritems(): | 403 for directory, files in computed_dirs.iteritems(): |
429 found_java_files = build_utils.FindInDirectory(directory, '*.java') | 404 found_java_files = build_utils.FindInDirectory(directory, '*.java') |
430 all_found_java_files.update(found_java_files) | 405 all_found_java_files.update(found_java_files) |
431 unwanted_java_files = set(found_java_files) - set(files) | 406 unwanted_java_files = set(found_java_files) - set(files) |
432 if unwanted_java_files: | 407 if unwanted_java_files: |
433 logging.debug('Directory requires excludes: %s', directory) | 408 logging.debug('Directory requires single files: %s', directory) |
434 excludes.extend( | 409 single_files.update(files) |
435 _ComputeExcludeFilters(files, unwanted_java_files, directory)) | 410 else: |
411 java_dirs.append(directory) | |
436 | 412 |
437 missing_java_files = set(java_files) - all_found_java_files | 413 missing_java_files = set(java_files) - all_found_java_files |
438 # Warn only about non-generated files that are missing. | 414 # Warn only about non-generated files that are missing. |
439 missing_java_files = [p for p in missing_java_files | 415 missing_java_files = [p for p in missing_java_files |
440 if not p.startswith(output_dir)] | 416 if not p.startswith(output_dir)] |
441 if missing_java_files: | 417 if missing_java_files: |
442 logging.warning( | 418 logging.warning( |
443 'Some java files were not found: %s', missing_java_files) | 419 'Some java files were not found: %s', missing_java_files) |
420 single_files.update(missing_java_files) | |
estevenson
2017/03/14 23:41:49
Does this ever happen? Doesn't missing_java_files
Peter Wen
2017/03/15 14:42:49
Done. Changed from warning to error message. No re
| |
444 | 421 |
445 return java_dirs, excludes | 422 return java_dirs, list(single_files) |
446 | 423 |
447 | 424 |
448 def _CreateRelativeSymlink(target_path, link_path): | 425 def _CreateRelativeSymlink(target_path, link_path): |
449 link_dir = os.path.dirname(link_path) | 426 link_dir = os.path.dirname(link_path) |
450 relpath = os.path.relpath(target_path, link_dir) | 427 relpath = os.path.relpath(target_path, link_dir) |
451 logging.debug('Creating symlink %s -> %s', link_path, relpath) | 428 logging.debug('Creating symlink %s -> %s', link_path, relpath) |
452 os.symlink(relpath, link_path) | 429 os.symlink(relpath, link_path) |
453 | 430 |
454 | 431 |
455 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... | |
511 return None | 488 return None |
512 | 489 |
513 variables['target_name'] = os.path.splitext(deps_info['name'])[0] | 490 variables['target_name'] = os.path.splitext(deps_info['name'])[0] |
514 variables['template_type'] = target_type | 491 variables['template_type'] = target_type |
515 variables['use_gradle_process_resources'] = ( | 492 variables['use_gradle_process_resources'] = ( |
516 generator.use_gradle_process_resources) | 493 generator.use_gradle_process_resources) |
517 source_properties = _ReadPropertiesFile( | 494 source_properties = _ReadPropertiesFile( |
518 _RebasePath(os.path.join(build_vars['android_sdk_build_tools'], | 495 _RebasePath(os.path.join(build_vars['android_sdk_build_tools'], |
519 'source.properties'))) | 496 'source.properties'))) |
520 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' | |
estevenson
2017/03/14 23:41:49
I was still prompted with an error about having th
Peter Wen
2017/03/15 14:42:49
Makes sense, added to docs.
| |
521 variables['compile_sdk_version'] = ( | 500 variables['compile_sdk_version'] = ( |
522 'android-%s' % build_vars['android_sdk_version']) | 501 'android-%s' % build_vars['android_sdk_version']) |
523 variables['main'] = generator.Generate(entry) | 502 variables['main'] = generator.Generate(entry) |
524 bootclasspath = gradle.get('bootclasspath') | 503 bootclasspath = gradle.get('bootclasspath') |
525 if bootclasspath: | 504 if bootclasspath: |
526 # Must use absolute path here. | 505 # Must use absolute path here. |
527 variables['bootclasspath'] = _RebasePath(bootclasspath) | 506 variables['bootclasspath'] = _RebasePath(bootclasspath) |
528 if entry.android_test_entry: | 507 if entry.android_test_entry: |
529 variables['android_test'] = generator.Generate( | 508 variables['android_test'] = generator.Generate( |
530 entry.android_test_entry) | 509 entry.android_test_entry) |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
730 | 709 |
731 if generated_inputs: | 710 if generated_inputs: |
732 logging.warning('Building generated source files...') | 711 logging.warning('Building generated source files...') |
733 targets = _RebasePath(generated_inputs, output_dir) | 712 targets = _RebasePath(generated_inputs, output_dir) |
734 _RunNinja(output_dir, targets) | 713 _RunNinja(output_dir, targets) |
735 | 714 |
736 if zip_tuples: | 715 if zip_tuples: |
737 _ExtractZips(generator.project_dir, zip_tuples) | 716 _ExtractZips(generator.project_dir, zip_tuples) |
738 | 717 |
739 logging.warning('Project created! (%d subprojects)', len(project_entries)) | 718 logging.warning('Project created! (%d subprojects)', len(project_entries)) |
740 logging.warning('Generated projects work best with Android Studio 2.2') | 719 logging.warning('Generated projects are targeting Android Studio 2.3') |
741 logging.warning('For more tips: https://chromium.googlesource.com/chromium' | 720 logging.warning('For more tips: https://chromium.googlesource.com/chromium' |
742 '/src.git/+/master/docs/android_studio.md') | 721 '/src.git/+/master/docs/android_studio.md') |
743 | 722 |
744 | 723 |
745 if __name__ == '__main__': | 724 if __name__ == '__main__': |
746 main() | 725 main() |
OLD | NEW |