Browse Source
Add a new `ShadowSource` Gradle task and update `spring-core.gradle` to include source for cglib, javapoet and objenesis. Closes gh-28892 Co-authored-by: Andy Wilkinson <wilkinsona@vmware.com>pull/28896/head
Phillip Webb
3 years ago
2 changed files with 201 additions and 0 deletions
@ -0,0 +1,175 @@
@@ -0,0 +1,175 @@
|
||||
package org.springframework.build.shadow; |
||||
|
||||
import java.io.File; |
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
import org.gradle.api.DefaultTask; |
||||
import org.gradle.api.artifacts.Configuration; |
||||
import org.gradle.api.artifacts.component.ModuleComponentSelector; |
||||
import org.gradle.api.artifacts.query.ArtifactResolutionQuery; |
||||
import org.gradle.api.artifacts.result.ArtifactResolutionResult; |
||||
import org.gradle.api.artifacts.result.ComponentArtifactsResult; |
||||
import org.gradle.api.artifacts.result.DependencyResult; |
||||
import org.gradle.api.artifacts.result.ResolutionResult; |
||||
import org.gradle.api.artifacts.result.ResolvedArtifactResult; |
||||
import org.gradle.api.file.DirectoryProperty; |
||||
import org.gradle.api.file.FileCopyDetails; |
||||
import org.gradle.api.file.FileTree; |
||||
import org.gradle.api.tasks.Classpath; |
||||
import org.gradle.api.tasks.Input; |
||||
import org.gradle.api.tasks.Nested; |
||||
import org.gradle.api.tasks.Optional; |
||||
import org.gradle.api.tasks.OutputDirectory; |
||||
import org.gradle.api.tasks.TaskAction; |
||||
import org.gradle.jvm.JvmLibrary; |
||||
import org.gradle.language.base.artifact.SourcesArtifact; |
||||
|
||||
/** |
||||
* Gradle task to add source from shadowed jars into our own source jars. |
||||
* |
||||
* @author Phillip Webb |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
public class ShadowSource extends DefaultTask { |
||||
|
||||
private final DirectoryProperty outputDirectory = getProject().getObjects().directoryProperty(); |
||||
|
||||
private List<Configuration> configurations = new ArrayList<>(); |
||||
|
||||
private final List<Relocation> relocations = new ArrayList<>(); |
||||
|
||||
|
||||
@Classpath |
||||
@Optional |
||||
public List<Configuration> getConfigurations() { |
||||
return this.configurations; |
||||
} |
||||
|
||||
public void setConfigurations(List<Configuration> configurations) { |
||||
this.configurations = configurations; |
||||
} |
||||
|
||||
@Nested |
||||
public List<Relocation> getRelocations() { |
||||
return this.relocations; |
||||
} |
||||
|
||||
public void relocate(String pattern, String destination) { |
||||
this.relocations.add(new Relocation(pattern, destination)); |
||||
} |
||||
|
||||
@OutputDirectory |
||||
DirectoryProperty getOutputDirectory() { |
||||
return this.outputDirectory; |
||||
} |
||||
|
||||
@TaskAction |
||||
void syncSourceJarFiles() { |
||||
sync(getSourceJarFiles()); |
||||
} |
||||
|
||||
private List<File> getSourceJarFiles() { |
||||
List<File> sourceJarFiles = new ArrayList<>(); |
||||
for (Configuration configuration : this.configurations) { |
||||
ResolutionResult resolutionResult = configuration.getIncoming().getResolutionResult(); |
||||
resolutionResult.getRootComponent().get().getDependencies().forEach(dependency -> { |
||||
Set<ComponentArtifactsResult> artifactsResults = resolveSourceArtifacts(dependency); |
||||
for (ComponentArtifactsResult artifactResult : artifactsResults) { |
||||
artifactResult.getArtifacts(SourcesArtifact.class).forEach(sourceArtifact -> { |
||||
sourceJarFiles.add(((ResolvedArtifactResult) sourceArtifact).getFile()); |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
return Collections.unmodifiableList(sourceJarFiles); |
||||
} |
||||
|
||||
private Set<ComponentArtifactsResult> resolveSourceArtifacts(DependencyResult dependency) { |
||||
ModuleComponentSelector componentSelector = (ModuleComponentSelector) dependency.getRequested(); |
||||
ArtifactResolutionQuery query = getProject().getDependencies().createArtifactResolutionQuery() |
||||
.forModule(componentSelector.getGroup(), componentSelector.getModule(), componentSelector.getVersion()); |
||||
return executeQuery(query).getResolvedComponents(); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private ArtifactResolutionResult executeQuery(ArtifactResolutionQuery query) { |
||||
return query.withArtifacts(JvmLibrary.class, SourcesArtifact.class).execute(); |
||||
} |
||||
|
||||
private void sync(List<File> sourceJarFiles) { |
||||
getProject().sync(spec -> { |
||||
spec.into(this.outputDirectory); |
||||
spec.eachFile(this::relocateFile); |
||||
spec.filter(this::transformContent); |
||||
spec.exclude("META-INF/**"); |
||||
spec.setIncludeEmptyDirs(false); |
||||
sourceJarFiles.forEach(sourceJar -> spec.from(zipTree(sourceJar))); |
||||
}); |
||||
} |
||||
|
||||
private void relocateFile(FileCopyDetails details) { |
||||
String path = details.getPath(); |
||||
for (Relocation relocation : this.relocations) { |
||||
path = relocation.relocatePath(path); |
||||
} |
||||
details.setPath(path); |
||||
} |
||||
|
||||
private String transformContent(String content) { |
||||
for (Relocation relocation : this.relocations) { |
||||
content = relocation.transformContent(content); |
||||
} |
||||
return content; |
||||
} |
||||
|
||||
private FileTree zipTree(File sourceJar) { |
||||
return getProject().zipTree(sourceJar); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* A single relocation. |
||||
*/ |
||||
static class Relocation { |
||||
|
||||
private final String pattern; |
||||
|
||||
private final String pathPattern; |
||||
|
||||
private final String destination; |
||||
|
||||
private final String pathDestination; |
||||
|
||||
|
||||
Relocation(String pattern, String destination) { |
||||
this.pattern = pattern; |
||||
this.pathPattern = pattern.replace('.', '/'); |
||||
this.destination = destination; |
||||
this.pathDestination = destination.replace('.', '/'); |
||||
} |
||||
|
||||
|
||||
@Input |
||||
public String getPattern() { |
||||
return this.pattern; |
||||
} |
||||
|
||||
@Input |
||||
public String getDestination() { |
||||
return this.destination; |
||||
} |
||||
|
||||
String relocatePath(String path) { |
||||
return path.replace(this.pathPattern, this.pathDestination); |
||||
} |
||||
|
||||
public String transformContent(String content) { |
||||
return content.replaceAll("\\b" + this.pattern, this.destination); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue