如何在 gradle 插件中添加新的语言源目录?
How to add new language source directories in gradle plugin?
我想要以下适用于任意语言的 gradle 脚本 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"
}
}
}
我还想在 src/main/foo
、src/test/foo
.
处拥有标准 foo
源目录
如何编写 gradle 插件来实现这样的功能?有可能吗?
我有一个 "solution-like" 解决方法来满足我的需求,但仍然想了解添加新语言源目录的正确方法。
要实现这样的功能,应该扩展现有的源集(或至少 main
和 test
源集)。它看起来像 main
和 test
源集 are defined in JavaPlugin
。可以通过 Convention
对象进行扩展。
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());
});
}
}
任务 compileFoo
证明该插件确实有效。鉴于问题中的构建脚本片段,它会打印如下行:
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]
您的用例的源代码会很长,但这里有一些建议可以帮助您继续前进。
看看Scala Plugin。它完全满足您的需求(因为看起来您正在遵循 java 来源约定),而且还有更多。如果您正在尝试编写任何插件,我建议您查看整个 gradle 源代码。
您想查看的确切位置是:
ScalaBasePlugin#configureSourceSetDefaults
- 这是顶级配置发生的地方
DefaultScalaSourceSet
- 实际源集 class
在你的情况下,你可能只想将所有 scala
字符串重命名为 foo
并删除所有你不需要的配置(例如实际编译)。
该插件说明了如何添加默认源目录和方法:
public ScalaSourceSet scala(Closure configureClosure) {
configure(configureClosure, getScala());
return this;
}
负责添加生成的源。基本上它只需要默认的源目录工厂并使用它。您可以使用注入来添加所有默认的 gradle 工厂(请参阅 Scala 插件,只需使用 javax.inject.Inject
即可)。
您还可以查看 groovy 插件。请注意,例如DefaultGroovySourceSet
看起来像 scala 插件中的那个。
我想要以下适用于任意语言的 gradle 脚本 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"
}
}
}
我还想在 src/main/foo
、src/test/foo
.
foo
源目录
如何编写 gradle 插件来实现这样的功能?有可能吗?
我有一个 "solution-like" 解决方法来满足我的需求,但仍然想了解添加新语言源目录的正确方法。
要实现这样的功能,应该扩展现有的源集(或至少 main
和 test
源集)。它看起来像 main
和 test
源集 are defined in JavaPlugin
。可以通过 Convention
对象进行扩展。
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());
});
}
}
任务 compileFoo
证明该插件确实有效。鉴于问题中的构建脚本片段,它会打印如下行:
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]
您的用例的源代码会很长,但这里有一些建议可以帮助您继续前进。
看看Scala Plugin。它完全满足您的需求(因为看起来您正在遵循 java 来源约定),而且还有更多。如果您正在尝试编写任何插件,我建议您查看整个 gradle 源代码。
您想查看的确切位置是:
ScalaBasePlugin#configureSourceSetDefaults
- 这是顶级配置发生的地方DefaultScalaSourceSet
- 实际源集 class
在你的情况下,你可能只想将所有 scala
字符串重命名为 foo
并删除所有你不需要的配置(例如实际编译)。
该插件说明了如何添加默认源目录和方法:
public ScalaSourceSet scala(Closure configureClosure) {
configure(configureClosure, getScala());
return this;
}
负责添加生成的源。基本上它只需要默认的源目录工厂并使用它。您可以使用注入来添加所有默认的 gradle 工厂(请参阅 Scala 插件,只需使用 javax.inject.Inject
即可)。
您还可以查看 groovy 插件。请注意,例如DefaultGroovySourceSet
看起来像 scala 插件中的那个。