Shade external dependencies in the rest client jar#25780
Shade external dependencies in the rest client jar#25780hub-cap merged 8 commits intoelastic:masterfrom
Conversation
client/rest/build.gradle
Outdated
There was a problem hiding this comment.
heh, will fix this comment
client/test/build.gradle
Outdated
There was a problem hiding this comment.
why is httpcore replaced with the low-level rest client here?
There was a problem hiding this comment.
I think I get it. either we use the ordinary httpcore classes, or the internal ones but they come from our own big jar.
There was a problem hiding this comment.
well, we really cant use ordinary ones now. Since all of the dependencies in rest client are shaded to use internal.org.apache classes, if we leak anything like Header into an API, we need to use the internal.org.apache since those are in the method signatures. So, we have to use our internal ones always, which is why we removed the httpcore stuff, because client/test now uses internal.o.a.h.Header, for example.
There was a problem hiding this comment.
thanks for the explanation!
There was a problem hiding this comment.
don't we need to remove the existing jar entry without the suffix?
There was a problem hiding this comment.
Hopefully this will be explained better in the commit msg update
There was a problem hiding this comment.
I also do not understand why both of these are necessary. The rest client used by the test framework for REST integ tests should be using the jar with no classifier. The deps version above should replace the 2 http grants below? I don't see where the nodeps version would come in.
There was a problem hiding this comment.
It doesn't, anymore :)
There was a problem hiding this comment.
I lied, it does, in an IDE /sadface
There was a problem hiding this comment.
So we need the grant above for gradle and the grant below for the IDEs which don't use the fully shaded dependency. They use the -nodeps jar. I think they should be using the shadedDeps jar rather than the original dependencies. That way the packages line up.
There was a problem hiding this comment.
Id love for them to use the shaded jar itself, but we use project dependencies, and intellij is smarter than me when it comes to dealing w/ dependencies. here is what happens to the other projects, and they seem to (only in intellij) depend on the jar task w/ the funky classifier, even though I remove it from the runtime artifacts and remove the extendsFrom compile. So these stay, just for intellij purposes. And they are using the same packages anyway, since the -deps jar and the no classifier actual shaded jar have the same relocate bits.
|
@javanna Ill leave some better comments in the github commit on why the artifacts are split out like that. its somewhat confusing. |
|
ok I decided to just add better docs to the build.gradle instead. Its saner there anyway. |
rjernst
left a comment
There was a problem hiding this comment.
I left a couple comments. I also think we should think of a better package name prefix, since these are part of the api (sorry I did not realize that when suggesting the name in the first place!).
client/rest/build.gradle
Outdated
There was a problem hiding this comment.
Shouldn't there be no need to use relocate here? If there is then unit tests ran with unshaded classes, which is exactly what we were trying to avoid.
There was a problem hiding this comment.
This is the duplicated shadowing task that actually shades the classes in src as well as the internal. things.
There was a problem hiding this comment.
That is my point. We shade the dependency itself. Nothing in src should be referring to unshaded packages, so there should be no need to do t his relocation here.
There was a problem hiding this comment.
I also do not understand why both of these are necessary. The rest client used by the test framework for REST integ tests should be using the jar with no classifier. The deps version above should replace the 2 http grants below? I don't see where the nodeps version would come in.
client/rest/build.gradle
Outdated
There was a problem hiding this comment.
thanks for adding this comment!
|
@javanna @rjernst I have cleaned up the build so that it uses the actual shaded jar outside of the rest project, instead of relying on the transient project dependencies (which was the -deps.jar). I have also removed the -nodeps jar from existence outside of the build, so the shaded jar is the only thing that other projects know about / build to. |
|
Just a note about this in general: I think as a followup (for rc/GA) we need to pull javadocs from the deps and add them to the generated client jar javadocs. |
54c9d76 to
8e5060b
Compare
This commit removes all external dependencies from the rest client jar, and shades them in an 'internal.' package within the jar, using shadowJar gradle plugin. All projects that depended on the existing jar have been converted to using the 'internal.' package prefixes to interact with the rest client. Closes elastic#25208
We could, in the grand tradition of Java, go super verbose with something like |
tlrx
left a comment
There was a problem hiding this comment.
This looks promising. I have compilation errors in my IDE but maybe it's due to Intellij IDEA 2017.1.
client/rest/build.gradle
Outdated
|
|
||
| /** | ||
| * The rest client is a shaded jar. It contains the source of the rest client, as well as all the dependencies, | ||
| * shaded to the `internal.` package. 3 artifacts come out of this build process. |
There was a problem hiding this comment.
nit: doc needs to be updated once the package name is defined
| signature "org.codehaus.mojo.signature:java17:1.0@signature" | ||
| } | ||
|
|
||
| dependencyLicenses.dependencies = project.configurations.shade |
There was a problem hiding this comment.
I think we'll have to clean Apache license and notice files in the final Jar using a Shadow plugin Transformers or build our own one.
There was a problem hiding this comment.
Ill chat w/ ryan about this, good call for bringing it up
client/rest/build.gradle
Outdated
|
|
||
| /** | ||
| * The rest client is a shaded jar. It contains the source of the rest client, as well as all the dependencies, | ||
| * shaded to the `internal.` package. 3 artifacts come out of this build process. |
There was a problem hiding this comment.
internal. is no longer accurate.
client/rest/build.gradle
Outdated
| * 3) The *actual* jar that will be used by clients. This has no classifier, contains the rest client src and `internal.`. | ||
| * This jar is the only actual output artifact of this job. | ||
| * | ||
| * The IDE does not like removing artifacts and changing configurations on the fly, so the bits that make the build |
There was a problem hiding this comment.
s/The IDE/IDEs/ ? I expect you mean IntelliJ and Eclipse.
client/rest/build.gradle
Outdated
| * The reason this jar was not overwritten was because gradle knows what its inputs and outputs are for a given task | ||
| * and we should not alter that by overwriting the original jar. What we do is add a `nodeps` classifier to it instead. | ||
| * This jar is removed from the output artifacts in cli, and retained in IDE builds. | ||
| * 2) A jar that contains *only* the `internal.` dependencies. This is a jar that is built before the src is compiled. |
There was a problem hiding this comment.
I like this comment but I'd rephrase it, maybe moving the number 2 jar to the number 1 jar and explaining that it is also there for IDEs. I think it'd be good also to explain that we use the shaded package names in the source so we still jar up the bits that come out of javac without any post processing.
| allprojects { | ||
| if (project.path == ':test:framework') { | ||
| if (project.path == ':test:framework' || project.path == ':client:test') { | ||
| // :test:framework:test cannot run before and after :core:test |
There was a problem hiding this comment.
Can you add a comment explaining why :core:test also cannot run before :core:test?
There was a problem hiding this comment.
Ill leave that for ryan to answer heh
There was a problem hiding this comment.
I don't understand your statement @nik9000. The task graph cannot have cycles, and a dependency on yourself is still a cycle.
There was a problem hiding this comment.
Sorry, :client:test cannot run before :core:test. Basically, if we are going to leave a comment explaining why :test:framework needs this exemption we should probably explain the :client:test too.
There was a problem hiding this comment.
Ok I see the confusion. The comment should be updated. It means that if the code below this were to run, a circular dependency would be added between :test:framework:test and :core:test. Likewise, the new check is added because :client:test would have a circular task dep with :client:rest:test.
| shadowJar { | ||
| configurations = [project.configurations.shade] | ||
| classifier = null | ||
| relocate 'org.apache', 'org.elasticsearch.client' |
There was a problem hiding this comment.
I think it'd be clearer to do this with the regular jar task because you are just combining the two jar files into one, right? At least, I thought that is what we'd talked about doing.
There was a problem hiding this comment.
You are right, at this point I could combine the deps jar with the src/ in the project. I can follow up with this, as its a better idea than running another "very similar" shadow task. I can follow up with this
client/rest/build.gradle
Outdated
| } | ||
|
|
||
| jar { | ||
| // rename the default jar because we are removing the classifier from the shadowJar, which is a null classifier |
There was a problem hiding this comment.
I'd say something like "move the default jar to another classifier so the jar with the dependencies can have the empty classifier".
There was a problem hiding this comment.
So we need the grant above for gradle and the grant below for the IDEs which don't use the fully shaded dependency. They use the -nodeps jar. I think they should be using the shadedDeps jar rather than the original dependencies. That way the packages line up.
Please let's not do that. The package names have real costs (eg Windows file path limits). |
Fine by me. I'd certainly prefer it if all the shaded things were grouped together in some obvious way but I'm not going to block anything over it. |
rjernst
left a comment
There was a problem hiding this comment.
This works great for me from the CLI. I at first had issues testing it with IntelliJ, in 2016.2. I upgraded to 2017.2, but still had issues. I then tried using the "module per source set" option and it "sort of" worked, but I needed to downgrade to 2017.1. So, I think we should add a note in CONTRIBUTING that using the module per source set option is now required, and probably also a note that 2017.1 is recommended (2017.2 was just recently released so I expect the issue should be fixed in a patch release).
|
👍 ill create a few issues off this initial one based on the feedback here |
|
thanks @hub-cap ! Was this supposed to go to 5.x too? I see it has the 5.6 label. |
|
yes i have backported it, ty for keepin an eye out @javanna <3 |

This commit removes all external dependencies from the rest client jar,
and shades them in an 'internal.' package within the jar, using
shadowJar gradle plugin. All projects that depended on the existing jar
have been converted to using the 'internal.' package prefixes to
interact with the rest client.
Closes #25208