Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting & Configuring Gradle Builds

I'm reading up on Gradle and am very interested in it, specifically because (it appears) that it allows the introduction of inheritance into the build process. For instance, if I have a Java web app that might be packaged and deployed to Google App Engine instances as well as Amazon EC2 instances, I need a sophisticated build that can take the same Java, XML, PROPERTIES, CSS and image files and package/deploy them into 2 drastically-differently packaged WAR files.

GAE apps are very specific as to how they are packaged; EC2 (pretty much) just require that you conform to servlet specs. GAE apps get "deployed" by running an update command from the appcfg.sh script that comes with your SDK; EC2 has their own way to deploy apps. The point is, they are very different packaging/deployment processes for both PaaS providers:

public abstract class PackageTask {
    // ...
}

// Package my Eclipse project for deployment to GAE.
public class AppEnginePackageTask extends PackageTask {
    // ...
}

// Package my Eclipse project for deployment to EC2 instances.
public class AmazonPackageTask extends PackageTask {
    // ...
}

public abstract class DeployTask {
    // ...
}

// Deployment to GAE.
public class AppEngineDeployTask extends DeployTask {
    // ...
}

// Deployment to EC2.
public class AmazonDeployTask extends DeployTask {
    // ...
}

Then, I might have a myapp.gradle buildfile that templates the build order of tasks:

clean()
compile()
package()
deploy()

...and somehow, I can configure/inject AppEnginePackageTask/AppEngineDeployTask in place of package()/deploy() for a GAE-based build, or I can configure/inject AmazonPackageTask/AmazoneDeployTask into those templated tasks. Again, I'm not sure how to do this (or even if Gradle can do this), but it's what I'm after.

My understanding was that Gradle can do this. Ant can also be forced to have highly-modular, elegant builds that work this way, but being XML-based, it takes some finessing, whereas an OOP-based language like Groovy makes this cleaner and simpler.

However, all the examples I see of Gradle tasks take the following form:

task package(dependsOn: 'compile') {
    // ...
}

task deploy(dependsOn: 'package') {
    // ...
}

So I ask: these look/feel like non-OOP task definitions. Is my understanding of Gradle (and its OOP nature) fundamentally incorrect? What am I missing here? How can I accomplish these notions of "configurable/injectable build templates" and inheritance-based tasks? Thanks in advance!

Edit I re-tagged this question with "groovy" because Gradle buildscripts are written in a Groovy DSL, and someone who happens to be a Groovy-guru (say that 5 times fast) might also be able to chime in even if they know little about Gradle.

like image 693
IAmYourFaja Avatar asked Sep 08 '12 00:09

IAmYourFaja


1 Answers

As described here, there are simple tasks and enhanced tasks. The latter are much more flexible and powerful.

The following example isn't exactly what you describe, re:injection, but it illustrates OOP.

Here is the sample build.gradle file. It avoids "package" as that is a keyword in Java/Groovy. The 'build' target depends on 'compile' and some flavour of 'doPack', depending on a property called 'pkgTarget'.

task compile << { 
    println "compiling..." 
}

task build() << {
}

build.dependsOn { 
    compile
}

build.dependsOn { 

    if (pkgTarget == "Amazon") {
        task doPack(type: AmazonPackageTask)
    } else if (pkgTarget == "Google") {
        task doPack(type: GooglePackageTask)
    } else {
        task doPack(type: MyPackageTask) 
    }
}

where the tasks are defined later in the same file. (Per doc, this code can go into a "build src" directory):

// ----- 

class MyPackageTask extends DefaultTask {
    def init() { println 'common stuff' }
    @TaskAction
    def doPackage() {
        println 'hello from MyPackageTask'
    }
}

class AmazonPackageTask extends MyPackageTask {
    @TaskAction
    def doPackage() {
        init()
        println 'hello from AmazonPackageTask'
    }
}

class GooglePackageTask extends MyPackageTask {
    @TaskAction
    def doPackage() {
        init()
        println 'hello from GooglePackageTask'
    }
}

and here is the gradle.properties file:

pkgTarget=Amazon
like image 104
Michael Easter Avatar answered Oct 25 '22 04:10

Michael Easter