You can think of a gradle build script as some code which is delegated to an object which can respond to method calls written in it.
The script uses a lot of Groovy syntactic sugar, so removing them, it should look like this:
apply( [plugin: 'com.android.application'] );
android({
compileSdkVersion( 21 );
buildToolsVersion( "21.1.2" );
defaultConfig({
applicationId( "com.crittercism" );
minSdkVersion( 15 );
targetSdkVersion( 21 );
versionCode( 5 );
versionName( "5.0" );
});
});
dependencies({
compile( fileTree([dir: 'libs', include: ['*.jar']]) );
});
So the script is really a bunch of method calls:
def apply(Map)
def android(Closure)
def dependencies(Closure)
This android(Closure)
will receive a closure and will delegate the methods called in it to an object which can respond to these methods:
def compileSdkVersion(Integer)
def buildToolsVersion(String)
...
Given that, we can parse the script, delegate it to some object and then execute it.
Delegating using DelegatingBaseScript
is one way to do it (not sure if Gradle does it this way). Here is a dumbed down working version:
import org.codehaus.groovy.control.CompilerConfiguration
gradleScript = '''
apply plugin: 'com.android.application'
android({
compileSdkVersion( 21 )
buildToolsVersion( "21.1.2" )
})'''
class PocketGradle {
def config = [apply:[]].withDefault { [:] }
def apply(map) {
config.apply << map.plugin
}
def android(Closure closure) {
closure.delegate = new Expando(
compileSdkVersion: { Integer version ->
config.android.compileSdkVersion = version
},
buildToolsVersion : { String version ->
config.android.buildToolsVersion = version
},
)
closure()
}
}
def compiler = new CompilerConfiguration(scriptBaseClass: DelegatingScript.class.name)
shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)
script = shell.parse gradleScript
script.setDelegate( gradle = new PocketGradle() )
script.run()
assert gradle.config == [
apply: ['com.android.application'],
android: [
compileSdkVersion: 21,
buildToolsVersion: '21.1.2'
]
]
You can execute the script in Groovy Web Console
(click "Edit in console" and then "Execute script").
Most of the syntax explanation are in the DSL section:
- Command chains
Groovy lets you omit parentheses around the arguments of a method call for top-level statements. "command chain" feature extends this by allowing us to chain such parentheses-free method calls, requiring neither parentheses around arguments, nor dots between the chained calls.
There is also Groovy ConfigSlurper
, but i'm not sure if it can go as far as Gradle wants to.