• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1""" Custom rule to generate OSGi Manifest for Kotlin """
2
3load("@rules_java//java:defs.bzl", "JavaInfo")
4load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
5
6def osgi_kt_jvm_library(
7        name,
8        automatic_module_name,
9        bundle_description,
10        bundle_doc_url,
11        bundle_license,
12        bundle_name,
13        bundle_symbolic_name,
14        bundle_version,
15        bundle_additional_imports = [],
16        bundle_additional_exports = [],
17        deps = [],
18        exports = [],
19        exported_plugins = [],
20        neverlink = False,
21        runtime_deps = [],
22        visibility = [],
23        **kwargs):
24    """Extends `kt_jvm_library` to add OSGi headers to the MANIFEST.MF using bndlib
25
26    This macro should be usable as a drop-in replacement for kt_jvm_library.
27
28    The additional arguments are given the bndlib tool to generate an OSGi-compliant manifest file.
29    See [bnd documentation](https://bnd.bndtools.org/chapters/110-introduction.html)
30
31    Args:
32        name: (required) A unique name for this target.
33        automatic_module_name: (required) The Automatic-Module-Name header that represents
34            the name of the module when this bundle is used as an automatic
35            module.
36        bundle_description: (required) The Bundle-Description header defines a short
37            description of this bundle.
38        bundle_doc_url: (required) The Bundle-DocURL headers must contain a URL pointing
39            to documentation about this bundle.
40        bundle_license: (required) The Bundle-License header provides an optional machine
41            readable form of license information.
42        bundle_name: (required) The Bundle-Name header defines a readable name for this
43            bundle. This should be a short, human-readable name that can
44            contain spaces.
45        bundle_symbolic_name: (required) The Bundle-SymbolicName header specifies a
46            non-localizable name for this bundle. The bundle symbolic name
47            together with a version must identify a unique bundle though it can
48            be installed multiple times in a framework. The bundle symbolic
49            name should be based on the reverse domain name convention.
50        bundle_version: (required) The Bundle-Version header specifies the version string
51            for this bundle. The version string is expected to follow semantic
52            versioning conventions MAJOR.MINOR.PATCH[.BUILD]
53        bundle_additional_exports: The Export-Package header contains a
54            declaration of exported packages. These are additional export
55            package statements to be added before the default wildcard export
56            "*;version={$Bundle-Version}".
57        bundle_additional_imports: The Import-Package header declares the
58            imported packages for this bundle. These are additional import
59            package statements to be added before the default wildcard import
60            "*".
61        deps: The list of libraries to link into this library. See general
62            comments about deps at Typical attributes defined by most build
63            rules. The jars built by java_library rules listed in deps will be
64            on the compile-time classpath of this rule. Furthermore the
65            transitive closure of their deps, runtime_deps and exports will be
66            on the runtime classpath. By contrast, targets in the data
67            attribute are included in the runfiles but on neither the
68            compile-time nor runtime classpath.
69        exports: Exported libraries.
70        exported_plugins: The list of java_plugins (e.g. annotation processors)
71            to export to libraries that directly depend on this library. The
72            specified list of java_plugins will be applied to any library which
73            directly depends on this library, just as if that library had
74            explicitly declared these labels in plugins.
75        neverlink: Whether this library should only be used for compilation and
76            not at runtime. Useful if the library will be provided by the runtime
77            environment during execution. Examples of such libraries are the IDE
78            APIs for IDE plug-ins or tools.jar for anything running on a standard
79            JDK.
80        runtime_deps: Libraries to make available to the final binary or test
81            at runtime only. Like ordinary deps, these will appear on the runtime
82            classpath, but unlike them, not on the compile-time classpath.
83            Dependencies needed only at runtime should be listed here.
84            Dependency-analysis tools should ignore targets that appear in both
85            runtime_deps and deps
86        visibility: The visibility attribute on a target controls whether the
87            target can be used in other packages. See the documentation for
88            visibility.
89        **kwargs: Additional key-word arguments that are passed to the internal
90            java_library target.
91
92    """
93
94    # Build the private jar without the OSGI manifest
95    private_library_name = "%s-no-manifest-do-not-use" % name
96    kt_jvm_library(
97        name = private_library_name,
98        deps = deps,
99        runtime_deps = runtime_deps,
100        neverlink = True,
101        visibility = ["//visibility:private"],
102        **kwargs
103    )
104
105    # Repackage the jar with an OSGI manifest
106    _osgi_kt_jvm_jar(
107        name = name,
108        automatic_module_name = automatic_module_name,
109        bundle_description = bundle_description,
110        bundle_doc_url = bundle_doc_url,
111        bundle_license = bundle_license,
112        bundle_name = bundle_name,
113        bundle_symbolic_name = bundle_symbolic_name,
114        bundle_version = bundle_version,
115        export_package = bundle_additional_exports + ["*;version=${Bundle-Version}"],
116        import_package = bundle_additional_imports + ["*"],
117        target = private_library_name,
118        deps = deps,
119        runtime_deps = runtime_deps,
120        exported_plugins = exported_plugins,
121        neverlink = neverlink,
122        exports = exports,
123        visibility = visibility,
124    )
125
126def _run_osgi_wrapper(ctx, input_jar, output_jar):
127    args = ctx.actions.args()
128    args.add("--input_jar", input_jar.path)
129    args.add("--output_jar", output_jar.path)
130    args.add("--automatic_module_name", ctx.attr.automatic_module_name)
131    args.add("--bundle_copyright", ctx.attr.bundle_copyright)
132    args.add("--bundle_description", ctx.attr.bundle_description)
133    args.add("--bundle_doc_url", ctx.attr.bundle_doc_url)
134    args.add("--bundle_license", ctx.attr.bundle_license)
135    args.add("--bundle_name", ctx.attr.bundle_name)
136    args.add("--bundle_version", ctx.attr.bundle_version)
137    args.add("--bundle_symbolic_name", ctx.attr.bundle_symbolic_name)
138    args.add_joined("--export_package", ctx.attr.export_package, join_with = ",")
139    args.add_joined("--import_package", ctx.attr.import_package, join_with = ",")
140
141    ctx.actions.run(
142        inputs = [input_jar],
143        executable = ctx.executable._osgi_wrapper_exe,
144        arguments = [args],
145        outputs = [output_jar],
146        progress_message = "Generating OSGi bundle Manifest for %s" % input_jar.path,
147    )
148
149# Kotlin implementation of osgi jar, removes classpath and source_jar
150def _osgi_kt_jvm_jar_impl(ctx):
151    if len(ctx.attr.target[JavaInfo].java_outputs) != 1:
152        fail("osgi_jar rule can only be used on a single java target.")
153    target_java_output = ctx.attr.target[JavaInfo].java_outputs[0]
154
155    output_jar = ctx.outputs.output_jar
156
157    input_jar = target_java_output.class_jar
158
159    _run_osgi_wrapper(ctx, input_jar, output_jar)
160
161    return [
162        DefaultInfo(
163            files = depset([output_jar]),
164            # Workaround for https://github.com/bazelbuild/bazel/issues/15043
165            # Bazel's native rule such as sh_test do not pick up 'files' in
166            # DefaultInfo for a target in 'data'.
167            data_runfiles = ctx.runfiles([output_jar]),
168        ),
169        JavaInfo(
170            output_jar = output_jar,
171
172            # compile_jar should be an ijar, but using an ijar results in
173            # missing protobuf import version.
174            compile_jar = output_jar,
175            generated_class_jar = target_java_output.generated_class_jar,
176            native_headers_jar = target_java_output.native_headers_jar,
177            manifest_proto = target_java_output.manifest_proto,
178            neverlink = ctx.attr.neverlink,
179            deps = [dep[JavaInfo] for dep in ctx.attr.deps],
180            runtime_deps = [dep[JavaInfo] for dep in ctx.attr.runtime_deps],
181            exports = [exp[JavaInfo] for exp in ctx.attr.exports],
182            exported_plugins = ctx.attr.exported_plugins,
183        ),
184    ]
185
186_osgi_kt_jvm_jar = rule(
187    implementation = _osgi_kt_jvm_jar_impl,
188    outputs = {
189        "output_jar": "lib%{name}.jar",
190    },
191    attrs = {
192        "automatic_module_name": attr.string(),
193        "bundle_copyright": attr.string(),
194        "bundle_description": attr.string(),
195        "bundle_doc_url": attr.string(),
196        "bundle_license": attr.string(),
197        "bundle_name": attr.string(),
198        "bundle_version": attr.string(),
199        "bundle_symbolic_name": attr.string(),
200        "export_package": attr.string_list(),
201        "import_package": attr.string_list(),
202        "target": attr.label(),
203        "deps": attr.label_list(),
204        "runtime_deps": attr.label_list(),
205        "exports": attr.label_list(),
206        "neverlink": attr.bool(),
207        "exported_plugins": attr.label_list(),
208        "_osgi_wrapper_exe": attr.label(
209            executable = True,
210            cfg = "exec",
211            allow_files = True,
212            default = Label("//java/osgi:osgi_wrapper"),
213        ),
214    },
215)
216