When do configuration settings get set?

Edit2: Even simpler example, as perhaps it’s difficult to understand what I’m confused about.

I have a problem configuring a plugin that I’m developing. Specifically I don’t know how to get configuration in a project’s build.gradle to take effect in the plugin.

This is the complete code of my example plugin:

import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.api.tasks.Copy
  class MyTestPlugin implements Plugin<Project> {
    def void apply(Project project) {
        project.convention.plugins.mytest = new MyTestPluginConvention()
        project.task('copyscripts', type: Copy) {
            from 'scripts'
            into project.file(project.convention.plugins.mytest.buildScriptsLocation)
            expand(project.properties)
        }
        project.task('hello') << {
            println project.convention.plugins.mytest.message
        }
    }
}
  class MyTestPluginConvention {
    def String buildScriptsLocation = 'build/scripts'
    def String message = 'Default hello from TestPlugin'
          def mytest(Closure closure) {
        closure.delegate = this
        closure()
    }
}

This is the complete build.gradle, in a project that is using my example plugin:

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'mytest'
  mytest {
    buildScriptsLocation = 'build/scripts2'
    message = 'Hi from within closure'
}
  buildscript {
    repositories {
        flatDir dirs: 'locallibs'
    }
    dependencies {
        classpath ':MyTestPlugin:1.0.0'
    }
}

The following happens when I try to build in my test project:

  • “gradle hello” - This prints “Hi from within closure”, so obviously the configuration in the mytest closure of “build.gradle” has been run before the plugin’s execution phase.

  • “gradle clean copyscripts” - The contents of the scripts directory are copied to the “build/scripts” directory, not “build/scripts2”, i.e. the configuration in the mytest closure has not had any effect.

So my conclusion would be that the hello task works because as it runs during the execution phase, all configuration in “build.gradle” has been set, but the copy task of the plugin is set up before any configuration in “build.gradle” is considered.

My question is then: how should I go about to configure the plugin so that configuration in “build.gradle” can effect for example the copy task?

OK, I figured it out in the end: the “into” property of the Copy task needs to be a closure, along these lines:

project.task('copyscripts', type: Copy) {
            from 'scripts'
            into{ project.convention.plugins.mytest.buildScriptsLocation }
}

This makes it evaluate at the proper time.

Yes. This is one of several techniques that can be used in a plugin to get around the evaluation order problem. By the way, “project.convention.plugins.mytest” is only needed once for setting the convention object. After that you can refer to its properties simply with “project.someProperty”, e.g. “project.buildScriptsLocation” (at least when the plugin is written in Groovy).