How to add source language directories to gradle plugin?

I want to have the following working gradle script for arbitrary language foo :

 sourceSets { main { java { srcDir "${project.buildDir}/generated-sources/gen-java" } foo { srcDir "${project.buildDir}/generated-sources/gen-foo" } } test { java { srcDir "${project.buildDir}/generated-sources/gen-test-java" } foo { srcDir "${project.buildDir}/generated-sources/gen-test-foo" } } } 

I also want to have standard foo source directories in src/main/foo , src/test/foo .

How to write a gradle plugin to achieve this functionality? Is there any way to do this?

I have a workaround similar to my solutions, but still want to understand how to correctly add new language directories.

+7
gradle gradle-plugin
source share
2 answers

To achieve this functionality, it is necessary to expand existing sets of sources (or at least main and test source sets). It looks like the main and test source sets are defined in JavaPlugin . Extension is possible through the Convention object.

 public class FooPlugin implements Plugin<ProjectInternal> { @Override public void apply(ProjectInternal project) { project.getPluginManager().apply(JavaPlugin.class); FooExtension ext = project.getExtensions().create( "foo", FooExtension.class, project, project.getFileResolver() ); SourceSetContainer cont = (SourceSetContainer) project.getProperties().get("sourceSets"); cont.all((SourceSet ss) -> { String name = ss.getName(); File sources = project.file("src/" + name + "/foo"); FooSourceSet fss = ext.getSourceSetsContainer().maybeCreate(name); SourceDirectorySet sds = fss.getFoo(); sds.srcDir(sources); Convention sourceSetConvention = (Convention) InvokerHelper.getProperty(ss, "convention"); sourceSetConvention.getPlugins().put("foo", fss); }); project.task("compileFoo"); } } public class FooExtension { private final NamedDomainObjectContainer<FooSourceSet> sourceSetsContainer; public FooExtension(Project project, FileResolver fileResolver) { sourceSetsContainer = project.container( FooSourceSet.class, new FooSourceSetFactory(fileResolver) ); } public NamedDomainObjectContainer<FooSourceSet> getSourceSetsContainer() { return sourceSetsContainer; } public void srcDir(String file) { sourceSetsContainer.getByName("main").getFoo().srcDir(file); } } public class FooSourceSetFactory implements NamedDomainObjectFactory<FooSourceSet> { private final FileResolver fileResolver; public FooSourceSetFactory(FileResolver fileResolver) { this.fileResolver = fileResolver; } @Override public FooSourceSet create(String name) { return new DefaultFooSourceSet(name, fileResolver); } } public interface FooSourceSet { public String getName(); public SourceDirectorySet getFoo(); public FooSourceSet foo(Closure clsr); } public class DefaultFooSourceSet implements FooSourceSet { final String name; final SourceDirectorySet foo; public DefaultFooSourceSet(String displayName, FileResolver fileResolver) { this.name = displayName; DefaultDirectoryFileTreeFactory ddftf = new DefaultDirectoryFileTreeFactory(); foo = new DefaultSourceDirectorySet(name, fileResolver, ddftf); } @Override public String getName() { return name; } @Override public SourceDirectorySet getFoo() { return foo; } @Override public FooSourceSet foo(Closure clsr) { ConfigureUtil.configure(clsr, foo); return this; } } public class CompileFooTask extends DefaultTask { @TaskAction public void compileFoo() { SourceSetContainer cont = (SourceSetContainer) getProject().getProperties().get("sourceSets"); cont.all((SourceSet ss) -> { FooSourceSet fss = getProject() .getExtensions() .getByType(FooExtension.class) .getSourceSetsContainer() .maybeCreate(ss.getName()); System.out.println("directories under " + ss.getName() + ": " + fss.getFoo().getSrcDirs()); }); } } 

The compileFoo task shows that the plugin really works. Given the script build fragment from the question, it prints lines like these:

 directories under main: [<root>/src/main/foo, <root>/build/generated-sources/gen-foo] directories under test: [<root>/src/test/foo, <root>/build/generated-sources/gen-test-foo] 
+2
source share

The source code for your use case will be quite long, but there are a few pointers here that hopefully will suit you.

Take a look at the Scala Plugin . It does exactly what you need (since it looks like you are following the java conventions for sources), as well as much more. If you are trying to write some kind of plugin, I recommend checking out the entire gradle source code.

Exact places you want to see:

In your case, you probably just want to rename all scala lines to foo and delete all the configuration you don't need (e.g. actual compilation).

The plugin illustrates how to add default source directories and a method:

 public ScalaSourceSet scala(Closure configureClosure) { configure(configureClosure, getScala()); return this; } 

takes care of adding the generated sources. Basically it just uses the factory default source directory and uses it. You can use injection to add all the default gradle factories (see Scala plugin, just using javax.inject.Inject works).

You can also check out the groovy plugin. Please note that, for example, DefaultGroovySourceSet looks like in the Scala plugin.

+3
source share