Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 1 | # 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 | |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 15 | """Implementation of IntelliJ-specific information collecting aspect.""" |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 16 | |
| 17 | # Compile-time dependency attributes, grouped by type. |
Googler | 20416bb | 2017-02-09 18:39:13 +0000 | [diff] [blame] | 18 | DEPS = [ |
| 19 | "_cc_toolchain", # From C rules |
| 20 | "_java_toolchain", # From java rules |
| 21 | "deps", |
| 22 | "exports", |
| 23 | "_robolectric", # From android_robolectric_test |
Googler | 64f3eb0 | 2017-03-02 17:04:22 +0000 | [diff] [blame] | 24 | "_android_sdk", # from android rules |
| 25 | "aidl_lib", # from android_sdk |
Googler | 20416bb | 2017-02-09 18:39:13 +0000 | [diff] [blame] | 26 | ] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 27 | |
| 28 | # Run-time dependency attributes, grouped by type. |
Googler | 20416bb | 2017-02-09 18:39:13 +0000 | [diff] [blame] | 29 | RUNTIME_DEPS = [ |
| 30 | "runtime_deps", |
| 31 | ] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 32 | |
Googler | 20416bb | 2017-02-09 18:39:13 +0000 | [diff] [blame] | 33 | PREREQUISITE_DEPS = [] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 34 | |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 35 | # Dependency type enum |
| 36 | COMPILE_TIME = 0 |
| 37 | RUNTIME = 1 |
| 38 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 39 | ##### Helpers |
| 40 | |
| 41 | def struct_omit_none(**kwargs): |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 42 | """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) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 45 | |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 46 | def artifact_location(f): |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 47 | """Creates an ArtifactLocation proto from a File.""" |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 48 | if f == None: |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 49 | return None |
| 50 | |
| 51 | return struct_omit_none( |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 52 | 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, |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 56 | ) |
| 57 | |
| 58 | def is_external(label): |
| 59 | """Determines whether a label corresponds to an external artifact.""" |
| 60 | return label.workspace_root.startswith("external") |
| 61 | |
| 62 | def 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. |
Googler | 22e4144 | 2017-02-09 16:48:21 +0000 | [diff] [blame] | 73 | if is_external(artifact.owner) and artifact.short_path.startswith(".."): |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 74 | # 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 | |
| 78 | def 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 | |
| 86 | def all_unique_source_directories(resources): |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 87 | """Builds a list of unique ArtifactLocation protos.""" |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 88 | # Sets can contain tuples, but cannot contain structs. |
| 89 | # Use set of tuples to unquify source directories. |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 90 | source_directory_tuples = set([source_directory_tuple(f) for f in resources]) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 91 | 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 | |
| 96 | def 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 | |
| 104 | def 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( |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 109 | jar = artifact_location(java_output.class_jar), |
| 110 | interface_jar = artifact_location(java_output.ijar), |
| 111 | source_jar = artifact_location(java_output.source_jar), |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 112 | ) |
| 113 | |
| 114 | def annotation_processing_jars(annotation_processing): |
| 115 | """Creates a LibraryArtifact representing Java annotation processing jars.""" |
| 116 | return struct_omit_none( |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 117 | jar = artifact_location(annotation_processing.class_jar), |
| 118 | source_jar = artifact_location(annotation_processing.source_jar), |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 119 | ) |
| 120 | |
| 121 | def 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. |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 130 | def replace_empty_path_with_dot(path): |
| 131 | return path or "." |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 132 | |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 133 | def sources_from_target(ctx): |
| 134 | """Get the list of sources from a target as artifact locations.""" |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 135 | |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 136 | 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] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 140 | return [] |
| 141 | |
Googler | 20416bb | 2017-02-09 18:39:13 +0000 | [diff] [blame] | 142 | def _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 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 153 | def collect_targets_from_attrs(rule_attrs, attrs): |
| 154 | """Returns a list of targets from the given attributes.""" |
Googler | 20416bb | 2017-02-09 18:39:13 +0000 | [diff] [blame] | 155 | 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)] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 159 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 160 | def 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 | |
| 164 | def list_omit_none(value): |
| 165 | """Returns a list of the value, or the empty list if None.""" |
| 166 | return [value] if value else [] |
| 167 | |
| 168 | def is_valid_aspect_target(target): |
| 169 | """Returns whether the target has had the aspect run on it.""" |
Googler | 8febdbc | 2017-02-01 21:04:25 +0000 | [diff] [blame] | 170 | return hasattr(target, "intellij_info") |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 171 | |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 172 | def 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 | |
| 183 | def 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 | |
| 190 | def 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 | |
| 197 | def 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 | |
| 201 | def 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 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 208 | ##### Builders for individual parts of the aspect output |
| 209 | |
| 210 | def build_py_ide_info(target, ctx): |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 211 | """Build PyIdeInfo.""" |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 212 | 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 | |
| 223 | def build_c_ide_info(target, ctx): |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 224 | """Build CIdeInfo.""" |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 225 | 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 | |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 255 | def build_c_toolchain_ide_info(ctx): |
| 256 | """Build CToolchainIdeInfo.""" |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 257 | |
| 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 | |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 279 | def 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 | |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 286 | def build_java_ide_info(target, ctx, semantics): |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 287 | """Build JavaIdeInfo.""" |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 288 | java = get_java_provider(target) |
| 289 | if not java: |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 290 | 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): |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 294 | return (None, set(), set()) |
| 295 | |
| 296 | ide_info_files = set() |
| 297 | sources = sources_from_target(ctx) |
| 298 | |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 299 | 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)] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 301 | intellij_resolve_files = set(output_jars) |
| 302 | |
| 303 | gen_jars = [] |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 304 | if java.annotation_processing and java.annotation_processing.enabled: |
| 305 | gen_jars = [annotation_processing_jars(java.annotation_processing)] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 306 | intellij_resolve_files = intellij_resolve_files | set([ |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 307 | jar for jar in [java.annotation_processing.class_jar, |
| 308 | java.annotation_processing.source_jar] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 309 | if jar != None and not jar.is_source]) |
| 310 | |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 311 | jdeps = artifact_location(java.outputs.jdeps) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 312 | |
| 313 | java_sources, gen_java_sources, srcjars = divide_java_sources(ctx) |
| 314 | |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 315 | if java_semantics: |
| 316 | srcjars = java_semantics.filter_source_jars(target, ctx, srcjars) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 317 | |
| 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, |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 328 | java, |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 329 | 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, |
Googler | 3d89b68 | 2017-02-09 01:30:56 +0000 | [diff] [blame] | 341 | main_class = ctx.rule.attr.main_class if hasattr(ctx.rule.attr, "main_class") else None, |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 342 | ) |
| 343 | return (java_ide_info, ide_info_files, intellij_resolve_files) |
| 344 | |
Googler | 67fa75a | 2017-02-23 20:20:15 +0000 | [diff] [blame] | 345 | def _package_manifest_file_argument(f): |
| 346 | return f.root.path + "," + f.short_path + "," + ("1" if is_external(f.owner) else "0") |
| 347 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 348 | def 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"] |
Googler | 67fa75a | 2017-02-23 20:20:15 +0000 | [diff] [blame] | 355 | args += [":".join([_package_manifest_file_argument(f) for f in source_files])] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 356 | 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 | |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 370 | def build_filtered_gen_jar(ctx, target, java, gen_java_sources, srcjars): |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 371 | """Filters the passed jar to contain only classes from the given manifest.""" |
| 372 | jar_artifacts = [] |
| 373 | source_jar_artifacts = [] |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 374 | for jar in java.outputs.jars: |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 375 | 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 | |
| 412 | def 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 | |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 432 | def build_android_ide_info(target, ctx, semantics): |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 433 | """Build AndroidIdeInfo.""" |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 434 | if not hasattr(target, "android"): |
| 435 | return (None, set()) |
| 436 | |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 437 | 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 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 440 | 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), |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 452 | **extra_ide_info |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 453 | ) |
| 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 | |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 461 | def build_test_info(ctx): |
| 462 | """Build TestInfo.""" |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 463 | if not is_test_rule(ctx): |
| 464 | return None |
| 465 | return struct_omit_none( |
| 466 | size = ctx.rule.attr.size, |
| 467 | ) |
| 468 | |
| 469 | def is_test_rule(ctx): |
| 470 | kind_string = ctx.rule.kind |
| 471 | return kind_string.endswith("_test") |
| 472 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 473 | def 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 | |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 485 | def intellij_info_aspect_impl(target, ctx, semantics): |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 486 | """Aspect implementation function.""" |
Googler | a6f4202 | 2017-02-03 21:15:50 +0000 | [diff] [blame] | 487 | tags = ctx.rule.attr.tags |
| 488 | if "no-ide" in tags: |
| 489 | return struct() |
| 490 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 491 | rule_attrs = ctx.rule.attr |
| 492 | |
| 493 | # Collect direct dependencies |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 494 | direct_dep_targets = collect_targets_from_attrs( |
| 495 | rule_attrs, semantics_extra_deps(DEPS, semantics, "extra_deps")) |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 496 | direct_deps = make_deps(direct_dep_targets, COMPILE_TIME) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 497 | |
| 498 | # Add exports from direct dependencies |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 499 | 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 |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 505 | |
| 506 | # Propagate my own exports |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 507 | export_deps = [] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 508 | if hasattr(target, "java"): |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 509 | transitive_exports = target.java.transitive_exports |
| 510 | export_deps = [make_dep_from_label(label, COMPILE_TIME) for label in transitive_exports] |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 511 | # 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: |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 514 | export_deps = export_deps + compiletime_deps |
| 515 | export_deps = list(set(export_deps)) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 516 | |
| 517 | # runtime_deps |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 518 | runtime_dep_targets = collect_targets_from_attrs( |
| 519 | rule_attrs, semantics_extra_deps(RUNTIME_DEPS, semantics, "extra_runtime_deps")) |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 520 | runtime_deps = make_deps(runtime_dep_targets, RUNTIME) |
| 521 | all_deps = list(set(compiletime_deps + runtime_deps)) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 522 | |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 523 | # extra prerequisites |
| 524 | extra_prerequisite_targets = collect_targets_from_attrs( |
| 525 | rule_attrs, semantics_extra_deps(PREREQUISITE_DEPS, semantics, "extra_prerequisites")) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 526 | |
| 527 | # Roll up files from my prerequisites |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 528 | prerequisites = direct_dep_targets + runtime_dep_targets + extra_prerequisite_targets |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 529 | 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: |
Googler | 8febdbc | 2017-02-01 21:04:25 +0000 | [diff] [blame] | 533 | 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 |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 535 | |
| 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 | |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 544 | (c_toolchain_ide_info, c_toolchain_resolve_files) = build_c_toolchain_ide_info(ctx) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 545 | 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( |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 549 | target, ctx, semantics) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 550 | 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( |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 555 | target, ctx, semantics) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 556 | intellij_resolve_files = intellij_resolve_files | android_resolve_files |
| 557 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 558 | # java_toolchain |
| 559 | java_toolchain_ide_info = build_java_toolchain_ide_info(target) |
| 560 | |
| 561 | # Collect test info |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 562 | test_info = build_test_info(ctx) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 563 | |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 564 | 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 | |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 571 | # 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 | |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 576 | # Build TargetIdeInfo proto |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 577 | target_key = make_target_key(target.label, aspect_ids) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 578 | info = struct_omit_none( |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 579 | key = target_key, |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 580 | kind_string = ctx.rule.kind, |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 581 | deps = list(all_deps), |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 582 | 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, |
Googler | a6f4202 | 2017-02-03 21:15:50 +0000 | [diff] [blame] | 587 | tags = tags, |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 588 | test_info = test_info, |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 589 | java_toolchain_ide_info = java_toolchain_ide_info, |
| 590 | py_ide_info = py_ide_info, |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 591 | **extra_ide_info |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 592 | ) |
| 593 | |
| 594 | # Output the ide information file. |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 595 | output = ctx.new_file(file_name) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 596 | 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( |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 601 | output_groups = { |
| 602 | "intellij-info-text" : intellij_info_text, |
| 603 | "intellij-resolve" : intellij_resolve_files, |
| 604 | "intellij-compile": intellij_compile_files, |
| 605 | }, |
Googler | 8febdbc | 2017-02-01 21:04:25 +0000 | [diff] [blame] | 606 | intellij_info = struct( |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 607 | target_key = target_key, |
Googler | 8febdbc | 2017-02-01 21:04:25 +0000 | [diff] [blame] | 608 | intellij_info_text = intellij_info_text, |
| 609 | intellij_resolve_files = intellij_resolve_files, |
| 610 | export_deps = export_deps, |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 611 | ), |
Googler | 61bbde1 | 2017-02-02 18:53:08 +0000 | [diff] [blame] | 612 | ) |
Googler | 1a61733 | 2017-01-07 16:48:16 +0000 | [diff] [blame] | 613 | |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 614 | def semantics_extra_deps(base, semantics, name): |
| 615 | if not hasattr(semantics, name): |
| 616 | return base |
| 617 | extra_deps = getattr(semantics, name) |
Googler | 20416bb | 2017-02-09 18:39:13 +0000 | [diff] [blame] | 618 | return base + extra_deps |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 619 | |
| 620 | def 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 | |
Googler | 20416bb | 2017-02-09 18:39:13 +0000 | [diff] [blame] | 627 | attr_aspects = deps + runtime_deps + prerequisite_deps |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 628 | |
| 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, |
Googler | 83ca6a6 | 2017-03-01 18:15:00 +0000 | [diff] [blame] | 645 | required_aspect_providers = ["proto_java"], |
Googler | cf6e173 | 2017-01-08 18:14:12 +0000 | [diff] [blame] | 646 | ) |