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 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) |
| 20 import devil_chromium | 21 import devil_chromium |
| 21 from devil.utils import run_tests_helper | 22 from devil.utils import run_tests_helper |
| 22 from pylib import constants | 23 from pylib import constants |
| 23 from pylib.constants import host_paths | 24 from pylib.constants import host_paths |
| 24 | 25 |
| 25 sys.path.append(os.path.join(_BUILD_ANDROID, 'gyp')) | 26 sys.path.append(os.path.join(_BUILD_ANDROID, 'gyp')) |
| 26 import jinja_template | 27 import jinja_template |
| 27 from util import build_utils | 28 from util import build_utils |
| 28 | 29 |
| 29 | 30 |
| 30 _DEFAULT_ANDROID_MANIFEST_PATH = os.path.join( | 31 _DEFAULT_ANDROID_MANIFEST_PATH = os.path.join( |
| 31 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml') | 32 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml') |
| 32 _FILE_DIR = os.path.dirname(__file__) | 33 _FILE_DIR = os.path.dirname(__file__) |
| 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 | 37 |
| 38 _DEFAULT_TARGETS = [ | 38 _DEFAULT_TARGETS = [ |
| 39 # TODO(agrieve): Requires alternate android.jar to compile. | 39 # TODO(agrieve): Requires alternate android.jar to compile. |
| 40 # '//android_webview:system_webview_apk', | 40 # '//android_webview:system_webview_apk', |
| 41 '//android_webview/test:android_webview_apk', | 41 '//android_webview/test:android_webview_apk', |
| 42 '//android_webview/test:android_webview_test_apk', | 42 '//android_webview/test:android_webview_test_apk', |
| 43 '//base:base_junit_tests', | 43 '//base:base_junit_tests', |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 197 native_section = entry.BuildConfig().get('native') | 197 native_section = entry.BuildConfig().get('native') |
| 198 if native_section: | 198 if native_section: |
| 199 jni_libs = _CreateJniLibsDir( | 199 jni_libs = _CreateJniLibsDir( |
| 200 constants.GetOutDirectory(), self.EntryOutputDir(entry), | 200 constants.GetOutDirectory(), self.EntryOutputDir(entry), |
| 201 native_section.get('libraries')) | 201 native_section.get('libraries')) |
| 202 else: | 202 else: |
| 203 jni_libs = [] | 203 jni_libs = [] |
| 204 return jni_libs | 204 return jni_libs |
| 205 | 205 |
| 206 def _GenJavaDirs(self, entry): | 206 def _GenJavaDirs(self, entry): |
| 207 java_dirs = _CreateJavaSourceDir( | 207 java_dirs, excludes = _CreateJavaSourceDir( |
| 208 constants.GetOutDirectory(), self.EntryOutputDir(entry), | 208 constants.GetOutDirectory(), entry.JavaFiles()) |
| 209 entry.JavaFiles()) | |
| 210 if self.Srcjars(entry): | 209 if self.Srcjars(entry): |
| 211 java_dirs.append( | 210 java_dirs.append( |
| 212 os.path.join(self.EntryOutputDir(entry), _SRCJARS_SUBDIR)) | 211 os.path.join(self.EntryOutputDir(entry), _SRCJARS_SUBDIR)) |
| 213 return java_dirs | 212 return java_dirs, excludes |
| 214 | 213 |
| 215 def _Relativize(self, entry, paths): | 214 def _Relativize(self, entry, paths): |
| 216 return _RebasePath(paths, self.EntryOutputDir(entry)) | 215 return _RebasePath(paths, self.EntryOutputDir(entry)) |
| 217 | 216 |
| 218 def EntryOutputDir(self, entry): | 217 def EntryOutputDir(self, entry): |
| 219 return os.path.join(self.project_dir, entry.GradleSubdir()) | 218 return os.path.join(self.project_dir, entry.GradleSubdir()) |
| 220 | 219 |
| 221 def Srcjars(self, entry): | 220 def Srcjars(self, entry): |
| 222 srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', [])) | 221 srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', [])) |
| 223 if not self.use_gradle_process_resources: | 222 if not self.use_gradle_process_resources: |
| 224 srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars']) | 223 srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars']) |
| 225 return srcjars | 224 return srcjars |
| 226 | 225 |
| 227 def GeneratedInputs(self, entry): | 226 def GeneratedInputs(self, entry): |
| 228 generated_inputs = [] | 227 generated_inputs = [] |
| 229 generated_inputs.extend(self.Srcjars(entry)) | 228 generated_inputs.extend(self.Srcjars(entry)) |
| 230 generated_inputs.extend( | 229 generated_inputs.extend( |
| 231 p for p in entry.JavaFiles() if not p.startswith('..')) | 230 p for p in entry.JavaFiles() if not p.startswith('..')) |
| 232 generated_inputs.extend(entry.Gradle()['dependent_prebuilt_jars']) | 231 generated_inputs.extend(entry.Gradle()['dependent_prebuilt_jars']) |
| 233 return generated_inputs | 232 return generated_inputs |
| 234 | 233 |
| 235 def Generate(self, entry): | 234 def Generate(self, entry): |
| 236 variables = {} | 235 variables = {} |
| 237 android_test_manifest = entry.Gradle().get( | 236 android_test_manifest = entry.Gradle().get( |
| 238 'android_manifest', _DEFAULT_ANDROID_MANIFEST_PATH) | 237 'android_manifest', _DEFAULT_ANDROID_MANIFEST_PATH) |
| 239 variables['android_manifest'] = self._Relativize( | 238 variables['android_manifest'] = self._Relativize( |
| 240 entry, android_test_manifest) | 239 entry, android_test_manifest) |
| 241 variables['java_dirs'] = self._Relativize(entry, self._GenJavaDirs(entry)) | 240 java_dirs, excludes = self._GenJavaDirs(entry) |
| 241 variables['java_dirs'] = self._Relativize(entry, java_dirs) | |
| 242 variables['java_excludes'] = excludes | |
| 242 variables['jni_libs'] = self._Relativize(entry, self._GenJniLibs(entry)) | 243 variables['jni_libs'] = self._Relativize(entry, self._GenJniLibs(entry)) |
| 243 deps = [_ProjectEntry.FromBuildConfigPath(p) | 244 deps = [_ProjectEntry.FromBuildConfigPath(p) |
| 244 for p in entry.Gradle()['dependent_android_projects']] | 245 for p in entry.Gradle()['dependent_android_projects']] |
| 245 variables['android_project_deps'] = [d.ProjectName() for d in deps] | 246 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 | 247 # TODO(agrieve): Add an option to use interface jars and see if that speeds |
| 247 # things up at all. | 248 # things up at all. |
| 248 variables['prebuilts'] = self._Relativize( | 249 variables['prebuilts'] = self._Relativize( |
| 249 entry, entry.Gradle()['dependent_prebuilt_jars']) | 250 entry, entry.Gradle()['dependent_prebuilt_jars']) |
| 250 deps = [_ProjectEntry.FromBuildConfigPath(p) | 251 deps = [_ProjectEntry.FromBuildConfigPath(p) |
| 251 for p in entry.Gradle()['dependent_java_projects']] | 252 for p in entry.Gradle()['dependent_java_projects']] |
| 252 variables['java_project_deps'] = [d.ProjectName() for d in deps] | 253 variables['java_project_deps'] = [d.ProjectName() for d in deps] |
| 253 return variables | 254 return variables |
| 254 | 255 |
| 255 | 256 |
| 256 def _ComputeJavaSourceDirs(java_files): | 257 def _ComputeJavaSourceDirs(java_files): |
| 257 """Returns the list of source directories for the given files.""" | 258 """Returns a dictionary of source dirs with each given files in one.""" |
| 258 found_roots = set() | 259 found_roots = {} |
| 259 for path in java_files: | 260 for path in java_files: |
| 260 path_root = path | 261 path_root = path |
| 261 # Recognize these tokens as top-level. | 262 # Recognize these tokens as top-level. |
| 262 while True: | 263 while True: |
| 263 path_root = os.path.dirname(path_root) | 264 path_root = os.path.dirname(path_root) |
| 264 basename = os.path.basename(path_root) | 265 basename = os.path.basename(path_root) |
| 265 assert basename, 'Failed to find source dir for ' + path | 266 assert basename, 'Failed to find source dir for ' + path |
| 266 if basename in ('java', 'src'): | 267 if basename in ('java', 'src'): |
| 267 break | 268 break |
| 268 if basename in ('javax', 'org', 'com'): | 269 if basename in ('javax', 'org', 'com'): |
| 269 path_root = os.path.dirname(path_root) | 270 path_root = os.path.dirname(path_root) |
| 270 break | 271 break |
| 271 found_roots.add(path_root) | 272 if path_root not in found_roots: |
| 272 return list(found_roots) | 273 found_roots[path_root] = [] |
| 274 found_roots[path_root].append(path) | |
| 275 return found_roots | |
| 273 | 276 |
| 274 | 277 |
| 275 def _CreateRelativeSymlink(target_path, link_path): | 278 def _CreateRelativeSymlink(target_path, link_path): |
| 276 link_dir = os.path.dirname(link_path) | 279 link_dir = os.path.dirname(link_path) |
| 277 relpath = os.path.relpath(target_path, link_dir) | 280 relpath = os.path.relpath(target_path, link_dir) |
| 278 logging.debug('Creating symlink %s -> %s', link_path, relpath) | 281 logging.debug('Creating symlink %s -> %s', link_path, relpath) |
| 279 os.symlink(relpath, link_path) | 282 os.symlink(relpath, link_path) |
| 280 | 283 |
| 281 | 284 |
| 282 def _CreateSymlinkTree(entry_output_dir, symlink_dir, desired_files, | 285 def _CreateSymlinkTree(entry_output_dir, symlink_dir, desired_files, |
| 283 parent_dirs): | 286 parent_dirs): |
| 284 """Creates a directory tree of symlinks to the given files. | 287 """Creates a directory tree of symlinks to the given files. |
| 285 | 288 |
| 286 The idea here is to replicate a directory tree while leaving out files within | 289 The idea here is to replicate a directory tree while leaving out files within |
| 287 it not listed by |desired_files|. | 290 it not listed by |desired_files|. |
| 288 """ | 291 """ |
| 289 assert _IsSubpathOf(symlink_dir, entry_output_dir) | 292 assert _IsSubpathOf(symlink_dir, entry_output_dir) |
| 290 | 293 |
| 291 for target_path in desired_files: | 294 for target_path in desired_files: |
| 292 prefix = next(d for d in parent_dirs if target_path.startswith(d)) | 295 prefix = next(d for d in parent_dirs if target_path.startswith(d)) |
| 293 subpath = os.path.relpath(target_path, prefix) | 296 subpath = os.path.relpath(target_path, prefix) |
| 294 symlinked_path = os.path.join(symlink_dir, subpath) | 297 symlinked_path = os.path.join(symlink_dir, subpath) |
| 295 symlinked_dir = os.path.dirname(symlinked_path) | 298 symlinked_dir = os.path.dirname(symlinked_path) |
| 296 if not os.path.exists(symlinked_dir): | 299 if not os.path.exists(symlinked_dir): |
| 297 os.makedirs(symlinked_dir) | 300 os.makedirs(symlinked_dir) |
| 298 _CreateRelativeSymlink(target_path, symlinked_path) | 301 _CreateRelativeSymlink(target_path, symlinked_path) |
| 299 | 302 |
| 300 | 303 |
| 301 def _CreateJavaSourceDir(output_dir, entry_output_dir, java_files): | 304 def _CreateJavaSourceDir(output_dir, java_files): |
| 302 """Computes and constructs when necessary the list of java source directories. | 305 """Computes the list of java source directories and exclude patterns. |
| 303 | 306 |
| 304 1. Computes the root java source directories from the list of files. | 307 1. Computes the root java source directories from the list of files. |
| 305 2. Determines whether there are any .java files in them that are not included | 308 2. Compute exclude patterns that exclude all extra files only. |
| 306 in |java_files|. | 309 3. Returns the list of java source directories and exclude patterns. |
| 307 3. If not, returns the list of java source directories. If so, constructs a | |
| 308 tree of symlinks within |entry_output_dir| of all files in |java_files|. | |
| 309 """ | 310 """ |
| 310 java_dirs = [] | 311 java_dirs = [] |
| 312 excludes = [] | |
| 311 if java_files: | 313 if java_files: |
| 312 java_files = _RebasePath(java_files) | 314 java_files = _RebasePath(java_files) |
| 313 java_dirs = _ComputeJavaSourceDirs(java_files) | 315 computed_dirs = _ComputeJavaSourceDirs(java_files) |
| 316 java_dirs = computed_dirs.keys() | |
| 317 all_found_java_files = set() | |
| 314 | 318 |
| 315 found_java_files = build_utils.FindInDirectories(java_dirs, '*.java') | 319 for directory, files in computed_dirs.iteritems(): |
| 316 unwanted_java_files = set(found_java_files) - set(java_files) | 320 found_java_files = build_utils.FindInDirectory(directory, '*.java') |
| 317 missing_java_files = set(java_files) - set(found_java_files) | 321 all_found_java_files.update(found_java_files) |
| 322 unwanted_java_files = set(found_java_files) - set(files) | |
| 323 | |
| 324 if unwanted_java_files: | |
| 325 logging.debug('Target requires .java symlinks: %s, %s', | |
|
agrieve
2017/02/09 10:00:38
nit: update log message to not say symlinks
Peter Wen
2017/02/09 14:38:28
Done.
| |
| 326 directory, files) | |
| 327 # Shorten exclude list by globbing if possible. | |
|
agrieve
2017/02/09 10:00:38
Might be worth pulling this out into a helper func
Peter Wen
2017/02/09 14:38:28
Done.
| |
| 328 while unwanted_java_files: | |
| 329 unwanted_file = unwanted_java_files.pop() | |
| 330 target_exclude = os.path.join( | |
| 331 os.path.dirname(unwanted_file), '*.java') | |
| 332 found_files = glob.glob(target_exclude) | |
| 333 valid_files = set(found_files) & set(files) | |
| 334 if valid_files: | |
| 335 excludes.append(os.path.relpath(unwanted_file, directory)) | |
| 336 else: | |
| 337 excludes.append(os.path.relpath(target_exclude, directory)) | |
| 338 unwanted_java_files -= set(found_files) | |
|
agrieve
2017/02/09 10:00:38
you convert found_files to a set twice. Maybe just
Peter Wen
2017/02/09 14:38:28
Done.
| |
| 339 | |
| 340 missing_java_files = set(java_files) - set(all_found_java_files) | |
| 318 # Warn only about non-generated files that are missing. | 341 # Warn only about non-generated files that are missing. |
| 319 missing_java_files = [p for p in missing_java_files | 342 missing_java_files = [p for p in missing_java_files |
| 320 if not p.startswith(output_dir)] | 343 if not p.startswith(output_dir)] |
| 344 if missing_java_files: | |
| 345 logging.warning( | |
| 346 'Some java files were not found: %s', missing_java_files) | |
| 321 | 347 |
| 322 symlink_dir = os.path.join(entry_output_dir, _JAVA_SUBDIR) | 348 return java_dirs, excludes |
| 323 shutil.rmtree(symlink_dir, True) | |
| 324 | |
| 325 if unwanted_java_files: | |
| 326 logging.debug('Target requires .java symlinks: %s', entry_output_dir) | |
| 327 _CreateSymlinkTree(entry_output_dir, symlink_dir, java_files, java_dirs) | |
| 328 java_dirs = [symlink_dir] | |
| 329 | |
| 330 if missing_java_files: | |
| 331 logging.warning('Some java files were not found: %s', missing_java_files) | |
| 332 | |
| 333 return java_dirs | |
| 334 | 349 |
| 335 | 350 |
| 336 def _CreateJniLibsDir(output_dir, entry_output_dir, so_files): | 351 def _CreateJniLibsDir(output_dir, entry_output_dir, so_files): |
| 337 """Creates directory with symlinked .so files if necessary. | 352 """Creates directory with symlinked .so files if necessary. |
| 338 | 353 |
| 339 Returns list of JNI libs directories.""" | 354 Returns list of JNI libs directories.""" |
| 340 | 355 |
| 341 if so_files: | 356 if so_files: |
| 342 symlink_dir = os.path.join(entry_output_dir, _JNI_LIBS_SUBDIR) | 357 symlink_dir = os.path.join(entry_output_dir, _JNI_LIBS_SUBDIR) |
| 343 shutil.rmtree(symlink_dir, True) | 358 shutil.rmtree(symlink_dir, True) |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 590 _ExtractSrcjars(generator.project_dir, srcjar_tuples) | 605 _ExtractSrcjars(generator.project_dir, srcjar_tuples) |
| 591 | 606 |
| 592 logging.warning('Project created! (%d subprojects)', len(project_entries)) | 607 logging.warning('Project created! (%d subprojects)', len(project_entries)) |
| 593 logging.warning('Generated projects work best with Android Studio 2.2') | 608 logging.warning('Generated projects work best with Android Studio 2.2') |
| 594 logging.warning('For more tips: https://chromium.googlesource.com/chromium' | 609 logging.warning('For more tips: https://chromium.googlesource.com/chromium' |
| 595 '/src.git/+/master/docs/android_studio.md') | 610 '/src.git/+/master/docs/android_studio.md') |
| 596 | 611 |
| 597 | 612 |
| 598 if __name__ == '__main__': | 613 if __name__ == '__main__': |
| 599 main() | 614 main() |
| OLD | NEW |