-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Shade external dependencies in the rest client jar #25780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
client/rest/build.gradle
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
heh, will fix this comment
javanna
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a couple of comments, I will leave the gradle part to @rjernst for review. Did I get it right that the plan is to have two artifacts, one with deps and the other one without?
client/test/build.gradle
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is httpcore replaced with the low-level rest client here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the explanation!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't we need to remove the existing jar entry without the suffix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully this will be explained better in the commit msg update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't, anymore :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I lied, it does, in an IDE /sadface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ill chat w/ ryan about this, good call for bringing it up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment explaining why :core:test also cannot run before :core:test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ill leave that for ryan to answer heh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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