Android Builds-Gradle Style

Posted: September 1, 2009 in AndCooper, Android, Java, Mobile
Tags: ,

The main feature, one of them, of Groovy’s Gradle build framework  is that plug-ins will add task to the life-cycle. Life-cycle in this case is the build life-cycle. Since mobile java builds are different than enterprise java I have had to come up with my own build life cycle definition, which looks like this in Gradle:

gradle.taskGraph.whenReady {taskGraph ->

if (taskGraph.hasTask(':debug')) {
debug.doFirst(dependsOn: 'clean') {
}
debug.doFirst(dependsOn: 'generateJavaClassesFromTemplates') {
}
debug.doFirst(dependsOn: 'processJavaPreprocess') {
}
debug.doFirst(dependsOn: 'processSrcResources') {
}
debug.doFirst(dependsOn: 'compileAidlJavaClasses') {
}
debug.doFirst(dependsOn: 'processPreCompileReports') {
}
debug.doFirst(dependsOn: 'compile') {
}
debug.doFirst(dependsOn: 'processPostCompileReports') {
}
debubg.doFirst(dependsOn: 'processAssetsResources') {
}
debug.doFirst(dependsOn: 'processPackageResources') {
}
debug.doFirst(dependsOn: 'processDex'){
}
debug.doLast(dependsOn: 'appInstall') {
}
} else {
}
if (taskGraph.hasTask(':release')) {
debug.doFirst(dependsOn: 'clean') {
}
debug.doFirst(dependsOn: 'generateJavaClassesFromTemplates') {
}
debug.doFirst(dependsOn: 'processJavaPreprocess') {
}
debug.doFirst(dependsOn: 'processSrcResources') {
}
debug.doFirst(dependsOn: 'compileAidlJavaClasses') {
}
debug.doFirst(dependsOn: 'processPreCompileReports') {
}
debug.doFirst(dependsOn: 'compile') {
}
debug.doFirst(dependsOn: 'obfuscate') {
}
debug.doFirst(dependsOn: 'processPostCompileReports') {
}
debubg.doFirst(dependsOn: 'processAssetsResources') {
}
debug.doFirst(dependsOn: 'processPackageResources') {
}
debug.doFirst(dependsOn: 'processDex'){
}
debug.doLast(dependsOn; 'appProductionSigned') {
}
} else {
}
/**
* mockTestsSomething tasks are defined under the project tag
*/
if (taskGraph.hasTask(':tests:mockAll')) {
debug.doFirst(dependsOn: 'clean') {
}
debug.doFirst(dependsOn: 'generateJavaClassesFromTemplates') {
}
debug.doFirst(dependsOn: 'processJavaPreprocess') {
}
debug.doFirst(dependsOn: 'processSrcResources') {
}
debug.doFirst(dependsOn: 'compileAidlJavaClasses') {
}
debug.doFirst(dependsOn: 'processPreCompileReports') {
}
debug.doFirst(dependsOn: 'compile') {
}
debug.doFirst(dependsOn: 'processPostCompileReports') {
}
debubg.doFirst(dependsOn: 'processAssetsResources') {
}
debug.doFirst(dependsOn: 'processPackageResources') {
}
debug.doFirst(dependsOn: 'processDex'){
}
debug.doFirst(dependsOn: 'appReinstall')) {
}
} else {
}
if (taskGraph.hasTask(':tests:mockFunctional')) {
debug.doFirst(dependsOn: 'clean') {
}
debug.doFirst(dependsOn: 'generateJavaClassesFromTemplates') {
}
debug.doFirst(dependsOn: 'processJavaPreprocess') {
}
debug.doFirst(dependsOn: 'processSrcResources') {
}
debug.doFirst(dependsOn: 'compileAidlJavaClasses') {
}
debug.doFirst(dependsOn: 'processPreCompileReports') {
}
debug.doFirst(dependsOn: 'compile') {
}
debug.doFirst(dependsOn: 'processPostCompileReports') {
}
debubg.doFirst(dependsOn: 'processAssetsResources') {
}
debug.doFirst(dependsOn: 'processPackageResources') {
}
debug.doFirst(dependsOn: 'processDex'){
}
debug.doFirst(dependsOn: 'appReinstall')) {
}
} else {
}
if (taskGraph.hasTask(':tests:mockUnit')) {
debug.doFirst(dependsOn: 'clean') {
}
debug.doFirst(dependsOn: 'generateJavaClassesFromTemplates') {
}
debug.doFirst(dependsOn: 'processJavaPreprocess') {
}
debug.doFirst(dependsOn: 'processSrcResources') {
}
debug.doFirst(dependsOn: 'compileAidlJavaClasses') {
}
debug.doFirst(dependsOn: 'processPreCompileReports') {
}
debug.doFirst(dependsOn: 'compile') {
}
debug.doFirst(dependsOn: 'processPostCompileReports') {
}
debubg.doFirst(dependsOn: 'processAssetsResources') {
}
debug.doFirst(dependsOn: 'processPackageResources') {
}
debug.doFirst(dependsOn: 'processDex'){
}
debug.doFirst(dependsOn: 'appReinstall')) {
}
} else {
}
/**
*  Have to disallow individual task exuciton that is not from
*  the debug, release, and :tests:mockSomething entry points
*
*  we hack it by setting  tasks to false and
*  printing an error message
*/
if (taskGraph.hasTask(':clean')) {
clean.enabled = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskgraph.hasTask(':generateJavaClassesFromTemplates')) {
generateJavaClassesFromTemplates.enabled = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask(':processJavaPreprocess')) {
processJavaPreprocess.enabled = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('processSrcResources') {
processSrcResources.enabled = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('compileAidlJavaClasses') {
compileAidlJavaClasses.enabled = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('processPreCompileReports') {
processPreCompileReports.enabled = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('compile') {
compile.enabled = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('processPostCompileReports') {
processPostCompileReports.enable = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('processAssetsResources') {
processAssetsResources.enable = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('processPackageResources') {
processPackageResources.enable = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('processDex') {
processDex.enable = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('appReinstall') {
appReinstall.enable = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('appInstall') {
appInstall.enable = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}
if (taskGraph.hasTask('obfuscate') {
obfuscate.enable = false
logging.info('sorry please use debug, release, or :tests:MockSomething')
} else {
}

Basically, the only entry points are debug, release, and mockSomething tasks. I kept the dependencies group in the order of execution thus the build is both readable and understandable and functional. Now it is add in the details of all tasks and start testing each task one by one. With the Gradle 0.8 project feature I was able to eliminate the need for a separate build script to be in the tests/src folder and remotely execute that script.

I should optimize my Life-cycle definition by using Goovy switch statements. Than switch to switch statements for the if-else blocks in my configurations block and I should be down to a compact 300 lines and with the other task details filled in about 800 lines. The ANT build script with the same feature set was turning out ot be 300 lines of mind-numbing not easy to read and understand mess.

Reblog this post [with Zemanta]
Advertisements
Comments
  1. j pimmel says:

    Are the tasks which are being depended some part of some standard Ant tasks collection that I am missing?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s