Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Self applying Gradle plugin project
//place this content in your buildSrc/build.gradle file
//Then apply your plugin to its own build in build.gradle
import org.codehaus.groovy.control.CompilerConfiguration
apply plugin: 'groovy'
repositories {
jcenter()
}
// IntelliJ doesn't let you set the source path for a module outside of its directory.
// This logic basically only performs this configuration when not being resolved in IntelliJ
if (!project.plugins.collect { it.class.name}.any { it.endsWith('JetGradlePlugin')}) {
//Set the source directories for buildSrc to contain the source from the main project
sourceSets {
main {
java.srcDirs = ['src/main/java', '../src/main/java']
groovy.srcDirs = ['src/main/groovy', '../src/main/groovy']
resources.srcDirs = ['src/main/resources', '../src/main/resources']
}
}
}
// Prepare to have your mind blown
// This section evaluates the `build.gradle` from the root diretory and
// then grabs the dependencies block from it and evaluates it on this project.
// So in effect, we are building the main project with itself.
// BOOM
ScriptHolder holder = new ScriptHolder()
CompilerConfiguration cc = new CompilerConfiguration()
cc.setScriptBaseClass(DelegatingScript.class.name)
GroovyShell sh = new GroovyShell(Project.class.classLoader, new Binding(), cc)
//The build file for the main project
File projectBuildFile = file('../build.gradle')
//Use this parse command because Groovy wants to use the file name as the classname
//which fails if your Gradle build file has been renamed to contain an invalid character (i.e. '-')
DelegatingScript script = (DelegatingScript)sh.parse(projectBuildFile.text, 'GradlePlugins')
script.setDelegate(holder)
//Resolve the project main Gradle file against our ScriptHolder
script.run()
//Class for holding the evaluation of a Gradle script
//You may need to add some extra methods here depending on what you have all placed in build.gradle
class ScriptHolder {
Closure dependencies
void dependencies(Closure c) {
this.dependencies = c
}
void apply(Map map) {
}
}
//Grab the dependencies closure and resolve it against
//the buildSrc project dependencies
//This effectively applies the same dependenices from build.gradle into buildSrc/build.gradle
//This is required so that when buildSrc is compiled it has the dependencies to compile the source code
def closure = holder.dependencies.clone()
closure.delegate = project.dependencies
closure()
@ysb33r

This comment has been minimized.

Copy link

@ysb33r ysb33r commented Apr 14, 2015

This is a pretty fancy example.

Have you considered a simpler approach such as below

apply plugin: new GroovyScriptEngine(
        [file('src/main/groovy').absolutePath, file('src/main/resources').absolutePath]. 
            toArray(new String[2]), 
        this.class.classLoader
).loadScriptByName('org/ysb33r/gradle/bintray/BintrayPublishPlugin.groovy')

or is that not sufficient for your needs?

@liviutudor

This comment has been minimized.

Copy link

@liviutudor liviutudor commented Aug 20, 2015

Worked like a charm for me, thank you!

@grv87

This comment has been minimized.

Copy link

@grv87 grv87 commented Nov 1, 2017

@ysb33r, your approach has two drawbacks:

  1. It doesn't apply plugin dependencies to your build script. You need to combine both approaches to get it done, or provide dependencies to build script separately. @johnrengelman's approach doesn't apply plugin, it only copies dependencies, so both are required.
  2. Recent versions of Gradle say that script passed to loadScriptByName shouldn't contain a package statement.

I looked for a solution and found out that much nicer and cleaner way is to compile plugin in buildSrc and then apply its class to the main project. It is in the Gradle documentation.

@CliveEvans

This comment has been minimized.

Copy link

@CliveEvans CliveEvans commented May 9, 2018

@grv87 unless I'm missing something, you can't use buildSrc if you're also publishing your plugin. The method used by @ysb33r works, you just need to remember to add any dependencies to your buildscript dependencies (as classpath dependencies).

The script from @johnrengelman, OTOH, just didn't work for me. And it was far from clear why ...

@wheelerlaw

This comment has been minimized.

Copy link

@wheelerlaw wheelerlaw commented Jun 5, 2018

@CliveEvans I also couldn't get @johnrengelman script to work for me, although its likely because of the version of Gradle I am running. This was my error:

No signature of method: GradlePlugins.buildscript() is applicable for argument types: (GradlePlugins$_run_closure1) values: [GradlePlugins$_run_closure1@2e7cad0f]
@trejkaz

This comment has been minimized.

Copy link

@trejkaz trejkaz commented Feb 26, 2019

@wheelerlaw hard to know without the stack trace, but did you have buildscript defined in ScriptHolder?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.