Skip to content

Commit 758c17f

Browse files
committed
Invoke Mavenizer, asynchronously, at configuration time
1 parent cac2379 commit 758c17f

11 files changed

+360
-333
lines changed

src/main/java/net/minecraftforge/gradle/ForgeGradleFlowAction.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,10 @@ protected void run(Parameters parameters) throws IOException {
6565

6666
static abstract class AccessTransformersMissing extends ForgeGradleFlowAction<AccessTransformersMissing.Parameters> {
6767
static abstract class Parameters extends ForgeGradleFlowAction.Parameters {
68-
final Property<Boolean> appliedPlugin;
68+
final Property<Boolean> appliedPlugin = this.getObjects().property(Boolean.class).convention(false);
6969

7070
@Inject
71-
public Parameters() {
72-
this.appliedPlugin = this.getObjects().property(Boolean.class).convention(false);
73-
}
71+
public Parameters() { }
7472
}
7573

7674
@Inject

src/main/java/net/minecraftforge/gradle/ForgeGradleProblems.java

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ RuntimeException invalidMinecraftDependencyType(Dependency dependency) {
9797
return this.throwing(new IllegalArgumentException("Minecraft dependency is not a module dependency"), "unsupported-minecraft-dependency-type", "Non-module dependency used as Minecraft dependency", spec -> spec
9898
.details("""
9999
Attempted to use a non-module (or internal module) dependency as a Minecraft dependency.
100-
The Minecraft dependency must be an external module dependency, as it is resolved from the Minecraft Maven.
100+
The Minecraft dependency must be an external module dependency, as it is resolved from the Mavenizer output.
101101
This means that it cannot be substituted with file or project dependencies.
102102
Expected: (implementation of) %s, Actual: '%s
103103
Dependency: '%s'"""
@@ -109,22 +109,6 @@ RuntimeException invalidMinecraftDependencyType(Dependency dependency) {
109109
);
110110
}
111111

112-
@Deprecated(forRemoval = true)
113-
void reportMissingMetadata(Throwable throwable) {
114-
this.report("missing-metadata", "Failed to extract metadata", spec -> spec
115-
.details("""
116-
ForgeGradle failed to locate or extract the metadata generated for the Minecraft dependency.
117-
This is expected if the Minecraft Maven has not yet been synced.
118-
If you are seeing this after your first project sync, please report this as it might be a ForgeGradle bug.""")
119-
.severity(Severity.WARNING)
120-
.withException(throwable)
121-
.stackLocation()
122-
.solution("Re-run the synchronization for your Gradle project.")
123-
.solution("Manually run the " + SyncMinecraftMaven.NAME + " task if necessary.")
124-
.solution(HELP_MESSAGE)
125-
);
126-
}
127-
128112
RuntimeException changingMinecraftDependency(Dependency dependency) {
129113
return this.throwing(new IllegalArgumentException("Minecraft dependency cannot be changing"), "changing-minecraft-dependency", "Minecraft dependency marked as changing", spec -> spec
130114
.details("""
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package net.minecraftforge.gradle;
2+
3+
import org.gradle.api.Action;
4+
import org.gradle.api.Project;
5+
import org.gradle.api.file.ConfigurableFileCollection;
6+
import org.gradle.api.file.DirectoryProperty;
7+
import org.gradle.api.file.RegularFile;
8+
import org.gradle.api.logging.Logger;
9+
import org.gradle.api.logging.Logging;
10+
import org.gradle.api.model.ObjectFactory;
11+
import org.gradle.api.provider.Property;
12+
import org.gradle.jvm.toolchain.JavaLauncher;
13+
import org.gradle.process.ExecOperations;
14+
15+
import java.io.IOException;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
import java.util.Queue;
19+
import java.util.concurrent.CompletableFuture;
20+
import java.util.concurrent.ConcurrentLinkedQueue;
21+
import java.util.concurrent.ExecutionException;
22+
import java.util.concurrent.Future;
23+
import java.util.concurrent.TimeUnit;
24+
import java.util.concurrent.TimeoutException;
25+
import java.util.function.Consumer;
26+
27+
final class MavenizerAction implements Future<RegularFile> {
28+
private static final Logger LOGGER = Logging.getLogger(MavenizerAction.class);
29+
30+
final ConfigurableFileCollection classpath;
31+
final Property<JavaLauncher> javaLauncher;
32+
final Property<String> mainClass;
33+
final DirectoryProperty caches;
34+
final DirectoryProperty output;
35+
final Property<String> module;
36+
final Property<String> version;
37+
final Property<MinecraftMappings> mappings;
38+
39+
private final CapturingLogger capturingLogger;
40+
private final CapturingLogger capturingError;
41+
private final CompletableFuture<RegularFile> future;
42+
43+
private final ExecOperations execOperations;
44+
45+
MavenizerAction(ObjectFactory objects, ExecOperations execOperations, Action<? super MavenizerAction> action) {
46+
this.execOperations = execOperations;
47+
48+
this.classpath = objects.fileCollection();
49+
this.javaLauncher = objects.property(JavaLauncher.class);
50+
this.mainClass = objects.property(String.class);
51+
this.caches = objects.directoryProperty();
52+
this.output = objects.directoryProperty();
53+
this.module = objects.property(String.class);
54+
this.version = objects.property(String.class);
55+
this.mappings = objects.property(MinecraftMappings.class);
56+
57+
this.capturingLogger = new CapturingLogger(LOGGER::lifecycle);
58+
this.capturingError = new CapturingLogger(LOGGER::error);
59+
60+
action.execute(this);
61+
62+
this.classpath.finalizeValue();
63+
this.javaLauncher.finalizeValue();
64+
this.mainClass.finalizeValue();
65+
this.caches.finalizeValue();
66+
this.output.finalizeValue();
67+
this.module.finalizeValue();
68+
this.version.finalizeValue();
69+
this.mappings.finalizeValue();
70+
71+
this.future = CompletableFuture.supplyAsync(this::invoke);
72+
}
73+
74+
@Override
75+
public boolean cancel(boolean mayInterruptIfRunning) {
76+
return this.future.cancel(mayInterruptIfRunning);
77+
}
78+
79+
@Override
80+
public boolean isCancelled() {
81+
return this.future.isCancelled();
82+
}
83+
84+
@Override
85+
public boolean isDone() {
86+
return this.future.isDone();
87+
}
88+
89+
@Override
90+
public RegularFile get() throws InterruptedException, ExecutionException {
91+
return this.future.get();
92+
}
93+
94+
@Override
95+
public RegularFile get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
96+
return this.future.get(timeout, unit);
97+
}
98+
99+
void releaseLog() {
100+
this.capturingLogger.release();
101+
this.capturingError.release();
102+
}
103+
104+
private RegularFile invoke() {
105+
String group;
106+
String name;
107+
{
108+
var split = module.get().split(":");
109+
if (split.length != 2) {
110+
// TODO use problems API
111+
throw new IllegalArgumentException("Invalid Minecraft dependency module name: " + module.get());
112+
}
113+
group = split[0];
114+
name = split[1];
115+
}
116+
117+
try (var stdOut = Util.toLog(this.capturingLogger);
118+
var stdErr = Util.toLog(this.capturingError)) {
119+
this.execOperations.javaexec(spec -> {
120+
spec.setStandardOutput(stdOut);
121+
spec.setErrorOutput(stdErr);
122+
123+
spec.setClasspath(classpath);
124+
spec.setExecutable(javaLauncher.get().getExecutablePath());
125+
spec.getMainClass().set(mainClass);
126+
127+
spec.setArgs(getArgs());
128+
}).rethrowFailure();
129+
} catch (IOException e) {
130+
throw new RuntimeException(e);
131+
}
132+
133+
// TODO This assumes the placement of the metadata.zip file
134+
// It might be better to specify a location to output it, rather than include it as an artifact
135+
return output.file(Util.artifactPath(group, name, version.get(), "metadata", "zip")).get();
136+
}
137+
138+
private List<String> getArgs() {
139+
var args = new ArrayList<>(List.of(
140+
"--maven",
141+
"--cache", caches.get().getAsFile().getAbsolutePath(),
142+
"--output", output.get().getAsFile().getAbsolutePath(),
143+
"--jdk-cache", caches.dir("jdks").get().getAsFile().getAbsolutePath(),
144+
"--artifact", module.get(),
145+
"--version", version.get(),
146+
"--global-auxiliary-variants"
147+
));
148+
149+
if ("parchment".equals(mappings.get().channel())) {
150+
args.add("--parchment");
151+
args.add(mappings.get().version());
152+
}
153+
154+
return args;
155+
}
156+
157+
private static final class CapturingLogger implements Consumer<String> {
158+
private final Queue<String> lines = new ConcurrentLinkedQueue<>();
159+
private final Consumer<? super String> logger;
160+
private boolean capturing = true;
161+
162+
private CapturingLogger(Consumer<? super String> logger) {
163+
this.logger = logger;
164+
}
165+
166+
@Override
167+
public void accept(String s) {
168+
if (capturing) {
169+
lines.add(s);
170+
} else {
171+
logger.accept(s);
172+
}
173+
}
174+
175+
private void release() {
176+
if (!capturing) return;
177+
178+
lines.forEach(logger);
179+
capturing = false;
180+
}
181+
}
182+
}

0 commit comments

Comments
 (0)