A subproject which assembles and processes other subprojects and dependencies

Hi folks,

I have been beating my head against this and feel if I am to continue, I should just ask.

I have a project which consists of a bunch of subprojects. I am trying to write a plugin that allows me to write a build.gradle like

apply plugin: MyPlugin

dependencies {

runtime project(":subprocject1")

runtime project(":subproject2") }

for one of the subprojects which will be conditionally added to the given root project.

The plugin MyPlugin would have as dependencies on two subprojects subproject1 and subproject2. There would be a task foo that MyPlugin would add which gets the artifacts built for subproject1 and subproject2 and all of the recursive dependencies of those projects. The subprojects will be projects with the Java plugin applied and the recursive dependencies can include other java sub projects and jar dependencies that come in from Maven or Ivy or some such thing. I want foo to have a dependency which will build all artifacts which need to be built before foo runs.

The reason I am doing this is that I want to copy all of the artifacts or the recursive dependencies from the listed subprojects into a specified directory, all jars in my immediate need, and then postprocess all of the jars after they are copied.

What’s the question?

Thanks for responding. I suspect this will run through several iterations. Please be patient. I have read major parts of the manual and done a lot of Googling and looking at source code over the past week, and still haven’t figured out the details. I have tried lots of things and have gotten nowhere so figured it was time to ask.

I am looking for details about how to write the plugin. A skeleton plugin written in groovy that answers the following questions would get me started.

What APIs do I use to get a complete list of artifacts that need to be built from the subprojects with the Java plugin for the dependencies that I declare? How do I then add those dependencies onto a dependsOn for the foo task? What APIs do I use to get the artifacts that aren’t being built, e.g. coming from Maven or Ivy repositories?

Thanks, Peter.

Here is what I have so far. The buildDependents section isn’t working.

import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.plugins.BasePlugin
   class MyPlugin implements Plugin<Project>
{
    public static final String RUNTIME_CONFIGURATION_NAME = "runtime";
    public static final String BUILD_DEPENDENTS_TASK_NAME = "buildDependents";
          def void apply(Project project) {
      project.getPlugins().apply(BasePlugin.class);
      configureConfigurations(project)
      configureBuildDependents(project)
        def fooTask = project.task("foo");
      fooTask << {
        println project.configurations.runtime.resolvedConfiguration.runtime
      }
      fooTask.dependsOn(BUILD_DEPENDENTS_TASK_NAME)
    }
      void configureConfigurations(final Project project) {
        ConfigurationContainer configurations = project.getConfigurations();
           Configuration runtimeConfiguration = configurations.add(RUNTIME_CONFIGURATION_NAME).setVisible(false).setTransitive(true)
                .setDescription("Classpath for running the specified dependencies.");
            configurations.getByName(Dependency.DEFAULT_CONFIGURATION).extendsFrom(runtimeConfiguration);
    }
      void configureBuildDependents(Project project) {
        DefaultTask buildDependentsTask = project.getTasks().add(BUILD_DEPENDENTS_TASK_NAME, DefaultTask.class);
        buildDependentsTask.setDescription("Assembles this project and all projects that depend on it.");
        buildDependentsTask.setGroup(BasePlugin.BUILD_GROUP);
          buildDependentsTask.dependsOn { project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().getByName(
                                SourceSet.MAIN_SOURCE_SET_NAME).getRuntimeClasspath() }
    }
}

The initial thing I am trying to figure out now is how to figure out the dependencies given that they are contained in the build.gradle and dynamically get the right dependsOn call at the bottom of the plugin example. I know what is there is wrong, it was just one of a series of bad attempts to figure out how to make this work. I suspect the dependsOn call is being called before the DSL for the dependencies has been run in the build.gradle file.

‘project.configurations.runtime’ is a ‘java.lang.Iterable’ containing all dependencies for the ‘main’ source set. You can get similar (and even more accurate) information from the source set itself, e.g. ‘sourceSets.main.runtimeClasspath’. Make sure to only iterate these containers in a task action (i.e. at execution time), not in the body of the plugin (i.e. at configuration time). Otherwise you’ll resolve the dependencies for every build, even if none of the tasks that need them are being executed.

One way to get the correct task dependencies is with ‘myTask.dependsOn(container)’, where ‘container’ is one of the above (e.g. a configuration). Another way is to describe the container as an input of the task that needs it.

Best information sources to get started are the “Writing Custom Plugins” chapter in the Gradle User Guide and the Gradle source code (e.g. the various code quality plugins).

OK, thanks Peter. I will attempt to sort through this and see if I can figure it out. I may be back.

I did read the custom plugins chapter. I will read it again.

After going through the docs many more times I have something working.

project.afterEvaluate was an important key. I am sure I didn’t implement everything in Gradle best practices, but it is working. I should write up a tutorial because all of the info I needed was spread across many sections of the manual and having an example which covers something like this could potentially be useful.