Re-attach OSGI headers to lite,core, and util. This information was dropped in the move from maven to bazel.
PiperOrigin-RevId: 518267412pull/12295/head
parent
bf1ae222c9
commit
4b5652b030
8 changed files with 688 additions and 8 deletions
@ -0,0 +1,16 @@ |
||||
load("@rules_java//java:defs.bzl", "java_binary") |
||||
|
||||
package( |
||||
default_visibility = ["//java:__subpackages__"], |
||||
) |
||||
|
||||
java_binary( |
||||
name = "osgi_wrapper", |
||||
srcs = ["OsgiWrapper.java"], |
||||
main_class = "com.google.protobuf.osgi.OsgiWrapper", |
||||
deps = [ |
||||
"@maven//:biz_aQute_bnd_biz_aQute_bndlib", |
||||
"@maven//:com_google_guava_guava", |
||||
"@maven//:info_picocli_picocli", |
||||
], |
||||
) |
@ -0,0 +1,166 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf.osgi; |
||||
|
||||
import aQute.bnd.osgi.Analyzer; |
||||
import aQute.bnd.osgi.Jar; |
||||
import java.io.File; |
||||
import java.util.Arrays; |
||||
import java.util.concurrent.Callable; |
||||
import java.util.jar.Manifest; |
||||
import java.util.stream.Collectors; |
||||
import picocli.CommandLine; |
||||
import picocli.CommandLine.Command; |
||||
import picocli.CommandLine.Option; |
||||
|
||||
/** Java binary that runs bndlib to analyze a jar file to generate OSGi bundle manifest. */ |
||||
@Command(name = "osgi_wrapper") |
||||
public final class OsgiWrapper implements Callable<Integer> { |
||||
private static final String REMOVEHEADERS = |
||||
Arrays.stream( |
||||
new String[] { |
||||
"Embed-Dependency", |
||||
"Embed-Transitive", |
||||
"Built-By", |
||||
// "Tool",
|
||||
"Created-By", |
||||
// "Build-Jdk",
|
||||
"Originally-Created-By", |
||||
"Archiver-Version", |
||||
"Include-Resource", |
||||
"Private-Package", |
||||
"Ignore-Package", |
||||
// "Bnd-LastModified",
|
||||
"Target-Label" |
||||
}) |
||||
.collect(Collectors.joining(",")); |
||||
|
||||
@Option( |
||||
names = {"--input_jar"}, |
||||
description = "The jar file to wrap with OSGi metadata") |
||||
private File inputJar; |
||||
|
||||
@Option( |
||||
names = {"--output_jar"}, |
||||
description = "Output path to the wrapped jar") |
||||
private File outputJar; |
||||
|
||||
@Option( |
||||
names = {"--classpath"}, |
||||
description = "The classpath that contains dependencies of the input jar, separated with :") |
||||
private String classpath; |
||||
|
||||
@Option( |
||||
names = {"--bundle_copyright"}, |
||||
description = "Copyright string for the bundle") |
||||
private String bundleCopyright; |
||||
|
||||
@Option( |
||||
names = {"--bundle_description"}, |
||||
description = "Description of the bundle") |
||||
private String bundleDescription; |
||||
|
||||
@Option( |
||||
names = {"--bundle_doc_url"}, |
||||
description = "Documentation URL for the bundle") |
||||
private String bundleDocUrl; |
||||
|
||||
@Option( |
||||
names = {"--bundle_license"}, |
||||
description = "URL for the license of the bundle") |
||||
private String bundleLicense; |
||||
|
||||
@Option( |
||||
names = {"--bundle_name"}, |
||||
description = "The name of the bundle") |
||||
private String bundleName; |
||||
|
||||
@Option( |
||||
names = {"--bundle_symbolic_name"}, |
||||
description = "The symbolic name of the bundle") |
||||
private String bundleSymbolicName; |
||||
|
||||
@Option( |
||||
names = {"--bundle_version"}, |
||||
description = "The version of the bundle") |
||||
private String bundleVersion; |
||||
|
||||
@Option( |
||||
names = {"--export_package"}, |
||||
description = "The exported packages from this bundle") |
||||
private String exportPackage; |
||||
|
||||
@Option( |
||||
names = {"--import_package"}, |
||||
description = "The imported packages from this bundle") |
||||
private String importPackage; |
||||
|
||||
@Override |
||||
public Integer call() throws Exception { |
||||
Jar bin = new Jar(inputJar); |
||||
|
||||
Analyzer analyzer = new Analyzer(); |
||||
analyzer.setJar(bin); |
||||
analyzer.setProperty(Analyzer.BUNDLE_NAME, bundleName); |
||||
analyzer.setProperty(Analyzer.BUNDLE_SYMBOLICNAME, bundleSymbolicName); |
||||
analyzer.setProperty(Analyzer.BUNDLE_VERSION, bundleVersion); |
||||
analyzer.setProperty(Analyzer.IMPORT_PACKAGE, importPackage); |
||||
analyzer.setProperty(Analyzer.EXPORT_PACKAGE, exportPackage); |
||||
analyzer.setProperty(Analyzer.BUNDLE_DESCRIPTION, bundleDescription); |
||||
analyzer.setProperty(Analyzer.BUNDLE_COPYRIGHT, bundleCopyright); |
||||
analyzer.setProperty(Analyzer.BUNDLE_DOCURL, bundleDocUrl); |
||||
analyzer.setProperty(Analyzer.BUNDLE_LICENSE, bundleLicense); |
||||
analyzer.setProperty(Analyzer.REMOVEHEADERS, REMOVEHEADERS); |
||||
|
||||
if (classpath != null) { |
||||
for (String dep : Arrays.asList(classpath.split(":"))) { |
||||
analyzer.addClasspath(new File(dep)); |
||||
} |
||||
} |
||||
|
||||
analyzer.analyze(); |
||||
|
||||
Manifest manifest = analyzer.calcManifest(); |
||||
|
||||
if (analyzer.isOk()) { |
||||
analyzer.getJar().setManifest(manifest); |
||||
if (analyzer.save(outputJar, true)) { |
||||
return 0; |
||||
} |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
int exitCode = new CommandLine(new OsgiWrapper()).execute(args); |
||||
System.exit(exitCode); |
||||
} |
||||
} |
@ -0,0 +1,235 @@ |
||||
""" Custom rule to generate OSGi Manifest """ |
||||
|
||||
load("@rules_java//java:defs.bzl", "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, |
||||
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, |
||||
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("--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] |
||||
|
||||
if len(target_java_output.source_jars) > 1: |
||||
fail("osgi_jar rule doesn't know how to deal with more than one source jar.") |
||||
source_jar = target_java_output.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 = { |
||||
"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"), |
||||
), |
||||
}, |
||||
) |
Loading…
Reference in new issue