Skip to content

Commit

Permalink
Remap jar task
Browse files Browse the repository at this point in the history
  • Loading branch information
Earthcomputer committed Oct 9, 2021
1 parent ddcbe80 commit 2bb3fa9
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 7 deletions.
6 changes: 0 additions & 6 deletions subprojects/gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,6 @@ val lorenzTinyVersion: String by project
val mappingIoVersion: String by project
val featherVersion: String by project

repositories {
maven("https://maven.parchmentmc.org/") {
name = "ParchmentMC"
}
}

dependencies {
// All source sets
commonDeps(gradleApi())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.spongepowered.gradle.vanilla.internal.task;

import org.cadixdev.bombe.jar.JarEntryTransformer;

import java.io.IOException;

public interface JarEntryTransformerProvider {
JarEntryTransformer getJarEntryTransformer() throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.spongepowered.gradle.vanilla.internal.task;

import org.apache.tools.ant.filters.BaseFilterReader;
import org.apache.tools.ant.util.ReaderInputStream;
import org.cadixdev.bombe.jar.JarClassEntry;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.gradle.api.Project;
import org.gradle.api.file.CopySpec;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;

public class RemapFilter extends BaseFilterReader {
private @MonotonicNonNull JarEntryTransformerProvider remapper;
private @MonotonicNonNull Reader delegate;

public RemapFilter(Reader in) {
super(in);
}

public JarEntryTransformerProvider getRemapper() {
return remapper;
}

public void setRemapper(JarEntryTransformerProvider remapper) {
this.remapper = remapper;
}

public static CopySpec createCopySpec(Project project, JarEntryTransformerProvider remapper) {
return project.copySpec(spec -> {
spec.include("**/*.class");
spec.setFilteringCharset("ISO-8859-1");
spec.filter(Collections.singletonMap("remapper", remapper), RemapFilter.class);
});
}

private void initialize() throws IOException {
InputStream in = new ReaderInputStream(this.in, StandardCharsets.ISO_8859_1);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int n;
while ((n = in.read(buffer)) != -1) {
baos.write(buffer, 0, n);
}
byte[] bytes = baos.toByteArray();

JarClassEntry transformed = remapper.getJarEntryTransformer().transform(new JarClassEntry("Foo.class", 0, bytes));
if (transformed == null) {
delegate = this.in;
} else {
delegate = new InputStreamReader(new ByteArrayInputStream(transformed.getContents()), StandardCharsets.ISO_8859_1);
}
}

@Override
public int read() throws IOException {
if (!getInitialized()) {
initialize();
setInitialized(true);
}
return delegate.read();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ public CompletableFuture<ResolutionResult<MinecraftEnvironment>> provide(
try (final Atlas atlas = new Atlas(this.executor)) {
for (final CompletableFuture<ArtifactModifier.AtlasPopulator> populator : populators) {
ArtifactModifier.AtlasPopulator pop = populator.get();
atlas.install(ctx -> pop.provide(withAsmApi(ctx, Constants.ASM_VERSION), input.get(), side, (id, classifier, extension) -> this.sharedArtifactFileName(id, version, classifier, extension)));
atlas.install(ctx -> pop.provide(withAsmApi(ctx, Constants.ASM_VERSION), input.get(), side, sharedArtifactSupplier(version)));
}

atlas.run(input.get().jar(), outputTmp);
Expand Down Expand Up @@ -427,6 +427,10 @@ public CompletableFuture<ResolutionResult<MinecraftEnvironment>> provide(
));
}

public ArtifactModifier.SharedArtifactSupplier sharedArtifactSupplier(String version) {
return (id, classifier, extension) -> this.sharedArtifactFileName(id, version, classifier, extension);
}

private static final Field CPIP_CLASS_PROVIDER_FIELD;
private static final Constructor<AtlasTransformerContext> ATC_CONSTRUCTOR;
static {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package org.spongepowered.gradle.vanilla.task;

import org.cadixdev.atlas.jar.JarFile;
import org.cadixdev.atlas.util.CascadingClassProvider;
import org.cadixdev.bombe.asm.analysis.ClassProviderInheritanceProvider;
import org.cadixdev.bombe.asm.jar.ClassProvider;
import org.cadixdev.bombe.jar.JarEntryTransformer;
import org.cadixdev.lorenz.MappingSet;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Internal;
import org.gradle.jvm.tasks.Jar;
import org.spongepowered.gradle.vanilla.MinecraftExtension;
import org.spongepowered.gradle.vanilla.internal.Constants;
import org.spongepowered.gradle.vanilla.internal.MinecraftExtensionImpl;
import org.spongepowered.gradle.vanilla.internal.repository.MinecraftProviderService;
import org.spongepowered.gradle.vanilla.internal.task.JarEntryTransformerProvider;
import org.spongepowered.gradle.vanilla.internal.task.RemapFilter;
import org.spongepowered.gradle.vanilla.internal.transformer.AtlasTransformers;
import org.spongepowered.gradle.vanilla.repository.MinecraftResolver;
import org.spongepowered.gradle.vanilla.repository.MinecraftResolverImpl;
import org.spongepowered.gradle.vanilla.repository.mappings.MappingsEntry;
import org.spongepowered.gradle.vanilla.resolver.ResolutionResult;

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public abstract class RemapJar extends Jar implements JarEntryTransformerProvider {
private final Property<String> fromMappings;
private final Property<String> toMappings;
private FileCollection classpath;
private JarEntryTransformer cachedTransformer;

public RemapJar() {
final Project project = getProject();
final ObjectFactory objects = project.getObjects();

fromMappings = objects.property(String.class).convention(project.provider(() -> {
final MinecraftExtension extension = project.getExtensions().findByType(MinecraftExtension.class);
Objects.requireNonNull(extension, "Could not find minecraft extension in project");
return extension.minecraftMappings().get();
}));
toMappings = objects.property(String.class);

with(RemapFilter.createCopySpec(project, this));
}

@Input
public Property<String> getFromMappings() {
return fromMappings;
}

public void fromMappings(MappingsEntry mappings) {
fromMappings(mappings.getName());
}

public void fromMappings(String mappings) {
fromMappings.set(mappings);
}

public void toMappings(MappingsEntry mappings) {
toMappings(mappings.getName());
}

public void toMappings(String mappings) {
toMappings.set(mappings);
}

@Input
public Property<String> getToMappings() {
return toMappings;
}

@Classpath
public FileCollection getClasspath() {
return classpath;
}

public void setClasspath(FileCollection classpath) {
this.classpath = classpath;
}

@Internal
public abstract Property<MinecraftProviderService> getMinecraftProvider();

@Override
public synchronized JarEntryTransformer getJarEntryTransformer() throws IOException {
if (cachedTransformer != null) {
return cachedTransformer;
}
Project project = getProject();
MinecraftExtensionImpl extension = (MinecraftExtensionImpl) project.getExtensions().findByType(MinecraftExtension.class);
Objects.requireNonNull(extension, "Could not find minecraft extension in project");
MinecraftProviderService minecraftProvider = getMinecraftProvider().get();
minecraftProvider.primeResolver(project, extension.modifiers());
MinecraftResolverImpl resolver = (MinecraftResolverImpl) minecraftProvider.resolver();
String minecraftVersion = extension.version().get();
CompletableFuture<ResolutionResult<MinecraftResolver.MinecraftEnvironment>> envFuture =
resolver.provide(extension.platform().get(), minecraftVersion, extension.modifiers());
try {
resolver.processSyncTasksUntilComplete(envFuture);
} catch (final ExecutionException ex) {
throw new GradleException("Failed to remap", ex.getCause());
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new GradleException("Interrupted");
}
ResolutionResult<MinecraftResolver.MinecraftEnvironment> envResult = envFuture.join();
if (!envResult.isPresent()) {
throw new IllegalStateException("Could not find Minecraft environment");
}

List<FileTree> allFiles = new ArrayList<>();
getMainSpec().walk(res -> allFiles.add(res.getAllSource()));
FileCollection actualClasspath = project.files(classpath, allFiles);
MappingSet mappings = extension.getMappings().getByName(toMappings.get()).convertFrom(
fromMappings.get(),
resolver,
envResult.get(),
extension.platform().get(),
resolver.sharedArtifactSupplier(minecraftVersion)
);
List<ClassProvider> classProviders = new ArrayList<>();
for (File file : actualClasspath) {
if (file.getName().endsWith(".jar")) {
classProviders.add(new JarFile(file.toPath()));
}
}
classProviders.add(name -> {
Set<File> files = actualClasspath.getAsFileTree().matching(tree -> tree.include(name + ".class")).getFiles();
if (files.size() != 1) {
return null;
}
try {
return Files.readAllBytes(files.iterator().next().toPath());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
return cachedTransformer = AtlasTransformers.remap(mappings, new ClassProviderInheritanceProvider(
Constants.ASM_VERSION,
new CascadingClassProvider(classProviders))
);
}
}

0 comments on commit 2bb3fa9

Please sign in to comment.