Skip to content

Commit e44a915

Browse files
committed
WIP
going to be on my laptop for the weekend
1 parent 2f8916b commit e44a915

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1086
-758
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ dependencies {
2222
println("adding dependencies")
2323
implementation(mc.dependency)
2424

25-
mc.transformer(fileTree("src/main/resources/transformers"))
25+
// mc.transformer(fileTree("src/main/resources/transformers"))
2626

2727
compileOnly(cichlid.api("0.3.2"))
2828
cichlidRuntime(cichlid.runtime("0.3.2"))

plugin/build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ dependencies {
2121
implementation("net.neoforged:AutoRenamingTool:2.0.3")
2222
implementation("org.ow2.asm:asm-tree:9.7")
2323
implementation("org.vineflower:vineflower:1.11.1")
24+
25+
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
26+
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1")
27+
}
28+
29+
tasks.named<Test>("test") {
30+
useJUnitPlatform()
2431
}
2532

2633
tasks.named("shadowJar", com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package fish.cichlidmc.cichlid_gradle.cache;
2+
3+
public enum Artifact {
4+
JAR, SOURCES, POM
5+
}

plugin/src/main/java/fish/cichlidmc/cichlid_gradle/cache/CichlidCache.java

Lines changed: 18 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,48 @@
11
package fish.cichlidmc.cichlid_gradle.cache;
22

33
import fish.cichlidmc.cichlid_gradle.cache.storage.AssetStorage;
4+
import fish.cichlidmc.cichlid_gradle.cache.storage.DecompiledClassStorage;
5+
import fish.cichlidmc.cichlid_gradle.cache.storage.PomTemplateStorage;
6+
import fish.cichlidmc.cichlid_gradle.cache.storage.ReassembledJarStorage;
7+
import fish.cichlidmc.cichlid_gradle.cache.storage.TransformedClassStorage;
48
import fish.cichlidmc.cichlid_gradle.cache.storage.VersionStorage;
5-
import fish.cichlidmc.cichlid_gradle.cache.task.TaskContext;
6-
import fish.cichlidmc.pistonmetaparser.FullVersion;
7-
import fish.cichlidmc.pistonmetaparser.manifest.Version;
89
import org.gradle.api.Project;
910
import org.gradle.api.invocation.Gradle;
11+
import org.gradle.api.logging.Logger;
12+
import org.gradle.api.logging.Logging;
1013

1114
import java.nio.file.Path;
1215
import java.util.Objects;
1316

1417
/**
1518
* Interface for Cichlid's global Minecraft cache. Holds no state, just interfaces with the filesystem.
1619
* Layout is versioned, and each one can be found at {@code "root/v" + FORMAT}.
17-
* <p>
18-
* Layout:
19-
* <ul>
20-
* <li>
21-
* assets
22-
* <ul>
23-
* <li>indices</li>
24-
* <li>objects</li>
25-
* <li>.lock</li>
26-
* </ul>
27-
* </li>
28-
* <li>
29-
* $version
30-
* <ul>
31-
* <li>natives</li>
32-
* <li>mappings</li>
33-
* <li>jars</li>
34-
* <li>runs</li>
35-
* </ul>
36-
* </li>
37-
* </ul>
3820
*/
3921
public final class CichlidCache {
40-
public static final String MINECRAFT_GROUP = "net.minecraft";
41-
public static final String MINECRAFT_MODULE = "minecraft";
42-
4322
public static final String LOCAL_CACHE_PROPERTY = "cichlid.use_local_cache";
4423
public static final int FORMAT = 1;
4524
public static final String PATH = "cichlid-gradle-cache/v" + FORMAT;
4625

26+
private static final Logger logger = Logging.getLogger(CichlidCache.class);
27+
4728
public final Path root;
48-
// assets are shared by many versions, they're stored separately
4929
public final AssetStorage assets;
30+
public final ReassembledJarStorage reassembledJars;
31+
public final DecompiledClassStorage decompiledClasses;
32+
public final TransformedClassStorage transformedClasses;
33+
public final PomTemplateStorage pomTemplates;
5034

5135
private CichlidCache(Path root) {
5236
this.root = root;
53-
this.assets = new AssetStorage(this.root.resolve("assets"));
37+
this.assets = new AssetStorage(root.resolve("assets"));
38+
this.reassembledJars = new ReassembledJarStorage(root.resolve("reassembled"));
39+
this.decompiledClasses = new DecompiledClassStorage(root.resolve("decompiled"));
40+
this.transformedClasses = new TransformedClassStorage(root.resolve("transformed"));
41+
this.pomTemplates = new PomTemplateStorage(root.resolve("poms"));
5442
}
5543

5644
public VersionStorage getVersion(String version) {
57-
return new VersionStorage(this.root.resolve(version), version);
58-
}
59-
60-
public void ensureVersionIsCached(String versionId) {
61-
// see if this version actually exists
62-
Version version = ManifestCache.getVersion(versionId);
63-
if (version == null)
64-
return;
65-
66-
FullVersion fullVersion = ManifestCache.expand(version);
67-
68-
TaskContext ctx = new TaskContext();
69-
this.assets.submitInitialTasks(fullVersion.assetIndex, ctx);
70-
71-
VersionStorage storage = this.getVersion(versionId);
72-
storage.submitInitialTasks(fullVersion, ctx);
73-
74-
ctx.report();
75-
76-
// all tasks are done. If an exception wasn't thrown by report, everything was successful.
77-
storage.markComplete();
45+
return new VersionStorage(this.root.resolve("versions").resolve(version), version);
7846
}
7947

8048
public static CichlidCache get(Project project) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package fish.cichlidmc.cichlid_gradle.cache;
2+
3+
import java.io.File;
4+
5+
public record Transformers(Iterable<File> files, String hash) {
6+
}

plugin/src/main/java/fish/cichlidmc/cichlid_gradle/cache/mcmaven/McMavenResourceAccessor.java

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package fish.cichlidmc.cichlid_gradle.cache.mcmaven;
22

3-
import fish.cichlidmc.cichlid_gradle.util.FileUtils;
43
import org.gradle.api.resources.ResourceException;
5-
import org.gradle.internal.hash.HashCode;
64
import org.gradle.internal.resource.ExternalResource;
75
import org.gradle.internal.resource.ExternalResourceName;
86
import org.gradle.internal.resource.ResourceExceptions;
@@ -11,12 +9,8 @@
119
import org.gradle.internal.resource.transfer.ExternalResourceAccessor;
1210
import org.jetbrains.annotations.Nullable;
1311

14-
import java.io.IOException;
1512
import java.io.InputStream;
1613
import java.net.URI;
17-
import java.nio.file.Files;
18-
import java.nio.file.Path;
19-
import java.util.Date;
2014

2115
public final class McMavenResourceAccessor implements ExternalResourceAccessor {
2216
private final MinecraftMaven mcMaven;
@@ -31,13 +25,14 @@ public <T> T withContent(ExternalResourceName location, boolean revalidate,
3125
ExternalResource.ContentAndMetadataAction<T> action) throws ResourceException {
3226
URI uri = location.getUri();
3327
System.out.println("checking " + uri);
34-
Path file = this.mcMaven.getFile(uri);
35-
if (file == null)
36-
return null;
3728

38-
try (InputStream stream = Files.newInputStream(file)) {
29+
try {
30+
InputStream stream = this.mcMaven.get(uri);
31+
if (stream == null)
32+
return null;
33+
3934
return action.execute(stream, this.getMetaData(location, revalidate));
40-
} catch (IOException e) {
35+
} catch (Exception e) {
4136
throw ResourceExceptions.getFailed(uri, e);
4237
}
4338
}
@@ -47,22 +42,10 @@ public <T> T withContent(ExternalResourceName location, boolean revalidate,
4742
public ExternalResourceMetaData getMetaData(ExternalResourceName location, boolean revalidate) throws ResourceException {
4843
URI uri = location.getUri();
4944
System.out.println("checking " + uri);
50-
Path file = this.mcMaven.getFile(uri);
51-
if (file == null)
52-
return null;
5345

5446
try {
55-
return new DefaultExternalResourceMetaData(
56-
uri,
57-
new Date(Files.getLastModifiedTime(file).toMillis()),
58-
Files.size(file),
59-
null,
60-
null,
61-
HashCode.fromString(FileUtils.sha1(file)),
62-
file.getFileName().toString(),
63-
false
64-
);
65-
} catch (IOException e) {
47+
return this.mcMaven.get(uri) == null ? null : new DefaultExternalResourceMetaData(uri, -1, -1);
48+
} catch (Exception e) {
6649
throw ResourceExceptions.getFailed(uri, e);
6750
}
6851
}

plugin/src/main/java/fish/cichlidmc/cichlid_gradle/cache/mcmaven/MinecraftMaven.java

Lines changed: 93 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
11
package fish.cichlidmc.cichlid_gradle.cache.mcmaven;
22

3+
import fish.cichlidmc.cichlid_gradle.cache.Artifact;
34
import fish.cichlidmc.cichlid_gradle.cache.CichlidCache;
4-
import fish.cichlidmc.cichlid_gradle.cache.storage.JarsStorage;
5+
import fish.cichlidmc.cichlid_gradle.cache.ManifestCache;
6+
import fish.cichlidmc.cichlid_gradle.cache.Transformers;
7+
import fish.cichlidmc.cichlid_gradle.cache.task.CacheTaskEnvironment;
8+
import fish.cichlidmc.cichlid_gradle.cache.task.impl.AssetsTask;
9+
import fish.cichlidmc.cichlid_gradle.cache.task.impl.DecompileTask;
10+
import fish.cichlidmc.cichlid_gradle.cache.task.impl.ReassembleTask;
511
import fish.cichlidmc.cichlid_gradle.extension.def.MinecraftDefinition;
612
import fish.cichlidmc.cichlid_gradle.extension.def.MinecraftDefinitionImpl;
713
import fish.cichlidmc.cichlid_gradle.util.Distribution;
14+
import fish.cichlidmc.pistonmetaparser.FullVersion;
15+
import fish.cichlidmc.pistonmetaparser.manifest.Version;
16+
import org.gradle.api.InvalidUserDataException;
817
import org.gradle.api.NamedDomainObjectContainer;
918
import org.gradle.api.Project;
1019
import org.gradle.api.logging.Logger;
1120
import org.gradle.api.logging.Logging;
1221
import org.jetbrains.annotations.Nullable;
1322

23+
import java.io.ByteArrayInputStream;
1424
import java.io.File;
25+
import java.io.IOException;
26+
import java.io.InputStream;
1527
import java.net.URI;
28+
import java.nio.charset.StandardCharsets;
1629
import java.nio.file.Files;
1730
import java.nio.file.Path;
1831
import java.util.regex.Matcher;
@@ -23,6 +36,9 @@
2336
* Provides Minecraft jars and pom files for each version.
2437
*/
2538
public final class MinecraftMaven {
39+
public static final String GROUP = "net.minecraft";
40+
public static final String MODULE = "minecraft";
41+
2642
/**
2743
* Regex for files that could possibly be provided.
2844
*/
@@ -41,40 +57,79 @@ public MinecraftMaven(NamedDomainObjectContainer<MinecraftDefinition> defs, Cich
4157
this.cache = cache;
4258
}
4359

44-
/**
45-
* Find a path corresponding to the file at the requested location.
46-
* Returns null if one does not exist.
47-
*/
4860
@Nullable
49-
public Path getFile(URI uri) {
61+
public InputStream get(URI uri) throws IOException {
5062
Request request = extractRequest(uri);
5163
if (request == null)
5264
return null;
5365

5466
MinecraftDefinitionImpl def = (MinecraftDefinitionImpl) this.defs.findByName(request.def);
55-
if (def == null)
56-
return null;
67+
if (def == null) {
68+
throw new InvalidUserDataException("Minecraft definition '" + request.def + "' does not exist");
69+
}
5770

5871
String version = def.getVersionOrThrow();
5972

60-
System.out.println("resolving transformers");
73+
Iterable<File> transformerFiles = def.resolvableTransformers().getIncoming().getFiles();
74+
Transformers transformers = new Transformers(transformerFiles, request.hash);
75+
76+
return this.getArtifact(version, def.dist(), transformers, request);
77+
}
78+
79+
@Nullable
80+
private InputStream getArtifact(String versionId, Distribution dist, Transformers transformers, Request request) throws IOException {
81+
// see if this version actually exists
82+
Version version = ManifestCache.getVersion(versionId);
83+
if (version == null)
84+
return null;
6185

62-
for (File file : def.resolvableTransformers().getIncoming().getFiles()) {
63-
logger.quiet("Transformer: {}", file);
86+
FullVersion fullVersion = ManifestCache.expand(version);
87+
// and the dist. all versions have a client, check for server
88+
if (dist != Distribution.CLIENT && fullVersion.downloads.server.isEmpty())
89+
return null;
90+
91+
if (fullVersion.downloads.clientMappings.isEmpty()) {
92+
throw new InvalidUserDataException("Versions pre-mojmap are not currently supported!");
6493
}
6594

66-
this.cache.ensureVersionIsCached(version);
67-
JarsStorage storage = this.cache.getVersion(version).jars;
95+
if (request.artifact == Artifact.POM) {
96+
return this.getPom(fullVersion, dist, request);
97+
}
6898

69-
Distribution dist = def.getDistribution().get();
99+
boolean needsAssets = dist.needsAssets() && !this.cache.assets.isComplete(fullVersion.assetIndex);
100+
Path jar = this.cache.reassembledJars.get(versionId, transformers.hash(), dist, request.artifact);
101+
boolean needsJar = !Files.exists(jar);
70102

71-
Path path = switch (request.type) {
72-
case JAR -> storage.path(dist);
73-
case SOURCES -> storage.sources(dist);
74-
case POM -> storage.metadata(dist);
75-
};
103+
if (!needsAssets && !needsJar) {
104+
return Files.newInputStream(jar);
105+
}
106+
107+
CacheTaskEnvironment.Builder builder = new CacheTaskEnvironment.Builder(fullVersion, this.cache, dist, transformers);
108+
109+
if (needsAssets) {
110+
builder.add(AssetsTask::new);
111+
}
112+
113+
if (needsJar) {
114+
builder.add(env -> new ReassembleTask(env, request.artifact == Artifact.SOURCES));
115+
}
116+
117+
builder.start().report();
76118

77-
return Files.exists(path) ? path : null;
119+
// all tasks are done. If an exception wasn't thrown by report, everything was successful.
120+
return Files.newInputStream(jar);
121+
}
122+
123+
private InputStream getPom(FullVersion version, Distribution dist, Request request) throws IOException {
124+
Path template = this.cache.pomTemplates.get(version.id, dist);
125+
if (!Files.exists(template)) {
126+
PomGenerator.generate(version, template);
127+
}
128+
129+
// file should now exist
130+
String content = Files.readString(template);
131+
String filled = content.replace(PomGenerator.VERSION_PLACEHOLDER, request.gradleRequestedVersion());
132+
return new ByteArrayInputStream(filled.getBytes(StandardCharsets.UTF_8));
78133
}
79134

80135
@Nullable
@@ -97,22 +152,26 @@ private static Request extractRequest(URI uri) {
97152
if (!version1.equals(version2))
98153
return null;
99154

100-
// version is defName_hash, extract the name
101-
int underscore = version1.indexOf('_');
102-
if (underscore == -1)
155+
// version is defName$hash, extract the name
156+
int separator = version1.indexOf('$');
157+
if (separator == -1)
103158
return null;
104159

105-
String defName = version1.substring(0, underscore);
160+
String defName = version1.substring(0, separator);
161+
String hash = version1.substring(separator + 1);
106162

107-
Request.Type type = switch (matcher.group(3)) {
108-
case "jar" -> sources ? Request.Type.SOURCES : Request.Type.JAR;
109-
case "pom" -> Request.Type.POM;
110-
default -> throw new RuntimeException("Invalid Type");
163+
Artifact artifact = switch (matcher.group(3)) {
164+
case "jar" -> sources ? Artifact.SOURCES : Artifact.JAR;
165+
case "pom" -> Artifact.POM;
166+
default -> null;
111167
};
112168

113-
logger.quiet("Intercepted request for Minecraft definition {}, {}", defName, type);
169+
if (artifact == null)
170+
return null;
171+
172+
logger.quiet("Intercepted request for Minecraft definition {}, {}", defName, artifact);
114173

115-
return new Request(defName, type);
174+
return new Request(defName, hash, artifact);
116175
}
117176

118177
public static String createProtocol(Project project) {
@@ -135,9 +194,10 @@ private static char filterChar(char c) {
135194
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '+' || c == '-' || c == '.') ? c : '-';
136195
}
137196

138-
private record Request(String def, Type type) {
139-
private enum Type {
140-
JAR, SOURCES, POM
197+
private record Request(String def, String hash, Artifact artifact) {
198+
// the version specified in the pom needs to match what gradle requested exactly (defName$hash) or it'll be rejected
199+
private String gradleRequestedVersion() {
200+
return this.def + '$' + this.hash;
141201
}
142202
}
143203
}

0 commit comments

Comments
 (0)