/* * A Gradle plugin for the creation of Minecraft mods and MinecraftForge plugins. * Copyright (C) 2013 Minecraft Forge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA */ package net.minecraftforge.gradle.patcher; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import net.minecraftforge.gradle.util.SequencedInputSupplier; import net.minecraftforge.srg2source.util.io.FolderSupplier; import net.minecraftforge.srg2source.util.io.InputSupplier; import net.minecraftforge.srg2source.util.io.ZipInputSupplier; import org.gradle.api.DefaultTask; import org.gradle.api.file.FileCollection; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; import com.google.common.base.Strings; import com.google.common.collect.Sets; import com.google.common.io.ByteStreams; /** * The point of this task is to take 2 input sets, and then build a zip/jar containing the files that exist in the 2nd set, but not the first. */ class TaskExtractNew extends DefaultTask { //@formatter:off private final List<Object> clean = new LinkedList<Object>(); private final List<Object> dirty = new LinkedList<Object>(); @Input @Optional private String ending; @OutputFile private Object output; //@formatter:on //@formatter:off public TaskExtractNew() { super(); } //@formatter:on @TaskAction public void doStuff() throws IOException { ending = Strings.nullToEmpty(ending); InputSupplier cleanSupplier = getSupplier(getCleanSource()); InputSupplier dirtySupplier = getSupplier(getDirtySource()); Set<String> cleanFiles = Sets.newHashSet(cleanSupplier.gatherAll(ending)); File output = getOutput(); output.getParentFile().mkdirs(); boolean isClassEnding = false; //TODO: Figure out Abrar's logic for this... ending.equals(".class"); // this is a trigger for custom stuff ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(output)); for (String path : dirtySupplier.gatherAll(ending)) { if ( (isClassEnding && matchesClass(cleanFiles, path)) || cleanFiles.contains(path)) { continue; } zout.putNextEntry(new ZipEntry(path)); InputStream stream = dirtySupplier.getInput(path); ByteStreams.copy(stream, zout); stream.close(); zout.closeEntry(); } zout.close(); cleanSupplier.close(); dirtySupplier.close(); } private String stripEnding(String path) { if (path == null || path.length() < ending.length()) return null; return path.substring(0, path.length() - ending.length()); } private boolean matchesClass(Set<String> cleans, String path) { int innerIndex = path.indexOf('$'); if (innerIndex > 0) // better not be starting with $ { // get the parent class, since its an inner path = stripEnding(path).substring(0, innerIndex) + ending; // from start till just before $ } return cleans.contains(path); } private static InputSupplier getSupplier(List<File> files) throws IOException { SequencedInputSupplier supplier = new SequencedInputSupplier(files.size() + 1); for (File f : files) { if (f.isDirectory()) supplier.add(new FolderSupplier(f)); else { ZipInputSupplier supp = new ZipInputSupplier(); supp.readZip(f); supplier.add(supp); } } return supplier; } @InputFiles public FileCollection getCleanSources() { return getProject().files(clean); } public List<File> getCleanSource() { List<File> files = new LinkedList<File>(); for (Object f : clean) files.add(getProject().file(f)); return files; } public void addCleanSource(Object in) { this.clean.add(in); } @InputFiles public FileCollection getDirtySources() { return getProject().files(dirty); } public List<File> getDirtySource() { List<File> files = new LinkedList<File>(); for (Object f : dirty) files.add(getProject().file(f)); return files; } public void addDirtySource(Object in) { this.dirty.add(in); } public String getEnding() { return ending; } public void setEnding(String ending) { this.ending = ending; } public File getOutput() { return getProject().file(output); } public void setOutput(Object output) { this.output = output; } }