All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.minecraftforge.gradle.dev.DevBasePlugin Maven / Gradle / Ivy

There is a newer version: 3.2.0
Show newest version
package net.minecraftforge.gradle.dev;

import edu.sc.seis.launch4j.Launch4jPluginExtension;
import groovy.lang.Closure;
import groovy.util.MapEntry;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import net.minecraftforge.gradle.common.BasePlugin;
import net.minecraftforge.gradle.common.Constants;
import net.minecraftforge.gradle.json.version.Library;
import net.minecraftforge.gradle.json.version.OS;
import net.minecraftforge.gradle.delayed.DelayedFile;
import net.minecraftforge.gradle.json.JsonFactory;
import net.minecraftforge.gradle.tasks.CopyAssetsTask;
import net.minecraftforge.gradle.tasks.GenSrgTask;
import net.minecraftforge.gradle.tasks.MergeJarsTask;
import net.minecraftforge.gradle.tasks.abstractutil.DownloadTask;
import net.minecraftforge.gradle.tasks.abstractutil.ExtractTask;
import net.minecraftforge.gradle.tasks.dev.CompressLZMA;
import net.minecraftforge.gradle.tasks.dev.ObfuscateTask;

import org.apache.shiro.util.AntPathMatcher;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.file.FileTree;
import org.gradle.api.file.FileVisitDetails;
import org.gradle.api.file.FileVisitor;
import org.gradle.api.tasks.Copy;
import org.gradle.api.tasks.bundling.Zip;
import org.gradle.process.ExecSpec;

import argo.jdom.JsonNode;

import com.google.common.base.Charsets;
import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;

public abstract class DevBasePlugin extends BasePlugin
{
    private AntPathMatcher antMatcher = new AntPathMatcher();
    protected static final String[] JAVA_FILES = new String[] { "**.java", "*.java", "**/*.java" };

    @SuppressWarnings("serial")
    @Override
    public void applyPlugin()
    {
        ExtractTask task = makeTask("extractWorkspace", ExtractTask.class);
        {
            task.getOutputs().upToDateWhen(new Closure(null) {
                public Boolean call(Object... obj)
                {
                    File file = new File(project.getProjectDir(), "eclipse");
                    return (file.exists() && file.isDirectory());
                }
            });
            task.from(delayedFile(DevConstants.WORKSPACE_ZIP));
            task.into(delayedFile(DevConstants.WORKSPACE));
        }

        DownloadTask task1;
        if (hasInstaller())
        {
            // apply L4J
            this.applyExternalPlugin("launch4j");

            if (project.getTasks().findByName("uploadArchives") != null)
            {
                project.getTasks().getByName("uploadArchives").dependsOn("launch4j");
            }

            task1 = makeTask("downloadBaseInstaller", DownloadTask.class);
            {
                task1.setOutput(delayedFile(DevConstants.INSTALLER_BASE));
                task1.setUrl(delayedString(DevConstants.INSTALLER_URL));
            }

            task1 = makeTask("downloadL4J", DownloadTask.class);
            {
                task1.setOutput(delayedFile(DevConstants.LAUNCH4J));
                task1.setUrl(delayedString(DevConstants.LAUNCH4J_URL));
            }

            task = makeTask("extractL4J", ExtractTask.class);
            {
                task.dependsOn("downloadL4J");
                task.from(delayedFile(DevConstants.LAUNCH4J));
                task.into(delayedFile(DevConstants.LAUNCH4J_DIR));
            }
        }

        task1 = makeTask("updateJson", DownloadTask.class);
        {
            task1.getOutputs().upToDateWhen(Constants.CALL_FALSE);
            task1.setUrl(delayedString(DevConstants.MC_JSON_URL));
            task1.setOutput(delayedFile(DevConstants.JSON_BASE));
            task1.setDoesCache(false);
            task1.doLast(new Closure(project)
            {
                @Override
                public Boolean call()
                {
                    try
                    {
                        File json = delayedFile(DevConstants.JSON_BASE).call();
                        if (!json.exists())
                            return true;
                        List lines = Files.readLines(json, Charsets.UTF_8);
                        StringBuilder buf = new StringBuilder();
                        for (String line : lines)
                        {
                            buf = buf.append(line).append('\n');
                        }
                        Files.write(buf.toString().getBytes(Charsets.UTF_8), json);
                    }
                    catch (Throwable t)
                    {
                        Throwables.propagate(t);
                    }
                    return true;
                }
            }
            );
        }

        CompressLZMA task3 = makeTask("compressDeobfData", CompressLZMA.class);
        {
            task3.setInputFile(delayedFile(DevConstants.NOTCH_2_SRG_SRG));
            task3.setOutputFile(delayedFile(DevConstants.DEOBF_DATA));
            task3.dependsOn("genSrgs");
        }

        MergeJarsTask task4 = makeTask("mergeJars", MergeJarsTask.class);
        {
            task4.setClient(delayedFile(Constants.JAR_CLIENT_FRESH));
            task4.setServer(delayedFile(Constants.JAR_SERVER_FRESH));
            task4.setOutJar(delayedFile(Constants.JAR_MERGED));
            task4.setMergeCfg(delayedFile(DevConstants.MERGE_CFG));
            task4.dependsOn("downloadClient", "downloadServer", "updateJson");
        }

        CopyAssetsTask task5 = makeTask("copyAssets", CopyAssetsTask.class);
        {
            task5.setAssetsDir(delayedFile(Constants.ASSETS));
            task5.setOutputDir(delayedFile(DevConstants.ECLIPSE_ASSETS));
            task5.setAssetIndex(getAssetIndexClosure());
            task5.dependsOn("getAssets", "extractWorkspace");
        }

        GenSrgTask task6 = makeTask("genSrgs", GenSrgTask.class);
        {
            task6.setInSrg(delayedFile(DevConstants.JOINED_SRG));
            task6.setInExc(delayedFile(DevConstants.JOINED_EXC));
            task6.setMethodsCsv(delayedFile(DevConstants.METHODS_CSV));
            task6.setFieldsCsv(delayedFile(DevConstants.FIELDS_CSV));
            task6.setNotchToSrg(delayedFile(DevConstants.NOTCH_2_SRG_SRG));
            task6.setNotchToMcp(delayedFile(DevConstants.NOTCH_2_MCP_SRG));
            task6.setMcpToSrg(delayedFile(DevConstants.MCP_2_SRG_SRG));
            task6.setMcpToNotch(delayedFile(DevConstants.MCP_2_NOTCH_SRG));
            task6.setSrgExc(delayedFile(DevConstants.SRG_EXC));
            task6.setMcpExc(delayedFile(DevConstants.MCP_EXC));
            task6.setDoesCache(false);
        }
    }

    @Override
    public final void applyOverlayPlugin()
    {
        // nothing.
    }

    @Override
    public final boolean canOverlayPlugin()
    {
        return false;
    }

    private void configureLaunch4J()
    {
        if (!hasInstaller())
            return;

        final File installer = ((Zip) project.getTasks().getByName("packageInstaller")).getArchivePath();

        File output = new File(installer.getParentFile(), installer.getName().replace(".jar", "-win.exe"));
        project.getArtifacts().add("archives", output);

        Launch4jPluginExtension ext = (Launch4jPluginExtension) project.getExtensions().getByName("launch4j");
        ext.setOutfile(output.getAbsolutePath());
        ext.setJar(installer.getAbsolutePath());

        String command = delayedFile(DevConstants.LAUNCH4J_DIR).call().getAbsolutePath();
        command += "/launch4j";

        if (Constants.OPERATING_SYSTEM == OS.WINDOWS)
            command += "c.exe";
        else
        {
            final String extraCommand = command;

            Task task = project.getTasks().getByName("extractL4J");
            task.doLast(new Action() {

                @Override
                public void execute(Task task)
                {
                    File f = new File(extraCommand);
                    if (!f.canExecute())
                    {
                        boolean worked = f.setExecutable(true);
                        project.getLogger().info("Setting file +X "+worked + " : "+f.getPath());
                    }
                    FileTree tree = delayedFileTree(DevConstants.LAUNCH4J_DIR + "/bin").call();
                    tree.visit(new FileVisitor()
                    {
                        @Override public void visitDir(FileVisitDetails dirDetails){}
                        @Override
                        public void visitFile(FileVisitDetails fileDetails)
                        {
                            if (!fileDetails.getFile().canExecute())
                            {
                                boolean worked = fileDetails.getFile().setExecutable(true);
                                project.getLogger().info("Setting file +X "+worked + " : "+fileDetails.getPath());
                            }
                        }
                    });
                }
            });
        }

        ext.setLaunch4jCmd(command);

        Task task = project.getTasks().getByName("generateXmlConfig");
        task.dependsOn("packageInstaller", "extractL4J");
        task.getInputs().file(installer);

        String icon = ext.getIcon();
        if (icon == null || icon.isEmpty())
        {
            icon = delayedFile(DevConstants.LAUNCH4J_DIR + "/demo/SimpleApp/l4j/SimpleApp.ico").call().getAbsolutePath();
        }
        icon = new File(icon).getAbsolutePath();
        ext.setIcon(icon);
        ext.setMainClassName(delayedString("{MAIN_CLASS}").call());
    }

    @Override
    protected DelayedFile getDevJson()
    {
        return delayedFile(DevConstants.JSON_DEV);
    }

    @Override
    public void afterEvaluate()
    {
        super.afterEvaluate();

        configureLaunch4J();

        // set obfuscate extras
        Task t = project.getTasks().getByName("obfuscateJar");
        if (t != null)
        {
            ObfuscateTask obf = ((ObfuscateTask)t);
            obf.setExtraSrg(getExtension().getSrgExtra());
            obf.configureProject(getExtension().getSubprojects());
            obf.configureProject(getExtension().getDirtyProject());
        }

        try
        {
            Copy copyTask = makeTask("extractNatives", Copy.class);
            {
                copyTask.exclude("META-INF", "META-INF/**", "META-INF/*");
                copyTask.into(delayedString(DevConstants.ECLIPSE_NATIVES).call());
                copyTask.dependsOn("extractWorkspace");
            }

            DelayedFile devJson = getDevJson();
            if (devJson == null)
            {
                project.getLogger().info("Dev json not set, could not create native downloads tasks");
                return;
            }

            if (version == null)
            {
                File jsonFile = devJson.call().getAbsoluteFile();
                try
                {
                    version = JsonFactory.loadVersion(jsonFile);
                }
                catch (Exception e)
                {
                    project.getLogger().error("" + jsonFile + " could not be parsed");
                    Throwables.propagate(e);
                }
            }

            for (Library lib : version.getLibraries())
            {
                if (lib.natives != null)
                {
                    String path = lib.getPathNatives();
                    String taskName = "downloadNatives-" + lib.getArtifactName().split(":")[1];

                    DownloadTask task = makeTask(taskName, DownloadTask.class);
                    {
                        task.setOutput(delayedFile("{CACHE_DIR}/minecraft/" + path));
                        task.setUrl(delayedString(lib.getUrl() + path));
                    }

                    copyTask.from(delayedZipTree("{CACHE_DIR}/minecraft/" + path));
                    copyTask.dependsOn(taskName);
                }
            }

        }
        catch (Exception e)
        {
            Throwables.propagate(e);
        }
    }

    protected Class getExtensionClass()
    {
        return DevExtension.class;
    }

    protected DevExtension getOverlayExtension()
    {
        // never happens.
        return null;
    }

    protected String getServerClassPath(File json)
    {
        try
        {
            JsonNode node = Constants.PARSER.parse(Files.newReader(json, Charset.defaultCharset()));

            StringBuilder buf = new StringBuilder();

            for (JsonNode lib : node.getArrayNode("versionInfo", "libraries"))
            {
                if (lib.isNode("serverreq") && lib.getBooleanValue("serverreq"))
                {
                    String[] pts = lib.getStringValue("name").split(":");
                    buf.append(String.format("libraries/%s/%s/%s/%s-%s.jar ", pts[0].replace('.', '/'), pts[1], pts[2], pts[1], pts[2]));
                }
            }
            buf.append(delayedString("minecraft_server.{MC_VERSION}.jar").call());
            return buf.toString();
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String resolve(String pattern, Project project, DevExtension exten)
    {
        pattern = super.resolve(pattern, project, exten);

        // For simplicities sake, if the version is in the standard format of {MC_VERSION}-{realVersion}
        // lets trim the MC version from the replacement string.
        String version = project.getVersion().toString();
        String mcSafe = exten.getVersion().replace('-', '_');
        if (version.startsWith(mcSafe + "-"))
        {
            version = version.substring(mcSafe.length() + 1);
        }
        pattern = pattern.replace("{VERSION}", version);
        pattern = pattern.replace("{MAIN_CLASS}", exten.getMainClass());
        pattern = pattern.replace("{FML_TWEAK_CLASS}", exten.getTweakClass());
        pattern = pattern.replace("{INSTALLER_VERSION}", exten.getInstallerVersion());
        pattern = pattern.replace("{FML_DIR}", exten.getFmlDir());
        pattern = pattern.replace("{FORGE_DIR}", exten.getForgeDir());
        pattern = pattern.replace("{BUKKIT_DIR}", exten.getBukkitDir());
        pattern = pattern.replace("{MAPPINGS_DIR}", exten.getFmlDir() + "/conf");
        return pattern;
    }

    @SuppressWarnings("serial")
    protected static String runGit(final Project project, final File workDir, final String... args)
    {
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        project.exec(new Closure(project, project)
        {
            @Override
            public ExecSpec call()
            {
                ExecSpec exec = (ExecSpec) getDelegate();
                exec.setExecutable("git");
                exec.args((Object[]) args);
                exec.setStandardOutput(out);
                exec.setWorkingDir(workDir);
                return exec;
            }
        });

        return out.toString().trim();
    }

    private boolean shouldSign(String path, List includes, List excludes)
    {
        for (String exclude : excludes)
        {
            if (antMatcher.matches(exclude, path))
            {
                return false;
            }
        }

        for (String include : includes)
        {
            if (antMatcher.matches(include, path))
            {
                return true;
            }
        }

        return includes.size() == 0; //If it gets to here, then it matches nothing. default to true, if no includes were specified
    }

    @SuppressWarnings("unchecked")
    protected void signJar(File archive, String keyName,  String... filters) throws IOException
    {
        if (!project.hasProperty("jarsigner")) return;

        List excludes = new ArrayList();
        List includes = new ArrayList();

        for (String s : filters)
        {
            if (s.startsWith("!")) excludes.add(s.substring(1));
            else includes.add(s);
        }

        Map> unsigned = Maps.newHashMap();
        File temp = new File(archive.getAbsoluteFile() + ".tmp");
        File signed = new File(archive.getAbsoluteFile() + ".signed");

        if (temp.exists()) temp.delete();
        if (signed.exists()) signed.delete();

        // Create a temporary jar with only the things we want to sign
        ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(temp)));
        ZipFile base = new ZipFile(archive);
        for (ZipEntry e: Collections.list(base.entries()))
        {
            if (shouldSign(e.getName(), includes, excludes))
            {
                ZipEntry n = new ZipEntry(e.getName());
                n.setTime(e.getTime());
                out.putNextEntry(n);
                ByteStreams.copy(base.getInputStream(e), out);
            }
            else
            {
                unsigned.put(e.getName(), new MapEntry(ByteStreams.toByteArray(base.getInputStream(e)), e.getTime()));
            }
        }
        base.close();
        out.close();

        // Sign the temporary jar
        Map jarsigner = (Map)project.property("jarsigner");

        Map args = Maps.newHashMap();
        args.put("alias", keyName);
        args.put("storepass", jarsigner.get("storepass"));
        args.put("keypass", jarsigner.get("keypass"));
        args.put("keystore", new File(jarsigner.get("keystore")).getAbsolutePath());
        args.put("jar", temp.getAbsolutePath());
        args.put("signedjar", signed.getAbsolutePath());
        project.getAnt().invokeMethod("signjar", args);

        //Kill temp files to make room
        archive.delete();
        temp.delete();

        //Join the signed jar and our unsigned content
        out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(archive)));
        base = new ZipFile(signed);
        for (ZipEntry e: Collections.list(base.entries()))
        {
            if (e.isDirectory())
            {
                out.putNextEntry(e);
            }
            else
            {
                ZipEntry n = new ZipEntry(e.getName());
                n.setTime(e.getTime());
                out.putNextEntry(n);
                ByteStreams.copy(base.getInputStream(e), out);
            }
        }
        base.close();

        for (Map.Entry> e : unsigned.entrySet())
        {
            ZipEntry n = new ZipEntry(e.getKey());
            n.setTime(e.getValue().getValue());
            out.putNextEntry(n);
            out.write(e.getValue().getKey());
        }
        out.close();
        signed.delete();
    }

    protected boolean hasInstaller()
    {
        return true;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy