| """ Custom rule to generate OSGi Manifest """ | 
 |  | 
 | load("@rules_java//java:defs.bzl", "JavaInfo", "java_library") | 
 |  | 
 | # Note that this rule is currently agnostic of protobuf concerns and could be | 
 | # pulled out as a general purpose helper to allow migrations from maven to bazel | 
 | # for OSS release builds. | 
 | # | 
 | # There are (at least) 3 things that would nice to fix about this rule: | 
 | # 1. `deps` are captured by wrapping the java_library target into the | 
 | #    osgi_java_library target -- if possible, it would be better to get | 
 | #    the deps from the JavaInfo or some other provider from any java_library | 
 | #    target. | 
 | # 2. imports are probably not being calculated properly for deps that are more | 
 | #    than 1 step deep in the dependency chain. For example: //java:core depends | 
 | #    on //java/core:lite_runtime_only but does not calculate the need for | 
 | #    "sun.misc" like the //java/core:lite target does (even though the same code | 
 | #    is transitively included. Those imports can be explicitly added through | 
 | #    `bundle_additional_imports`, but it would be better if the calculation | 
 | #    applied correctly to transitive dependencies. | 
 | # 3. Versioned imports didn't work properly when an ijar is used as the | 
 | #    "compile_jar". Thus, this rule uses the full jar as the compile_jar, | 
 | #    which is probably sub-optimal. | 
 | def osgi_java_library( | 
 |         name, | 
 |         automatic_module_name, | 
 |         bundle_description, | 
 |         bundle_doc_url, | 
 |         bundle_license, | 
 |         bundle_name, | 
 |         bundle_symbolic_name, | 
 |         bundle_version, | 
 |         bundle_additional_imports = [], | 
 |         bundle_additional_exports = [], | 
 |         deps = [], | 
 |         exports = [], | 
 |         exported_plugins = [], | 
 |         neverlink = False, | 
 |         runtime_deps = [], | 
 |         visibility = [], | 
 |         **kwargs): | 
 |     """Extends `java_library` to add OSGi headers to the MANIFEST.MF using bndlib | 
 |  | 
 |     This macro should be usable as a drop-in replacement for java_library. | 
 |  | 
 |     The additional arguments are given the bndlib tool to generate an OSGi-compliant manifest file. | 
 |     See [bnd documentation](https://bnd.bndtools.org/chapters/110-introduction.html) | 
 |  | 
 |     Args: | 
 |         name: (required) A unique name for this target. | 
 |         bundle_description: (required) The Bundle-Description header defines a short | 
 |             description of this bundle. | 
 |         bundle_doc_url: (required) The Bundle-DocURL headers must contain a URL pointing | 
 |             to documentation about this bundle. | 
 |         bundle_license: (required) The Bundle-License header provides an optional machine | 
 |             readable form of license information. | 
 |         bundle_name: (required) The Bundle-Name header defines a readable name for this | 
 |             bundle. This should be a short, human-readable name that can | 
 |             contain spaces. | 
 |         bundle_symbolic_name: (required) The Bundle-SymbolicName header specifies a | 
 |             non-localizable name for this bundle. The bundle symbolic name | 
 |             together with a version must identify a unique bundle though it can | 
 |             be installed multiple times in a framework. The bundle symbolic | 
 |             name should be based on the reverse domain name convention. | 
 |         bundle_version: (required) The Bundle-Version header specifies the version string | 
 |             for this bundle. The version string is expected to follow semantic | 
 |             versioning conventions MAJOR.MINOR.PATCH[.BUILD] | 
 |         bundle_additional_exports: The Export-Package header contains a | 
 |             declaration of exported packages. These are additional export | 
 |             package statements to be added before the default wildcard export | 
 |             "*;version={$Bundle-Version}". | 
 |         bundle_additional_imports: The Import-Package header declares the | 
 |             imported packages for this bundle. These are additional import | 
 |             package statements to be added before the default wildcard import | 
 |             "*". | 
 |         deps: The list of libraries to link into this library. See general | 
 |             comments about deps at Typical attributes defined by most build | 
 |             rules. The jars built by java_library rules listed in deps will be | 
 |             on the compile-time classpath of this rule. Furthermore the | 
 |             transitive closure of their deps, runtime_deps and exports will be | 
 |             on the runtime classpath. By contrast, targets in the data | 
 |             attribute are included in the runfiles but on neither the | 
 |             compile-time nor runtime classpath. | 
 |         exports: Exported libraries. | 
 |         exported_plugins: The list of java_plugins (e.g. annotation processors) | 
 |             to export to libraries that directly depend on this library. The | 
 |             specified list of java_plugins will be applied to any library which | 
 |             directly depends on this library, just as if that library had | 
 |             explicitly declared these labels in plugins. | 
 |         neverlink: Whether this library should only be used for compilation and | 
 |             not at runtime. Useful if the library will be provided by the runtime | 
 |             environment during execution. Examples of such libraries are the IDE | 
 |             APIs for IDE plug-ins or tools.jar for anything running on a standard | 
 |             JDK. | 
 |         runtime_deps: Libraries to make available to the final binary or test | 
 |             at runtime only. Like ordinary deps, these will appear on the runtime | 
 |             classpath, but unlike them, not on the compile-time classpath. | 
 |             Dependencies needed only at runtime should be listed here. | 
 |             Dependency-analysis tools should ignore targets that appear in both | 
 |             runtime_deps and deps | 
 |         visibility: The visibility attribute on a target controls whether the | 
 |             target can be used in other packages. See the documentation for | 
 |             visibility. | 
 |         **kwargs: Additional key-word arguments that are passed to the internal | 
 |             java_library target. | 
 |     """ | 
 |  | 
 |     # Build the private jar without the OSGI manifest | 
 |     private_library_name = "%s-no-manifest-do-not-use" % name | 
 |     java_library( | 
 |         name = private_library_name, | 
 |         deps = deps, | 
 |         runtime_deps = runtime_deps, | 
 |         neverlink = True, | 
 |         exported_plugins = exported_plugins, | 
 |         visibility = ["//visibility:private"], | 
 |         **kwargs | 
 |     ) | 
 |  | 
 |     # Repackage the jar with an OSGI manifest | 
 |     _osgi_jar( | 
 |         name = name, | 
 |         automatic_module_name = automatic_module_name, | 
 |         bundle_description = bundle_description, | 
 |         bundle_doc_url = bundle_doc_url, | 
 |         bundle_license = bundle_license, | 
 |         bundle_name = bundle_name, | 
 |         bundle_symbolic_name = bundle_symbolic_name, | 
 |         bundle_version = bundle_version, | 
 |         export_package = bundle_additional_exports + ["*;version=${Bundle-Version}"], | 
 |         import_package = bundle_additional_imports + ["*"], | 
 |         target = private_library_name, | 
 |         deps = deps, | 
 |         runtime_deps = runtime_deps, | 
 |         exported_plugins = exported_plugins, | 
 |         neverlink = neverlink, | 
 |         exports = exports, | 
 |         visibility = visibility, | 
 |     ) | 
 |  | 
 | def _run_osgi_wrapper(ctx, input_jar, classpath_jars, output_jar): | 
 |     args = ctx.actions.args() | 
 |     args.add_joined("--classpath", classpath_jars, join_with = ":") | 
 |     args.add("--input_jar", input_jar.path) | 
 |     args.add("--output_jar", output_jar.path) | 
 |     args.add("--automatic_module_name", ctx.attr.automatic_module_name) | 
 |     args.add("--bundle_copyright", ctx.attr.bundle_copyright) | 
 |     args.add("--bundle_description", ctx.attr.bundle_description) | 
 |     args.add("--bundle_doc_url", ctx.attr.bundle_doc_url) | 
 |     args.add("--bundle_license", ctx.attr.bundle_license) | 
 |     args.add("--bundle_name", ctx.attr.bundle_name) | 
 |     args.add("--bundle_version", ctx.attr.bundle_version) | 
 |     args.add("--bundle_symbolic_name", ctx.attr.bundle_symbolic_name) | 
 |     args.add_joined("--export_package", ctx.attr.export_package, join_with = ",") | 
 |     args.add_joined("--import_package", ctx.attr.import_package, join_with = ",") | 
 |  | 
 |     ctx.actions.run( | 
 |         inputs = [input_jar] + classpath_jars, | 
 |         executable = ctx.executable._osgi_wrapper_exe, | 
 |         arguments = [args], | 
 |         outputs = [output_jar], | 
 |         progress_message = "Generating OSGi bundle Manifest for %s" % input_jar.path, | 
 |     ) | 
 |  | 
 | def _osgi_jar_impl(ctx): | 
 |     if len(ctx.attr.target[JavaInfo].java_outputs) != 1: | 
 |         fail("osgi_jar rule can only be used on a single java target.") | 
 |     target_java_output = ctx.attr.target[JavaInfo].java_outputs[0] | 
 |  | 
 |     # source_jars may be a list or a Depset due to: | 
 |     # https://github.com/bazelbuild/bazel/issues/18966 | 
 |     source_jars = target_java_output.source_jars | 
 |     if hasattr(source_jars, "to_list"): | 
 |         source_jars = source_jars.to_list() | 
 |     if len(source_jars) > 1: | 
 |         fail("osgi_jar rule doesn't know how to deal with more than one source jar.") | 
 |     source_jar = source_jars[0] | 
 |  | 
 |     output_jar = ctx.outputs.output_jar | 
 |  | 
 |     input_jar = target_java_output.class_jar | 
 |     classpath_jars = ctx.attr.target[JavaInfo].compilation_info.compilation_classpath.to_list() | 
 |  | 
 |     _run_osgi_wrapper(ctx, input_jar, classpath_jars, output_jar) | 
 |  | 
 |     return [ | 
 |         DefaultInfo( | 
 |             files = depset([output_jar]), | 
 |             # Workaround for https://github.com/bazelbuild/bazel/issues/15043 | 
 |             # Bazel's native rule such as sh_test do not pick up 'files' in | 
 |             # DefaultInfo for a target in 'data'. | 
 |             data_runfiles = ctx.runfiles([output_jar]), | 
 |         ), | 
 |         JavaInfo( | 
 |             output_jar = output_jar, | 
 |  | 
 |             # compile_jar should be an ijar, but using an ijar results in | 
 |             # missing protobuf import version. | 
 |             compile_jar = output_jar, | 
 |             source_jar = source_jar, | 
 |             compile_jdeps = target_java_output.compile_jdeps, | 
 |             generated_class_jar = target_java_output.generated_class_jar, | 
 |             generated_source_jar = target_java_output.generated_source_jar, | 
 |             native_headers_jar = target_java_output.native_headers_jar, | 
 |             manifest_proto = target_java_output.manifest_proto, | 
 |             neverlink = ctx.attr.neverlink, | 
 |             deps = [dep[JavaInfo] for dep in ctx.attr.deps], | 
 |             runtime_deps = [dep[JavaInfo] for dep in ctx.attr.runtime_deps], | 
 |             exports = [exp[JavaInfo] for exp in ctx.attr.exports], | 
 |             exported_plugins = ctx.attr.exported_plugins, | 
 |             jdeps = target_java_output.jdeps, | 
 |         ), | 
 |     ] | 
 |  | 
 | _osgi_jar = rule( | 
 |     implementation = _osgi_jar_impl, | 
 |     outputs = { | 
 |         "output_jar": "lib%{name}.jar", | 
 |     }, | 
 |     attrs = { | 
 |         "automatic_module_name": attr.string(), | 
 |         "bundle_copyright": attr.string(), | 
 |         "bundle_description": attr.string(), | 
 |         "bundle_doc_url": attr.string(), | 
 |         "bundle_license": attr.string(), | 
 |         "bundle_name": attr.string(), | 
 |         "bundle_version": attr.string(), | 
 |         "bundle_symbolic_name": attr.string(), | 
 |         "export_package": attr.string_list(), | 
 |         "import_package": attr.string_list(), | 
 |         "target": attr.label(), | 
 |         "deps": attr.label_list(), | 
 |         "runtime_deps": attr.label_list(), | 
 |         "exports": attr.label_list(), | 
 |         "neverlink": attr.bool(), | 
 |         "exported_plugins": attr.label_list(), | 
 |         "_osgi_wrapper_exe": attr.label( | 
 |             executable = True, | 
 |             cfg = "exec", | 
 |             allow_files = True, | 
 |             default = Label("//java/osgi:osgi_wrapper"), | 
 |         ), | 
 |     }, | 
 | ) |