Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Side by Side Diff: build/android/gradle/generate_gradle.py

Issue 2508553002: generate_gradle.py: Add support for junit and java_binary targets (Closed)
Patch Set: update docs/android_studio.md to no long say junit doesn't work Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/android/gradle/build.gradle.jinja ('k') | build/android/gyp/write_build_config.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 18 matching lines...) Expand all
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 _JINJA_TEMPLATE_PATH = os.path.join( 32 _JINJA_TEMPLATE_PATH = os.path.join(
33 os.path.dirname(__file__), 'build.gradle.jinja') 33 os.path.dirname(__file__), 'build.gradle.jinja')
34 34
35 _JAVA_SUBDIR = 'symlinked-java' 35 _JAVA_SUBDIR = 'symlinked-java'
36 _SRCJARS_SUBDIR = 'extracted-srcjars' 36 _SRCJARS_SUBDIR = 'extracted-srcjars'
37 37
38 _DEFAULT_TARGETS = [ 38 _DEFAULT_TARGETS = [
39 '//android_webview:system_webview_apk', 39 # TODO(agrieve): Requires alternate android.jar to compile.
40 # '//android_webview:system_webview_apk',
40 '//android_webview/test:android_webview_apk', 41 '//android_webview/test:android_webview_apk',
41 '//android_webview/test:android_webview_test_apk', 42 '//android_webview/test:android_webview_test_apk',
43 '//base:base_junit_tests',
44 '//chrome/android:chrome_junit_tests',
42 '//chrome/android:chrome_public_apk', 45 '//chrome/android:chrome_public_apk',
43 '//chrome/android:chrome_public_test_apk', 46 '//chrome/android:chrome_public_test_apk',
44 '//chrome/android:chrome_sync_shell_apk', 47 '//chrome/android:chrome_sync_shell_apk',
45 '//chrome/android:chrome_sync_shell_test_apk', 48 '//chrome/android:chrome_sync_shell_test_apk',
49 '//content/public/android:content_junit_tests',
50 '//content/shell/android:content_shell_apk',
46 ] 51 ]
47 52
48 def _RebasePath(path_or_list, new_cwd=None, old_cwd=None): 53 def _RebasePath(path_or_list, new_cwd=None, old_cwd=None):
49 """Makes the given path(s) relative to new_cwd, or absolute if not specified. 54 """Makes the given path(s) relative to new_cwd, or absolute if not specified.
50 55
51 If new_cwd is not specified, absolute paths are returned. 56 If new_cwd is not specified, absolute paths are returned.
52 If old_cwd is not specified, constants.GetOutDirectory() is assumed. 57 If old_cwd is not specified, constants.GetOutDirectory() is assumed.
53 """ 58 """
54 if not isinstance(path_or_list, basestring): 59 if not isinstance(path_or_list, basestring):
55 return [_RebasePath(p, new_cwd, old_cwd) for p in path_or_list] 60 return [_RebasePath(p, new_cwd, old_cwd) for p in path_or_list]
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 """Returns the target type from its .build_config.""" 163 """Returns the target type from its .build_config."""
159 return self.BuildConfig()['deps_info']['type'] 164 return self.BuildConfig()['deps_info']['type']
160 165
161 166
162 def _ComputeJavaSourceDirs(java_files): 167 def _ComputeJavaSourceDirs(java_files):
163 """Returns the list of source directories for the given files.""" 168 """Returns the list of source directories for the given files."""
164 found_roots = set() 169 found_roots = set()
165 for path in java_files: 170 for path in java_files:
166 path_root = path 171 path_root = path
167 # Recognize these tokens as top-level. 172 # Recognize these tokens as top-level.
168 while os.path.basename(path_root) not in ('javax', 'org', 'com', 'src'): 173 while True:
169 assert path_root, 'Failed to find source dir for ' + path
170 path_root = os.path.dirname(path_root) 174 path_root = os.path.dirname(path_root)
171 # Assume that if we've hit "src", the we're at the root. 175 basename = os.path.basename(path_root)
172 if os.path.basename(path_root) != 'src': 176 assert basename, 'Failed to find source dir for ' + path
173 path_root = os.path.dirname(path_root) 177 if basename in ('java', 'src'):
178 break
179 if basename in ('javax', 'org', 'com'):
180 path_root = os.path.dirname(path_root)
181 break
174 found_roots.add(path_root) 182 found_roots.add(path_root)
175 return list(found_roots) 183 return list(found_roots)
176 184
177 185
178 def _CreateSymlinkTree(entry_output_dir, symlink_dir, desired_files, 186 def _CreateSymlinkTree(entry_output_dir, symlink_dir, desired_files,
179 parent_dirs): 187 parent_dirs):
180 """Creates a directory tree of symlinks to the given files. 188 """Creates a directory tree of symlinks to the given files.
181 189
182 The idea here is to replicate a directory tree while leaving out files within 190 The idea here is to replicate a directory tree while leaving out files within
183 it not listed by |desired_files|. 191 it not listed by |desired_files|.
184 """ 192 """
185 assert _IsSubpathOf(symlink_dir, entry_output_dir) 193 assert _IsSubpathOf(symlink_dir, entry_output_dir)
186 if os.path.exists(symlink_dir):
187 shutil.rmtree(symlink_dir)
188 194
189 for target_path in desired_files: 195 for target_path in desired_files:
190 prefix = next(d for d in parent_dirs if target_path.startswith(d)) 196 prefix = next(d for d in parent_dirs if target_path.startswith(d))
191 subpath = os.path.relpath(target_path, prefix) 197 subpath = os.path.relpath(target_path, prefix)
192 symlinked_path = os.path.join(symlink_dir, subpath) 198 symlinked_path = os.path.join(symlink_dir, subpath)
193 symlinked_dir = os.path.dirname(symlinked_path) 199 symlinked_dir = os.path.dirname(symlinked_path)
194 if not os.path.exists(symlinked_dir): 200 if not os.path.exists(symlinked_dir):
195 os.makedirs(symlinked_dir) 201 os.makedirs(symlinked_dir)
196 relpath = os.path.relpath(target_path, symlinked_dir) 202 relpath = os.path.relpath(target_path, symlinked_dir)
197 logging.debug('Creating symlink %s -> %s', symlinked_path, relpath) 203 logging.debug('Creating symlink %s -> %s', symlinked_path, relpath)
(...skipping 13 matching lines...) Expand all
211 if java_files: 217 if java_files:
212 java_files = _RebasePath(java_files) 218 java_files = _RebasePath(java_files)
213 java_dirs = _ComputeJavaSourceDirs(java_files) 219 java_dirs = _ComputeJavaSourceDirs(java_files)
214 220
215 found_java_files = build_utils.FindInDirectories(java_dirs, '*.java') 221 found_java_files = build_utils.FindInDirectories(java_dirs, '*.java')
216 unwanted_java_files = set(found_java_files) - set(java_files) 222 unwanted_java_files = set(found_java_files) - set(java_files)
217 missing_java_files = set(java_files) - set(found_java_files) 223 missing_java_files = set(java_files) - set(found_java_files)
218 # Warn only about non-generated files that are missing. 224 # Warn only about non-generated files that are missing.
219 missing_java_files = [p for p in missing_java_files 225 missing_java_files = [p for p in missing_java_files
220 if not p.startswith(output_dir)] 226 if not p.startswith(output_dir)]
227
228 symlink_dir = os.path.join(entry_output_dir, _JAVA_SUBDIR)
229 shutil.rmtree(symlink_dir, True)
230
221 if unwanted_java_files: 231 if unwanted_java_files:
222 logging.debug('Target requires .java symlinks: %s', entry_output_dir) 232 logging.debug('Target requires .java symlinks: %s', entry_output_dir)
223 symlink_dir = os.path.join(entry_output_dir, _JAVA_SUBDIR)
224 _CreateSymlinkTree(entry_output_dir, symlink_dir, java_files, java_dirs) 233 _CreateSymlinkTree(entry_output_dir, symlink_dir, java_files, java_dirs)
225 java_dirs = [symlink_dir] 234 java_dirs = [symlink_dir]
226 235
227 if missing_java_files: 236 if missing_java_files:
228 logging.warning('Some java files were not found: %s', missing_java_files) 237 logging.warning('Some java files were not found: %s', missing_java_files)
229 238
230 return java_dirs 239 return java_dirs
231 240
232 241
233 def _GenerateLocalProperties(sdk_dir): 242 def _GenerateLocalProperties(sdk_dir):
234 """Returns the data for project.properties as a string.""" 243 """Returns the data for project.properties as a string."""
235 return '\n'.join([ 244 return '\n'.join([
236 '# Generated by //build/android/gradle/generate_gradle.py', 245 '# Generated by //build/android/gradle/generate_gradle.py',
237 'sdk.dir=%s' % sdk_dir, 246 'sdk.dir=%s' % sdk_dir,
238 '']) 247 ''])
239 248
240 249
241 def _GenerateGradleFile(build_config, build_vars, java_dirs, relativize, 250 def _GenerateGradleFile(build_config, build_vars, java_dirs, relativize,
242 use_gradle_process_resources, jinja_processor): 251 use_gradle_process_resources, jinja_processor):
243 """Returns the data for a project's build.gradle.""" 252 """Returns the data for a project's build.gradle."""
244 deps_info = build_config['deps_info'] 253 deps_info = build_config['deps_info']
245 gradle = build_config['gradle'] 254 gradle = build_config['gradle']
246 255
256 variables = {
257 'sourceSetName': 'main',
258 'depCompileName': 'compile',
259 }
247 if deps_info['type'] == 'android_apk': 260 if deps_info['type'] == 'android_apk':
248 target_type = 'android_apk' 261 target_type = 'android_apk'
249 elif deps_info['type'] == 'java_library' and not deps_info['is_prebuilt']: 262 elif deps_info['type'] == 'java_library':
263 if deps_info['is_prebuilt'] or deps_info['gradle_treat_as_prebuilt']:
264 return None
265
250 if deps_info['requires_android']: 266 if deps_info['requires_android']:
251 target_type = 'android_library' 267 target_type = 'android_library'
252 else: 268 else:
253 target_type = 'java_library' 269 target_type = 'java_library'
270 elif deps_info['type'] == 'java_binary':
271 if gradle['main_class'] == 'org.chromium.testing.local.JunitTestMain':
272 target_type = 'android_junit'
273 variables['sourceSetName'] = 'test'
274 variables['depCompileName'] = 'testCompile'
275 else:
276 target_type = 'java_binary'
277 variables['main_class'] = gradle['main_class']
254 else: 278 else:
255 return None 279 return None
256 280
257 variables = {} 281 variables['target_name'] = os.path.splitext(deps_info['name'])[0]
258 variables['template_type'] = target_type 282 variables['template_type'] = target_type
259 variables['use_gradle_process_resources'] = use_gradle_process_resources 283 variables['use_gradle_process_resources'] = use_gradle_process_resources
260 variables['build_tools_version'] = ( 284 variables['build_tools_version'] = (
261 build_vars['android_sdk_build_tools_version']) 285 build_vars['android_sdk_build_tools_version'])
262 variables['compile_sdk_version'] = build_vars['android_sdk_version'] 286 variables['compile_sdk_version'] = build_vars['android_sdk_version']
263 android_manifest = gradle.get('android_manifest', 287 android_manifest = gradle.get('android_manifest',
264 _DEFAULT_ANDROID_MANIFEST_PATH) 288 _DEFAULT_ANDROID_MANIFEST_PATH)
265 variables['android_manifest'] = relativize(android_manifest) 289 variables['android_manifest'] = relativize(android_manifest)
266 variables['java_dirs'] = relativize(java_dirs) 290 variables['java_dirs'] = relativize(java_dirs)
291 # TODO(agrieve): Add an option to use interface jars and see if that speeds
292 # things up at all.
267 variables['prebuilts'] = relativize(gradle['dependent_prebuilt_jars']) 293 variables['prebuilts'] = relativize(gradle['dependent_prebuilt_jars'])
268 deps = [_ProjectEntry.FromBuildConfigPath(p) 294 deps = [_ProjectEntry.FromBuildConfigPath(p)
269 for p in gradle['dependent_android_projects']] 295 for p in gradle['dependent_android_projects']]
270 296
271 variables['android_project_deps'] = [d.ProjectName() for d in deps] 297 variables['android_project_deps'] = [d.ProjectName() for d in deps]
272 deps = [_ProjectEntry.FromBuildConfigPath(p) 298 deps = [_ProjectEntry.FromBuildConfigPath(p)
273 for p in gradle['dependent_java_projects']] 299 for p in gradle['dependent_java_projects']]
274 variables['java_project_deps'] = [d.ProjectName() for d in deps] 300 variables['java_project_deps'] = [d.ProjectName() for d in deps]
275 301
276 return jinja_processor.Render(_JINJA_TEMPLATE_PATH, variables) 302 return jinja_processor.Render(_JINJA_TEMPLATE_PATH, variables)
(...skipping 20 matching lines...) Expand all
297 lines.append('project(":%s").projectDir = new File(settingsDir, "%s")' % 323 lines.append('project(":%s").projectDir = new File(settingsDir, "%s")' %
298 (entry.ProjectName(), entry.GradleSubdir())) 324 (entry.ProjectName(), entry.GradleSubdir()))
299 return '\n'.join(lines) 325 return '\n'.join(lines)
300 326
301 327
302 def _ExtractSrcjars(entry_output_dir, srcjar_tuples): 328 def _ExtractSrcjars(entry_output_dir, srcjar_tuples):
303 """Extracts all srcjars to the directory given by the tuples.""" 329 """Extracts all srcjars to the directory given by the tuples."""
304 extracted_paths = set(s[1] for s in srcjar_tuples) 330 extracted_paths = set(s[1] for s in srcjar_tuples)
305 for extracted_path in extracted_paths: 331 for extracted_path in extracted_paths:
306 assert _IsSubpathOf(extracted_path, entry_output_dir) 332 assert _IsSubpathOf(extracted_path, entry_output_dir)
307 if os.path.exists(extracted_path): 333 shutil.rmtree(extracted_path, True)
308 shutil.rmtree(extracted_path)
309 334
310 for srcjar_path, extracted_path in srcjar_tuples: 335 for srcjar_path, extracted_path in srcjar_tuples:
311 logging.info('Extracting %s to %s', srcjar_path, extracted_path) 336 logging.info('Extracting %s to %s', srcjar_path, extracted_path)
312 with zipfile.ZipFile(srcjar_path) as z: 337 with zipfile.ZipFile(srcjar_path) as z:
313 z.extractall(extracted_path) 338 z.extractall(extracted_path)
314 339
315 340
316 def _FindAllProjectEntries(main_entries): 341 def _FindAllProjectEntries(main_entries):
317 """Returns the list of all _ProjectEntry instances given the root project.""" 342 """Returns the list of all _ProjectEntry instances given the root project."""
318 found = set() 343 found = set()
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 if args.all: 393 if args.all:
369 # Run GN gen if necessary (faster than running "gn gen" in the no-op case). 394 # Run GN gen if necessary (faster than running "gn gen" in the no-op case).
370 _RunNinja(output_dir, ['build.ninja']) 395 _RunNinja(output_dir, ['build.ninja'])
371 # Query ninja for all __build_config targets. 396 # Query ninja for all __build_config targets.
372 targets = _QueryForAllGnTargets(output_dir) 397 targets = _QueryForAllGnTargets(output_dir)
373 else: 398 else:
374 targets = args.targets or _DEFAULT_TARGETS 399 targets = args.targets or _DEFAULT_TARGETS
375 # TODO(agrieve): See if it makes sense to utilize Gradle's test constructs 400 # TODO(agrieve): See if it makes sense to utilize Gradle's test constructs
376 # for our instrumentation tests. 401 # for our instrumentation tests.
377 targets = [re.sub(r'_test_apk$', '_test_apk__apk', t) for t in targets] 402 targets = [re.sub(r'_test_apk$', '_test_apk__apk', t) for t in targets]
403 targets = [re.sub(r'_junit_tests$', '_junit_tests__java_binary', t)
404 for t in targets]
378 405
379 main_entries = [_ProjectEntry(t) for t in targets] 406 main_entries = [_ProjectEntry(t) for t in targets]
380 407
381 logging.warning('Building .build_config files...') 408 logging.warning('Building .build_config files...')
382 _RunNinja(output_dir, [e.NinjaBuildConfigTarget() for e in main_entries]) 409 _RunNinja(output_dir, [e.NinjaBuildConfigTarget() for e in main_entries])
383 410
384 # There are many unused libraries, so restrict to those that are actually used 411 # There are many unused libraries, so restrict to those that are actually used
385 # when using --all. 412 # when using --all.
386 if args.all: 413 if args.all:
387 main_entries = [e for e in main_entries if e.GetType() == 'android_apk'] 414 main_entries = [e for e in main_entries if e.GetType() == 'android_apk']
388 415
389 all_entries = _FindAllProjectEntries(main_entries) 416 all_entries = _FindAllProjectEntries(main_entries)
390 logging.info('Found %d dependent build_config targets.', len(all_entries)) 417 logging.info('Found %d dependent build_config targets.', len(all_entries))
391 418
392 logging.warning('Writing .gradle files...') 419 logging.warning('Writing .gradle files...')
393 jinja_processor = jinja_template.JinjaProcessor(host_paths.DIR_SOURCE_ROOT) 420 jinja_processor = jinja_template.JinjaProcessor(host_paths.DIR_SOURCE_ROOT)
394 build_vars = _ReadBuildVars(output_dir) 421 build_vars = _ReadBuildVars(output_dir)
395 project_entries = [] 422 project_entries = []
396 srcjar_tuples = [] 423 srcjar_tuples = []
397 generated_inputs = [] 424 generated_inputs = []
398 for entry in all_entries: 425 for entry in all_entries:
399 if entry.GetType() not in ('android_apk', 'java_library'): 426 if entry.GetType() not in ('android_apk', 'java_library', 'java_binary'):
400 continue 427 continue
401 428
402 entry_output_dir = os.path.join(gradle_output_dir, entry.GradleSubdir()) 429 entry_output_dir = os.path.join(gradle_output_dir, entry.GradleSubdir())
403 relativize = lambda x, d=entry_output_dir: _RebasePath(x, d) 430 relativize = lambda x, d=entry_output_dir: _RebasePath(x, d)
404 build_config = entry.BuildConfig() 431 build_config = entry.BuildConfig()
405 432
406 srcjars = _RebasePath(build_config['gradle'].get('bundled_srcjars', [])) 433 srcjars = _RebasePath(build_config['gradle'].get('bundled_srcjars', []))
407 if not args.use_gradle_process_resources: 434 if not args.use_gradle_process_resources:
408 srcjars += _RebasePath(build_config['javac']['srcjars']) 435 srcjars += _RebasePath(build_config['javac']['srcjars'])
409 436
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 _ExtractSrcjars(gradle_output_dir, srcjar_tuples) 477 _ExtractSrcjars(gradle_output_dir, srcjar_tuples)
451 478
452 logging.warning('Project created! (%d subprojects)', len(project_entries)) 479 logging.warning('Project created! (%d subprojects)', len(project_entries))
453 logging.warning('Generated projects work best with Android Studio 2.2') 480 logging.warning('Generated projects work best with Android Studio 2.2')
454 logging.warning('For more tips: https://chromium.googlesource.com/chromium' 481 logging.warning('For more tips: https://chromium.googlesource.com/chromium'
455 '/src.git/+/master/docs/android_studio.md') 482 '/src.git/+/master/docs/android_studio.md')
456 483
457 484
458 if __name__ == '__main__': 485 if __name__ == '__main__':
459 main() 486 main()
OLDNEW
« no previous file with comments | « build/android/gradle/build.gradle.jinja ('k') | build/android/gyp/write_build_config.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698