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

net.minecraftforge.gradle.tasks.ExtractS2SRangeTask Maven / Gradle / Ivy

package net.minecraftforge.gradle.tasks;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import net.minecraftforge.gradle.PredefInputSupplier;
import net.minecraftforge.gradle.SequencedInputSupplier;
import net.minecraftforge.gradle.common.BasePlugin;
import net.minecraftforge.gradle.common.Constants;
import net.minecraftforge.gradle.delayed.DelayedFile;
import net.minecraftforge.srg2source.ast.RangeExtractor;
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.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.internal.AbstractTask;
import org.gradle.api.logging.LogLevel;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;

import com.google.code.regexp.Pattern;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;

public class ExtractS2SRangeTask extends DefaultTask
{
    @InputFiles
    private FileCollection libs;
    private DelayedFile projectFile; // to get classpath from a subproject
    private String projectConfig; // Also for a subProject
    private boolean includeJar = false; //Include the 'jar' task for subproject.
    
    // stuff defined on the tasks..
    private final List in = new LinkedList();
    
    @OutputFile
    private DelayedFile rangeMap;
    
    private boolean allCached = false;
    private static final Pattern FILE_FROM = Pattern.compile("\\s+@\\|([\\w\\d/.]+)\\|.*$");
    private static final Pattern FILE_START = Pattern.compile("\\s*Class Start\\: ([\\w\\d.]+)$");
    
    @TaskAction
    public void doTask() throws IOException
    {
        List ins = getIn();
        File rangemap = getRangeMap();
        
        InputSupplier inSup;
        
        if (ins.size() == 0)
            return; // no input.
        else if (ins.size() == 1)
        {
            // just 1 supplier.
            inSup = getInput(ins.get(0));
        }
        else
        {
            // multinput
            inSup = new SequencedInputSupplier();
            for (File f : ins)
            {
                ((SequencedInputSupplier) inSup).add(getInput(f));
            }
        }
        
        // cache
        inSup = cacheInputs(inSup, rangemap);
        
        if (rangemap.exists())
        {
            if (allCached)
            {
                return;
            }
            
            List files = inSup.gatherAll(".java");
            
            // read rangemap
            List lines = Files.readLines(rangemap, Charsets.UTF_8);
            {
                Iterator it = lines.iterator();
                while(it.hasNext())
                {
                    String line = it.next();
                    
                    com.google.code.regexp.Matcher match;
                    String fileMatch = null;
                    if (line.trim().startsWith("@"))
                    {
                        match = FILE_FROM.matcher(line);
                        if (match.matches())
                        {
                            fileMatch = match.group(1).replace('\\', '/');
                        }
                    }
                    else
                    {
                        match = FILE_START.matcher(line);
                        if (match.matches())
                        {
                            fileMatch = match.group(1).replace('.', '/') + ".java";
                        }
                    }
                    
                    if (fileMatch != null && files.contains(fileMatch))
                    {
                        it.remove();
                    }
                }
            }
            
            generateRangeMap(inSup, rangemap);
            
            lines.addAll(Files.readLines(rangemap, Charsets.UTF_8));
            Files.write(Joiner.on(Constants.NEWLINE).join(lines), rangemap, Charsets.UTF_8);
        }
        else
        {
            generateRangeMap(inSup, rangemap);
        }
    }
    
    private InputSupplier cacheInputs(InputSupplier input, File out) throws IOException
    {
        boolean outExists = out.exists();
        
        // read the cache
        File cacheFile = new File(out + ".inputCache");
        HashSet cache = readCache(cacheFile);
        
        // generate the cache
        List strings = input.gatherAll(".java");
        HashSet genCache = Sets.newHashSetWithExpectedSize(strings.size());
        PredefInputSupplier predef = new PredefInputSupplier();
        for (String rel : strings)
        {
            File root = new File(input.getRoot(rel)).getCanonicalFile();
            
            InputStream fis = input.getInput(rel);
            byte[] array = ByteStreams.toByteArray(fis);
            fis.close();
            
            CacheEntry entry = new CacheEntry(rel, root, Constants.hash(array));
            genCache.add(entry);
            
            if (!outExists || !cache.contains(entry))
            {
                predef.addFile(rel, root, array);
            }
        }
        
        if (!predef.isEmpty())
        {
            writeCache(cacheFile, genCache);
        }
        else
        {
            allCached = true;
        }

        return predef;
    }
    
    private HashSet readCache(File cacheFile) throws IOException
    {
        if (!cacheFile.exists())
            return Sets.newHashSetWithExpectedSize(0);
        
        List lines = Files.readLines(cacheFile, Charsets.UTF_8);
        HashSet cache = Sets.newHashSetWithExpectedSize(lines.size());
        
        for (String s : lines)
        {
            String[] tokens = s.split(";");
            if (tokens.length != 3)
            {
                getLogger().info("Corrupted input cache! {}", cacheFile);
                break;
            }
            cache.add(new CacheEntry(tokens[0], new File(tokens[1]), tokens[2]));
        }
        
        return cache;
    }
    
    private void writeCache(File cacheFile, Collection cache) throws IOException
    {
        if (cacheFile.exists())
            cacheFile.delete();
        
        cacheFile.getParentFile().mkdirs();
        cacheFile.createNewFile();
        
        BufferedWriter writer = Files.newWriter(cacheFile, Charsets.UTF_8);
        for (CacheEntry e : cache)
        {
            writer.write(e.toString());
            writer.newLine();
        }
        
        writer.close();
    }
    
    private void generateRangeMap(InputSupplier inSup, File rangeMap)
    {
        RangeExtractor extractor = new RangeExtractor();
        extractor.addLibs(getLibs().getAsPath()).setSrc(inSup);
        
        PrintStream stream = new PrintStream(Constants.createLogger(getLogger(), LogLevel.DEBUG));
        extractor.setOutLogger(stream);
        
        boolean worked = extractor.generateRangeMap(rangeMap);
        
        stream.close();
        
        if (!worked)
            throw new RuntimeException("RangeMap generation Failed!!!");
    }
    
    private InputSupplier getInput(File f) throws IOException
    {
        if (f.isDirectory())
            return new FolderSupplier(f);
        else if (f.getPath().endsWith(".jar") || f.getPath().endsWith(".zip"))
        {
            ZipInputSupplier supp = new ZipInputSupplier();
            supp.readZip(f);
            return supp;
        }
        else
            throw new IllegalArgumentException("Can only make suppliers out of directories and zips right now!");
    }
    
    public File getRangeMap()
    {
        return rangeMap.call();
    }

    public void setRangeMap(DelayedFile out)
    {
        this.rangeMap = out;
    }

    @InputFiles
    public FileCollection getIns()
    {
        return getProject().files(in);
    }
    
    public List getIn()
    {
        List files = new LinkedList();
        for (DelayedFile f : in)
            files.add(f.call());
        return files;
    }

    public void addIn(DelayedFile in)
    {
        this.in.add(in);
    }
    
    public FileCollection getLibs()
    {
        if (projectFile != null && libs == null) // libs == null to avoid doing this any more than necessary..
        {
            File buildscript = projectFile.call();
            if (!buildscript.exists())
                return null;
            
            Project proj = BasePlugin.getProject(buildscript, getProject());
            libs = proj.getConfigurations().getByName(projectConfig);

            if (includeJar)
            {
                AbstractTask jarTask = (AbstractTask)proj.getTasks().getByName("jar");
                executeTask(jarTask);
                File compiled = (File)jarTask.property("archivePath");
                libs = getProject().files(compiled, libs);
            }
        }
        
        return libs;
    }

    private void executeTask(AbstractTask task)
    {
        for (Object dep : task.getTaskDependencies().getDependencies(task))
        {
            executeTask((AbstractTask) dep);
        }

        if (!task.getState().getExecuted())
        {
            getLogger().lifecycle(task.getPath());
            task.execute();
        }
    }

    public void setLibs(FileCollection libs)
    {
        this.libs = libs;
    }
    
    public void setLibsFromProject(DelayedFile buildscript, String config, boolean includeJar)
    {
        this.projectFile = buildscript;
        this.projectConfig = config;
        this.includeJar = includeJar;
    }
    
    private static class CacheEntry
    {
        public final String path, hash;
        public final File root;
        
        public CacheEntry(String path, File root, String hash) throws IOException
        {
            this.path = path.replace('\\', '/');
            this.hash = hash;
            this.root = root.getCanonicalFile();
        }
        
        @Override
        public int hashCode()
        {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((hash == null) ? 0 : hash.hashCode());
            result = prime * result + ((path == null) ? 0 : path.hashCode());
            result = prime * result + ((root == null) ? 0 : root.hashCode());
            return result;
        }
        
        @Override
        public boolean equals(Object obj)
        {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            CacheEntry other = (CacheEntry) obj;
            if (hash == null)
            {
                if (other.hash != null)
                    return false;
            }
            else if (!hash.equals(other.hash))
                return false;
            if (path == null)
            {
                if (other.path != null)
                    return false;
            }
            else if (!path.equals(other.path))
                return false;
            if (root == null)
            {
                if (other.root != null)
                    return false;
            }
            else if (!root.getAbsolutePath().equals(other.root.getAbsolutePath()))
                return false;
            return true;
        }
        
        @Override
        public String toString()
        {
            return ""+path+";"+root+";"+hash;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy