Skip to content

Commit 4b3aee9

Browse files
authored
Gradle plugin (#5)
* Add a gradle plugin, WIP * Use MapProperty and ConfigurableFileCollection * Use newer JavaTransformer without the symbol solver dependency * Configure plugin project properly
1 parent 279a990 commit 4b3aee9

19 files changed

Lines changed: 923 additions & 16 deletions

File tree

build.gradle

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ buildscript {
33
jcenter()
44
maven { url "https://plugins.gradle.org/m2/" }
55
}
6-
dependencies { classpath 'org.minimallycorrect.gradle:DefaultsPlugin:0.0.51' }
6+
dependencies { classpath 'org.minimallycorrect.gradle:DefaultsPlugin:0.0.52' }
77
}
88
plugins {
99
id 'java'
@@ -42,10 +42,6 @@ allprojects {
4242
all {
4343
resolutionStrategy {
4444
failOnVersionConflict()
45-
46-
force('com.google.code.findbugs:jsr305:3.0.2')
47-
48-
cacheChangingModulesFor 10, 'seconds'
4945
}
5046
}
5147
}
@@ -54,15 +50,5 @@ allprojects {
5450
dependencies {
5551
testImplementation "junit:junit:4.12"
5652
implementation 'me.nallar.whocalled:WhoCalled:1.1'
57-
api 'org.minimallycorrect.javatransformer:JavaTransformer:1.8.12'
58-
}
59-
60-
// fails with shipkit
61-
// https://github.com/mockito/shipkit/issues/847
62-
/*
63-
def gradlePluginJar = tasks.getByPath(':gradle-plugin:jar')
64-
gradlePluginJar.getArchiveClassifier().set("gradle-plugin")
65-
artifacts {
66-
add("archives", gradlePluginJar)
53+
api 'org.minimallycorrect.javatransformer:JavaTransformer:1.8.15'
6754
}
68-
*/

gradle-plugin/build.gradle

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
plugins {
2+
id 'groovy'
3+
id 'java'
4+
id 'java-gradle-plugin'
5+
id 'org.minimallycorrect.gradle.DefaultsPlugin'
6+
}
7+
8+
minimallyCorrectDefaults {
9+
shipkit = false
10+
configureProject(project)
11+
}
12+
13+
dependencies {
14+
//compileOnly 'com.google.guava:guava:25.1-jre' // bundled with gradle
15+
implementation rootProject
16+
testImplementation('org.spockframework:spock-core:1.3-groovy-2.4') {
17+
exclude module: 'groovy-all'
18+
}
19+
testImplementation('io.github.classgraph:classgraph:4.8.59')
20+
}
21+
22+
gradlePlugin {
23+
plugins {
24+
mixinGradlePlugin {
25+
id = 'org.minimallycorrect.mixin.gradle-plugin'
26+
implementationClass = 'org.minimallycorrect.mixinplugin.MixinGradlePlugin'
27+
}
28+
}
29+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.minimallycorrect.mixinplugin;
2+
3+
import java.io.File;
4+
5+
import lombok.NonNull;
6+
import lombok.val;
7+
8+
import org.gradle.api.file.ConfigurableFileCollection;
9+
import org.gradle.api.provider.Property;
10+
import org.gradle.api.tasks.Classpath;
11+
import org.gradle.api.tasks.Input;
12+
import org.gradle.api.tasks.InputFiles;
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
15+
16+
import org.minimallycorrect.mixin.internal.ApplicationType;
17+
import org.minimallycorrect.mixin.internal.MixinApplicator;
18+
19+
public abstract class ApplyMixins {
20+
private static final Logger logger = LoggerFactory.getLogger(ApplyMixins.class);
21+
22+
@Input
23+
@NonNull
24+
public abstract Property<ApplicationType> getApplicationType();
25+
26+
@Classpath
27+
@InputFiles
28+
@NonNull
29+
public abstract ConfigurableFileCollection getMixinSource();
30+
31+
/*
32+
removed this cache in case it's causing trouble
33+
@Internal
34+
private transient MixinApplicator applicator;
35+
*/
36+
37+
public MixinApplicator makeApplicator() {
38+
/*if (applicator != null) {
39+
return applicator;
40+
}*/
41+
val applicator = new MixinApplicator();
42+
applicator.setNoMixinIsError(true);
43+
applicator.setNotAppliedIsError(true);
44+
if (logger != null) {
45+
applicator.setLog(logger::info);
46+
}
47+
for (File file : getMixinSource().getFiles()) {
48+
applicator.addSource(file.toPath());
49+
}
50+
applicator.setApplicationType(getApplicationType().get());
51+
//this.applicator = applicator;
52+
return applicator;
53+
}
54+
55+
public void transformArtifact(File input, File output) {
56+
logger.info("Transforming " + input + " to " + output);
57+
makeApplicator().getMixinTransformer().transform(input.toPath(), output.toPath());
58+
}
59+
60+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.minimallycorrect.mixinplugin;
2+
3+
import javax.inject.Inject;
4+
5+
import lombok.NonNull;
6+
7+
import org.gradle.api.file.ConfigurableFileCollection;
8+
import org.gradle.api.model.ObjectFactory;
9+
import org.gradle.api.provider.Property;
10+
import org.gradle.api.tasks.Classpath;
11+
import org.gradle.api.tasks.Input;
12+
import org.gradle.api.tasks.InputFiles;
13+
14+
import org.minimallycorrect.mixin.internal.ApplicationType;
15+
16+
/**
17+
* Separate concrete impl, only used when not using transforms. Old gradle can't create getters for the Properties.
18+
*/
19+
public class ApplyMixinsImpl extends ApplyMixins {
20+
@Input
21+
private final Property<ApplicationType> applicationType;
22+
23+
@InputFiles
24+
@Classpath
25+
private final ConfigurableFileCollection mixinSource;
26+
27+
@Inject
28+
public ApplyMixinsImpl(ObjectFactory objectFactory, ConfigurableFileCollection mixinSource) {
29+
applicationType = objectFactory.property(ApplicationType.class);
30+
this.mixinSource = mixinSource;
31+
}
32+
33+
@NonNull
34+
@Input
35+
public Property<ApplicationType> getApplicationType() {
36+
return this.applicationType;
37+
}
38+
39+
@NonNull
40+
@InputFiles
41+
@Classpath
42+
public ConfigurableFileCollection getMixinSource() {
43+
return this.mixinSource;
44+
}
45+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package org.minimallycorrect.mixinplugin;
2+
3+
import java.io.File;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
7+
import lombok.AllArgsConstructor;
8+
import lombok.NonNull;
9+
import lombok.val;
10+
11+
import org.gradle.api.artifacts.Configuration;
12+
import org.gradle.api.artifacts.Dependency;
13+
import org.gradle.api.artifacts.DependencySet;
14+
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
15+
import org.gradle.api.artifacts.dsl.DependencyHandler;
16+
import org.gradle.api.artifacts.query.ArtifactResolutionQuery;
17+
import org.gradle.api.artifacts.result.ResolvedArtifactResult;
18+
import org.gradle.api.tasks.Internal;
19+
import org.gradle.api.tasks.Nested;
20+
import org.gradle.api.tasks.OutputDirectory;
21+
import org.gradle.maven.MavenModule;
22+
import org.gradle.maven.MavenPomArtifact;
23+
24+
import org.minimallycorrect.mixinplugin.deps.MModuleComponentIdentifier;
25+
26+
@AllArgsConstructor
27+
public class ApplyMixinsRepo {
28+
private ApplyMixins applyMixins;
29+
30+
@NonNull
31+
public File repo;
32+
33+
@NonNull
34+
private transient Configuration mixinConfiguration;
35+
36+
@Nested
37+
public ApplyMixins getApplyMixins() {
38+
return this.applyMixins;
39+
}
40+
41+
@NonNull
42+
@OutputDirectory
43+
public File getRepo() {
44+
return this.repo;
45+
}
46+
47+
@Internal
48+
@NonNull
49+
public final Map<Dependency, File> getOutputDependencyFiles() {
50+
val result = new HashMap<Dependency, File>();
51+
for (Dependency dependency : mixinConfiguration.getDependencies()) {
52+
result.put(dependency, new File(repo, getMavenPath(dependency.getGroup(), dependency.getName(), dependency.getVersion() + '-' + getStage()) + ".jar"));
53+
}
54+
return result;
55+
}
56+
57+
@Internal
58+
@NonNull
59+
public String getStage() {
60+
val type = applyMixins.getApplicationType().get();
61+
switch (type) {
62+
case PRE_PATCH:
63+
return "pre";
64+
case FINAL_PATCH:
65+
return "final";
66+
}
67+
throw new IllegalStateException("Unexpected value: " + type);
68+
}
69+
70+
@SuppressWarnings("unchecked")
71+
public void remapMixinArtifacts(@NonNull DependencyHandler dependencyHandler) {
72+
val applicator = applyMixins.makeApplicator();
73+
val config = mixinConfiguration;
74+
config.resolve();
75+
val resolved = config.getResolvedConfiguration();
76+
val stage = getStage();
77+
resolved.rethrowFailure();
78+
79+
for (val artifact : resolved.getResolvedArtifacts()) {
80+
val id = artifact.getId().getComponentIdentifier();
81+
if (id instanceof ModuleComponentIdentifier) {
82+
val mcid = (ModuleComponentIdentifier) id;
83+
val output = new File(repo, getMavenPath(mcid.getGroup(), mcid.getModule(), mcid.getVersion() + '-' + stage) + ".jar");
84+
output.getParentFile().mkdirs();
85+
applicator.getMixinTransformer().transform(artifact.getFile().toPath(), output.toPath());
86+
}
87+
}
88+
89+
ArtifactResolutionQuery query = artifactResolution(dependencyHandler, mixinConfiguration.getDependencies());
90+
query = query.withArtifacts(MavenModule.class, MavenPomArtifact.class);
91+
val result = query.execute();
92+
for (val resolvedComponent : result.getResolvedComponents()) {
93+
val id = resolvedComponent.getId();
94+
if (id instanceof ModuleComponentIdentifier) {
95+
val mcid = (ModuleComponentIdentifier) id;
96+
for (val artifact : resolvedComponent.getArtifacts(MavenPomArtifact.class)) {
97+
if (artifact instanceof ResolvedArtifactResult) {
98+
Utils.setPomRootVal(((ResolvedArtifactResult) artifact).getFile(), new File(repo, getMavenPath(mcid.getGroup(), mcid.getModule(), mcid.getVersion() + '-' + stage) + ".pom"), "version", ((ModuleComponentIdentifier) id).getVersion() + '-' + stage);
99+
}
100+
}
101+
}
102+
}
103+
}
104+
105+
private static ArtifactResolutionQuery artifactResolution(DependencyHandler dependencyHandler, DependencySet dependencies) {
106+
ArtifactResolutionQuery query = dependencyHandler.createArtifactResolutionQuery();
107+
for (val target : dependencies) {
108+
query = query.forComponents(new MModuleComponentIdentifier(target.getGroup(), target.getName(), target.getVersion()));
109+
}
110+
return query;
111+
}
112+
113+
private static String getMavenPath(String group, String name, String version) {
114+
return group.replace('.', '/') + '/' + name + '/' + version + '/' + name + '-' + version;
115+
}
116+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.minimallycorrect.mixinplugin;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import javax.inject.Inject;
7+
8+
import org.gradle.api.DefaultTask;
9+
import org.gradle.api.Project;
10+
import org.gradle.api.Task;
11+
import org.gradle.api.artifacts.Dependency;
12+
import org.gradle.api.model.ObjectFactory;
13+
import org.gradle.api.provider.Property;
14+
import org.gradle.api.tasks.CacheableTask;
15+
import org.gradle.api.tasks.Nested;
16+
import org.gradle.api.tasks.TaskAction;
17+
18+
import org.minimallycorrect.mixinplugin.deps.GeneratedDependency;
19+
import org.minimallycorrect.mixinplugin.deps.MModuleComponentIdentifier;
20+
21+
@CacheableTask
22+
public class ApplyMixinsTask extends DefaultTask {
23+
private final Property<ApplyMixinsRepo> applyMixinsRepo;
24+
25+
@Nested
26+
public Property<ApplyMixinsRepo> getApplyMixinsRepo() {
27+
return applyMixinsRepo;
28+
}
29+
30+
@Inject
31+
public ApplyMixinsTask(ObjectFactory factory) {
32+
applyMixinsRepo = factory.property(ApplyMixinsRepo.class);
33+
}
34+
35+
@TaskAction
36+
public void run() {
37+
applyMixinsRepo.get().remapMixinArtifacts(getProject().getDependencies());
38+
}
39+
40+
public List<Dependency> getGeneratedDependenciesForOutputs(Project project, Task task) {
41+
List<Dependency> result = new ArrayList<>();
42+
applyMixinsRepo.get().getOutputDependencyFiles().forEach((dep, file) -> result.add(GeneratedDependency.makeGeneratedDependency(project, task == null ? this : task, file,
43+
new MModuleComponentIdentifier(dep.getGroup(), dep.getName(), dep.getVersion()))));
44+
return result;
45+
}
46+
}

0 commit comments

Comments
 (0)