Need to use live configuration methods here.
Need to use live configuration methods here.

/*
 * Copyright 2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gradle.ide.visualstudio.plugins

import org.gradle.api.Action
import org.gradle.api.Incubating
import org.gradle.api.Plugin
import org.gradle.api.Task
import org.gradle.api.internal.file.FileResolver
import org.gradle.api.internal.project.ProjectIdentifier
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.TaskContainer
import org.gradle.ide.visualstudio.VisualStudioExtension
import org.gradle.ide.visualstudio.VisualStudioProject
import org.gradle.ide.visualstudio.VisualStudioSolution
import org.gradle.ide.visualstudio.internal.DefaultVisualStudioExtension
import org.gradle.ide.visualstudio.internal.DefaultVisualStudioProject
import org.gradle.ide.visualstudio.internal.VisualStudioProjectConfiguration
import org.gradle.ide.visualstudio.tasks.GenerateFiltersFileTask
import org.gradle.ide.visualstudio.tasks.GenerateProjectFileTask
import org.gradle.ide.visualstudio.tasks.GenerateSolutionFileTask
import org.gradle.internal.reflect.Instantiator
import org.gradle.internal.service.ServiceRegistry
import org.gradle.model.Model
import org.gradle.model.Mutate
import org.gradle.model.RuleSource
import org.gradle.nativebinaries.ProjectNativeBinary
import org.gradle.nativebinaries.ProjectNativeComponent
import org.gradle.nativebinaries.internal.resolve.ProjectLocator
import org.gradle.nativebinaries.plugins.NativeComponentModelPlugin
import org.gradle.runtime.base.BinaryContainer

import javax.inject.Inject

@Incubating
class VisualStudioPlugin implements Plugin<ProjectInternal> {
    private final Instantiator instantiator
    private final ProjectLocator projectLocator
    private final FileResolver fileResolver

    @Inject
    VisualStudioPlugin(Instantiator instantiator, ProjectLocator projectLocator, FileResolver fileResolver) {
        this.instantiator = instantiator
        this.projectLocator = projectLocator
        this.fileResolver = fileResolver
    }

    void apply(ProjectInternal project) {
        project.plugins.apply(NativeComponentModelPlugin)
    }

    @RuleSource
    static class Rules {

        @Model
        static DefaultVisualStudioExtension visualStudio(ServiceRegistry serviceRegistry) {
            def instantiator = serviceRegistry.get(Instantiator)
            def projectLocator = serviceRegistry.get(ProjectLocator)
            def fileResolver = serviceRegistry.get(FileResolver)

            return instantiator.newInstance(DefaultVisualStudioExtension, instantiator, projectLocator, fileResolver)
        }

        @Mutate
        static void includeBuildFileInProject(DefaultVisualStudioExtension visualStudio, ProjectIdentifier projectIdentifier) {
            visualStudio.projects.all {
                if (projectIdentifier.buildFile != null) {
                    ((DefaultVisualStudioProject) it).addSourceFile(projectIdentifier.buildFile)
                }
            }
        }

        @Mutate
        @SuppressWarnings("GroovyUnusedDeclaration")
        public static void createVisualStudioModelForBinaries(DefaultVisualStudioExtension visualStudioExtension, BinaryContainer binaryContainer) {
            for (ProjectNativeBinary binary : binaryContainer.withType(ProjectNativeBinary.class)) {
                VisualStudioProjectConfiguration configuration = visualStudioExtension.getProjectRegistry().addProjectConfiguration(binary);

                // Only create a solution if one of the binaries is buildable
                if (binary.isBuildable()) {
                    DefaultVisualStudioProject visualStudioProject = configuration.getProject();
                    visualStudioExtension.getSolutionRegistry().addSolution(visualStudioProject);
                }
            }
        }

        @Mutate
        @SuppressWarnings("GroovyUnusedDeclaration")
        public static void createTasksForVisualStudio(TaskContainer tasks, VisualStudioExtension visualStudioExtension) {
            for (VisualStudioProject vsProject : visualStudioExtension.getProjects()) {
                vsProject.builtBy(createProjectsFileTask(tasks, vsProject));
                vsProject.builtBy(createFiltersFileTask(tasks, vsProject));
            }

            for (VisualStudioSolution vsSolution : visualStudioExtension.getSolutions()) {
                Task solutionTask = tasks.create(vsSolution.getName() + "VisualStudio");
                solutionTask.setDescription(String.format("Generates the '%s' Visual Studio solution file.", vsSolution.getName()));
                vsSolution.setBuildTask(solutionTask);
                vsSolution.builtBy(createSolutionTask(tasks, vsSolution));

                // Lifecycle task for component
                ProjectNativeComponent component = vsSolution.getComponent();
                Task lifecycleTask = tasks.maybeCreate(component.getName() + "VisualStudio");
                lifecycleTask.dependsOn(vsSolution);
                lifecycleTask.setGroup("IDE");
                lifecycleTask.setDescription(String.format("Generates the Visual Studio solution for %s.", component));
            }

            addCleanTask(tasks);
        }

        private static void addCleanTask(TaskContainer tasks) {
            Delete cleanTask = tasks.create("cleanVisualStudio", Delete.class);
            for (Task task : tasks.withType(GenerateSolutionFileTask.class)) {
                cleanTask.delete(task.getOutputs().getFiles());
            }
            for (Task task : tasks.withType(GenerateFiltersFileTask.class)) {
                cleanTask.delete(task.getOutputs().getFiles());
            }
            for (Task task : tasks.withType(GenerateProjectFileTask.class)) {
                cleanTask.delete(task.getOutputs().getFiles());
            }
            cleanTask.setGroup("IDE");
            cleanTask.setDescription("Removes all generated Visual Studio project and solution files");
        }

        private static Task createSolutionTask(TaskContainer tasks, VisualStudioSolution solution) {
            GenerateSolutionFileTask solutionFileTask = tasks.create(solution.getName() + "VisualStudioSolution", GenerateSolutionFileTask.class);
            solutionFileTask.setVisualStudioSolution(solution);
            return solutionFileTask;
        }

        private static Task createProjectsFileTask(TaskContainer tasks, VisualStudioProject vsProject) {
            GenerateProjectFileTask task = tasks.create(vsProject.getName() + "VisualStudioProject", GenerateProjectFileTask.class);
            task.setVisualStudioProject(vsProject);
            task.initGradleCommand();
            return task;
        }

        private static Task createFiltersFileTask(TaskContainer tasks, VisualStudioProject vsProject) {
            GenerateFiltersFileTask task = tasks.create(vsProject.getName() + "VisualStudioFilters", GenerateFiltersFileTask.class);
            task.setVisualStudioProject(vsProject);
            return task;
        }
    }

    private class IncludeBuildFileInProject implements Action<VisualStudioExtension> {
        private final ProjectInternal project;

        IncludeBuildFileInProject(ProjectInternal project) {
            this.project = project
        }

        void execute(VisualStudioExtension extension) {
            extension.projects.all {
                if (project.getBuildFile() != null) {
                    ((DefaultVisualStudioProject) it).addSourceFile(project.getBuildFile())
                }
            }
        }
    }
}

/*
 * Copyright 2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gradle.ide.visualstudio.plugins

import org.gradle.api.Action
import org.gradle.api.Incubating
import org.gradle.api.Plugin
import org.gradle.api.Task
import org.gradle.api.internal.file.FileResolver
import org.gradle.api.internal.project.ProjectIdentifier
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.TaskContainer
import org.gradle.ide.visualstudio.VisualStudioExtension
import org.gradle.ide.visualstudio.VisualStudioProject
import org.gradle.ide.visualstudio.VisualStudioSolution
import org.gradle.ide.visualstudio.internal.DefaultVisualStudioExtension
import org.gradle.ide.visualstudio.internal.DefaultVisualStudioProject
import org.gradle.ide.visualstudio.internal.VisualStudioProjectConfiguration
import org.gradle.ide.visualstudio.tasks.GenerateFiltersFileTask
import org.gradle.ide.visualstudio.tasks.GenerateProjectFileTask
import org.gradle.ide.visualstudio.tasks.GenerateSolutionFileTask
import org.gradle.internal.reflect.Instantiator
import org.gradle.internal.service.ServiceRegistry
import org.gradle.model.Model
import org.gradle.model.Mutate
import org.gradle.model.RuleSource
import org.gradle.nativebinaries.ProjectNativeBinary
import org.gradle.nativebinaries.ProjectNativeComponent
import org.gradle.nativebinaries.internal.resolve.ProjectLocator
import org.gradle.nativebinaries.plugins.NativeComponentModelPlugin
import org.gradle.runtime.base.BinaryContainer

import javax.inject.Inject

@Incubating
class VisualStudioPlugin implements Plugin<ProjectInternal> {
    private final Instantiator instantiator
    private final ProjectLocator projectLocator
    private final FileResolver fileResolver

    @Inject
    VisualStudioPlugin(Instantiator instantiator, ProjectLocator projectLocator, FileResolver fileResolver) {
        this.instantiator = instantiator
        this.projectLocator = projectLocator
        this.fileResolver = fileResolver
    }

    void apply(ProjectInternal project) {
        project.plugins.apply(NativeComponentModelPlugin)
    }

    @RuleSource
    static class Rules {

        @Model
        static DefaultVisualStudioExtension visualStudio(ServiceRegistry serviceRegistry) {
            def instantiator = serviceRegistry.get(Instantiator)
            def projectLocator = serviceRegistry.get(ProjectLocator)
            def fileResolver = serviceRegistry.get(FileResolver)

            return instantiator.newInstance(DefaultVisualStudioExtension, instantiator, projectLocator, fileResolver)
        }

        @Mutate
        static void includeBuildFileInProject(DefaultVisualStudioExtension visualStudio, ProjectIdentifier projectIdentifier) {
            visualStudio.projects.each {
                if (projectIdentifier.buildFile != null) {
                    ((DefaultVisualStudioProject) it).addSourceFile(projectIdentifier.buildFile)
                }
            }
        }

        @Mutate
        @SuppressWarnings("GroovyUnusedDeclaration")
        public static void createVisualStudioModelForBinaries(DefaultVisualStudioExtension visualStudioExtension, BinaryContainer binaryContainer) {
            for (ProjectNativeBinary binary : binaryContainer.withType(ProjectNativeBinary.class)) {
                VisualStudioProjectConfiguration configuration = visualStudioExtension.getProjectRegistry().addProjectConfiguration(binary);

                // Only create a solution if one of the binaries is buildable
                if (binary.isBuildable()) {
                    DefaultVisualStudioProject visualStudioProject = configuration.getProject();
                    visualStudioExtension.getSolutionRegistry().addSolution(visualStudioProject);
                }
            }
        }

        @Mutate
        @SuppressWarnings("GroovyUnusedDeclaration")
        public static void createTasksForVisualStudio(TaskContainer tasks, VisualStudioExtension visualStudioExtension) {
            for (VisualStudioProject vsProject : visualStudioExtension.getProjects()) {
                vsProject.builtBy(createProjectsFileTask(tasks, vsProject));
                vsProject.builtBy(createFiltersFileTask(tasks, vsProject));
            }

            for (VisualStudioSolution vsSolution : visualStudioExtension.getSolutions()) {
                Task solutionTask = tasks.create(vsSolution.getName() + "VisualStudio");
                solutionTask.setDescription(String.format("Generates the '%s' Visual Studio solution file.", vsSolution.getName()));
                vsSolution.setBuildTask(solutionTask);
                vsSolution.builtBy(createSolutionTask(tasks, vsSolution));

                // Lifecycle task for component
                ProjectNativeComponent component = vsSolution.getComponent();
                Task lifecycleTask = tasks.maybeCreate(component.getName() + "VisualStudio");
                lifecycleTask.dependsOn(vsSolution);
                lifecycleTask.setGroup("IDE");
                lifecycleTask.setDescription(String.format("Generates the Visual Studio solution for %s.", component));
            }

            addCleanTask(tasks);
        }

        private static void addCleanTask(TaskContainer tasks) {
            Delete cleanTask = tasks.create("cleanVisualStudio", Delete.class);
            for (Task task : tasks.withType(GenerateSolutionFileTask.class)) {
                cleanTask.delete(task.getOutputs().getFiles());
            }
            for (Task task : tasks.withType(GenerateFiltersFileTask.class)) {
                cleanTask.delete(task.getOutputs().getFiles());
            }
            for (Task task : tasks.withType(GenerateProjectFileTask.class)) {
                cleanTask.delete(task.getOutputs().getFiles());
            }
            cleanTask.setGroup("IDE");
            cleanTask.setDescription("Removes all generated Visual Studio project and solution files");
        }

        private static Task createSolutionTask(TaskContainer tasks, VisualStudioSolution solution) {
            GenerateSolutionFileTask solutionFileTask = tasks.create(solution.getName() + "VisualStudioSolution", GenerateSolutionFileTask.class);
            solutionFileTask.setVisualStudioSolution(solution);
            return solutionFileTask;
        }

        private static Task createProjectsFileTask(TaskContainer tasks, VisualStudioProject vsProject) {
            GenerateProjectFileTask task = tasks.create(vsProject.getName() + "VisualStudioProject", GenerateProjectFileTask.class);
            task.setVisualStudioProject(vsProject);
            task.initGradleCommand();
            return task;
        }

        private static Task createFiltersFileTask(TaskContainer tasks, VisualStudioProject vsProject) {
            GenerateFiltersFileTask task = tasks.create(vsProject.getName() + "VisualStudioFilters", GenerateFiltersFileTask.class);
            task.setVisualStudioProject(vsProject);
            return task;
        }
    }

    private class IncludeBuildFileInProject implements Action<VisualStudioExtension> {
        private final ProjectInternal project;

        IncludeBuildFileInProject(ProjectInternal project) {
            this.project = project
        }

        void execute(VisualStudioExtension extension) {
            extension.projects.all {
                if (project.getBuildFile() != null) {
                    ((DefaultVisualStudioProject) it).addSourceFile(project.getBuildFile())
                }
            }
        }
    }
}
