|
| 1 | +""" Custom rule to generate OSGi Manifest for Kotlin """ |
| 2 | + |
| 3 | +load("@rules_java//java:defs.bzl", "JavaInfo") |
| 4 | +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") |
| 5 | + |
| 6 | +def 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 | + |
| 126 | +def _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 |
| 150 | +def _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 | +) |
0 commit comments