add OSGi metadata and reproducible build#428
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
988bfca to
c0ba08d
Compare
|
Not entirely sure about Do we want: a) is currently implemented. It is based on the maven artifact GAV ( |
|
As a ignorant developer supporting a library with OSGi users, I found adding a unit test helpful comfort, wdyt? This project might want reproducible jars? I don't believe bnd does that by default (my build snippet if helpful). |
I'm going to steal that 😄 for my own project. Also I think making this project reproducible is more important than OSGi so hopefully that will be the case. I didn't see it in the list: https://github.com/jvm-repo-rebuild/reproducible-central#readme @ben-manes do you know if it is currently reproducible (jspecify jars)? |
|
@ben-manes thanks a lot for the pointers. I tried adding your suggestions about reproducible builds - although I must admit I have no experience with it, so could you double check it? Regarding unit test: generally good idea. What would you test for here? Last point:
Sorry, german here, don't get it ;) What's is with this "ignorant"? |
Prior to @chrisrueger's change, those jar look non-reproducible because it included the timestamps (those gradle flags were not set). $ unzip -l jspecify-0.3.0.jar
Archive: jspecify-0.3.0.jar
Length Date Time Name
--------- ---------- ----- ----
0 12-13-2022 12:34 META-INF/
46 12-13-2022 12:34 META-INF/MANIFEST.MF
...When set it would look more like, unzip -l caffeine-3.1.8.jar
Archive: caffeine-3.1.8.jar
Length Date Time Name
--------- ---------- ----- ----
0 02-01-1980 00:00 META-INF/
792 02-01-1980 00:00 META-INF/MANIFEST.MF
11358 02-01-1980 00:00 META-INF/LICENSE
...
I suppose maybe a reflection query if the annotation is found on a dummy test class? I believe since it runs in a custom classloader the Caffeine test is just ensuring that its library can be loaded by the runtime.
haha, I just meant that I have not actually ever used OSGi and only know of it as some magic flags that I set to satisfy other developers. I don't trust myself to not break them by an innocent refactor, so I can stay naive but more assured. |
lgtm (but just an observer) Inspection➜ Downloads gh repo clone jspecify/jspecify
fatal: destination path 'jspecify' already exists and is not an empty directory.
failed to run git: exit status 128
➜ Downloads cd jspecify
➜ jspecify git:(add-osgi-metadata) gh pr checkout 428
From https://github.com/jspecify/jspecify
* branch refs/pull/428/head -> FETCH_HEAD
Already up to date.
➜ jspecify git:(add-osgi-metadata) ./gradlew -q jar
➜ jspecify git:(add-osgi-metadata) cd build/libs
➜ libs git:(add-osgi-metadata) unzip -l jspecify-0.0.0-SNAPSHOT.jar
Archive: jspecify-0.0.0-SNAPSHOT.jar
Length Date Time Name
--------- ---------- ----- ----
0 02-01-1980 00:00 META-INF/
626 02-01-1980 00:00 META-INF/MANIFEST.MF
0 02-01-1980 00:00 META-INF/versions/
0 02-01-1980 00:00 META-INF/versions/9/
0 02-01-1980 00:00 META-INF/versions/9/OSGI-INF/
145 02-01-1980 00:00 META-INF/versions/9/OSGI-INF/MANIFEST.MF
187 02-01-1980 00:00 META-INF/versions/9/module-info.class
0 02-01-1980 00:00 org/
0 02-01-1980 00:00 org/jspecify/
0 02-01-1980 00:00 org/jspecify/annotations/
434 02-01-1980 00:00 org/jspecify/annotations/NonNull.class
498 02-01-1980 00:00 org/jspecify/annotations/NullMarked.class
488 02-01-1980 00:00 org/jspecify/annotations/NullUnmarked.class
436 02-01-1980 00:00 org/jspecify/annotations/Nullable.class
--------- -------
2814 14 files
➜ libs git:(add-osgi-metadata) unzip jspecify-0.0.0-SNAPSHOT.jar
Archive: jspecify-0.0.0-SNAPSHOT.jar
creating: META-INF/
inflating: META-INF/MANIFEST.MF
creating: META-INF/versions/
creating: META-INF/versions/9/
creating: META-INF/versions/9/OSGI-INF/
inflating: META-INF/versions/9/OSGI-INF/MANIFEST.MF
inflating: META-INF/versions/9/module-info.class
creating: org/
creating: org/jspecify/
creating: org/jspecify/annotations/
inflating: org/jspecify/annotations/NonNull.class
inflating: org/jspecify/annotations/NullMarked.class
inflating: org/jspecify/annotations/NullUnmarked.class
inflating: org/jspecify/annotations/Nullable.class
➜ libs git:(add-osgi-metadata) cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Bundle-Description: An artifact of well-specified annotations to power
static analysis checks and JVM language interop.
Bundle-DocURL: https://jspecify.dev/docs/start-here
Bundle-License: https://www.apache.org/licenses/LICENSE-2.0
Bundle-ManifestVersion: 2
Bundle-Name: jspecify
Bundle-SymbolicName: org.jspecify.jspecify
Bundle-Vendor: jspecify.dev
Bundle-Version: 0.0.0.SNAPSHOT
Export-Package: org.jspecify.annotations;version="0.0.0.SNAPSHOT"
Import-Package: java.lang,java.lang.annotation
Multi-Release: true
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" |
Thanks a lot. |
|
@ben-manes Sorry I didn't mean for you to go actually check 😄 just if you knew offhand. Thanks for checking though! The reason is because it is missing from : https://github.com/jvm-repo-rebuild/reproducible-central#readme I will see if I can add it to the list today. I think you can add an artifact without being a project owner. I will say checking the timestamp in the zip contents sometimes isn't enough because some Maven plugins have (had) bugs like Moditect that accidentally put something like timestamp somewhere in the zip that for some reason isn't visible in the zip manifest (e.g. checksum changes on each build). However this project uses Gradle (and I guess Blaze internally) so probably not a problem. |
| @@ -0,0 +1,10 @@ | |||
| Bundle-SymbolicName: org.jspecify.jspecify | |||
| Bundle-Name: jspecify | |||
There was a problem hiding this comment.
How about to make it more human readable by JSpecify annotations
Also pom.xml 0.3.0 states: <name>JSpecify annotations</name>
There was a problem hiding this comment.
Thanks for the review. Added your suggestion @bjmi
|
Regarding failing JDK 11 build I forgot that bnd 7.0.0 requires JDK 17 as a minimum. |
@cpovirk could you trigger a rebuild to check if JDK11 build now runs? |
|
Done. Looks like it's unhappy with the module-info under the multi-release jar root. If that's a significant obstacle, feel free to move it back to the main root (#484). |
Thanks. I have applied a fix. I try to investigate if there are other options like doing different things depending on JDK version. |
|
You can run gradle on 17 independently from the execution tasks. In the latest version, you can add the gradle-daemon-jvm.properties tool version and use bnd, but build on a lower jdk using the java.toolchain.languageVersion. Does that help? |
Thanks. Not sure. My first thought was to try something like this: https://discuss.gradle.org/t/conditional-dependency-based-on-toolchains-version/46369 Is this what you mean? |
|
Nope. Bnd only needs to run in gradle so as long as the daemon is 17+ then everything else will work. You can now force that with a daemon toolchain. The Java version for tasks like compile, test, exec are from the language toolchain. Instead of inferring it by the daemon jvm, it should be set explicitly. An external env variable can be used, which then lets you cross build. The jdk release flag is also useful as it will ensure that the output matches a desired version as well. Caffeine’s build uses this, but it’s a few parts to set up. |
|
(I'd be happy for someone to make that happen, especially after the fun in #517. I don't expect to get to it myself on any particular timeline, unfortunately.) |
|
Thanks for the pointers @ben-manes
It seems that it is currently in (unreleased) Gradle 8.8.-rc-1 and I first need to get familiar with the whole toolchain stuff. No gradle expert. |
cpovirk
left a comment
There was a problem hiding this comment.
We're going to see if we can dig up any other people who know OSGi, but I've found that the community review has made me pretty comfortable with this.
I'm re-approving so that we can see where CI stands now.
|
OK, so the failure when building under Java 11 is what's expected from the bnd version, as discussed above. (Sorry, I have half-watched this develop but not retained much information.) I don't know that anyone will have time to sort out toolchains in the immediate future (though of course we've had opportunities dating back some time now...), so this might well miss the 1.0.0 release. But we can at least try to get back to it sometime afterward, and of course everyone is welcome to continue to rescue us by handing us a tweaked PR that passes while still including testing under the currently tested JDKs. |
Yes that is expected. min. JDK17 for bnd >= 7.0.0
Ok understood. Thanks for considering it later. Keeping my fingers crossed somebody with deep gradle toolchain knowledge could help. |
This generates the following META-INF/MANIFEST.MF during a gradle build Manifest-Version: 1.0 Bnd-LastModified: 1702331529321 Bundle-Description: An artifact of well-specified annotations to power static analysis checks and JVM language interop. Bundle-DocURL: https://jspecify.dev/docs/start-here Bundle-ManifestVersion: 2 Bundle-Name: org.jspecify Bundle-SymbolicName: jspecify Bundle-Vendor: jspecify.dev Bundle-Version: 0.0.0.SNAPSHOT Created-By: 17.0.9 (Eclipse Adoptium) Export-Package: org.jspecify.annotations;version="0.0.0.SNAPSHOT" Import-Package: java.lang,java.lang.annotation Multi-Release: true Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" Tool: Bnd-7.0.0.202310060912 specify Bundle-SymbolicName to org.jspecify.jspecify
as suggested in review at github
dilemma: unfortunatelly bnd in 6.4.0 does not support multi-release jars. It starts being support in 7.0.0 but this requires min.JDK 17. So the only way is to suppress the warning via -fixupmessage (see bndtools/bnd#3514 and https://bnd.bndtools.org/instructions/fixupmessages.html)
This reverts commit 64520dd.
This reverts commit 871e57b.
8313ad3 to
aa303ab
Compare
|
@wmdietl or anyone else, any other concerns? |
wmdietl
left a comment
There was a problem hiding this comment.
Changes look good to me, but I understand none of the used tools :-)
|
You and me both :) Thanks. (Actually, the discussion here has given me plenty of reason to feel comfortable with merging this. I just don't think anyone will confuse me with someone who has knowledge of OSGi anytime soon....) |
|
And thank you and kudos to @ben-manes for all the help 👍 |
|
For the more OSGi-literate, here's what the 1.0.0 data is shaping up to look like: META-INF/MANIFEST.MFMETA-INF/versions/9/OSGI-INF/MANIFEST.MF |
|
haha, I think @chrisrueger is the only OSGi literate one here. If you want to validate then you could write a unit test (example) to have some assurance that things were okay. |
|
Thanks @cpovirk for the update. For documentation purposes here are some screenshots of how the bndtools Eclipse Plugin shows the bundle when I import it as a dependency. This time I added it to a local file repo, but 1.0.0 will e.g. come from Maven Central then.
I also started the bundle for the sake of testing with our app and verified with the OSGi console that the bundle is successfully started and in an Active state: For sake of completeness the pretty-printed output of the bndtools' JARViewer: |
|
Thanks. Real-world usage is more reassuring than a test, but a test also adds reassurance. I cobbled together something based on Caffeine and ancient Google Groups postings in 3dd3700. It passes, and if I revert the commit from this PR, then it fails with |
|
First of all, I would like to thank you for your efforts that have led to a solution. Now for two irregularities that I noticed. If both MANIFEST.MF files don't differ in META-INF/versions/9/OSGI-INF/MANIFEST.MF I'm not convince of BSN |
based on discussion in jspecify#428 (comment)
Feeling the same a bit after some distance now.
I like It transports the intention of the bundle in its current state - which is about "annotations". Regarding the other thing, the redundancy of the This was auto-generated by bnd and I am not familiar with Multi-Release-Jars (MRJ) / JPMS. Only thing I can point out regarding the version range:
|


Closes #362
This PR generates OSGi metadata during the build the following META-INF/MANIFEST.MF during a gradle build and should address #362 . In other words it creates a proper OSGi bundle.
It uses the bndtools Gradle Plugin (see here and here)
An additional side effect of this PR is that the build is made reproducible.
Why?
Simplifies adoption for people using an OSGi environment.
More Detailed View using bndtools Jar-Viewer:
The bundle-Version is automatically taken from the
versioninsidegradle.properties.