Skip to content

Commit 1b97652

Browse files
authored
Build: Move shadow customizations into common code (#32014)
Moves the customizations to the build to produce nice shadow jars and javadocs into common build code, mostly BuildPlugin with a little into the root build.gradle file. This means that any project that applies the shadow plugin will automatically be set up just like the high level rest client: * The non-shadow jar will not be built * The shadow jar will not have a "classifier" * Tests will run against the shadow jar * Javadoc will include all of the shadowed classes * Service files in `META-INF/services` will be merged
1 parent 1c63eb1 commit 1b97652

File tree

8 files changed

+153
-173
lines changed

8 files changed

+153
-173
lines changed

benchmarks/build.gradle

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
buildscript {
21-
repositories {
22-
maven {
23-
url 'https://plugins.gradle.org/m2/'
24-
}
25-
}
26-
dependencies {
27-
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
28-
}
29-
}
30-
3120
apply plugin: 'elasticsearch.build'
3221

3322
// order of this section matters, see: https://github.com/johnrengelman/shadow/issues/336
@@ -81,10 +70,6 @@ thirdPartyAudit.excludes = [
8170
'org.openjdk.jmh.util.Utils'
8271
]
8372

84-
shadowJar {
85-
classifier = 'benchmarks'
86-
}
87-
8873
runShadow {
8974
executable = new File(project.runtimeJavaHome, 'bin/java')
9075
}

build.gradle

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* under the License.
1818
*/
1919

20-
20+
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
2121
import org.apache.tools.ant.taskdefs.condition.Os
2222
import org.apache.tools.ant.filters.ReplaceTokens
2323
import org.elasticsearch.gradle.BuildPlugin
@@ -303,18 +303,55 @@ subprojects {
303303
if (project.plugins.hasPlugin(BuildPlugin)) {
304304
String artifactsHost = VersionProperties.elasticsearch.isSnapshot() ? "https://snapshots.elastic.co" : "https://artifacts.elastic.co"
305305
Closure sortClosure = { a, b -> b.group <=> a.group }
306-
Closure depJavadocClosure = { dep ->
307-
if (dep.group != null && dep.group.startsWith('org.elasticsearch')) {
308-
Project upstreamProject = dependencyToProject(dep)
309-
if (upstreamProject != null) {
310-
project.javadoc.dependsOn "${upstreamProject.path}:javadoc"
311-
String artifactPath = dep.group.replaceAll('\\.', '/') + '/' + dep.name.replaceAll('\\.', '/') + '/' + dep.version
312-
project.javadoc.options.linksOffline artifactsHost + "/javadoc/" + artifactPath, "${upstreamProject.buildDir}/docs/javadoc/"
306+
Closure depJavadocClosure = { shadowed, dep ->
307+
if (dep.group == null || false == dep.group.startsWith('org.elasticsearch')) {
308+
return
309+
}
310+
Project upstreamProject = dependencyToProject(dep)
311+
if (upstreamProject == null) {
312+
return
313+
}
314+
if (shadowed) {
315+
/*
316+
* Include the source of shadowed upstream projects so we don't
317+
* have to publish their javadoc.
318+
*/
319+
project.evaluationDependsOn(upstreamProject.path)
320+
project.javadoc.source += upstreamProject.javadoc.source
321+
/*
322+
* Do not add those projects to the javadoc classpath because
323+
* we are going to resolve them with their source instead.
324+
*/
325+
project.javadoc.classpath = project.javadoc.classpath.filter { f ->
326+
false == upstreamProject.configurations.archives.artifacts.files.files.contains(f)
313327
}
328+
/*
329+
* Instead we need the upstream project's javadoc classpath so
330+
* we don't barf on the classes that it references.
331+
*/
332+
project.javadoc.classpath += upstreamProject.javadoc.classpath
333+
} else {
334+
// Link to non-shadowed dependant projects
335+
project.javadoc.dependsOn "${upstreamProject.path}:javadoc"
336+
String artifactPath = dep.group.replaceAll('\\.', '/') + '/' + dep.name.replaceAll('\\.', '/') + '/' + dep.version
337+
project.javadoc.options.linksOffline artifactsHost + "/javadoc/" + artifactPath, "${upstreamProject.buildDir}/docs/javadoc/"
314338
}
315339
}
316-
project.configurations.compile.dependencies.findAll().toSorted(sortClosure).each(depJavadocClosure)
317-
project.configurations.compileOnly.dependencies.findAll().toSorted(sortClosure).each(depJavadocClosure)
340+
boolean hasShadow = project.plugins.hasPlugin(ShadowPlugin)
341+
project.configurations.compile.dependencies
342+
.findAll()
343+
.toSorted(sortClosure)
344+
.each({ c -> depJavadocClosure(hasShadow, c) })
345+
project.configurations.compileOnly.dependencies
346+
.findAll()
347+
.toSorted(sortClosure)
348+
.each({ c -> depJavadocClosure(hasShadow, c) })
349+
if (hasShadow) {
350+
project.configurations.shadow.dependencies
351+
.findAll()
352+
.toSorted(sortClosure)
353+
.each({ c -> depJavadocClosure(false, c) })
354+
}
318355
}
319356
}
320357
}

buildSrc/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ dependencies {
104104
compile 'de.thetaphi:forbiddenapis:2.5'
105105
compile 'org.apache.rat:apache-rat:0.11'
106106
compile "org.elasticsearch:jna:4.5.1"
107+
compile 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
107108
testCompile "junit:junit:${props.getProperty('junit')}"
108109
}
109110

buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.elasticsearch.gradle
2020

2121
import com.carrotsearch.gradle.junit4.RandomizedTestingTask
22+
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
2223
import org.apache.tools.ant.taskdefs.condition.Os
2324
import org.eclipse.jgit.lib.Constants
2425
import org.eclipse.jgit.lib.RepositoryBuilder
@@ -36,12 +37,14 @@ import org.gradle.api.artifacts.ModuleDependency
3637
import org.gradle.api.artifacts.ModuleVersionIdentifier
3738
import org.gradle.api.artifacts.ProjectDependency
3839
import org.gradle.api.artifacts.ResolvedArtifact
40+
import org.gradle.api.artifacts.SelfResolvingDependency
3941
import org.gradle.api.artifacts.dsl.RepositoryHandler
4042
import org.gradle.api.execution.TaskExecutionGraph
4143
import org.gradle.api.plugins.JavaPlugin
4244
import org.gradle.api.publish.maven.MavenPublication
4345
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
4446
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
47+
import org.gradle.api.tasks.SourceSet
4548
import org.gradle.api.tasks.bundling.Jar
4649
import org.gradle.api.tasks.compile.GroovyCompile
4750
import org.gradle.api.tasks.compile.JavaCompile
@@ -498,7 +501,41 @@ class BuildPlugin implements Plugin<Project> {
498501
}
499502
}
500503
}
504+
project.plugins.withType(ShadowPlugin).whenPluginAdded {
505+
project.publishing {
506+
publications {
507+
nebula(MavenPublication) {
508+
artifact project.tasks.shadowJar
509+
artifactId = project.archivesBaseName
510+
/*
511+
* Configure the pom to include the "shadow" as compile dependencies
512+
* because that is how we're using them but remove all other dependencies
513+
* because they've been shaded into the jar.
514+
*/
515+
pom.withXml { XmlProvider xml ->
516+
Node root = xml.asNode()
517+
root.remove(root.dependencies)
518+
Node dependenciesNode = root.appendNode('dependencies')
519+
project.configurations.shadow.allDependencies.each {
520+
if (false == it instanceof SelfResolvingDependency) {
521+
Node dependencyNode = dependenciesNode.appendNode('dependency')
522+
dependencyNode.appendNode('groupId', it.group)
523+
dependencyNode.appendNode('artifactId', it.name)
524+
dependencyNode.appendNode('version', it.version)
525+
dependencyNode.appendNode('scope', 'compile')
526+
}
527+
}
528+
// Be tidy and remove the element if it is empty
529+
if (dependenciesNode.children.empty) {
530+
root.remove(dependenciesNode)
531+
}
532+
}
533+
}
534+
}
535+
}
536+
}
501537
}
538+
502539
}
503540

504541
/** Adds compiler settings to the project */
@@ -660,6 +697,28 @@ class BuildPlugin implements Plugin<Project> {
660697
}
661698
}
662699
}
700+
project.plugins.withType(ShadowPlugin).whenPluginAdded {
701+
/*
702+
* When we use the shadow plugin we entirely replace the
703+
* normal jar with the shadow jar so we no longer want to run
704+
* the jar task.
705+
*/
706+
project.tasks.jar.enabled = false
707+
project.tasks.shadowJar {
708+
/*
709+
* Replace the default "shadow" classifier with null
710+
* which will leave the classifier off of the file name.
711+
*/
712+
classifier = null
713+
/*
714+
* Not all cases need service files merged but it is
715+
* better to be safe
716+
*/
717+
mergeServiceFiles()
718+
}
719+
// Make sure we assemble the shadow jar
720+
project.tasks.assemble.dependsOn project.tasks.shadowJar
721+
}
663722
}
664723

665724
/** Returns a closure of common configuration shared by unit and integration tests. */
@@ -744,6 +803,18 @@ class BuildPlugin implements Plugin<Project> {
744803
}
745804

746805
exclude '**/*$*.class'
806+
807+
project.plugins.withType(ShadowPlugin).whenPluginAdded {
808+
/*
809+
* If we make a shaded jar we test against it.
810+
*/
811+
classpath -= project.tasks.compileJava.outputs.files
812+
classpath -= project.configurations.compile
813+
classpath -= project.configurations.runtime
814+
classpath += project.configurations.shadow
815+
classpath += project.tasks.shadowJar.outputs.files
816+
dependsOn project.tasks.shadowJar
817+
}
747818
}
748819
}
749820

@@ -766,7 +837,26 @@ class BuildPlugin implements Plugin<Project> {
766837
additionalTest.dependsOn(project.tasks.testClasses)
767838
test.dependsOn(additionalTest)
768839
});
769-
return test
840+
841+
project.plugins.withType(ShadowPlugin).whenPluginAdded {
842+
/*
843+
* We need somewhere to configure dependencies that we don't wish
844+
* to shade into the jar. The shadow plugin creates a "shadow"
845+
* configuration which is *almost* exactly that. It is never
846+
* bundled into the shaded jar but is used for main source
847+
* compilation. Unfortunately, by default it is not used for
848+
* *test* source compilation and isn't used in tests at all. This
849+
* change makes it available for test compilation.
850+
*
851+
* Note that this isn't going to work properly with qa projects
852+
* but they have no business applying the shadow plugin in the
853+
* firstplace.
854+
*/
855+
SourceSet testSourceSet = project.sourceSets.findByName('test')
856+
if (testSourceSet != null) {
857+
testSourceSet.compileClasspath += project.configurations.shadow
858+
}
859+
}
770860
}
771861

772862
private static configurePrecommit(Project project) {

buildSrc/src/main/groovy/org/elasticsearch/gradle/plugin/PluginBuildPlugin.groovy

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
*/
1919
package org.elasticsearch.gradle.plugin
2020

21+
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
2122
import nebula.plugin.info.scm.ScmInfoPlugin
2223
import org.elasticsearch.gradle.BuildPlugin
2324
import org.elasticsearch.gradle.NoticeTask
2425
import org.elasticsearch.gradle.test.RestIntegTestTask
2526
import org.elasticsearch.gradle.test.RunTask
27+
import org.gradle.api.InvalidUserDataException
2628
import org.gradle.api.JavaVersion
2729
import org.gradle.api.Project
2830
import org.gradle.api.Task
@@ -46,6 +48,18 @@ public class PluginBuildPlugin extends BuildPlugin {
4648
@Override
4749
public void apply(Project project) {
4850
super.apply(project)
51+
project.plugins.withType(ShadowPlugin).whenPluginAdded {
52+
/*
53+
* We've not tested these plugins together and we're fairly sure
54+
* they aren't going to work properly as is *and* we're not really
55+
* sure *why* you'd want to shade stuff in plugins. So we throw an
56+
* exception here to make you come and read this comment. If you
57+
* have a need for shadow while building plugins then know that you
58+
* are probably going to have to fight with gradle for a while....
59+
*/
60+
throw new InvalidUserDataException('elasticsearch.esplugin is not '
61+
+ 'compatible with com.github.johnrengelman.shadow');
62+
}
4963
configureDependencies(project)
5064
// this afterEvaluate must happen before the afterEvaluate added by integTest creation,
5165
// so that the file name resolution for installing the plugin will be setup

client/benchmark/build.gradle

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
buildscript {
21-
repositories {
22-
maven {
23-
url 'https://plugins.gradle.org/m2/'
24-
}
25-
}
26-
dependencies {
27-
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
28-
}
29-
}
30-
31-
3220
apply plugin: 'elasticsearch.build'
3321
// build an uberjar with all benchmarks
3422
apply plugin: 'com.github.johnrengelman.shadow'

0 commit comments

Comments
 (0)