diff options
author | 2017-01-07 16:48:16 +0000 | |
---|---|---|
committer | 2017-01-09 10:15:31 +0000 | |
commit | 1a6173339ec78e7d321d309b616c1f6ae9cb9be9 (patch) | |
tree | 2f64d3e8fe68aa3b6c93ee0c81cd93b0f2cac9f2 /tools/ide/intellij_info.bzl | |
parent | 2433b600e92ec16091c2a2482428abbd83e2c77c (diff) |
Create indirections to intellij_info.bzl.
--
PiperOrigin-RevId: 143864069
MOS_MIGRATED_REVID=143864069
Diffstat (limited to 'tools/ide/intellij_info.bzl')
-rw-r--r-- | tools/ide/intellij_info.bzl | 626 |
1 files changed, 3 insertions, 623 deletions
diff --git a/tools/ide/intellij_info.bzl b/tools/ide/intellij_info.bzl index 671b1f301d..0faf5a7d34 100644 --- a/tools/ide/intellij_info.bzl +++ b/tools/ide/intellij_info.bzl @@ -1,4 +1,4 @@ -# Copyright 2016 The Bazel Authors. All rights reserved. +# Copyright 2017 The Bazel Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,626 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Implementation of AndroidStudio-specific information collecting aspect. +"""Bazel-specific intellij aspect.""" -# A map to convert JavaApiFlavor to ProtoLibraryLegacyJavaIdeInfo.ApiFlavor -_api_flavor_to_id = { - "FLAVOR_NONE": 0, - "FLAVOR_IMMUTABLE": 1, - "FLAVOR_MUTABLE": 2, - "FLAVOR_BOTH": 3, -} - -# Compile-time dependency attributes, grouped by type. -DEPS = struct( - label = [ - "binary_under_test", # From android_test - "java_lib", # From proto_library - "_proto1_java_lib", # From proto_library - "_junit", # From android_robolectric_test - "_cc_toolchain", # From C rules - "module_target", - "_java_toolchain", # From java rules - "test", - ], - label_list = [ - "deps", - "exports", - "_robolectric", # From android_robolectric_test - ], -) - -# Run-time dependency attributes, grouped by type. -RUNTIME_DEPS = struct( - label = [], - label_list = [ - "runtime_deps", - ], -) - -# All dependency attributes along which the aspect propagates, grouped by type. -ALL_DEPS = struct( - label = DEPS.label + RUNTIME_DEPS.label, - label_list = DEPS.label_list + RUNTIME_DEPS.label_list, -) - -LEGACY_RESOURCE_ATTR = "resources" - -##### Helpers - -def struct_omit_none(**kwargs): - """A replacement for standard `struct` function that omits the fields with None value.""" - d = {name: kwargs[name] for name in kwargs if kwargs[name] != None} - return struct(**d) - -def artifact_location(file): - """Creates an ArtifactLocation proto from a File.""" - if file == None: - return None - - return struct_omit_none( - relative_path = get_relative_path(file), - is_source = file.is_source, - is_external = is_external(file.owner), - root_execution_path_fragment = file.root.path if not file.is_source else None, - ) - -def is_external(label): - """Determines whether a label corresponds to an external artifact.""" - return label.workspace_root.startswith("external") - -def get_relative_path(artifact): - """A temporary workaround to find the root-relative path from an artifact. - - This is required because 'short_path' is incorrect for external source artifacts. - - Args: - artifact: the input artifact - Returns: - string: the root-relative path for this artifact. - """ - # TODO(bazel-team): remove this workaround when Artifact::short_path is fixed. - if artifact.is_source and is_external(artifact.owner) and artifact.short_path.startswith(".."): - # short_path is '../repo_name/path', we want 'external/repo_name/path' - return "external" + artifact.short_path[2:] - return artifact.short_path - -def source_directory_tuple(resource_file): - """Creates a tuple of (source directory, is_source, root execution path).""" - return ( - str(android_common.resource_source_directory(resource_file)), - resource_file.is_source, - resource_file.root.path if not resource_file.is_source else None - ) - -def all_unique_source_directories(resources): - """Builds a list of ArtifactLocation protos. - - This is done for all source directories for a list of Android resources. - """ - # Sets can contain tuples, but cannot contain structs. - # Use set of tuples to unquify source directories. - source_directory_tuples = set([source_directory_tuple(file) for file in resources]) - return [struct_omit_none(relative_path = relative_path, - is_source = is_source, - root_execution_path_fragment = root_execution_path_fragment) - for (relative_path, is_source, root_execution_path_fragment) in source_directory_tuples] - -def build_file_artifact_location(ctx): - """Creates an ArtifactLocation proto representing a location of a given BUILD file.""" - return struct( - relative_path = ctx.build_file_path, - is_source = True, - is_external = is_external(ctx.label) - ) - -def library_artifact(java_output): - """Creates a LibraryArtifact representing a given java_output.""" - if java_output == None or java_output.class_jar == None: - return None - return struct_omit_none( - jar = artifact_location(java_output.class_jar), - interface_jar = artifact_location(java_output.ijar), - source_jar = artifact_location(java_output.source_jar), - ) - -def annotation_processing_jars(annotation_processing): - """Creates a LibraryArtifact representing Java annotation processing jars.""" - return struct_omit_none( - jar = artifact_location(annotation_processing.class_jar), - source_jar = artifact_location(annotation_processing.source_jar), - ) - -def jars_from_output(output): - """Collect jars for intellij-resolve-files from Java output.""" - if output == None: - return [] - return [jar - for jar in [output.class_jar, output.ijar, output.source_jar] - if jar != None and not jar.is_source] - -# TODO(salguarnieri) Remove once skylark provides the path safe string from a PathFragment. -def replace_empty_path_with_dot(pathString): - return "." if len(pathString) == 0 else pathString - -def sources_from_target(context): - """ - Get the list of sources from a target as artifact locations. - - Returns the list of sources as artifact locations for a target or an empty list if no sources are - present. - """ - - if hasattr(context.rule.attr, "srcs"): - return [artifact_location(file) - for src in context.rule.attr.srcs - for file in src.files] - return [] - -def collect_targets_from_attrs(rule_attrs, attrs): - """Returns a list of targets from the given attributes.""" - list_deps = [dep for attr_name in attrs.label_list - if hasattr(rule_attrs, attr_name) - for dep in getattr(rule_attrs, attr_name)] - - scalar_deps = [getattr(rule_attrs, attr_name) for attr_name in attrs.label - if hasattr(rule_attrs, attr_name)] - - return [dep for dep in (list_deps + scalar_deps) if is_valid_aspect_target(dep)] - -def collect_transitive_exports(targets): - """Build a union of all export dependencies.""" - result = set() - for dep in targets: - result = result | dep.export_deps - return result - -def get_legacy_resource_dep(rule_attrs): - """Gets the legacy 'resources' attribute.""" - legacy_resource_target = None - if hasattr(rule_attrs, LEGACY_RESOURCE_ATTR): - dep = getattr(rule_attrs, LEGACY_RESOURCE_ATTR) - # resources can sometimes be a list attribute, in which case we don't want it - if dep and is_valid_aspect_target(dep): - legacy_resource_target = dep - return legacy_resource_target - -def targets_to_labels(targets): - """Returns a set of label strings for the given targets.""" - return set([str(target.label) for target in targets]) - -def list_omit_none(value): - """Returns a list of the value, or the empty list if None.""" - return [value] if value else [] - -def is_valid_aspect_target(target): - """Returns whether the target has had the aspect run on it.""" - return hasattr(target, "intellij_aspect") - -super_secret_rule_name = "".join(["gen", "m", "p", "m"]) # Take that, leak test -is_bazel = not hasattr(native, super_secret_rule_name) -def tool_label(label_str): - """Returns a label that points to a blaze/bazel tool. - - Will be removed once the aspect is migrated out of core. - """ - return Label("@bazel_tools" + label_str if is_bazel else label_str) - -##### Builders for individual parts of the aspect output - -def build_py_ide_info(target, ctx): - """Build PyIdeInfo. - - Returns a tuple of (PyIdeInfo proto, a set of intellij-resolve-files). - (or (None, empty set) if the target is not a python rule). - """ - if not hasattr(target, "py"): - return (None, set()) - - sources = sources_from_target(ctx) - transitive_sources = target.py.transitive_sources - - py_ide_info = struct_omit_none( - sources = sources, - ) - return (py_ide_info, transitive_sources) - -def build_c_ide_info(target, ctx): - """Build CIdeInfo. - - Returns a tuple of (CIdeInfo proto, a set of intellij-resolve-files). - (or (None, empty set) if the target is not a C rule). - """ - if not hasattr(target, "cc"): - return (None, set()) - - sources = sources_from_target(ctx) - - target_includes = [] - if hasattr(ctx.rule.attr, "includes"): - target_includes = ctx.rule.attr.includes - target_defines = [] - if hasattr(ctx.rule.attr, "defines"): - target_defines = ctx.rule.attr.defines - target_copts = [] - if hasattr(ctx.rule.attr, "copts"): - target_copts = ctx.rule.attr.copts - - cc_provider = target.cc - - c_ide_info = struct_omit_none( - source = sources, - target_include = target_includes, - target_define = target_defines, - target_copt = target_copts, - transitive_include_directory = cc_provider.include_directories, - transitive_quote_include_directory = cc_provider.quote_include_directories, - transitive_define = cc_provider.defines, - transitive_system_include_directory = cc_provider.system_include_directories, - ) - intellij_resolve_files = cc_provider.transitive_headers - return (c_ide_info, intellij_resolve_files) - -def build_c_toolchain_ide_info(target, ctx): - """Build CToolchainIdeInfo. - - Returns a pair of (CToolchainIdeInfo proto, a set of intellij-resolve-files). - (or (None, empty set) if the target is not a cc_toolchain rule). - """ - - if ctx.rule.kind != "cc_toolchain": - return (None, set()) - - # This should exist because we requested it in our aspect definition. - cc_fragment = ctx.fragments.cpp - - c_toolchain_ide_info = struct_omit_none( - target_name = cc_fragment.target_gnu_system_name, - base_compiler_option = cc_fragment.compiler_options(ctx.features), - c_option = cc_fragment.c_options, - cpp_option = cc_fragment.cxx_options(ctx.features), - link_option = cc_fragment.link_options, - unfiltered_compiler_option = cc_fragment.unfiltered_compiler_options(ctx.features), - preprocessor_executable = replace_empty_path_with_dot( - str(cc_fragment.preprocessor_executable)), - cpp_executable = str(cc_fragment.compiler_executable), - built_in_include_directory = [str(d) - for d in cc_fragment.built_in_include_directories], - ) - return (c_toolchain_ide_info, set()) - -def build_java_ide_info(target, ctx): - """ - Build JavaIdeInfo. - - Returns a pair of - (JavaIdeInfo proto, a set of ide-info-files, a set of intellij-resolve-files). - (or (None, empty set, empty set) if the target is not Java rule). - """ - if not hasattr(target, "java") or ctx.rule.kind == "proto_library": - return (None, set(), set()) - - ide_info_files = set() - sources = sources_from_target(ctx) - - jars = [library_artifact(output) for output in target.java.outputs.jars] - output_jars = [jar for output in target.java.outputs.jars for jar in jars_from_output(output)] - intellij_resolve_files = set(output_jars) - - gen_jars = [] - if target.java.annotation_processing and target.java.annotation_processing.enabled: - gen_jars = [annotation_processing_jars(target.java.annotation_processing)] - intellij_resolve_files = intellij_resolve_files | set([ - jar for jar in [target.java.annotation_processing.class_jar, - target.java.annotation_processing.source_jar] - if jar != None and not jar.is_source]) - - jdeps = artifact_location(target.java.outputs.jdeps) - - java_sources, gen_java_sources, srcjars = divide_java_sources(ctx) - - # HACK -- android_library rules with the resources attribute do not support srcjar inputs - # to the filtered gen jar generation, because we don't want all resource classes in this jar. - # This can be removed once android_resources is deleted - if hasattr(ctx.rule.attr, LEGACY_RESOURCE_ATTR) and ctx.rule.kind.startswith("android_"): - srcjars = [] - - package_manifest = None - if java_sources: - package_manifest = build_java_package_manifest(ctx, target, java_sources, ".java-manifest") - ide_info_files = ide_info_files | set([package_manifest]) - - filtered_gen_jar = None - if java_sources and (gen_java_sources or srcjars): - filtered_gen_jar, filtered_gen_resolve_files = build_filtered_gen_jar( - ctx, - target, - gen_java_sources, - srcjars - ) - intellij_resolve_files = intellij_resolve_files | filtered_gen_resolve_files - - java_ide_info = struct_omit_none( - sources = sources, - jars = jars, - jdeps = jdeps, - generated_jars = gen_jars, - package_manifest = artifact_location(package_manifest), - filtered_gen_jar = filtered_gen_jar, - ) - return (java_ide_info, ide_info_files, intellij_resolve_files) - -def build_java_package_manifest(ctx, target, source_files, suffix): - """Builds the java package manifest for the given source files.""" - output = ctx.new_file(target.label.name + suffix) - - args = [] - args += ["--output_manifest", output.path] - args += ["--sources"] - args += [":".join([f.root.path + "," + f.short_path for f in source_files])] - argfile = ctx.new_file(ctx.configuration.bin_dir, - target.label.name + suffix + ".params") - ctx.file_action(output=argfile, content="\n".join(args)) - - ctx.action( - inputs = source_files + [argfile], - outputs = [output], - executable = ctx.executable._package_parser, - arguments = ["@" + argfile.path], - mnemonic = "JavaPackageManifest", - progress_message = "Parsing java package strings for " + str(target.label), - ) - return output - -def build_filtered_gen_jar(ctx, target, gen_java_sources, srcjars): - """Filters the passed jar to contain only classes from the given manifest.""" - jar_artifacts = [] - source_jar_artifacts = [] - for jar in target.java.outputs.jars: - if jar.ijar: - jar_artifacts.append(jar.ijar) - elif jar.class_jar: - jar_artifacts.append(jar.class_jar) - if jar.source_jar: - source_jar_artifacts.append(jar.source_jar) - - filtered_jar = ctx.new_file(target.label.name + "-filtered-gen.jar") - filtered_source_jar = ctx.new_file(target.label.name + "-filtered-gen-src.jar") - args = [] - args += ["--filter_jars"] - args += [":".join([jar.path for jar in jar_artifacts])] - args += ["--filter_source_jars"] - args += [":".join([jar.path for jar in source_jar_artifacts])] - args += ["--filtered_jar", filtered_jar.path] - args += ["--filtered_source_jar", filtered_source_jar.path] - if gen_java_sources: - args += ["--keep_java_files"] - args += [":".join([java_file.path for java_file in gen_java_sources])] - if srcjars: - args += ["--keep_source_jars"] - args += [":".join([source_jar.path for source_jar in srcjars])] - ctx.action( - inputs = jar_artifacts + source_jar_artifacts + gen_java_sources + srcjars, - outputs = [filtered_jar, filtered_source_jar], - executable = ctx.executable._jar_filter, - arguments = args, - mnemonic = "JarFilter", - progress_message = "Filtering generated code for " + str(target.label), - ) - output_jar = struct( - jar=artifact_location(filtered_jar), - source_jar=artifact_location(filtered_source_jar), - ) - intellij_resolve_files = set([filtered_jar, filtered_source_jar]) - return output_jar, intellij_resolve_files - -def divide_java_sources(ctx): - """Divide sources into plain java, generated java, and srcjars.""" - - java_sources = [] - gen_java_sources = [] - srcjars = [] - if hasattr(ctx.rule.attr, "srcs"): - srcs = ctx.rule.attr.srcs - for src in srcs: - for f in src.files: - if f.basename.endswith(".java"): - if f.is_source: - java_sources.append(f) - else: - gen_java_sources.append(f) - elif f.basename.endswith(".srcjar"): - srcjars.append(f) - - return java_sources, gen_java_sources, srcjars - -def build_android_ide_info(target, ctx, legacy_resource_label): - """Build AndroidIdeInfo. - - Returns a pair of (AndroidIdeInfo proto, a set of intellij-resolve-files). - (or (None, empty set) if the target is not Android rule). - """ - if not hasattr(target, "android"): - return (None, set()) - - android = target.android - android_ide_info = struct_omit_none( - java_package = android.java_package, - idl_import_root = android.idl.import_root if hasattr(android.idl, "import_root") else None, - manifest = artifact_location(android.manifest), - apk = artifact_location(android.apk), - dependency_apk = [artifact_location(apk) for apk in android.apks_under_test], - has_idl_sources = android.idl.output != None, - idl_jar = library_artifact(android.idl.output), - generate_resource_class = android.defines_resources, - resources = all_unique_source_directories(android.resources), - resource_jar = library_artifact(android.resource_jar), - legacy_resources = legacy_resource_label, - ) - intellij_resolve_files = set(jars_from_output(android.idl.output)) - - if android.manifest and not android.manifest.is_source: - intellij_resolve_files = intellij_resolve_files | set([android.manifest]) - - return (android_ide_info, intellij_resolve_files) - -def build_test_info(target, ctx): - """Build TestInfo""" - if not is_test_rule(ctx): - return None - return struct_omit_none( - size = ctx.rule.attr.size, - ) - -def is_test_rule(ctx): - kind_string = ctx.rule.kind - return kind_string.endswith("_test") - -def build_proto_library_legacy_java_ide_info(target, ctx): - """Build ProtoLibraryLegacyJavaIdeInfo.""" - if not hasattr(target, "proto_legacy_java"): - return None - proto_info = target.proto_legacy_java.legacy_info - return struct_omit_none( - api_version = proto_info.api_version, - api_flavor = _api_flavor_to_id[proto_info.api_flavor], - jars1 = [library_artifact(output) for output in proto_info.jars1], - jars_mutable = [library_artifact(output) for output in proto_info.jars_mutable], - jars_immutable = [library_artifact(output) for output in proto_info.jars_immutable], - ) - -def build_java_toolchain_ide_info(target): - """Build JavaToolchainIdeInfo.""" - if not hasattr(target, "java_toolchain"): - return None - toolchain_info = target.java_toolchain - return struct_omit_none( - source_version = toolchain_info.source_version, - target_version = toolchain_info.target_version, - ) - -##### Main aspect function - -def _aspect_impl(target, ctx): - """Aspect implementation function.""" - rule_attrs = ctx.rule.attr - - # Collect direct dependencies - direct_dep_targets = collect_targets_from_attrs(rule_attrs, DEPS) - - # Add exports from direct dependencies - exported_deps_from_deps = collect_transitive_exports(direct_dep_targets) - compiletime_deps = targets_to_labels(direct_dep_targets) | exported_deps_from_deps - - # Propagate my own exports - export_deps = set() - if hasattr(target, "java"): - export_deps = set([str(l) for l in target.java.transitive_exports]) - # Empty android libraries export all their dependencies. - if ctx.rule.kind == "android_library": - if not hasattr(rule_attrs, "srcs") or not ctx.rule.attr.srcs: - export_deps = export_deps | compiletime_deps - - # runtime_deps - runtime_dep_targets = collect_targets_from_attrs(rule_attrs, RUNTIME_DEPS) - runtime_deps = targets_to_labels(runtime_dep_targets) - - # resources - legacy_resource_target = get_legacy_resource_dep(rule_attrs) - legacy_resource_label = str(legacy_resource_target.label) if legacy_resource_target else None - - # Roll up files from my prerequisites - prerequisites = direct_dep_targets + runtime_dep_targets + list_omit_none(legacy_resource_target) - intellij_info_text = set() - intellij_resolve_files = set() - intellij_compile_files = target.output_group("files_to_compile_INTERNAL_") - for dep in prerequisites: - intellij_info_text = intellij_info_text | dep.intellij_info_files.intellij_info_text - intellij_resolve_files = intellij_resolve_files | dep.intellij_info_files.intellij_resolve_files - - # Collect python-specific information - (py_ide_info, py_resolve_files) = build_py_ide_info(target, ctx) - intellij_resolve_files = intellij_resolve_files | py_resolve_files - - # Collect C-specific information - (c_ide_info, c_resolve_files) = build_c_ide_info(target, ctx) - intellij_resolve_files = intellij_resolve_files | c_resolve_files - - (c_toolchain_ide_info, c_toolchain_resolve_files) = build_c_toolchain_ide_info(target, ctx) - intellij_resolve_files = intellij_resolve_files | c_toolchain_resolve_files - - # Collect Java-specific information - (java_ide_info, java_ide_info_files, java_resolve_files) = build_java_ide_info( - target, ctx) - intellij_info_text = intellij_info_text | java_ide_info_files - intellij_resolve_files = intellij_resolve_files | java_resolve_files - - # Collect Android-specific information - (android_ide_info, android_resolve_files) = build_android_ide_info( - target, ctx, legacy_resource_label) - intellij_resolve_files = intellij_resolve_files | android_resolve_files - - # legacy proto_library support - proto_library_legacy_java_ide_info = build_proto_library_legacy_java_ide_info(target, ctx) - - # java_toolchain - java_toolchain_ide_info = build_java_toolchain_ide_info(target) - - # Collect test info - test_info = build_test_info(target, ctx) - - # Build TargetIdeInfo proto - info = struct_omit_none( - label = str(target.label), - kind_string = ctx.rule.kind, - dependencies = list(compiletime_deps), - runtime_deps = list(runtime_deps), - build_file_artifact_location = build_file_artifact_location(ctx), - c_ide_info = c_ide_info, - c_toolchain_ide_info = c_toolchain_ide_info, - java_ide_info = java_ide_info, - android_ide_info = android_ide_info, - tags = ctx.rule.attr.tags, - test_info = test_info, - proto_library_legacy_java_ide_info = proto_library_legacy_java_ide_info, - java_toolchain_ide_info = java_toolchain_ide_info, - py_ide_info = py_ide_info, - ) - - # Output the ide information file. - output = ctx.new_file(target.label.name + ".intellij-info.txt") - ctx.file_action(output, info.to_proto()) - intellij_info_text = intellij_info_text | set([output]) - - # Return providers. - return struct_omit_none( - intellij_aspect = True, - output_groups = { - "intellij-info-text" : intellij_info_text, - "intellij-resolve" : intellij_resolve_files, - "intellij-compile": intellij_compile_files, - }, - intellij_info_files = struct( - intellij_info_text = intellij_info_text, - intellij_resolve_files = intellij_resolve_files, - ), - export_deps = export_deps, - ) - -intellij_info_aspect = aspect( - attrs = { - "_package_parser": attr.label( - default = tool_label("//tools/android:PackageParser"), - cfg = "host", - executable = True, - allow_files = True), - "_jar_filter": attr.label( - default = tool_label("//tools/android:JarFilter"), - cfg = "host", - executable = True, - allow_files = True), - }, - attr_aspects = ALL_DEPS.label + ALL_DEPS.label_list + [LEGACY_RESOURCE_ATTR], - fragments = ["cpp"], - implementation = _aspect_impl, -) +load("@bazel_tools//tools/ide:intellij_info_impl.bzl", "intellij_info_aspect") |