How can I modify the buildscript block's dependencies (i.e. classpath) from within a custom plugin?

I am trying to create a custom plugin to standardize the application and use of the ‘cargo’ plugin within my organization. I created my own plugin called, say, ‘corp-cargo’ with source looking like this:


package com.corp.myproject.gradle.plugins

import org.gradle.api.Plugin

import org.gradle.api.Project

/**

*/

class CorpCargoPlugin implements Plugin {

@Override

void apply(Project project) {

project.plugins.apply(‘corp-base’)

project.buildscript {

repositories {

mavenCentral()

add(new org.apache.ivy.plugins.resolver.URLResolver()) {

name = ‘GitHub’

addArtifactPattern ‘http://cloud.github.com/downloads/[organisation]/[module]/[module]-[revision].[ext]

}

}

dependencies {

classpath ‘bmuschko:gradle-cargo-plugin:0.3’

}

}

project.plugins.apply(‘cargo’)

//dependencies for cargo plugin

project.dependencies {

def cargoVersion = ‘1.3.3’

project.cargo “org.codehaus.cargo:cargo-core-uberjar:$cargoVersion”,

“org.codehaus.cargo:cargo-ant:$cargoVersion”,

'jaxen:jaxen:1.1.1

}

project.cargo {

containerId = config.CONTAINER_ID

port = config.PORT

context = ‘’

remote {

hostname = config.HOSTNAME

username = config.USERNAME

password = config.PASSWORD

}

}

project.task (“deployWar”){

dependsOn ([‘cargoUndeployRemote’, ‘cargoDeployRemote’])

}

project.tasks.cargoDeployRemote.mustRunAfter cargoUndeployRemote

}

}


The problem is that gradle is complaining about the plugin apply method trying to modify the project.buildscript, producing the following error message:

A problem occurred evaluating root project ‘myBaseProject’.

You can’t change a configuration which is not in unresolved state!

I saw a post on a gradle forum which asked a question about this … a different specific problem but one which produced the same error message. Luke from Gradleware answered it as follows:

Wrap the code in a task, and then run the task.

As soon as you call «configuration».files or anything that calls it, you are resolving the configuraiton.

From that point on new dependencies cannot be added which is what is happening in your build.

I spoke with another consultant who advised me to maybe pull out the dependency declaration into an init script, but I’d really like to have the plugin take care of declaring its own dependencies and encapsulate the whole use of cargo within our custom plugin (sort of wrapping the cargo plugin and all its requirements. More specifically, I want to be able to apply this plugin from the main build.gradle and not have to have any other mention of ‘cargo’ anywhere in my script or initialization code other than in the plugin file(s).

So … any ideas folks?

Regards,

Peter

A plugin can’t manipulate the build script class path of a build script that applies the plugin. (The build script class path must be known before the build script can even be compiled.) Instead, you need to publish your plugin as a Maven or Ivy module. Clients then declare a dependency on that module in their ‘buildscript’ section, and transitive dependency management takes care of the rest.

OK. I appreciate the fast response! Can you provide a pointer to some doc describing how to rewrite or package a plugin as a maven/ivy module? Or is there some other strategy that you would suggest I use to accomplish my goal?

Same as for any other Gradle build. See the Maven/Ivy chapters in the user guide and/or the samples in the full Gradle distribution.