Niko
Niko

Reputation: 4448

Gradle: Get all sourceSets from root project

I’m writing a plugin to do some custom file indexing for an internal use-case we have where I currently work.

Doing some tinkering I’ve found that I can create my task/plugin in the rootProject’s buildSrc apply a task to each module via

subprojects {
    apply plugin: MyCustomIndexerPlugin
}

My plugin's implementation looks like this, and works just fine in the context of that single module:

@Override
public void apply(Project project) {
    Convention convention = project.getConvention();
    System.out.println("Working: " + project.getName());
    JavaPluginConvention javaPluginConvention = convention.getPlugin(JavaPluginConvention.class);
    SourceSetContainer sourceSets = javaPluginConvention.getSourceSets();

    TaskContainer taskContainer = project.getTasks();
    MyCustomIndexerTask myCustomIndexerTask = taskContainer.create("myCustomIndexerTask", MyCustomIndexerTask.class, task -> task.setSourceSetContainer(sourceSets));

    Task build = taskContainer.getByName("build");
    build.dependsOn(myCustomIndexerTask);
}

And here is my task:

@TaskAction
public void taskAction() {
    SortedMap<String, SourceSet> asMap = getSourceSetContainer().getAsMap();
    for (String sourceSetName : asMap.keySet()) {
        SourceSet sourceSet = asMap.get(sourceSetName);
        Set<File> files = sourceSet.getAllJava().getFiles();
        for (File file : files) {
            System.out.println(sourceSetName + " -> " + file);
        }
    }
}

This is (sorta) okay as a proof of concept, but I’d like to have my custom task performed at the rootProject level. So after all modules build successfully I run my code against all sourceSets. Is this possible or do I need to somehow pass this data from module to module as my project builds?

I’m having a difficult time finding the right documentation to do the right meta-coding I need to perform.

Upvotes: 2

Views: 5422

Answers (2)

Col-E
Col-E

Reputation: 185

Conventions are deprecated in Gradle as of 7.5.1 (The move to do so has been around since 2017)

You can accomplish the same results by using extensions:

rootProject.getSubprojects().forEach(subProject -> {
    JavaPluginExtension javaExtension = subProject.getExtensions().getByType(JavaPluginExtension.class);
    javaExtension.getSourceSets().forEach(set -> {
        // do things with source-set
    });
});

Upvotes: 3

Hiery Nomus
Hiery Nomus

Reputation: 17769

You can apply the plugin in the rootProject's build.gradle file. You could then do something like the following:

@Override
def apply(Project project) {
  if (project != project.rootProject) { throw new IllegalStateException("Can only be applied to rootProject") }
  def myCustomIndexerTask = taskContainer.create("myCustomIndexerTask", MyCustomIndexerTask.class)
  project.tasks.getByName("build").dependsOn myCustomIndexerTask

  project.subprojects.each { sp ->
    sp.whenPluginAdded(JavaPlugin) { jp ->
      def javaPluginConvention = sp.getConvention().getPlugin(JavaPluginConvention)
      def sourceSets = javaPluginConvention.getSourceSets()
      myCustomIndexerTask.addSourceSetContainer(sourceSets)
    }
  }
}

In your custom task you would then need to iterate over all the SourceSetContainers that were added.

Upvotes: 3

Related Questions