|
|
|
""" 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"),
|
|
|
|
),
|
|
|
|
},
|
|
|
|
)
|