Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/main/java/net/minecraftforge/mcmaven/cli/MavenTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

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

// per-projct cache directory, This is where all the post processed files are cached
var localCacheO = parser.accepts("local-cache",
"Directory to store the project specific cache files, opposed to the global cache")
.withRequiredArg().ofType(File.class).defaultsTo(new File("cache/local"));

// jdk cache directory
var jdkCacheO = parser.accepts("jdk-cache",
"Directory to store jdks downloaded from the disoco api")
Expand Down Expand Up @@ -104,9 +111,11 @@ static OptionParser run(String[] args, boolean getParser) throws Exception {

var accessTransformerO = parser.accepts("access-transformer",
"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")
.availableUnless(stubO)
.withRequiredArg().ofType(File.class);
stubO.availableUnless(accessTransformerO);

var facadeConfigO = parser.accepts("facade-config",
"A Facade Config, which allows injecting interfaces to the built artifacts.")
.withRequiredArg().ofType(File.class);

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

Artifact artifact = null;
for (var entry : artifacts.entrySet()) {
Expand Down Expand Up @@ -193,14 +205,15 @@ static OptionParser run(String[] args, boolean getParser) throws Exception {
var mcmaven = new MinecraftMaven(
output,
options.has(dependenciesOnlyO),
cache,
jdkCache,
new Cache(cache, localCache, jdkCache, foreignRepositories),
mappings,
foreignRepositories,
options.has(globalAuxiliaryVariantsO),
options.has(disableGradleO),
options.has(stubO),
new HashSet<>(),
new ArrayList<>(options.valuesOf(accessTransformerO)),
new ArrayList<>(options.valuesOf(facadeConfigO)),
options.valueOf(outputJsonO)
);
mcmaven.run(artifact);
Expand Down
207 changes: 123 additions & 84 deletions src/main/java/net/minecraftforge/mcmaven/impl/MinecraftMaven.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import net.minecraftforge.mcmaven.impl.util.Constants;
import net.minecraftforge.mcmaven.impl.util.POMBuilder;
import net.minecraftforge.mcmaven.impl.util.ProcessUtils;
import net.minecraftforge.mcmaven.impl.util.Task;
import net.minecraftforge.mcmaven.impl.util.Util;
import net.minecraftforge.srgutils.MinecraftVersion;
import net.minecraftforge.util.data.json.JsonData;
Expand Down Expand Up @@ -71,18 +72,13 @@ public record MinecraftMaven(
boolean stubJars,
Set<String> mcpConfigVersions,
List<File> accessTransformer,
List<File> facadeConfigs,
@Nullable File outputJsonFile
) {
// Only 1.14.4+ has official mappings, we can support more when we add more mappings
private static final MinecraftVersion MIN_OFFICIAL_MAPPINGS = MinecraftVersion.from("1.14.4");
private static final ComparableVersion MIN_SUPPORTED_FORGE = new ComparableVersion("1.14.4");

public MinecraftMaven(File output, boolean dependenciesOnly, File cacheRoot, File jdkCacheRoot, Mappings mappings,
Map<String, String> foreignRepositories, boolean globalAuxiliaryVariants, boolean disableGradle, boolean stubJars,
List<File> accessTransformer, @Nullable File outputJsonFile) {
this(output, dependenciesOnly, new Cache(cacheRoot, jdkCacheRoot, foreignRepositories), mappings, foreignRepositories, globalAuxiliaryVariants, disableGradle, stubJars, new HashSet<>(), accessTransformer, outputJsonFile);
}

public MinecraftMaven {
LOGGER.info(" Output: " + output.getAbsolutePath());
if (outputJsonFile != null)
Expand All @@ -99,27 +95,31 @@ public MinecraftMaven(File output, boolean dependenciesOnly, File cacheRoot, Fil
LOGGER.info(" GradleVariantHack: " + globalAuxiliaryVariants);
LOGGER.info(" Disable Gradle: " + disableGradle);
LOGGER.info(" Stub Jars: " + stubJars);
if (!accessTransformer.isEmpty()) {
var first = true;
var itor = accessTransformer.iterator();
while (itor.hasNext()) {
var file = itor.next();
if (first) {
LOGGER.getInfo().print(" Access Transformer: ");
first = false;
} else {
LOGGER.getInfo().print(" ");
}
LOGGER.getInfo().print(file.getAbsolutePath());
if (!file.exists()) {
LOGGER.getInfo().print(" SKIPPING DOESN'T EXIST");
itor.remove();
}
LOGGER.getInfo().println();
if (!accessTransformer.isEmpty())
filter(" Access Transformer: ", accessTransformer);
if (!facadeConfigs.isEmpty())
filter(" Facade Config: ", facadeConfigs);
LOGGER.info();
}

private static void filter(String header, List<File> files) {
var prefix = header;
var itor = files.iterator();
while (itor.hasNext()) {
var file = itor.next();
LOGGER.getInfo().print(prefix);
if (prefix == header)
prefix = " ".repeat(header.length());

LOGGER.getInfo().print(file.getAbsolutePath());

if (!file.exists()) {
LOGGER.getInfo().print(" SKIPPING DOESN'T EXIST");
itor.remove();
}
LOGGER.getInfo().println();
}
LOGGER.info();
LOGGER.getInfo().println();
}

public void run(Artifact artifact) {
Expand Down Expand Up @@ -225,13 +225,13 @@ protected void createMinecraft(Artifact artifact, MCPConfigRepo mcprepo, Map<Str
List<PendingArtifact> artifacts = null;
if (hasMcp(mcprepo, ver.id))
artifacts = mcprepo.process(versioned, mappings.withMCVersion(ver.id), outputJson);
else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo, ver.id) || !mcprepo.isObfuscated(ver.id)))
else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo, ver.id) || !MCPConfigRepo.isObfuscated(ver.id)))
artifacts = mcprepo.processWithoutMcp(versioned, mappings.withMCVersion(ver.id), outputJson);
else {
LOGGER.info("Skipping " + versioned + " no mcp config");
continue;
}
finalize(artifact, mappings, artifacts);
finalize(versioned, mappings, artifacts);
}
} else {
var mcVersion = mcpToMcVersion(version);
Expand All @@ -240,7 +240,7 @@ else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo,
List<PendingArtifact> artifacts = null;
if (hasMcp(mcprepo, version))
artifacts = mcprepo.process(artifact, mappings, outputJson);
else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo, mcVersion) || !mcprepo.isObfuscated(mcVersion)))
else if (mappings.channel().equals("official") && (hasOfficialMappings(mcprepo, mcVersion) || !MCPConfigRepo.isObfuscated(mcVersion)))
artifacts = mcprepo.processWithoutMcp(artifact, mappings, outputJson);
else
throw new IllegalStateException("Can not process " + artifact + " as it does not have a MCPConfig ror official mappings");
Expand Down Expand Up @@ -300,11 +300,26 @@ protected void finalize(Artifact module, Mappings mappings, List<Repo.PendingArt
// Simplest case would be different mapping channels.
// I haven't added an opt-in for making artifacts that use mappings, so just assume any artifact with variants
var artifact = pending.artifact();
var isJar = "jar".equals(artifact.getExtension());
var isSources = "sources".equals(artifact.getClassifier());

if (stubJars && "jar".equals(artifact.getExtension())) {
if (isJar) {
// No sources allowed in stub repos
if ("sources".equals(artifact.getClassifier()))
if (stubJars && isSources)
continue;

// Only transform main artifacts - This should be the main artifact but that may be a breaking change
if (!accessTransformer.isEmpty() && artifact.getClassifier() == null)
pending = pending.withTask(accessTransform(pending));

// The main artifact
if (artifact.equals(module)) {
if (!facadeConfigs.isEmpty())
pending = pending.withTask(facade(pending));
}

if (stubJars)
pending = pending.withTask(stub(pending));
}

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

private void updateFile(File target, File source, Artifact artifact) {
var isJar = "jar".equals(artifact.getExtension());
if (isJar) {
if (stubJars) {
writeStub(target, source, artifact);
return;
}

// Only transform main artifacts
if (!accessTransformer.isEmpty() && artifact.getClassifier() == null) {
writeAccessTransformed(target, source, artifact);
return;
}
}

var cache = Util.cache(target)
.add("source", source);

Expand Down Expand Up @@ -404,81 +405,119 @@ private void updateFile(File target, File source, Artifact artifact) {
}
}

private void writeStub(File target, File source, Artifact artifact) {
private Task stub(PendingArtifact pending) {
var input = pending.task();
return Task.named("stub", Task.deps(input), () -> stub(input, pending.artifact()));
}

private File stub(Task inputTask, Artifact artifact) {
var tool = this.cache.maven().download(Constants.STUBIFY);
var target = new File(this.cache.localCache(), artifact.appendClassifier("stub").getLocalPath());
var input = inputTask.execute();

var cache = Util.cache(target)
.add("tool", tool)
.add("source", source);
.add("input", input);

if (Mavenizer.checkCache(target, cache))
return;
return target;

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

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

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

private void writeAccessTransformed(File target, File source, Artifact artifact) {
private File accessTransform(Task inputTask, Artifact artifact) {
var tool = this.cache.maven().download(Constants.ACCESS_TRANSFORMER);
var target = new File(this.cache.localCache(), artifact.appendClassifier("ated").getLocalPath());
var input = inputTask.execute();

var cache = Util.cache(target)
.add("tool", tool)
.add(accessTransformer)
.add("source", source);
.add("input", input);

if (Mavenizer.checkCache(target, cache))
return;

File jdk;
try {
jdk = this.cache.jdks().get(Constants.ACCESS_TRANSFORMER_JAVA_VERSION);
} catch (Exception e) {
throw new IllegalStateException("Failed to find JDK for version " + Constants.ACCESS_TRANSFORMER_JAVA_VERSION, e);
}
return target;

var log = new File(source.getAbsolutePath() + ".accesstransformer.log");
var args = new ArrayList<>(List.of(
"--inJar", source.getAbsolutePath(),
"--inJar", input.getAbsolutePath(),
"--outJar", target.getAbsolutePath()
));

for (var file : accessTransformer) {
if (!file.exists())
throw new IllegalStateException("Access Transformer config does not exist: " + file.getAbsolutePath());
args.add("--atfile");
args.add(file.getAbsolutePath());
}

execute("Access Transform", Constants.ACCESS_TRANSFORMER_JAVA_VERSION, tool, args, target);
cache.save();
return target;
}

private Task facade(PendingArtifact pending) {
var input = pending.task();
return Task.named("facade", Task.deps(input), () -> facade(input, pending.artifact()));
}

private File facade(Task inputTask, Artifact artifact) {
var tool = this.cache.maven().download(Constants.FACADE);
var target = new File(this.cache.localCache(), artifact.appendClassifier("facade").getLocalPath());
var input = inputTask.execute();

var cache = Util.cache(target)
.add("tool", tool)
.add(facadeConfigs)
.add("input", input);

if (Mavenizer.checkCache(target, cache))
return target;

var args = new ArrayList<>(List.of(
"--input", input.getAbsolutePath(),
"--output", target.getAbsolutePath()
));

for (var file : facadeConfigs) {
if (!file.exists())
throw new IllegalStateException("Facade config does not exist: " + file.getAbsolutePath());
args.add("--config");
args.add(file.getAbsolutePath());
}

execute("facade ", Constants.FACAD_JAVA_VERSION, tool, args, target);
cache.save();
return target;
}

private void execute(String name, int javaVersion, File tool, List<String> args, File target) {
File jdk;
try {
jdk = this.cache.jdks().get(javaVersion);
} catch (Exception e) {
throw new IllegalStateException("Failed to find JDK for version " + javaVersion, e);
}

// Older versions of AT have a bug where it wont create the directories as needed.
var parent = target.getParentFile();
if (parent != null && !parent.exists())
parent.mkdirs();

var ret = ProcessUtils.runJar(jdk, source.getParentFile(), log, tool, Collections.emptyList(), args);

var log = new File(target.getAbsolutePath() + ".log");
var ret = ProcessUtils.runJar(jdk, parent, log, tool, Collections.emptyList(), args);
if (ret.exitCode != 0)
throw new IllegalStateException("Failed to Access Transform jar file (exit code " + ret.exitCode + "), See log: " + log.getAbsolutePath());
throw new IllegalStateException("Failed to " + name + " file (exit code " + ret.exitCode + "), See log: " + log.getAbsolutePath());

try {
cache.save();
HashUtils.updateHash(target);
} catch (Throwable t) {
throw new RuntimeException("Failed to generate artifact: %s".formatted(artifact), t);
}
}

private void updateVariants(Artifact artifact) {
Expand Down
Loading
Loading