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

com.commercehub.gradle.plugin.avro.AvroPlugin Maven / Gradle / Ivy

package com.commercehub.gradle.plugin.avro;

import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.internal.ConventionMapping;
import org.gradle.api.internal.IConventionAware;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.plugins.ide.idea.GenerateIdeaModule;
import org.gradle.plugins.ide.idea.IdeaPlugin;
import org.gradle.plugins.ide.idea.model.IdeaModule;

import java.io.File;
import java.io.FileFilter;
import java.util.concurrent.Callable;

import static com.commercehub.gradle.plugin.avro.Constants.*;

public class AvroPlugin implements Plugin {
    @Override
    public void apply(final Project project) {
        project.getPlugins().apply(JavaPlugin.class);
        project.getPlugins().apply(AvroBasePlugin.class);
        configureTasks(project);
        configureIntelliJ(project);
    }

    private static void configureTasks(final Project project) {
        getSourceSets(project).all(new Action() {
            public void execute(SourceSet sourceSet) {
                GenerateAvroProtocolTask protoTask = configureProtocolGenerationTask(project, sourceSet);
                configureJavaGenerationTask(project, sourceSet, protoTask);
            }
        });
    }

    private static void configureIntelliJ(final Project project) {
        project.getPlugins().withType(IdeaPlugin.class).all(new Action() {
            @Override
            public void execute(IdeaPlugin ideaPlugin) {
                SourceSet mainSourceSet = getMainSourceSet(project);
                SourceSet testSourceSet = getTestSourceSet(project);
                final File mainGeneratedOutputDir = getGeneratedOutputDir(project, mainSourceSet, JAVA_EXTENSION);
                final File testGeneratedOutputDir = getGeneratedOutputDir(project, testSourceSet, JAVA_EXTENSION);
                project.getTasks().withType(GenerateIdeaModule.class).all(new Action() {
                    @Override
                    public void execute(GenerateIdeaModule generateIdeaModule) {
                        generateIdeaModule.doFirst(new Action() {
                            @Override
                            public void execute(Task task) {
                                project.mkdir(mainGeneratedOutputDir);
                                project.mkdir(testGeneratedOutputDir);
                            }
                        });
                    }
                });
                IdeaModule module = ideaPlugin.getModel().getModule();
                module.setSourceDirs(new SetBuilder()
                    .addAll(module.getSourceDirs())
                    .add(getAvroSourceDir(project, mainSourceSet))
                    .add(mainGeneratedOutputDir)
                    .build());
                module.setTestSourceDirs(new SetBuilder()
                    .addAll(module.getTestSourceDirs())
                    .add(getAvroSourceDir(project, testSourceSet))
                    .add(testGeneratedOutputDir)
                    .build());
                // IntelliJ doesn't allow source directories beneath an excluded directory.
                // Thus, we remove the build directory exclude and add all non-generated sub-directories as excludes.
                SetBuilder excludeDirs = new SetBuilder();
                excludeDirs.addAll(module.getExcludeDirs()).remove(project.getBuildDir());
                File buildDir = project.getBuildDir();
                if (buildDir.isDirectory()) {
                    excludeDirs.addAll(project.getBuildDir().listFiles(new NonGeneratedDirectoryFileFilter()));
                }
                module.setExcludeDirs(excludeDirs.build());
            }
        });
    }

    private static GenerateAvroProtocolTask configureProtocolGenerationTask(final Project project, final SourceSet sourceSet) {
        String taskName = sourceSet.getTaskName("generate", "avroProtocol");
        GenerateAvroProtocolTask task = project.getTasks().create(taskName, GenerateAvroProtocolTask.class);
        task.setDescription(
            String.format("Generates %s Avro protocol definition files from IDL files.", sourceSet.getName()));
        task.setGroup(GROUP_SOURCE_GENERATION);
        task.source(getAvroSourceDir(project, sourceSet));
        task.include("**/*." + IDL_EXTENSION);
        task.getConventionMapping().map("outputDir", new Callable() {
            @Override
            public File call() throws Exception {
                return getGeneratedOutputDir(project, sourceSet, PROTOCOL_EXTENSION);
            }
        });
        return task;
    }

    private static GenerateAvroJavaTask configureJavaGenerationTask(final Project project, final SourceSet sourceSet,
                                                                    GenerateAvroProtocolTask protoTask) {
        String taskName = sourceSet.getTaskName("generate", "avroJava");
        GenerateAvroJavaTask task = project.getTasks().create(taskName, GenerateAvroJavaTask.class);
        task.setDescription(String.format("Generates %s Avro Java source files from schema/protocol definition files.",
            sourceSet.getName()));
        task.setGroup(GROUP_SOURCE_GENERATION);
        task.source(getAvroSourceDir(project, sourceSet));
        task.source(protoTask.getOutputDir());
        task.source(protoTask.getOutputs());
        task.include("**/*." + SCHEMA_EXTENSION, "**/*." + PROTOCOL_EXTENSION);
        task.getConventionMapping().map("outputDir", new Callable() {
            @Override
            public File call() throws Exception {
                return getGeneratedOutputDir(project, sourceSet, JAVA_EXTENSION);
            }
        });

        final JavaCompile compileJavaTask = getCompileJavaTask(project, sourceSet);
        compileJavaTask.source(task.getOutputDir());
        compileJavaTask.source(task.getOutputs());

        final AvroExtension avroExtension = project.getExtensions().findByType(AvroExtension.class);
        ConventionMapping taskMapping = conventionMapping(task);
        taskMapping.map(OPTION_OUTPUT_CHARACTER_ENCODING, new Callable() {
            @Override
            public String call() throws Exception {
                String compilationEncoding = compileJavaTask.getOptions().getEncoding();
                String extensionEncoding = avroExtension.getOutputCharacterEncoding();
                return compilationEncoding != null ? compilationEncoding : extensionEncoding;
            }
        });
        return task;
    }

    private static File getAvroSourceDir(Project project, SourceSet sourceSet) {
        return project.file(String.format("src/%s/avro", sourceSet.getName()));
    }

    private static File getGeneratedOutputDir(Project project, SourceSet sourceSet, String extension) {
        return new File(project.getBuildDir(), String.format("generated-%s-avro-%s", sourceSet.getName(), extension));
    }

    private static JavaCompile getCompileJavaTask(Project project, SourceSet sourceSet) {
        return (JavaCompile) project.getTasks().getByName(sourceSet.getCompileJavaTaskName());
    }

    private static SourceSetContainer getSourceSets(Project project) {
        return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets();
    }

    private static SourceSet getMainSourceSet(Project project) {
        return getSourceSets(project).getByName(SourceSet.MAIN_SOURCE_SET_NAME);
    }

    private static SourceSet getTestSourceSet(Project project) {
        return getSourceSets(project).getByName(SourceSet.TEST_SOURCE_SET_NAME);
    }

    private static ConventionMapping conventionMapping(Object conventionAware) {
        // TODO: try other alternatives to convention mapping
        // Convention mapping is an internal API.
        // Other options here:
        // http://forums.gradle.org/gradle/topics/how_can_i_do_convention_mappings_from_java_without_depending_on_an_internal_api
        return ((IConventionAware) conventionAware).getConventionMapping();
    }

    private static class NonGeneratedDirectoryFileFilter implements FileFilter {
        @Override
        public boolean accept(File file) {
            return file.isDirectory() && !file.getName().startsWith("generated-");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy