Skip to content

Commit 610bb2b

Browse files
authored
Add facade support (#28)
1 parent 650e1f0 commit 610bb2b

6 files changed

Lines changed: 160 additions & 92 deletions

File tree

src/main/java/net/minecraftforge/mcmaven/cli/MavenTask.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
import java.io.File;
88
import java.util.ArrayList;
99
import java.util.HashMap;
10+
import java.util.HashSet;
1011
import java.util.Map;
1112

1213
import joptsimple.OptionParser;
1314
import joptsimple.OptionSpecBuilder;
1415
import net.minecraftforge.mcmaven.impl.Mavenizer;
1516
import net.minecraftforge.mcmaven.impl.MinecraftMaven;
17+
import net.minecraftforge.mcmaven.impl.cache.Cache;
1618
import net.minecraftforge.mcmaven.impl.mappings.Mappings;
1719
import net.minecraftforge.mcmaven.impl.mappings.ParchmentMappings;
1820
import net.minecraftforge.mcmaven.impl.util.Artifact;
@@ -36,6 +38,11 @@ static OptionParser run(String[] args, boolean getParser) throws Exception {
3638
"Directory to store data needed for this program")
3739
.withRequiredArg().ofType(File.class).defaultsTo(new File("cache"));
3840

41+
// per-projct cache directory, This is where all the post processed files are cached
42+
var localCacheO = parser.accepts("local-cache",
43+
"Directory to store the project specific cache files, opposed to the global cache")
44+
.withRequiredArg().ofType(File.class).defaultsTo(new File("cache/local"));
45+
3946
// jdk cache directory
4047
var jdkCacheO = parser.accepts("jdk-cache",
4148
"Directory to store jdks downloaded from the disoco api")
@@ -104,9 +111,11 @@ static OptionParser run(String[] args, boolean getParser) throws Exception {
104111

105112
var accessTransformerO = parser.accepts("access-transformer",
106113
"An AccessTransformer config to apply to the artifacts have been built. This is a work around for Gradle's broken ArtifactTransformer system. https://github.com/MinecraftForge/ForgeGradle/issues/1023")
107-
.availableUnless(stubO)
108114
.withRequiredArg().ofType(File.class);
109-
stubO.availableUnless(accessTransformerO);
115+
116+
var facadeConfigO = parser.accepts("facade-config",
117+
"A Facade Config, which allows injecting interfaces to the built artifacts.")
118+
.withRequiredArg().ofType(File.class);
110119

111120
var outputJsonO = parser.accepts("output-json",
112121
"File to write extended output data to. Not compatible with bulk operations.")
@@ -165,6 +174,9 @@ static OptionParser run(String[] args, boolean getParser) throws Exception {
165174
var jdkCache = !options.has(cacheO) || options.has(jdkCacheO)
166175
? options.valueOf(jdkCacheO)
167176
: new File(cache, "jdks");
177+
var localCache = !options.has(cacheO) || options.has(localCacheO)
178+
? options.valueOf(localCacheO)
179+
: new File(cache, "local");
168180

169181
Artifact artifact = null;
170182
for (var entry : artifacts.entrySet()) {
@@ -193,14 +205,15 @@ static OptionParser run(String[] args, boolean getParser) throws Exception {
193205
var mcmaven = new MinecraftMaven(
194206
output,
195207
options.has(dependenciesOnlyO),
196-
cache,
197-
jdkCache,
208+
new Cache(cache, localCache, jdkCache, foreignRepositories),
198209
mappings,
199210
foreignRepositories,
200211
options.has(globalAuxiliaryVariantsO),
201212
options.has(disableGradleO),
202213
options.has(stubO),
214+
new HashSet<>(),
203215
new ArrayList<>(options.valuesOf(accessTransformerO)),
216+
new ArrayList<>(options.valuesOf(facadeConfigO)),
204217
options.valueOf(outputJsonO)
205218
);
206219
mcmaven.run(artifact);

src/main/java/net/minecraftforge/mcmaven/impl/MinecraftMaven.java

Lines changed: 123 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import net.minecraftforge.mcmaven.impl.util.Constants;
2020
import net.minecraftforge.mcmaven.impl.util.POMBuilder;
2121
import net.minecraftforge.mcmaven.impl.util.ProcessUtils;
22+
import net.minecraftforge.mcmaven.impl.util.Task;
2223
import net.minecraftforge.mcmaven.impl.util.Util;
2324
import net.minecraftforge.srgutils.MinecraftVersion;
2425
import net.minecraftforge.util.data.json.JsonData;
@@ -71,18 +72,13 @@ public record MinecraftMaven(
7172
boolean stubJars,
7273
Set<String> mcpConfigVersions,
7374
List<File> accessTransformer,
75+
List<File> facadeConfigs,
7476
@Nullable File outputJsonFile
7577
) {
7678
// Only 1.14.4+ has official mappings, we can support more when we add more mappings
7779
private static final MinecraftVersion MIN_OFFICIAL_MAPPINGS = MinecraftVersion.from("1.14.4");
7880
private static final ComparableVersion MIN_SUPPORTED_FORGE = new ComparableVersion("1.14.4");
7981

80-
public MinecraftMaven(File output, boolean dependenciesOnly, File cacheRoot, File jdkCacheRoot, Mappings mappings,
81-
Map<String, String> foreignRepositories, boolean globalAuxiliaryVariants, boolean disableGradle, boolean stubJars,
82-
List<File> accessTransformer, @Nullable File outputJsonFile) {
83-
this(output, dependenciesOnly, new Cache(cacheRoot, jdkCacheRoot, foreignRepositories), mappings, foreignRepositories, globalAuxiliaryVariants, disableGradle, stubJars, new HashSet<>(), accessTransformer, outputJsonFile);
84-
}
85-
8682
public MinecraftMaven {
8783
LOGGER.info(" Output: " + output.getAbsolutePath());
8884
if (outputJsonFile != null)
@@ -99,27 +95,31 @@ public MinecraftMaven(File output, boolean dependenciesOnly, File cacheRoot, Fil
9995
LOGGER.info(" GradleVariantHack: " + globalAuxiliaryVariants);
10096
LOGGER.info(" Disable Gradle: " + disableGradle);
10197
LOGGER.info(" Stub Jars: " + stubJars);
102-
if (!accessTransformer.isEmpty()) {
103-
var first = true;
104-
var itor = accessTransformer.iterator();
105-
while (itor.hasNext()) {
106-
var file = itor.next();
107-
if (first) {
108-
LOGGER.getInfo().print(" Access Transformer: ");
109-
first = false;
110-
} else {
111-
LOGGER.getInfo().print(" ");
112-
}
113-
LOGGER.getInfo().print(file.getAbsolutePath());
114-
if (!file.exists()) {
115-
LOGGER.getInfo().print(" SKIPPING DOESN'T EXIST");
116-
itor.remove();
117-
}
118-
LOGGER.getInfo().println();
98+
if (!accessTransformer.isEmpty())
99+
filter(" Access Transformer: ", accessTransformer);
100+
if (!facadeConfigs.isEmpty())
101+
filter(" Facade Config: ", facadeConfigs);
102+
LOGGER.info();
103+
}
104+
105+
private static void filter(String header, List<File> files) {
106+
var prefix = header;
107+
var itor = files.iterator();
108+
while (itor.hasNext()) {
109+
var file = itor.next();
110+
LOGGER.getInfo().print(prefix);
111+
if (prefix == header)
112+
prefix = " ".repeat(header.length());
113+
114+
LOGGER.getInfo().print(file.getAbsolutePath());
115+
116+
if (!file.exists()) {
117+
LOGGER.getInfo().print(" SKIPPING DOESN'T EXIST");
118+
itor.remove();
119119
}
120120
LOGGER.getInfo().println();
121121
}
122-
LOGGER.info();
122+
LOGGER.getInfo().println();
123123
}
124124

125125
public void run(Artifact artifact) {
@@ -225,13 +225,13 @@ protected void createMinecraft(Artifact artifact, MCPConfigRepo mcprepo, Map<Str
225225
List<PendingArtifact> artifacts = null;
226226
if (hasMcp(mcprepo, ver.id))
227227
artifacts = mcprepo.process(versioned, mappings.withMCVersion(ver.id), outputJson);
228-
else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo, ver.id) || !mcprepo.isObfuscated(ver.id)))
228+
else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo, ver.id) || !MCPConfigRepo.isObfuscated(ver.id)))
229229
artifacts = mcprepo.processWithoutMcp(versioned, mappings.withMCVersion(ver.id), outputJson);
230230
else {
231231
LOGGER.info("Skipping " + versioned + " no mcp config");
232232
continue;
233233
}
234-
finalize(artifact, mappings, artifacts);
234+
finalize(versioned, mappings, artifacts);
235235
}
236236
} else {
237237
var mcVersion = mcpToMcVersion(version);
@@ -240,7 +240,7 @@ else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo,
240240
List<PendingArtifact> artifacts = null;
241241
if (hasMcp(mcprepo, version))
242242
artifacts = mcprepo.process(artifact, mappings, outputJson);
243-
else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo, mcVersion) || !mcprepo.isObfuscated(mcVersion)))
243+
else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo, mcVersion) || !MCPConfigRepo.isObfuscated(mcVersion)))
244244
artifacts = mcprepo.processWithoutMcp(artifact, mappings, outputJson);
245245
else
246246
throw new IllegalStateException("Can not process " + artifact + " as it does not have a MCPConfig ror official mappings");
@@ -300,11 +300,26 @@ protected void finalize(Artifact module, Mappings mappings, List<Repo.PendingArt
300300
// Simplest case would be different mapping channels.
301301
// I haven't added an opt-in for making artifacts that use mappings, so just assume any artifact with variants
302302
var artifact = pending.artifact();
303+
var isJar = "jar".equals(artifact.getExtension());
304+
var isSources = "sources".equals(artifact.getClassifier());
303305

304-
if (stubJars && "jar".equals(artifact.getExtension())) {
306+
if (isJar) {
305307
// No sources allowed in stub repos
306-
if ("sources".equals(artifact.getClassifier()))
308+
if (stubJars && isSources)
307309
continue;
310+
311+
// Only transform main artifacts - This should be the main artifact but that may be a breaking change
312+
if (!accessTransformer.isEmpty() && artifact.getClassifier() == null)
313+
pending = pending.withTask(accessTransform(pending));
314+
315+
// The main artifact
316+
if (artifact.equals(module)) {
317+
if (!facadeConfigs.isEmpty())
318+
pending = pending.withTask(facade(pending));
319+
}
320+
321+
if (stubJars)
322+
pending = pending.withTask(stub(pending));
308323
}
309324

310325
String suffix = null;
@@ -360,20 +375,6 @@ protected void finalize(Artifact module, Mappings mappings, List<Repo.PendingArt
360375
}
361376

362377
private void updateFile(File target, File source, Artifact artifact) {
363-
var isJar = "jar".equals(artifact.getExtension());
364-
if (isJar) {
365-
if (stubJars) {
366-
writeStub(target, source, artifact);
367-
return;
368-
}
369-
370-
// Only transform main artifacts
371-
if (!accessTransformer.isEmpty() && artifact.getClassifier() == null) {
372-
writeAccessTransformed(target, source, artifact);
373-
return;
374-
}
375-
}
376-
377378
var cache = Util.cache(target)
378379
.add("source", source);
379380

@@ -404,81 +405,119 @@ private void updateFile(File target, File source, Artifact artifact) {
404405
}
405406
}
406407

407-
private void writeStub(File target, File source, Artifact artifact) {
408+
private Task stub(PendingArtifact pending) {
409+
var input = pending.task();
410+
return Task.named("stub", Task.deps(input), () -> stub(input, pending.artifact()));
411+
}
412+
413+
private File stub(Task inputTask, Artifact artifact) {
408414
var tool = this.cache.maven().download(Constants.STUBIFY);
415+
var target = new File(this.cache.localCache(), artifact.appendClassifier("stub").getLocalPath());
416+
var input = inputTask.execute();
417+
409418
var cache = Util.cache(target)
410419
.add("tool", tool)
411-
.add("source", source);
420+
.add("input", input);
412421

413422
if (Mavenizer.checkCache(target, cache))
414-
return;
423+
return target;
415424

416-
File jdk;
417-
try {
418-
jdk = this.cache.jdks().get(Constants.STUBIFY_JAVA_VERSION);
419-
} catch (Exception e) {
420-
throw new IllegalStateException("Failed to find JDK for version " + Constants.STUBIFY_JAVA_VERSION, e);
421-
}
425+
var args = List.of("--input", input.getAbsolutePath(), "--output", target.getAbsolutePath());
426+
execute("stubify", Constants.STUBIFY_JAVA_VERSION, tool, args, target);
422427

423-
var log = new File(source.getAbsolutePath() + ".stubify.log");
424-
var ret = ProcessUtils.runJar(jdk, source.getParentFile(), log, tool, Collections.emptyList(),
425-
List.of("--input", source.getAbsolutePath(), "--output", target.getAbsolutePath())
426-
);
427-
if (ret.exitCode != 0)
428-
throw new IllegalStateException("Failed to stubify jar file (exit code " + ret.exitCode + "), See log: " + log.getAbsolutePath());
428+
cache.save();
429+
return target;
430+
}
429431

430-
try {
431-
cache.save();
432-
HashUtils.updateHash(target);
433-
} catch (Throwable t) {
434-
throw new RuntimeException("Failed to generate artifact: %s".formatted(artifact), t);
435-
}
432+
private Task accessTransform(PendingArtifact pending) {
433+
var input = pending.task();
434+
return Task.named("access-transform", Task.deps(input), () -> accessTransform(input, pending.artifact()));
436435
}
437436

438-
private void writeAccessTransformed(File target, File source, Artifact artifact) {
437+
private File accessTransform(Task inputTask, Artifact artifact) {
439438
var tool = this.cache.maven().download(Constants.ACCESS_TRANSFORMER);
439+
var target = new File(this.cache.localCache(), artifact.appendClassifier("ated").getLocalPath());
440+
var input = inputTask.execute();
441+
440442
var cache = Util.cache(target)
441443
.add("tool", tool)
442444
.add(accessTransformer)
443-
.add("source", source);
445+
.add("input", input);
444446

445447
if (Mavenizer.checkCache(target, cache))
446-
return;
447-
448-
File jdk;
449-
try {
450-
jdk = this.cache.jdks().get(Constants.ACCESS_TRANSFORMER_JAVA_VERSION);
451-
} catch (Exception e) {
452-
throw new IllegalStateException("Failed to find JDK for version " + Constants.ACCESS_TRANSFORMER_JAVA_VERSION, e);
453-
}
448+
return target;
454449

455-
var log = new File(source.getAbsolutePath() + ".accesstransformer.log");
456450
var args = new ArrayList<>(List.of(
457-
"--inJar", source.getAbsolutePath(),
451+
"--inJar", input.getAbsolutePath(),
458452
"--outJar", target.getAbsolutePath()
459453
));
454+
460455
for (var file : accessTransformer) {
461456
if (!file.exists())
462457
throw new IllegalStateException("Access Transformer config does not exist: " + file.getAbsolutePath());
463458
args.add("--atfile");
464459
args.add(file.getAbsolutePath());
465460
}
466461

462+
execute("Access Transform", Constants.ACCESS_TRANSFORMER_JAVA_VERSION, tool, args, target);
463+
cache.save();
464+
return target;
465+
}
466+
467+
private Task facade(PendingArtifact pending) {
468+
var input = pending.task();
469+
return Task.named("facade", Task.deps(input), () -> facade(input, pending.artifact()));
470+
}
471+
472+
private File facade(Task inputTask, Artifact artifact) {
473+
var tool = this.cache.maven().download(Constants.FACADE);
474+
var target = new File(this.cache.localCache(), artifact.appendClassifier("facade").getLocalPath());
475+
var input = inputTask.execute();
476+
477+
var cache = Util.cache(target)
478+
.add("tool", tool)
479+
.add(facadeConfigs)
480+
.add("input", input);
481+
482+
if (Mavenizer.checkCache(target, cache))
483+
return target;
484+
485+
var args = new ArrayList<>(List.of(
486+
"--input", input.getAbsolutePath(),
487+
"--output", target.getAbsolutePath()
488+
));
489+
490+
for (var file : facadeConfigs) {
491+
if (!file.exists())
492+
throw new IllegalStateException("Facade config does not exist: " + file.getAbsolutePath());
493+
args.add("--config");
494+
args.add(file.getAbsolutePath());
495+
}
496+
497+
execute("facade ", Constants.FACAD_JAVA_VERSION, tool, args, target);
498+
cache.save();
499+
return target;
500+
}
501+
502+
private void execute(String name, int javaVersion, File tool, List<String> args, File target) {
503+
File jdk;
504+
try {
505+
jdk = this.cache.jdks().get(javaVersion);
506+
} catch (Exception e) {
507+
throw new IllegalStateException("Failed to find JDK for version " + javaVersion, e);
508+
}
509+
467510
// Older versions of AT have a bug where it wont create the directories as needed.
468511
var parent = target.getParentFile();
469512
if (parent != null && !parent.exists())
470513
parent.mkdirs();
471514

472-
var ret = ProcessUtils.runJar(jdk, source.getParentFile(), log, tool, Collections.emptyList(), args);
515+
516+
var log = new File(target.getAbsolutePath() + ".log");
517+
var ret = ProcessUtils.runJar(jdk, parent, log, tool, Collections.emptyList(), args);
473518
if (ret.exitCode != 0)
474-
throw new IllegalStateException("Failed to Access Transform jar file (exit code " + ret.exitCode + "), See log: " + log.getAbsolutePath());
519+
throw new IllegalStateException("Failed to " + name + " file (exit code " + ret.exitCode + "), See log: " + log.getAbsolutePath());
475520

476-
try {
477-
cache.save();
478-
HashUtils.updateHash(target);
479-
} catch (Throwable t) {
480-
throw new RuntimeException("Failed to generate artifact: %s".formatted(artifact), t);
481-
}
482521
}
483522

484523
private void updateVariants(Artifact artifact) {

0 commit comments

Comments
 (0)