blob: a7de3754c58c59aad1c7394316883974d2f24ed7 [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.
Googler20416bb2017-02-09 18:39:13 +000018DEPS = [
19 "_cc_toolchain", # From C rules
20 "_java_toolchain", # From java rules
21 "deps",
22 "exports",
23 "_robolectric", # From android_robolectric_test
Googler64f3eb02017-03-02 17:04:22 +000024 "_android_sdk", # from android rules
25 "aidl_lib", # from android_sdk
Googler20416bb2017-02-09 18:39:13 +000026]
Googler1a617332017-01-07 16:48:16 +000027
28# Run-time dependency attributes, grouped by type.
Googler20416bb2017-02-09 18:39:13 +000029RUNTIME_DEPS = [
30 "runtime_deps",
31]
Googler1a617332017-01-07 16:48:16 +000032
Googler20416bb2017-02-09 18:39:13 +000033PREREQUISITE_DEPS = []
Googler1a617332017-01-07 16:48:16 +000034
Googler83ca6a62017-03-01 18:15:00 +000035# Dependency type enum
36COMPILE_TIME = 0
37RUNTIME = 1
38
Googler1a617332017-01-07 16:48:16 +000039##### Helpers
40
41def struct_omit_none(**kwargs):
Googler61bbde12017-02-02 18:53:08 +000042 """A replacement for standard `struct` function that omits the fields with None value."""
43 d = {name: kwargs[name] for name in kwargs if kwargs[name] != None}
44 return struct(**d)
Googler1a617332017-01-07 16:48:16 +000045
Googler61bbde12017-02-02 18:53:08 +000046def artifact_location(f):
Googler1a617332017-01-07 16:48:16 +000047 """Creates an ArtifactLocation proto from a File."""
Googler61bbde12017-02-02 18:53:08 +000048 if f == None:
Googler1a617332017-01-07 16:48:16 +000049 return None
50
51 return struct_omit_none(
Googler61bbde12017-02-02 18:53:08 +000052 relative_path = get_relative_path(f),
53 is_source = f.is_source,
54 is_external = is_external(f.owner),
55 root_execution_path_fragment = f.root.path if not f.is_source else None,
Googler1a617332017-01-07 16:48:16 +000056 )
57
58def is_external(label):
59 """Determines whether a label corresponds to an external artifact."""
60 return label.workspace_root.startswith("external")
61
62def get_relative_path(artifact):
63 """A temporary workaround to find the root-relative path from an artifact.
64
65 This is required because 'short_path' is incorrect for external source artifacts.
66
67 Args:
68 artifact: the input artifact
69 Returns:
70 string: the root-relative path for this artifact.
71 """
72 # TODO(bazel-team): remove this workaround when Artifact::short_path is fixed.
Googler22e41442017-02-09 16:48:21 +000073 if is_external(artifact.owner) and artifact.short_path.startswith(".."):
Googler1a617332017-01-07 16:48:16 +000074 # short_path is '../repo_name/path', we want 'external/repo_name/path'
75 return "external" + artifact.short_path[2:]
76 return artifact.short_path
77
78def source_directory_tuple(resource_file):
79 """Creates a tuple of (source directory, is_source, root execution path)."""
80 return (
81 str(android_common.resource_source_directory(resource_file)),
82 resource_file.is_source,
83 resource_file.root.path if not resource_file.is_source else None
84 )
85
86def all_unique_source_directories(resources):
Googler61bbde12017-02-02 18:53:08 +000087 """Builds a list of unique ArtifactLocation protos."""
Googler1a617332017-01-07 16:48:16 +000088 # Sets can contain tuples, but cannot contain structs.
89 # Use set of tuples to unquify source directories.
Googler61bbde12017-02-02 18:53:08 +000090 source_directory_tuples = set([source_directory_tuple(f) for f in resources])
Googler1a617332017-01-07 16:48:16 +000091 return [struct_omit_none(relative_path = relative_path,
92 is_source = is_source,
93 root_execution_path_fragment = root_execution_path_fragment)
94 for (relative_path, is_source, root_execution_path_fragment) in source_directory_tuples]
95
96def build_file_artifact_location(ctx):
97 """Creates an ArtifactLocation proto representing a location of a given BUILD file."""
98 return struct(
99 relative_path = ctx.build_file_path,
100 is_source = True,
101 is_external = is_external(ctx.label)
102 )
103
104def library_artifact(java_output):
105 """Creates a LibraryArtifact representing a given java_output."""
106 if java_output == None or java_output.class_jar == None:
107 return None
108 return struct_omit_none(
Googler61bbde12017-02-02 18:53:08 +0000109 jar = artifact_location(java_output.class_jar),
110 interface_jar = artifact_location(java_output.ijar),
111 source_jar = artifact_location(java_output.source_jar),
Googler1a617332017-01-07 16:48:16 +0000112 )
113
114def annotation_processing_jars(annotation_processing):
115 """Creates a LibraryArtifact representing Java annotation processing jars."""
116 return struct_omit_none(
Googler61bbde12017-02-02 18:53:08 +0000117 jar = artifact_location(annotation_processing.class_jar),
118 source_jar = artifact_location(annotation_processing.source_jar),
Googler1a617332017-01-07 16:48:16 +0000119 )
120
121def jars_from_output(output):
122 """Collect jars for intellij-resolve-files from Java output."""
123 if output == None:
124 return []
125 return [jar
126 for jar in [output.class_jar, output.ijar, output.source_jar]
127 if jar != None and not jar.is_source]
128
129# TODO(salguarnieri) Remove once skylark provides the path safe string from a PathFragment.
Googler61bbde12017-02-02 18:53:08 +0000130def replace_empty_path_with_dot(path):
131 return path or "."
Googler1a617332017-01-07 16:48:16 +0000132
Googler61bbde12017-02-02 18:53:08 +0000133def sources_from_target(ctx):
134 """Get the list of sources from a target as artifact locations."""
Googler1a617332017-01-07 16:48:16 +0000135
Googler61bbde12017-02-02 18:53:08 +0000136 if hasattr(ctx.rule.attr, "srcs"):
137 return [artifact_location(f)
138 for src in ctx.rule.attr.srcs
139 for f in src.files]
Googler1a617332017-01-07 16:48:16 +0000140 return []
141
Googler20416bb2017-02-09 18:39:13 +0000142def _collect_target_from_attr(rule_attrs, attr_name, result):
143 """Collects the targets from the given attr into the result."""
144 if not hasattr(rule_attrs, attr_name):
145 return
146 attr_value = getattr(rule_attrs, attr_name)
147 type_name = type(attr_value)
148 if type_name == "Target":
149 result.append(attr_value)
150 elif type_name == "list":
151 result.extend(attr_value)
152
Googler1a617332017-01-07 16:48:16 +0000153def collect_targets_from_attrs(rule_attrs, attrs):
154 """Returns a list of targets from the given attributes."""
Googler20416bb2017-02-09 18:39:13 +0000155 result = []
156 for attr_name in attrs:
157 _collect_target_from_attr(rule_attrs, attr_name, result)
158 return [target for target in result if is_valid_aspect_target(target)]
Googler1a617332017-01-07 16:48:16 +0000159
Googler1a617332017-01-07 16:48:16 +0000160def targets_to_labels(targets):
161 """Returns a set of label strings for the given targets."""
162 return set([str(target.label) for target in targets])
163
164def list_omit_none(value):
165 """Returns a list of the value, or the empty list if None."""
166 return [value] if value else []
167
168def is_valid_aspect_target(target):
169 """Returns whether the target has had the aspect run on it."""
Googler8febdbc2017-02-01 21:04:25 +0000170 return hasattr(target, "intellij_info")
Googler1a617332017-01-07 16:48:16 +0000171
Googler83ca6a62017-03-01 18:15:00 +0000172def get_aspect_ids(ctx, target):
173 """Returns the all aspect ids, filtering out self."""
174 aspect_ids = None
175 if hasattr(ctx, "aspect_ids"):
176 aspect_ids = ctx.aspect_ids
177 elif hasattr(target, "aspect_ids"):
178 aspect_ids = target.aspect_ids
179 else:
180 return None
181 return [aspect_id for aspect_id in aspect_ids if "intellij_info_aspect" not in aspect_id]
182
183def make_target_key(label, aspect_ids):
184 """Returns a TargetKey proto struct from a target."""
185 return struct_omit_none(
186 label = str(label),
187 aspect_ids = tuple(aspect_ids) if aspect_ids else None
188 )
189
190def make_dep(dep, dependency_type):
191 """Returns a Dependency proto struct."""
192 return struct(
193 target = dep.intellij_info.target_key,
194 dependency_type = dependency_type,
195 )
196
197def make_deps(deps, dependency_type):
198 """Returns a list of Dependency proto structs."""
199 return [make_dep(dep, dependency_type) for dep in deps]
200
201def make_dep_from_label(label, dependency_type):
202 """Returns a Dependency proto struct from a label."""
203 return struct(
204 target = struct(label = str(label)),
205 dependency_type = dependency_type,
206 )
207
Googler1a617332017-01-07 16:48:16 +0000208##### Builders for individual parts of the aspect output
209
210def build_py_ide_info(target, ctx):
Googler61bbde12017-02-02 18:53:08 +0000211 """Build PyIdeInfo."""
Googler1a617332017-01-07 16:48:16 +0000212 if not hasattr(target, "py"):
213 return (None, set())
214
215 sources = sources_from_target(ctx)
216 transitive_sources = target.py.transitive_sources
217
218 py_ide_info = struct_omit_none(
219 sources = sources,
220 )
221 return (py_ide_info, transitive_sources)
222
223def build_c_ide_info(target, ctx):
Googler61bbde12017-02-02 18:53:08 +0000224 """Build CIdeInfo."""
Googler1a617332017-01-07 16:48:16 +0000225 if not hasattr(target, "cc"):
226 return (None, set())
227
228 sources = sources_from_target(ctx)
229
230 target_includes = []
231 if hasattr(ctx.rule.attr, "includes"):
232 target_includes = ctx.rule.attr.includes
233 target_defines = []
234 if hasattr(ctx.rule.attr, "defines"):
235 target_defines = ctx.rule.attr.defines
236 target_copts = []
237 if hasattr(ctx.rule.attr, "copts"):
238 target_copts = ctx.rule.attr.copts
239
240 cc_provider = target.cc
241
242 c_ide_info = struct_omit_none(
243 source = sources,
244 target_include = target_includes,
245 target_define = target_defines,
246 target_copt = target_copts,
247 transitive_include_directory = cc_provider.include_directories,
248 transitive_quote_include_directory = cc_provider.quote_include_directories,
249 transitive_define = cc_provider.defines,
250 transitive_system_include_directory = cc_provider.system_include_directories,
251 )
252 intellij_resolve_files = cc_provider.transitive_headers
253 return (c_ide_info, intellij_resolve_files)
254
Googler61bbde12017-02-02 18:53:08 +0000255def build_c_toolchain_ide_info(ctx):
256 """Build CToolchainIdeInfo."""
Googler1a617332017-01-07 16:48:16 +0000257
258 if ctx.rule.kind != "cc_toolchain":
259 return (None, set())
260
261 # This should exist because we requested it in our aspect definition.
262 cc_fragment = ctx.fragments.cpp
263
264 c_toolchain_ide_info = struct_omit_none(
265 target_name = cc_fragment.target_gnu_system_name,
266 base_compiler_option = cc_fragment.compiler_options(ctx.features),
267 c_option = cc_fragment.c_options,
268 cpp_option = cc_fragment.cxx_options(ctx.features),
269 link_option = cc_fragment.link_options,
270 unfiltered_compiler_option = cc_fragment.unfiltered_compiler_options(ctx.features),
271 preprocessor_executable = replace_empty_path_with_dot(
272 str(cc_fragment.preprocessor_executable)),
273 cpp_executable = str(cc_fragment.compiler_executable),
274 built_in_include_directory = [str(d)
275 for d in cc_fragment.built_in_include_directories],
276 )
277 return (c_toolchain_ide_info, set())
278
Googler83ca6a62017-03-01 18:15:00 +0000279def get_java_provider(target):
280 if hasattr(target, "proto_java"):
281 return target.proto_java
282 if hasattr(target, "java"):
283 return target.java
284 return None
285
Googlercf6e1732017-01-08 18:14:12 +0000286def build_java_ide_info(target, ctx, semantics):
Googler61bbde12017-02-02 18:53:08 +0000287 """Build JavaIdeInfo."""
Googler83ca6a62017-03-01 18:15:00 +0000288 java = get_java_provider(target)
289 if not java:
Googlercf6e1732017-01-08 18:14:12 +0000290 return (None, set(), set())
291
292 java_semantics = semantics.java if hasattr(semantics, "java") else None
293 if java_semantics and java_semantics.skip_target(target, ctx):
Googler1a617332017-01-07 16:48:16 +0000294 return (None, set(), set())
295
296 ide_info_files = set()
297 sources = sources_from_target(ctx)
298
Googler83ca6a62017-03-01 18:15:00 +0000299 jars = [library_artifact(output) for output in java.outputs.jars]
300 output_jars = [jar for output in java.outputs.jars for jar in jars_from_output(output)]
Googler1a617332017-01-07 16:48:16 +0000301 intellij_resolve_files = set(output_jars)
302
303 gen_jars = []
Googler83ca6a62017-03-01 18:15:00 +0000304 if java.annotation_processing and java.annotation_processing.enabled:
305 gen_jars = [annotation_processing_jars(java.annotation_processing)]
Googler1a617332017-01-07 16:48:16 +0000306 intellij_resolve_files = intellij_resolve_files | set([
Googler83ca6a62017-03-01 18:15:00 +0000307 jar for jar in [java.annotation_processing.class_jar,
308 java.annotation_processing.source_jar]
Googler1a617332017-01-07 16:48:16 +0000309 if jar != None and not jar.is_source])
310
Googler83ca6a62017-03-01 18:15:00 +0000311 jdeps = artifact_location(java.outputs.jdeps)
Googler1a617332017-01-07 16:48:16 +0000312
313 java_sources, gen_java_sources, srcjars = divide_java_sources(ctx)
314
Googlercf6e1732017-01-08 18:14:12 +0000315 if java_semantics:
316 srcjars = java_semantics.filter_source_jars(target, ctx, srcjars)
Googler1a617332017-01-07 16:48:16 +0000317
318 package_manifest = None
319 if java_sources:
320 package_manifest = build_java_package_manifest(ctx, target, java_sources, ".java-manifest")
321 ide_info_files = ide_info_files | set([package_manifest])
322
323 filtered_gen_jar = None
324 if java_sources and (gen_java_sources or srcjars):
325 filtered_gen_jar, filtered_gen_resolve_files = build_filtered_gen_jar(
326 ctx,
327 target,
Googler83ca6a62017-03-01 18:15:00 +0000328 java,
Googler1a617332017-01-07 16:48:16 +0000329 gen_java_sources,
330 srcjars
331 )
332 intellij_resolve_files = intellij_resolve_files | filtered_gen_resolve_files
333
334 java_ide_info = struct_omit_none(
335 sources = sources,
336 jars = jars,
337 jdeps = jdeps,
338 generated_jars = gen_jars,
339 package_manifest = artifact_location(package_manifest),
340 filtered_gen_jar = filtered_gen_jar,
Googler3d89b682017-02-09 01:30:56 +0000341 main_class = ctx.rule.attr.main_class if hasattr(ctx.rule.attr, "main_class") else None,
Googler1a617332017-01-07 16:48:16 +0000342 )
343 return (java_ide_info, ide_info_files, intellij_resolve_files)
344
Googler67fa75a2017-02-23 20:20:15 +0000345def _package_manifest_file_argument(f):
346 return f.root.path + "," + f.short_path + "," + ("1" if is_external(f.owner) else "0")
347
Googler1a617332017-01-07 16:48:16 +0000348def build_java_package_manifest(ctx, target, source_files, suffix):
349 """Builds the java package manifest for the given source files."""
350 output = ctx.new_file(target.label.name + suffix)
351
352 args = []
353 args += ["--output_manifest", output.path]
354 args += ["--sources"]
Googler67fa75a2017-02-23 20:20:15 +0000355 args += [":".join([_package_manifest_file_argument(f) for f in source_files])]
Googler1a617332017-01-07 16:48:16 +0000356 argfile = ctx.new_file(ctx.configuration.bin_dir,
357 target.label.name + suffix + ".params")
358 ctx.file_action(output=argfile, content="\n".join(args))
359
360 ctx.action(
361 inputs = source_files + [argfile],
362 outputs = [output],
363 executable = ctx.executable._package_parser,
364 arguments = ["@" + argfile.path],
365 mnemonic = "JavaPackageManifest",
366 progress_message = "Parsing java package strings for " + str(target.label),
367 )
368 return output
369
Googler83ca6a62017-03-01 18:15:00 +0000370def build_filtered_gen_jar(ctx, target, java, gen_java_sources, srcjars):
Googler1a617332017-01-07 16:48:16 +0000371 """Filters the passed jar to contain only classes from the given manifest."""
372 jar_artifacts = []
373 source_jar_artifacts = []
Googler83ca6a62017-03-01 18:15:00 +0000374 for jar in java.outputs.jars:
Googler1a617332017-01-07 16:48:16 +0000375 if jar.ijar:
376 jar_artifacts.append(jar.ijar)
377 elif jar.class_jar:
378 jar_artifacts.append(jar.class_jar)
379 if jar.source_jar:
380 source_jar_artifacts.append(jar.source_jar)
381
382 filtered_jar = ctx.new_file(target.label.name + "-filtered-gen.jar")
383 filtered_source_jar = ctx.new_file(target.label.name + "-filtered-gen-src.jar")
384 args = []
385 args += ["--filter_jars"]
386 args += [":".join([jar.path for jar in jar_artifacts])]
387 args += ["--filter_source_jars"]
388 args += [":".join([jar.path for jar in source_jar_artifacts])]
389 args += ["--filtered_jar", filtered_jar.path]
390 args += ["--filtered_source_jar", filtered_source_jar.path]
391 if gen_java_sources:
392 args += ["--keep_java_files"]
393 args += [":".join([java_file.path for java_file in gen_java_sources])]
394 if srcjars:
395 args += ["--keep_source_jars"]
396 args += [":".join([source_jar.path for source_jar in srcjars])]
397 ctx.action(
398 inputs = jar_artifacts + source_jar_artifacts + gen_java_sources + srcjars,
399 outputs = [filtered_jar, filtered_source_jar],
400 executable = ctx.executable._jar_filter,
401 arguments = args,
402 mnemonic = "JarFilter",
403 progress_message = "Filtering generated code for " + str(target.label),
404 )
405 output_jar = struct(
406 jar=artifact_location(filtered_jar),
407 source_jar=artifact_location(filtered_source_jar),
408 )
409 intellij_resolve_files = set([filtered_jar, filtered_source_jar])
410 return output_jar, intellij_resolve_files
411
412def divide_java_sources(ctx):
413 """Divide sources into plain java, generated java, and srcjars."""
414
415 java_sources = []
416 gen_java_sources = []
417 srcjars = []
418 if hasattr(ctx.rule.attr, "srcs"):
419 srcs = ctx.rule.attr.srcs
420 for src in srcs:
421 for f in src.files:
422 if f.basename.endswith(".java"):
423 if f.is_source:
424 java_sources.append(f)
425 else:
426 gen_java_sources.append(f)
427 elif f.basename.endswith(".srcjar"):
428 srcjars.append(f)
429
430 return java_sources, gen_java_sources, srcjars
431
Googlercf6e1732017-01-08 18:14:12 +0000432def build_android_ide_info(target, ctx, semantics):
Googler61bbde12017-02-02 18:53:08 +0000433 """Build AndroidIdeInfo."""
Googler1a617332017-01-07 16:48:16 +0000434 if not hasattr(target, "android"):
435 return (None, set())
436
Googlercf6e1732017-01-08 18:14:12 +0000437 android_semantics = semantics.android if hasattr(semantics, "android") else None
438 extra_ide_info = android_semantics.extra_ide_info(target, ctx) if android_semantics else {}
439
Googler1a617332017-01-07 16:48:16 +0000440 android = target.android
441 android_ide_info = struct_omit_none(
442 java_package = android.java_package,
443 idl_import_root = android.idl.import_root if hasattr(android.idl, "import_root") else None,
444 manifest = artifact_location(android.manifest),
445 apk = artifact_location(android.apk),
446 dependency_apk = [artifact_location(apk) for apk in android.apks_under_test],
447 has_idl_sources = android.idl.output != None,
448 idl_jar = library_artifact(android.idl.output),
449 generate_resource_class = android.defines_resources,
450 resources = all_unique_source_directories(android.resources),
451 resource_jar = library_artifact(android.resource_jar),
Googlercf6e1732017-01-08 18:14:12 +0000452 **extra_ide_info
Googler1a617332017-01-07 16:48:16 +0000453 )
454 intellij_resolve_files = set(jars_from_output(android.idl.output))
455
456 if android.manifest and not android.manifest.is_source:
457 intellij_resolve_files = intellij_resolve_files | set([android.manifest])
458
459 return (android_ide_info, intellij_resolve_files)
460
Googler61bbde12017-02-02 18:53:08 +0000461def build_test_info(ctx):
462 """Build TestInfo."""
Googler1a617332017-01-07 16:48:16 +0000463 if not is_test_rule(ctx):
464 return None
465 return struct_omit_none(
466 size = ctx.rule.attr.size,
467 )
468
469def is_test_rule(ctx):
470 kind_string = ctx.rule.kind
471 return kind_string.endswith("_test")
472
Googler1a617332017-01-07 16:48:16 +0000473def build_java_toolchain_ide_info(target):
474 """Build JavaToolchainIdeInfo."""
475 if not hasattr(target, "java_toolchain"):
476 return None
477 toolchain_info = target.java_toolchain
478 return struct_omit_none(
479 source_version = toolchain_info.source_version,
480 target_version = toolchain_info.target_version,
481 )
482
483##### Main aspect function
484
Googlercf6e1732017-01-08 18:14:12 +0000485def intellij_info_aspect_impl(target, ctx, semantics):
Googler1a617332017-01-07 16:48:16 +0000486 """Aspect implementation function."""
Googlera6f42022017-02-03 21:15:50 +0000487 tags = ctx.rule.attr.tags
488 if "no-ide" in tags:
489 return struct()
490
Googler1a617332017-01-07 16:48:16 +0000491 rule_attrs = ctx.rule.attr
492
493 # Collect direct dependencies
Googlercf6e1732017-01-08 18:14:12 +0000494 direct_dep_targets = collect_targets_from_attrs(
495 rule_attrs, semantics_extra_deps(DEPS, semantics, "extra_deps"))
Googler83ca6a62017-03-01 18:15:00 +0000496 direct_deps = make_deps(direct_dep_targets, COMPILE_TIME)
Googler1a617332017-01-07 16:48:16 +0000497
498 # Add exports from direct dependencies
Googler83ca6a62017-03-01 18:15:00 +0000499 exported_deps_from_deps = []
500 for dep in direct_dep_targets:
501 exported_deps_from_deps = exported_deps_from_deps + dep.intellij_info.export_deps
502
503 # Combine into all compile time deps
504 compiletime_deps = direct_deps + exported_deps_from_deps
Googler1a617332017-01-07 16:48:16 +0000505
506 # Propagate my own exports
Googler83ca6a62017-03-01 18:15:00 +0000507 export_deps = []
Googler1a617332017-01-07 16:48:16 +0000508 if hasattr(target, "java"):
Googler83ca6a62017-03-01 18:15:00 +0000509 transitive_exports = target.java.transitive_exports
510 export_deps = [make_dep_from_label(label, COMPILE_TIME) for label in transitive_exports]
Googler1a617332017-01-07 16:48:16 +0000511 # Empty android libraries export all their dependencies.
512 if ctx.rule.kind == "android_library":
513 if not hasattr(rule_attrs, "srcs") or not ctx.rule.attr.srcs:
Googler83ca6a62017-03-01 18:15:00 +0000514 export_deps = export_deps + compiletime_deps
515 export_deps = list(set(export_deps))
Googler1a617332017-01-07 16:48:16 +0000516
517 # runtime_deps
Googlercf6e1732017-01-08 18:14:12 +0000518 runtime_dep_targets = collect_targets_from_attrs(
519 rule_attrs, semantics_extra_deps(RUNTIME_DEPS, semantics, "extra_runtime_deps"))
Googler83ca6a62017-03-01 18:15:00 +0000520 runtime_deps = make_deps(runtime_dep_targets, RUNTIME)
521 all_deps = list(set(compiletime_deps + runtime_deps))
Googler1a617332017-01-07 16:48:16 +0000522
Googlercf6e1732017-01-08 18:14:12 +0000523 # extra prerequisites
524 extra_prerequisite_targets = collect_targets_from_attrs(
525 rule_attrs, semantics_extra_deps(PREREQUISITE_DEPS, semantics, "extra_prerequisites"))
Googler1a617332017-01-07 16:48:16 +0000526
527 # Roll up files from my prerequisites
Googlercf6e1732017-01-08 18:14:12 +0000528 prerequisites = direct_dep_targets + runtime_dep_targets + extra_prerequisite_targets
Googler1a617332017-01-07 16:48:16 +0000529 intellij_info_text = set()
530 intellij_resolve_files = set()
531 intellij_compile_files = target.output_group("files_to_compile_INTERNAL_")
532 for dep in prerequisites:
Googler8febdbc2017-02-01 21:04:25 +0000533 intellij_info_text = intellij_info_text | dep.intellij_info.intellij_info_text
534 intellij_resolve_files = intellij_resolve_files | dep.intellij_info.intellij_resolve_files
Googler1a617332017-01-07 16:48:16 +0000535
536 # Collect python-specific information
537 (py_ide_info, py_resolve_files) = build_py_ide_info(target, ctx)
538 intellij_resolve_files = intellij_resolve_files | py_resolve_files
539
540 # Collect C-specific information
541 (c_ide_info, c_resolve_files) = build_c_ide_info(target, ctx)
542 intellij_resolve_files = intellij_resolve_files | c_resolve_files
543
Googler61bbde12017-02-02 18:53:08 +0000544 (c_toolchain_ide_info, c_toolchain_resolve_files) = build_c_toolchain_ide_info(ctx)
Googler1a617332017-01-07 16:48:16 +0000545 intellij_resolve_files = intellij_resolve_files | c_toolchain_resolve_files
546
547 # Collect Java-specific information
548 (java_ide_info, java_ide_info_files, java_resolve_files) = build_java_ide_info(
Googlercf6e1732017-01-08 18:14:12 +0000549 target, ctx, semantics)
Googler1a617332017-01-07 16:48:16 +0000550 intellij_info_text = intellij_info_text | java_ide_info_files
551 intellij_resolve_files = intellij_resolve_files | java_resolve_files
552
553 # Collect Android-specific information
554 (android_ide_info, android_resolve_files) = build_android_ide_info(
Googlercf6e1732017-01-08 18:14:12 +0000555 target, ctx, semantics)
Googler1a617332017-01-07 16:48:16 +0000556 intellij_resolve_files = intellij_resolve_files | android_resolve_files
557
Googler1a617332017-01-07 16:48:16 +0000558 # java_toolchain
559 java_toolchain_ide_info = build_java_toolchain_ide_info(target)
560
561 # Collect test info
Googler61bbde12017-02-02 18:53:08 +0000562 test_info = build_test_info(ctx)
Googler1a617332017-01-07 16:48:16 +0000563
Googler83ca6a62017-03-01 18:15:00 +0000564 file_name = target.label.name
565 aspect_ids = get_aspect_ids(ctx, target)
566 if aspect_ids:
567 aspect_hash = hash(".".join(aspect_ids))
568 file_name = file_name + "-" + str(aspect_hash)
569 file_name = file_name + ".intellij-info.txt"
570
Googlercf6e1732017-01-08 18:14:12 +0000571 # Any extra ide info
572 extra_ide_info = {}
573 if hasattr(semantics, "extra_ide_info"):
574 extra_ide_info = semantics.extra_ide_info(target, ctx)
575
Googler1a617332017-01-07 16:48:16 +0000576 # Build TargetIdeInfo proto
Googler83ca6a62017-03-01 18:15:00 +0000577 target_key = make_target_key(target.label, aspect_ids)
Googler1a617332017-01-07 16:48:16 +0000578 info = struct_omit_none(
Googler83ca6a62017-03-01 18:15:00 +0000579 key = target_key,
Googler1a617332017-01-07 16:48:16 +0000580 kind_string = ctx.rule.kind,
Googler83ca6a62017-03-01 18:15:00 +0000581 deps = list(all_deps),
Googler1a617332017-01-07 16:48:16 +0000582 build_file_artifact_location = build_file_artifact_location(ctx),
583 c_ide_info = c_ide_info,
584 c_toolchain_ide_info = c_toolchain_ide_info,
585 java_ide_info = java_ide_info,
586 android_ide_info = android_ide_info,
Googlera6f42022017-02-03 21:15:50 +0000587 tags = tags,
Googler1a617332017-01-07 16:48:16 +0000588 test_info = test_info,
Googler1a617332017-01-07 16:48:16 +0000589 java_toolchain_ide_info = java_toolchain_ide_info,
590 py_ide_info = py_ide_info,
Googlercf6e1732017-01-08 18:14:12 +0000591 **extra_ide_info
Googler1a617332017-01-07 16:48:16 +0000592 )
593
594 # Output the ide information file.
Googler83ca6a62017-03-01 18:15:00 +0000595 output = ctx.new_file(file_name)
Googler1a617332017-01-07 16:48:16 +0000596 ctx.file_action(output, info.to_proto())
597 intellij_info_text = intellij_info_text | set([output])
598
599 # Return providers.
600 return struct_omit_none(
Googler1a617332017-01-07 16:48:16 +0000601 output_groups = {
602 "intellij-info-text" : intellij_info_text,
603 "intellij-resolve" : intellij_resolve_files,
604 "intellij-compile": intellij_compile_files,
605 },
Googler8febdbc2017-02-01 21:04:25 +0000606 intellij_info = struct(
Googler83ca6a62017-03-01 18:15:00 +0000607 target_key = target_key,
Googler8febdbc2017-02-01 21:04:25 +0000608 intellij_info_text = intellij_info_text,
609 intellij_resolve_files = intellij_resolve_files,
610 export_deps = export_deps,
Googler1a617332017-01-07 16:48:16 +0000611 ),
Googler61bbde12017-02-02 18:53:08 +0000612 )
Googler1a617332017-01-07 16:48:16 +0000613
Googlercf6e1732017-01-08 18:14:12 +0000614def semantics_extra_deps(base, semantics, name):
615 if not hasattr(semantics, name):
616 return base
617 extra_deps = getattr(semantics, name)
Googler20416bb2017-02-09 18:39:13 +0000618 return base + extra_deps
Googlercf6e1732017-01-08 18:14:12 +0000619
620def make_intellij_info_aspect(aspect_impl, semantics):
621 """Creates the aspect given the semantics."""
622 tool_label = semantics.tool_label
623 deps = semantics_extra_deps(DEPS, semantics, "extra_deps")
624 runtime_deps = semantics_extra_deps(RUNTIME_DEPS, semantics, "extra_runtime_deps")
625 prerequisite_deps = semantics_extra_deps(PREREQUISITE_DEPS, semantics, "extra_prerequisites")
626
Googler20416bb2017-02-09 18:39:13 +0000627 attr_aspects = deps + runtime_deps + prerequisite_deps
Googlercf6e1732017-01-08 18:14:12 +0000628
629 return aspect(
630 attrs = {
631 "_package_parser": attr.label(
632 default = tool_label("//tools/android:PackageParser"),
633 cfg = "host",
634 executable = True,
635 allow_files = True),
636 "_jar_filter": attr.label(
637 default = tool_label("//tools/android:JarFilter"),
638 cfg = "host",
639 executable = True,
640 allow_files = True),
641 },
642 attr_aspects = attr_aspects,
643 fragments = ["cpp"],
644 implementation = aspect_impl,
Googler83ca6a62017-03-01 18:15:00 +0000645 required_aspect_providers = ["proto_java"],
Googlercf6e1732017-01-08 18:14:12 +0000646 )