Closed restlessronin closed 1 year ago
@restlessronin thank you for your question here.
Personally I do not have dependencies to UI toolkit such as SWT in my builds.
For gradle, in parallel of working on this project that generates BOM files, I have worked a lot on improving @nedtwigg's gradle plugin com.diffplug.eclipse.mavencentral
(that I am sometimes using in my builds as well) where I know that you can do:
buildscript {
dependencies {
classpath 'com.diffplug.gradle:goomph:3.37.0'
}
}
apply plugin: 'com.diffplug.eclipse.mavencentral'
eclipseMavenCentral {
release '4.24.0', {
implementation 'org.eclipse.jdt.core'
// specify this to add the native jars for this platform
useNativesForRunningPlatform()
// specify that all transitive dependencies should be from this release
constrainTransitivesToThisRelease()
}
}
Project https://github.com/diffplug/goomph/
useNativesForRunningPlatform
does what you need.
Now if I understand your problem correctly:
Some dependencies like:
<groupId>org.eclipse.platform</groupId>
<artifactId>org.eclipse.swt</artifactId>
<version>3.120.0</version>
Have in their dependency in the dependencies
list:
<dependencies>
<dependency>
<groupId>org.eclipse.platform</groupId>
<artifactId>org.eclipse.swt.${osgi.platform}</artifactId>
<version>[3.120.0,3.120.0]</version>
</dependency>
</dependencies>
Source: org.eclipse.swt-3.120.0.pom
And this is not supported by Gradle?
I am not sure to understand what I can do at BOM file level to help you with this case.
Apparently
<artifactId>org.eclipse.swt.${osgi.platform}</artifactId>
is a maven'ism that gradle doesn't understand.
But, no worries. I kind of expected there wasn't a simple answer, so I'm not disappointed.
I actually found this repo through nedtwiggs goomph
repo. I'll use the com.diffplug.eclipse.mavencentral
plugin as you suggest.
About having ${osgi.platform}
in the artifactId
I think this is a big hack even for maven.
The approach is presented in this video: Eclipse Artifacts on Maven Central | EclipseCon Europe 2018 at 20:56.
Stephan Herrmann the author of this approach knows it.
I think this works in Gradle:
configurations.all {
resolutionStrategy {
eachDependency {
if (requested.name.contains('${osgi.platform}')) {
// use MacOs X86 as "osgi.platform" when computing the dependencies
useTarget requested.toString().replace('${osgi.platform}', 'cocoa.macosx.x86_64')
}
}
}
}
Of course cocoa.macosx.x86_64
is hard coded, but should match with the platform you are targeting.
Since I am not a gradle expert, I can't tell you the difference with the dependencySubstitution
you proposed, but the advantage is that with this eachDependency
is that you do not have to specify the SWT Version.
I was inspired by this issue https://github.com/gradle/gradle/issues/14396 to come up with my solution.
And on twitter I got an other answer.
Adding a line:
withModule<TypesafeConfigGuiceRule>(TypesafeConfigGuiceRule.TYPESAFE_CONFIG_GUICE_MODULE)
But you need to have this TypesafeConfigGuiceRule
class, provided by a plugin.
And this is for an other problem, so the code would be different.
@jmini, thank you. 🙏🏽
Stephen Herrman's solution that you suggested works for me. It isn't very scalable, but in my (and for many others I suspect) case, SWT is the only module that's involved, so scalability is not an issue.
I'm very far from being a gradle expert, so I didn't look too far into the other solution that you pointed at.
🙏🏽🙏🏽
@jmini I just read your blog https://jmini.github.io/blog/2021/2021-01-27_osgi-java-inject.html. I'm having exactly this problem now. Having used your mavencentral
derived platform, I can resolve most of the dependencies in my RCP project.
There are now a handful of dependencies that (I guess) are not marked as being transitive dependencies in the meta-data but which prevent the bundles from being loaded by OSGI. I'm guessing, because gradle doesn't show them as being unresolved in the dependencies report.
I went through the error log on the OSGI launch, and found that these were all the missing packages
com.ibm.icu.util
javax.inject
com.ibm.icu.text
javax.servlet
org.osgi.util.function
org.bouncycastle.openpgp
org.bouncycastle.bcpg
org.slf4j.impl (org.slf4j)
org.osgi.service.event
Of these, javax.servlet
was marked optional in some (but not all) references.
Do you have any suggestion on how to work with these?
My idea was to create a "missing" platform and insert these dependencies manually as "runtimeOnly" into the classpath. Perhaps even publish a BOM similar to what you've done with the platform? Is there a better way to approach this?
Of course, ideally the Eclipse guys would add the 'Orbit' drops into maven central.
Your problem is that you need the dependencies with proper OSGi metadata (in the MANIFEST.MF
file inside the jar).
For some of them (referenced in the transitive dependencies list of the published POM in maven central), the OSGi metadata is not present. Meaning that this is not the exact same jar as the one used by the Eclipse project (coming typically from the Eclipse orbit project).
I think that once approach is to publish the jars somewhere in a Maven Repo and then work with dependency substitutions in Gradle.
I remember that we did it for:
javax.inject
project as mentioned in the blog post.com.ibm.icu:icu4j
dependency (see this twitt)You are right this might be the case for other dependencies you have listed.
That said I am not an OSGi expert, and it seems that nowadays, some people are also patching the jars directly during the build. I got this feedback https://github.com/jmini/jmini.github.io/issues/2#issue-795075766 when I wrote my blog article.
@restlessronin: You might be interested in a tool I just published RepubJar
If you try to start jdt-core
version 3.20.0
(published with release 2019-12
- version 4.14
) inside an OSGi runtime you will notice that you need icu4j
, other it fails with:
Resolution failed. Capabilities satisfying the following requirements could not be found:
[<<INITIAL>>]
⇒ osgi.identity: (osgi.identity=lerimpoc-impl)
⇒ [lerimpoc-impl version=1.0.0.SNAPSHOT]
⇒ osgi.wiring.package: (osgi.wiring.package=org.eclipse.jdt.core)
⇒ [org.eclipse.jdt.core version=3.20.0.v20191203-2131]
⇒ osgi.wiring.bundle: (&(osgi.wiring.bundle=org.eclipse.text)(bundle-version>=3.6.0)(!(bundle-version>=4.0.0)))
⇒ [org.eclipse.text version=3.10.0.v20191122-2108]
⇒ osgi.wiring.package: (osgi.wiring.package=com.ibm.icu.text)
Note If I am not mistaken, newer version of bundle
org.eclipse.text
no longer requiresicu4j
So you have to start the bundle com.ibm.icu.text
as well.
com.ibm.icu:icu4j:64.2
on maven central will not help you, since it does not contains the proper OSGi metadata.
You need to have icu4j
jar that was published on Update Site of the 2019-12
release: com.ibm.icu_64.2.0.v20190507-1337.jar
(update site https://download.eclipse.org/eclipse/updates/4.14/)
But consuming the jar (and the companion sources jar) directly from their URL in not convenient:
It would be better to have them in a maven repository, so that Maven or Gradle can easily access them.
The RepubJar tool can download the two jars and the pom from Maven Central and republish everything.
@jmini thank you. this looks like a really useful tool. It would be even better if it could somehow be run automatically on all missing dependencies.
For context, I was trying to recreate the PDE build and launch for a simple eclipse RCP application in pure Gradle, so that I could use IntelliJ IDEA to run/debug the RCP program, after importing the gradle project.
Gradle does a good job of finding all the transitive dependencies that it knows about, but AFAICT, it doesn't look at the OSGI manifests. So one only finds out that a dependency is missing when the osgi runtime complains.
I spent a couple of days trying to track down missing dependencies and looking for alternative repositories for each one. Sometimes the alternative sources are using different package names for the same jar, which further complicates things. There are no canonical maven GAV sources for many standard java libraries, including those put out by the apache foundation.
What would be great is if there was a way to automate the process of finding the missing dependences (going through all the OSGI manifests?), mapping them to the relevant p2/update sites (knowledge of p2 metadata needed?), and then calling RepubJar to get them into mavenLocal.
I'm a gradle newbie and my knowledge of OSGI is only that of a casual (long-time) user (via RCP apps), so I don't know enough to be able to do either of these tasks efficiently. I took a look at the BNDtools work, but wasn't willing to take the learning curve to use it. At this point, I've temporarily given up on solving the problem and gone back to using eclipse only.
So unfortunately, I won't be able to test out your tool, since I'm not chasing dependencies down manually anymore (which would have to be repeated each time the target platform was updated to a newer eclipse release). But it sounds like an important building block for the total solution.
Firstly. Thanks for the project. I like the simplicity of the approach, where instead of depending on a gradle plugin, one depends directly on the generated BOM.
I tried using your example for a gradle build using
but I had problems with SWT.
There's a workaround for this (forgot where I found it, so I can't reference the original)
Unfortunately, this requires plugging in the SWT version, which sort of defeats the purpose of using a platform (I didn't write the original code, so there may be a simple fix I don't know about).
Am I missing something obvious?