blob: 7bb1f8763cfe1a7c19d5cf8683aa06a8c17b52bc [file] [log] [blame]
Googler1a617332017-01-07 16:48:16 +00001# Copyright 2016 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Googler61bbde12017-02-02 18:53:08 +000015"""Implementation of IntelliJ-specific information collecting aspect."""
Googler1a617332017-01-07 16:48:16 +000016
17# Compile-time dependency attributes, grouped by type.
18DEPS = struct(
19 label = [
Googler1a617332017-01-07 16:48:16 +000020 "_cc_toolchain", # From C rules
Googler1a617332017-01-07 16:48:16 +000021 "_java_toolchain", # From java rules
Googler1a617332017-01-07 16:48:16 +000022 ],
23 label_list = [
24 "deps",
25 "exports",
26 "_robolectric", # From android_robolectric_test
27 ],
28)
29
30# Run-time dependency attributes, grouped by type.
31RUNTIME_DEPS = struct(
32 label = [],
33 label_list = [
34 "runtime_deps",
35 ],
36)
37
Googlercf6e1732017-01-08 18:14:12 +000038PREREQUISITE_DEPS = struct(
39 label = [],
40 label_list = [],
Googler1a617332017-01-07 16:48:16 +000041)
42
Googler1a617332017-01-07 16:48:16 +000043##### Helpers
44
45def struct_omit_none(**kwargs):
Googler61bbde12017-02-02 18:53:08 +000046 """A replacement for standard `struct` function that omits the fields with None value."""
47 d = {name: kwargs[name] for name in kwargs if kwargs[name] != None}
48 return struct(**d)
Googler1a617332017-01-07 16:48:16 +000049
Googler61bbde12017-02-02 18:53:08 +000050def artifact_location(f):
Googler1a617332017-01-07 16:48:16 +000051 """Creates an ArtifactLocation proto from a File."""
Googler61bbde12017-02-02 18:53:08 +000052 if f == None:
Googler1a617332017-01-07 16:48:16 +000053 return None
54
55 return struct_omit_none(
Googler61bbde12017-02-02 18:53:08 +000056 relative_path = get_relative_path(f),
57 is_source = f.is_source,
58 is_external = is_external(f.owner),
59 root_execution_path_fragment = f.root.path if not f.is_source else None,
Googler1a617332017-01-07 16:48:16 +000060 )
61
62def is_external(label):
63 """Determines whether a label corresponds to an external artifact."""
64 return label.workspace_root.startswith("external")
65
66def get_relative_path(artifact):
67 """A temporary workaround to find the root-relative path from an artifact.
68
69 This is required because 'short_path' is incorrect for external source artifacts.
70
71 Args:
72 artifact: the input artifact
73 Returns:
74 string: the root-relative path for this artifact.
75 """
76 # TODO(bazel-team): remove this workaround when Artifact::short_path is fixed.
77 if artifact.is_source and is_external(artifact.owner) and artifact.short_path.startswith(".."):
78 # short_path is '../repo_name/path', we want 'external/repo_name/path'
79 return "external" + artifact.short_path[2:]
80 return artifact.short_path
81
82def source_directory_tuple(resource_file):
83 """Creates a tuple of (source directory, is_source, root execution path)."""
84 return (
85 str(android_common.resource_source_directory(resource_file)),
86 resource_file.is_source,
87 resource_file.root.path if not resource_file.is_source else None
88 )
89
90def all_unique_source_directories(resources):
Googler61bbde12017-02-02 18:53:08 +000091 """Builds a list of unique ArtifactLocation protos."""
Googler1a617332017-01-07 16:48:16 +000092 # Sets can contain tuples, but cannot contain structs.
93 # Use set of tuples to unquify source directories.
Googler61bbde12017-02-02 18:53:08 +000094 source_directory_tuples = set([source_directory_tuple(f) for f in resources])
Googler1a617332017-01-07 16:48:16 +000095 return [struct_omit_none(relative_path = relative_path,
96 is_source = is_source,
97 root_execution_path_fragment = root_execution_path_fragment)
98 for (relative_path, is_source, root_execution_path_fragment) in source_directory_tuples]
99
100def build_file_artifact_location(ctx):
101 """Creates an ArtifactLocation proto representing a location of a given BUILD file."""
102 return struct(
103 relative_path = ctx.build_file_path,
104 is_source = True,
105 is_external = is_external(ctx.label)
106 )
107
108def library_artifact(java_output):
109 """Creates a LibraryArtifact representing a given java_output."""
110 if java_output == None or java_output.class_jar == None:
111 return None
112 return struct_omit_none(
Googler61bbde12017-02-02 18:53:08 +0000113 jar = artifact_location(java_output.class_jar),
114 interface_jar = artifact_location(java_output.ijar),
115 source_jar = artifact_location(java_output.source_jar),
Googler1a617332017-01-07 16:48:16 +0000116 )
117
118def annotation_processing_jars(annotation_processing):
119 """Creates a LibraryArtifact representing Java annotation processing jars."""
120 return struct_omit_none(
Googler61bbde12017-02-02 18:53:08 +0000121 jar = artifact_location(annotation_processing.class_jar),
122 source_jar = artifact_location(annotation_processing.source_jar),
Googler1a617332017-01-07 16:48:16 +0000123 )
124
125def jars_from_output(output):
126 """Collect jars for intellij-resolve-files from Java output."""
127 if output == None:
128 return []
129 return [jar
130 for jar in [output.class_jar, output.ijar, output.source_jar]
131 if jar != None and not jar.is_source]
132
133# TODO(salguarnieri) Remove once skylark provides the path safe string from a PathFragment.
Googler61bbde12017-02-02 18:53:08 +0000134def replace_empty_path_with_dot(path):
135 return path or "."
Googler1a617332017-01-07 16:48:16 +0000136
Googler61bbde12017-02-02 18:53:08 +0000137def sources_from_target(ctx):
138 """Get the list of sources from a target as artifact locations."""
Googler1a617332017-01-07 16:48:16 +0000139
Googler61bbde12017-02-02 18:53:08 +0000140 if hasattr(ctx.rule.attr, "srcs"):
141 return [artifact_location(f)
142 for src in ctx.rule.attr.srcs
143 for f in src.files]
Googler1a617332017-01-07 16:48:16 +0000144 return []
145
146def collect_targets_from_attrs(rule_attrs, attrs):
147 """Returns a list of targets from the given attributes."""
148 list_deps = [dep for attr_name in attrs.label_list
149 if hasattr(rule_attrs, attr_name)
150 for dep in getattr(rule_attrs, attr_name)]
151
152 scalar_deps = [getattr(rule_attrs, attr_name) for attr_name in attrs.label
153 if hasattr(rule_attrs, attr_name)]
154
155 return [dep for dep in (list_deps + scalar_deps) if is_valid_aspect_target(dep)]
156
157def collect_transitive_exports(targets):
158 """Build a union of all export dependencies."""
159 result = set()
160 for dep in targets:
Googler8febdbc2017-02-01 21:04:25 +0000161 result = result | dep.intellij_info.export_deps
Googler1a617332017-01-07 16:48:16 +0000162 return result
163
Googler1a617332017-01-07 16:48:16 +0000164def targets_to_labels(targets):
165 """Returns a set of label strings for the given targets."""
166 return set([str(target.label) for target in targets])
167
168def list_omit_none(value):
169 """Returns a list of the value, or the empty list if None."""
170 return [value] if value else []
171
172def is_valid_aspect_target(target):
173 """Returns whether the target has had the aspect run on it."""
Googler8febdbc2017-02-01 21:04:25 +0000174 return hasattr(target, "intellij_info")
Googler1a617332017-01-07 16:48:16 +0000175
Googler1a617332017-01-07 16:48:16 +0000176##### Builders for individual parts of the aspect output
177
178def build_py_ide_info(target, ctx):
Googler61bbde12017-02-02 18:53:08 +0000179 """Build PyIdeInfo."""
Googler1a617332017-01-07 16:48:16 +0000180 if not hasattr(target, "py"):
181 return (None, set())
182
183 sources = sources_from_target(ctx)
184 transitive_sources = target.py.transitive_sources
185
186 py_ide_info = struct_omit_none(
187 sources = sources,
188 )
189 return (py_ide_info, transitive_sources)
190
191def build_c_ide_info(target, ctx):
Googler61bbde12017-02-02 18:53:08 +0000192 """Build CIdeInfo."""
Googler1a617332017-01-07 16:48:16 +0000193 if not hasattr(target, "cc"):
194 return (None, set())
195
196 sources = sources_from_target(ctx)
197
198 target_includes = []
199 if hasattr(ctx.rule.attr, "includes"):
200 target_includes = ctx.rule.attr.includes
201 target_defines = []
202 if hasattr(ctx.rule.attr, "defines"):
203 target_defines = ctx.rule.attr.defines
204 target_copts = []
205 if hasattr(ctx.rule.attr, "copts"):
206 target_copts = ctx.rule.attr.copts
207
208 cc_provider = target.cc
209
210 c_ide_info = struct_omit_none(
211 source = sources,
212 target_include = target_includes,
213 target_define = target_defines,
214 target_copt = target_copts,
215 transitive_include_directory = cc_provider.include_directories,
216 transitive_quote_include_directory = cc_provider.quote_include_directories,
217 transitive_define = cc_provider.defines,
218 transitive_system_include_directory = cc_provider.system_include_directories,
219 )
220 intellij_resolve_files = cc_provider.transitive_headers
221 return (c_ide_info, intellij_resolve_files)
222
Googler61bbde12017-02-02 18:53:08 +0000223def build_c_toolchain_ide_info(ctx):
224 """Build CToolchainIdeInfo."""
Googler1a617332017-01-07 16:48:16 +0000225
226 if ctx.rule.kind != "cc_toolchain":
227 return (None, set())
228
229 # This should exist because we requested it in our aspect definition.
230 cc_fragment = ctx.fragments.cpp
231
232 c_toolchain_ide_info = struct_omit_none(
233 target_name = cc_fragment.target_gnu_system_name,
234 base_compiler_option = cc_fragment.compiler_options(ctx.features),
235 c_option = cc_fragment.c_options,
236 cpp_option = cc_fragment.cxx_options(ctx.features),
237 link_option = cc_fragment.link_options,
238 unfiltered_compiler_option = cc_fragment.unfiltered_compiler_options(ctx.features),
239 preprocessor_executable = replace_empty_path_with_dot(
240 str(cc_fragment.preprocessor_executable)),
241 cpp_executable = str(cc_fragment.compiler_executable),
242 built_in_include_directory = [str(d)
243 for d in cc_fragment.built_in_include_directories],
244 )
245 return (c_toolchain_ide_info, set())
246
Googlercf6e1732017-01-08 18:14:12 +0000247def build_java_ide_info(target, ctx, semantics):
Googler61bbde12017-02-02 18:53:08 +0000248 """Build JavaIdeInfo."""
Googlercf6e1732017-01-08 18:14:12 +0000249 if not hasattr(target, "java"):
250 return (None, set(), set())
251
252 java_semantics = semantics.java if hasattr(semantics, "java") else None
253 if java_semantics and java_semantics.skip_target(target, ctx):
Googler1a617332017-01-07 16:48:16 +0000254 return (None, set(), set())
255
256 ide_info_files = set()
257 sources = sources_from_target(ctx)
258
259 jars = [library_artifact(output) for output in target.java.outputs.jars]
260 output_jars = [jar for output in target.java.outputs.jars for jar in jars_from_output(output)]
261 intellij_resolve_files = set(output_jars)
262
263 gen_jars = []
264 if target.java.annotation_processing and target.java.annotation_processing.enabled:
265 gen_jars = [annotation_processing_jars(target.java.annotation_processing)]
266 intellij_resolve_files = intellij_resolve_files | set([
267 jar for jar in [target.java.annotation_processing.class_jar,
268 target.java.annotation_processing.source_jar]
269 if jar != None and not jar.is_source])
270
271 jdeps = artifact_location(target.java.outputs.jdeps)
272
273 java_sources, gen_java_sources, srcjars = divide_java_sources(ctx)
274
Googlercf6e1732017-01-08 18:14:12 +0000275 if java_semantics:
276 srcjars = java_semantics.filter_source_jars(target, ctx, srcjars)
Googler1a617332017-01-07 16:48:16 +0000277
278 package_manifest = None
279 if java_sources:
280 package_manifest = build_java_package_manifest(ctx, target, java_sources, ".java-manifest")
281 ide_info_files = ide_info_files | set([package_manifest])
282
283 filtered_gen_jar = None
284 if java_sources and (gen_java_sources or srcjars):
285 filtered_gen_jar, filtered_gen_resolve_files = build_filtered_gen_jar(
286 ctx,
287 target,
288 gen_java_sources,
289 srcjars
290 )
291 intellij_resolve_files = intellij_resolve_files | filtered_gen_resolve_files
292
293 java_ide_info = struct_omit_none(
294 sources = sources,
295 jars = jars,
296 jdeps = jdeps,
297 generated_jars = gen_jars,
298 package_manifest = artifact_location(package_manifest),
299 filtered_gen_jar = filtered_gen_jar,
300 )
301 return (java_ide_info, ide_info_files, intellij_resolve_files)
302
303def build_java_package_manifest(ctx, target, source_files, suffix):
304 """Builds the java package manifest for the given source files."""
305 output = ctx.new_file(target.label.name + suffix)
306
307 args = []
308 args += ["--output_manifest", output.path]
309 args += ["--sources"]
310 args += [":".join([f.root.path + "," + f.short_path for f in source_files])]
311 argfile = ctx.new_file(ctx.configuration.bin_dir,
312 target.label.name + suffix + ".params")
313 ctx.file_action(output=argfile, content="\n".join(args))
314
315 ctx.action(
316 inputs = source_files + [argfile],
317 outputs = [output],
318 executable = ctx.executable._package_parser,
319 arguments = ["@" + argfile.path],
320 mnemonic = "JavaPackageManifest",
321 progress_message = "Parsing java package strings for " + str(target.label),
322 )
323 return output
324
325def build_filtered_gen_jar(ctx, target, gen_java_sources, srcjars):
326 """Filters the passed jar to contain only classes from the given manifest."""
327 jar_artifacts = []
328 source_jar_artifacts = []
329 for jar in target.java.outputs.jars:
330 if jar.ijar:
331 jar_artifacts.append(jar.ijar)
332 elif jar.class_jar:
333 jar_artifacts.append(jar.class_jar)
334 if jar.source_jar:
335 source_jar_artifacts.append(jar.source_jar)
336
337 filtered_jar = ctx.new_file(target.label.name + "-filtered-gen.jar")
338 filtered_source_jar = ctx.new_file(target.label.name + "-filtered-gen-src.jar")
339 args = []
340 args += ["--filter_jars"]
341 args += [":".join([jar.path for jar in jar_artifacts])]
342 args += ["--filter_source_jars"]
343 args += [":".join([jar.path for jar in source_jar_artifacts])]
344 args += ["--filtered_jar", filtered_jar.path]
345 args += ["--filtered_source_jar", filtered_source_jar.path]
346 if gen_java_sources:
347 args += ["--keep_java_files"]
348 args += [":".join([java_file.path for java_file in gen_java_sources])]
349 if srcjars:
350 args += ["--keep_source_jars"]
351 args += [":".join([source_jar.path for source_jar in srcjars])]
352 ctx.action(
353 inputs = jar_artifacts + source_jar_artifacts + gen_java_sources + srcjars,
354 outputs = [filtered_jar, filtered_source_jar],
355 executable = ctx.executable._jar_filter,
356 arguments = args,
357 mnemonic = "JarFilter",
358 progress_message = "Filtering generated code for " + str(target.label),
359 )
360 output_jar = struct(
361 jar=artifact_location(filtered_jar),
362 source_jar=artifact_location(filtered_source_jar),
363 )
364 intellij_resolve_files = set([filtered_jar, filtered_source_jar])
365 return output_jar, intellij_resolve_files
366
367def divide_java_sources(ctx):
368 """Divide sources into plain java, generated java, and srcjars."""
369
370 java_sources = []
371 gen_java_sources = []
372 srcjars = []
373 if hasattr(ctx.rule.attr, "srcs"):
374 srcs = ctx.rule.attr.srcs
375 for src in srcs:
376 for f in src.files:
377 if f.basename.endswith(".java"):
378 if f.is_source:
379 java_sources.append(f)
380 else:
381 gen_java_sources.append(f)
382 elif f.basename.endswith(".srcjar"):
383 srcjars.append(f)
384
385 return java_sources, gen_java_sources, srcjars
386
Googlercf6e1732017-01-08 18:14:12 +0000387def build_android_ide_info(target, ctx, semantics):
Googler61bbde12017-02-02 18:53:08 +0000388 """Build AndroidIdeInfo."""
Googler1a617332017-01-07 16:48:16 +0000389 if not hasattr(target, "android"):
390 return (None, set())
391
Googlercf6e1732017-01-08 18:14:12 +0000392 android_semantics = semantics.android if hasattr(semantics, "android") else None
393 extra_ide_info = android_semantics.extra_ide_info(target, ctx) if android_semantics else {}
394
Googler1a617332017-01-07 16:48:16 +0000395 android = target.android
396 android_ide_info = struct_omit_none(
397 java_package = android.java_package,
398 idl_import_root = android.idl.import_root if hasattr(android.idl, "import_root") else None,
399 manifest = artifact_location(android.manifest),
400 apk = artifact_location(android.apk),
401 dependency_apk = [artifact_location(apk) for apk in android.apks_under_test],
402 has_idl_sources = android.idl.output != None,
403 idl_jar = library_artifact(android.idl.output),
404 generate_resource_class = android.defines_resources,
405 resources = all_unique_source_directories(android.resources),
406 resource_jar = library_artifact(android.resource_jar),
Googlercf6e1732017-01-08 18:14:12 +0000407 **extra_ide_info
Googler1a617332017-01-07 16:48:16 +0000408 )
409 intellij_resolve_files = set(jars_from_output(android.idl.output))
410
411 if android.manifest and not android.manifest.is_source:
412 intellij_resolve_files = intellij_resolve_files | set([android.manifest])
413
414 return (android_ide_info, intellij_resolve_files)
415
Googler61bbde12017-02-02 18:53:08 +0000416def build_test_info(ctx):
417 """Build TestInfo."""
Googler1a617332017-01-07 16:48:16 +0000418 if not is_test_rule(ctx):
419 return None
420 return struct_omit_none(
421 size = ctx.rule.attr.size,
422 )
423
424def is_test_rule(ctx):
425 kind_string = ctx.rule.kind
426 return kind_string.endswith("_test")
427
Googler1a617332017-01-07 16:48:16 +0000428def build_java_toolchain_ide_info(target):
429 """Build JavaToolchainIdeInfo."""
430 if not hasattr(target, "java_toolchain"):
431 return None
432 toolchain_info = target.java_toolchain
433 return struct_omit_none(
434 source_version = toolchain_info.source_version,
435 target_version = toolchain_info.target_version,
436 )
437
438##### Main aspect function
439
Googlercf6e1732017-01-08 18:14:12 +0000440def intellij_info_aspect_impl(target, ctx, semantics):
Googler1a617332017-01-07 16:48:16 +0000441 """Aspect implementation function."""
Googlera6f42022017-02-03 21:15:50 +0000442 tags = ctx.rule.attr.tags
443 if "no-ide" in tags:
444 return struct()
445
Googler1a617332017-01-07 16:48:16 +0000446 rule_attrs = ctx.rule.attr
447
448 # Collect direct dependencies
Googlercf6e1732017-01-08 18:14:12 +0000449 direct_dep_targets = collect_targets_from_attrs(
450 rule_attrs, semantics_extra_deps(DEPS, semantics, "extra_deps"))
Googler1a617332017-01-07 16:48:16 +0000451
452 # Add exports from direct dependencies
453 exported_deps_from_deps = collect_transitive_exports(direct_dep_targets)
454 compiletime_deps = targets_to_labels(direct_dep_targets) | exported_deps_from_deps
455
456 # Propagate my own exports
457 export_deps = set()
458 if hasattr(target, "java"):
459 export_deps = set([str(l) for l in target.java.transitive_exports])
460 # Empty android libraries export all their dependencies.
461 if ctx.rule.kind == "android_library":
462 if not hasattr(rule_attrs, "srcs") or not ctx.rule.attr.srcs:
463 export_deps = export_deps | compiletime_deps
464
465 # runtime_deps
Googlercf6e1732017-01-08 18:14:12 +0000466 runtime_dep_targets = collect_targets_from_attrs(
467 rule_attrs, semantics_extra_deps(RUNTIME_DEPS, semantics, "extra_runtime_deps"))
Googler1a617332017-01-07 16:48:16 +0000468 runtime_deps = targets_to_labels(runtime_dep_targets)
469
Googlercf6e1732017-01-08 18:14:12 +0000470 # extra prerequisites
471 extra_prerequisite_targets = collect_targets_from_attrs(
472 rule_attrs, semantics_extra_deps(PREREQUISITE_DEPS, semantics, "extra_prerequisites"))
Googler1a617332017-01-07 16:48:16 +0000473
474 # Roll up files from my prerequisites
Googlercf6e1732017-01-08 18:14:12 +0000475 prerequisites = direct_dep_targets + runtime_dep_targets + extra_prerequisite_targets
Googler1a617332017-01-07 16:48:16 +0000476 intellij_info_text = set()
477 intellij_resolve_files = set()
478 intellij_compile_files = target.output_group("files_to_compile_INTERNAL_")
479 for dep in prerequisites:
Googler8febdbc2017-02-01 21:04:25 +0000480 intellij_info_text = intellij_info_text | dep.intellij_info.intellij_info_text
481 intellij_resolve_files = intellij_resolve_files | dep.intellij_info.intellij_resolve_files
Googler1a617332017-01-07 16:48:16 +0000482
483 # Collect python-specific information
484 (py_ide_info, py_resolve_files) = build_py_ide_info(target, ctx)
485 intellij_resolve_files = intellij_resolve_files | py_resolve_files
486
487 # Collect C-specific information
488 (c_ide_info, c_resolve_files) = build_c_ide_info(target, ctx)
489 intellij_resolve_files = intellij_resolve_files | c_resolve_files
490
Googler61bbde12017-02-02 18:53:08 +0000491 (c_toolchain_ide_info, c_toolchain_resolve_files) = build_c_toolchain_ide_info(ctx)
Googler1a617332017-01-07 16:48:16 +0000492 intellij_resolve_files = intellij_resolve_files | c_toolchain_resolve_files
493
494 # Collect Java-specific information
495 (java_ide_info, java_ide_info_files, java_resolve_files) = build_java_ide_info(
Googlercf6e1732017-01-08 18:14:12 +0000496 target, ctx, semantics)
Googler1a617332017-01-07 16:48:16 +0000497 intellij_info_text = intellij_info_text | java_ide_info_files
498 intellij_resolve_files = intellij_resolve_files | java_resolve_files
499
500 # Collect Android-specific information
501 (android_ide_info, android_resolve_files) = build_android_ide_info(
Googlercf6e1732017-01-08 18:14:12 +0000502 target, ctx, semantics)
Googler1a617332017-01-07 16:48:16 +0000503 intellij_resolve_files = intellij_resolve_files | android_resolve_files
504
Googler1a617332017-01-07 16:48:16 +0000505 # java_toolchain
506 java_toolchain_ide_info = build_java_toolchain_ide_info(target)
507
508 # Collect test info
Googler61bbde12017-02-02 18:53:08 +0000509 test_info = build_test_info(ctx)
Googler1a617332017-01-07 16:48:16 +0000510
Googlercf6e1732017-01-08 18:14:12 +0000511 # Any extra ide info
512 extra_ide_info = {}
513 if hasattr(semantics, "extra_ide_info"):
514 extra_ide_info = semantics.extra_ide_info(target, ctx)
515
Googler1a617332017-01-07 16:48:16 +0000516 # Build TargetIdeInfo proto
517 info = struct_omit_none(
518 label = str(target.label),
519 kind_string = ctx.rule.kind,
520 dependencies = list(compiletime_deps),
521 runtime_deps = list(runtime_deps),
522 build_file_artifact_location = build_file_artifact_location(ctx),
523 c_ide_info = c_ide_info,
524 c_toolchain_ide_info = c_toolchain_ide_info,
525 java_ide_info = java_ide_info,
526 android_ide_info = android_ide_info,
Googlera6f42022017-02-03 21:15:50 +0000527 tags = tags,
Googler1a617332017-01-07 16:48:16 +0000528 test_info = test_info,
Googler1a617332017-01-07 16:48:16 +0000529 java_toolchain_ide_info = java_toolchain_ide_info,
530 py_ide_info = py_ide_info,
Googlercf6e1732017-01-08 18:14:12 +0000531 **extra_ide_info
Googler1a617332017-01-07 16:48:16 +0000532 )
533
534 # Output the ide information file.
535 output = ctx.new_file(target.label.name + ".intellij-info.txt")
536 ctx.file_action(output, info.to_proto())
537 intellij_info_text = intellij_info_text | set([output])
538
539 # Return providers.
540 return struct_omit_none(
Googler1a617332017-01-07 16:48:16 +0000541 output_groups = {
542 "intellij-info-text" : intellij_info_text,
543 "intellij-resolve" : intellij_resolve_files,
544 "intellij-compile": intellij_compile_files,
545 },
Googler8febdbc2017-02-01 21:04:25 +0000546 intellij_info = struct(
547 intellij_info_text = intellij_info_text,
548 intellij_resolve_files = intellij_resolve_files,
549 export_deps = export_deps,
Googler1a617332017-01-07 16:48:16 +0000550 ),
Googler61bbde12017-02-02 18:53:08 +0000551 )
Googler1a617332017-01-07 16:48:16 +0000552
Googlercf6e1732017-01-08 18:14:12 +0000553def semantics_extra_deps(base, semantics, name):
554 if not hasattr(semantics, name):
555 return base
556 extra_deps = getattr(semantics, name)
557 return struct(
558 label = base.label + extra_deps.label,
559 label_list = base.label_list + extra_deps.label_list,
560 )
561
562def make_intellij_info_aspect(aspect_impl, semantics):
563 """Creates the aspect given the semantics."""
564 tool_label = semantics.tool_label
565 deps = semantics_extra_deps(DEPS, semantics, "extra_deps")
566 runtime_deps = semantics_extra_deps(RUNTIME_DEPS, semantics, "extra_runtime_deps")
567 prerequisite_deps = semantics_extra_deps(PREREQUISITE_DEPS, semantics, "extra_prerequisites")
568
569 attr_aspects = deps.label + deps.label_list
570 attr_aspects += runtime_deps.label + runtime_deps.label_list
571 attr_aspects += prerequisite_deps.label + prerequisite_deps.label_list
572
573 return aspect(
574 attrs = {
575 "_package_parser": attr.label(
576 default = tool_label("//tools/android:PackageParser"),
577 cfg = "host",
578 executable = True,
579 allow_files = True),
580 "_jar_filter": attr.label(
581 default = tool_label("//tools/android:JarFilter"),
582 cfg = "host",
583 executable = True,
584 allow_files = True),
585 },
586 attr_aspects = attr_aspects,
587 fragments = ["cpp"],
588 implementation = aspect_impl,
589 )