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

net.minecraftforge.gradle.common.util.runs.IntellijRunGenerator Maven / Gradle / Ivy

/*
 * ForgeGradle
 * Copyright (C) 2018 Forge Development LLC
 *
 * 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.common.util.runs;

import net.minecraftforge.gradle.common.util.RunConfig;
import net.minecraftforge.gradle.common.util.Utils;

import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.plugins.ide.idea.model.IdeaModel;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

public class IntellijRunGenerator extends RunConfigGenerator.XMLConfigurationBuilder
{
    boolean useGradlePaths = true;

    public IntellijRunGenerator(@Nonnull final Project project)
    {
        detectGradleDelegation(project);
    }

    private void detectGradleDelegation(Project project)
    {
        XPath xpath = XPathFactory.newInstance().newXPath();

        // This file contains the current gradle import settings.
        File ideaGradleSettings = project.file(".idea/gradle.xml");
        if (ideaGradleSettings.exists() && ideaGradleSettings.isFile())
        {
            try
            {
                Node value = (Node) xpath.evaluate(
                        "/project/component[@name='GradleSettings']/option[@name='linkedExternalProjectsSettings']/GradleProjectSettings/option[@name='delegatedBuild']/@value",
                        new InputSource(new FileInputStream(ideaGradleSettings)),
                        XPathConstants.NODE);
                if (value != null)
                {
                    useGradlePaths = Boolean.parseBoolean(value.getTextContent());
                    return;
                }
            }
            catch (IOException | XPathExpressionException e)
            {
                e.printStackTrace();
            }
        }

        // This value is normally true, and won't be used unless the project's gradle.xml is missing.
        File ideaWorkspace = project.file(".idea/workspace.xml");
        if (ideaWorkspace.exists() && ideaWorkspace.isFile())
        {
            try
            {
                Node value = (Node) xpath.evaluate(
                        "/project/component[@name='DefaultGradleProjectSettings']/option[@name='delegatedBuild']/@value",
                        new InputSource(new FileInputStream(ideaWorkspace)),
                        XPathConstants.NODE);
                if (value != null)
                {
                    useGradlePaths = Boolean.parseBoolean(value.getTextContent());
                    return;
                }
            }
            catch (IOException | XPathExpressionException e)
            {
                e.printStackTrace();
            }
        }

        // Fallback, in case someone has a file-based project instead of a directory-based project.
        final IdeaModel idea = project.getExtensions().findByType(IdeaModel.class);
        File ideaFileProject = project.file(idea != null ? idea.getProject().getOutputFile() : (project.getName() + ".ipr"));
        if (ideaFileProject.exists() && ideaFileProject.isFile())
        {
            try
            {
                Node value = (Node) xpath.evaluate(
                        "/project/component[@name='GradleSettings']/option[@name='linkedExternalProjectsSettings']/GradleProjectSettings/option[@name='delegatedBuild']/@value",
                        new InputSource(new FileInputStream(ideaFileProject)),
                        XPathConstants.NODE);
                if (value != null)
                {
                    useGradlePaths = Boolean.parseBoolean(value.getTextContent());
                    return;
                }
            }
            catch (IOException | XPathExpressionException e)
            {
                e.printStackTrace();
            }
        }
    }

    @Override
    @Nonnull
    protected Map createRunConfiguration(@Nonnull final Project project, @Nonnull final RunConfig runConfig, @Nonnull final DocumentBuilder documentBuilder, List additionalClientArgs) {
        final Map documents = new LinkedHashMap<>();

        Map> updatedTokens = configureTokensLazy(project, runConfig,
                useGradlePaths
                    ? mapModClassesToGradle(project, runConfig)
                    : mapModClassesToIdea(project, runConfig)
        );

        // Java run config
        final Document javaDocument = documentBuilder.newDocument();
        {
            final Element rootElement = javaDocument.createElement("component");
            {
                final Element configuration = javaDocument.createElement("configuration");
                {
                    configuration.setAttribute("default", "false");
                    configuration.setAttribute("name", runConfig.getUniqueName());
                    configuration.setAttribute("type", "Application");
                    configuration.setAttribute("factoryName", "Application");
                    configuration.setAttribute("singleton", runConfig.isSingleInstance() ? "true" : "false");

                    elementOption(javaDocument, configuration, "MAIN_CLASS_NAME", runConfig.getMain());
                    elementOption(javaDocument, configuration, "VM_PARAMETERS",
                            getJvmArgs(runConfig, additionalClientArgs, updatedTokens));
                    elementOption(javaDocument, configuration, "PROGRAM_PARAMETERS",
                            getArgs(runConfig, updatedTokens));
                    elementOption(javaDocument, configuration, "WORKING_DIRECTORY",
                            replaceRootDirBy(project, runConfig.getWorkingDirectory(), "$PROJECT_DIR$"));

                    final Element module = javaDocument.createElement("module");
                    {
                        module.setAttribute("name", runConfig.getIdeaModule());
                    }
                    configuration.appendChild(module);

                    final Element envs = javaDocument.createElement("envs");
                    {
                        runConfig.getEnvironment().forEach((name, value) -> {
                            final Element envEntry = javaDocument.createElement("env");
                            {
                                envEntry.setAttribute("name", name);
                                envEntry.setAttribute("value", replaceRootDirBy(project, runConfig.replace(updatedTokens, value), "$PROJECT_DIR$"));
                            }
                            envs.appendChild(envEntry);
                        });
                    }
                    configuration.appendChild(envs);

                    final Element methods = javaDocument.createElement("method");
                    {
                        methods.setAttribute("v", "2");

                        final Element makeTask = javaDocument.createElement("option");
                        {
                            makeTask.setAttribute("name", "Make");
                            makeTask.setAttribute("enabled", "true");
                        }
                        methods.appendChild(makeTask);

                        final Element gradleTask = javaDocument.createElement("option");
                        {
                            gradleTask.setAttribute("name", "Gradle.BeforeRunTask");
                            gradleTask.setAttribute("enabled", "true");
                            gradleTask.setAttribute("tasks", project.getTasks().getByName("prepare" + Utils.capitalize(runConfig.getTaskName())).getPath());
                            gradleTask.setAttribute("externalProjectPath", "$PROJECT_DIR$");
                        }
                        methods.appendChild(gradleTask);
                    }
                    configuration.appendChild(methods);
                }
                rootElement.appendChild(configuration);
            }
            javaDocument.appendChild(rootElement);
        }
        documents.put(runConfig.getUniqueFileName() + ".xml", javaDocument);

        return documents;
    }

    private static Stream mapModClassesToIdea(@Nonnull final Project project, @Nonnull final RunConfig runConfig) {
        final IdeaModel idea = project.getExtensions().findByType(IdeaModel.class);

        JavaPluginExtension javaPlugin = project.getExtensions().getByType(JavaPluginExtension.class);
        SourceSetContainer sourceSets = javaPlugin.getSourceSets();
        final SourceSet main = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
        if (runConfig.getMods().isEmpty()) {
            return getIdeaPathsForSourceset(project, idea, "production", null);
        } else {

            return runConfig.getMods().stream()
                    .map(modConfig -> {
                        return modConfig.getSources().stream().flatMap(source -> {
                            String outName = source == main ? "production" : source.getName();
                            return getIdeaPathsForSourceset(project, idea, outName, modConfig.getName());
                        });
                    })
                    .flatMap(Function.identity());
        }
    }

    private static Stream getIdeaPathsForSourceset(@Nonnull Project project, @Nullable IdeaModel idea, String outName, @Nullable String modName)
    {
        String ideaResources, ideaClasses;
        try
        {
            String outputPath = idea != null
                    ? idea.getProject().getPathFactory().path("$PROJECT_DIR$").getCanonicalUrl()
                    : project.getProjectDir().getCanonicalPath();

            ideaResources = Paths.get(outputPath, "out", outName, "resources").toFile().getCanonicalPath();
            ideaClasses = Paths.get(outputPath, "out", outName, "classes").toFile().getCanonicalPath();
        }
        catch (IOException e)
        {
            throw new RuntimeException("Error getting paths for idea run configs", e);
        }

        if (modName != null)
        {
            ideaResources = modName + "%%" + ideaResources;
            ideaClasses = modName + "%%" + ideaClasses;
        }

        return Stream.of(ideaResources, ideaClasses);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy