Search code examples
androidgradleandroid-gradle-plugingradlew

Android - top level gradle task with parameter type:Exec runs automatically on build, why?


I have a task that runs a shell script. It resides in my top level gradle file only. So the gradle file im talking about can be seen here:

enter image description here

Now for the interesting part, i have a task in the file called copyFiles which just runs a simple shell script to copy files. Im going to show you my entire build.gradle top level file now:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

task copyFiles(type:Exec) {
    exec {
        commandLine 'sh', './copyFiles.sh'
    }
}

Now whenever i build the project this task gets executed. As long as i build the project (aka compile it) this task runs. Is that normal ? i put a print line in there to make sure and yes it gets run everytime i build the 'app' module. Is this normal. What if i wanted it not to do that ?

UPDATE: Now after researching i found that some gradle tasks can be executed right away without being invoked if defined like this:

//option 1, this runs right away on build
    task foo(type: Exec) {
    // this is configuration
    // i.e. it runs regardless
}
//option 2 this runs only when called on
  task bar(type: Exec) << {
    // this is execution
    // i.e. it only runs if you call the task
}

So then i thought i'd try the same thing with :

task copyFiles(type: Copy) {
    from '/Users/myuser/Documents/androidstudio/MyApplication/Common/'
    into '/Users/myuser/Documents/androidstudio/MyApplication/app/src/main/assets'
}

but to my surprise it does not get run on its own. I actually have to call it ? How is this different then type:Exec ? why is there no consistency ?

UPDATE:

I wrote a blog about the gradle lifecycle for anyone who needs help after my analysis.


Solution

  • You might have to read about the build lifecycle. When you run your build, this build goes through 3 phases: Initialization, Configuration and Execution.

    When you declare a closure as:

    task foo(type: Exec) {
        // this is configuration
        // i.e. it runs regardless
    }
    

    then this closure is executed for all the task at the configuration phase, that is why your print line is always called, even if a task shell not be executed. It's just a part of the whole configuration.

    But if you declare a closure with <<, as:

    task bar(type: Exec) << {
        // this is execution
        // i.e. it only runs if you call the task
    }
    

    it's executed at the execution phase. Actually, << is equals to doLast for the task.

    Furthermore, then you use a exec {} notation within a task, you create a execution subtask within it.

    So, if you don't want to run it at the configuration, then just use it with the <<, or don't call an additional exec task within a task, which is by itself of type Exec and just properly configure it, like:

    task copyFiles(type:Exec) {
       commandLine 'sh', './copyFiles.sh'
    }