17

I am trying to execute a command with gradle with the below task:

task stopServer(dependsOn: war, type: Exec) << {
    commandLine 'pkill -9 tomcat'
}

When I run it I get the following error:

* What went wrong:
Execution failed for task ':stopServer'.
> execCommand == null!

And when my task is like this:

task stopServer(dependsOn: war) << {
    exec {
        commandLine 'pkill -9 tomcat'
    }
}

I get this error:

* What went wrong:
Execution failed for task ':stopServer'.
> A problem occurred starting process 'command 'pkill -9 tomcat''

Can you tell me where I am going wrong in each of these approaches?

If neither of above are right way of executing then please specify the way of doing it probably with an example.

Ram Patra
  • 16,266
  • 13
  • 66
  • 81
  • 1
    This doesn't really fit as part of my answer, but I really don't think you want to `pkill java`. That will kill any java process, including your IDE, and potentially gradle itself. – Paul Phillips Nov 23 '14 at 17:43
  • I changed it to `tomcat` – Ram Patra Nov 23 '14 at 17:57
  • Just in case if anyone is still facing issue with it, I have changed the dx Command i am facing issue to include '.bat' like below and it started working. `commandLine 'sdk/dx.bat' --dex` – Guna Aug 19 '16 at 10:21

2 Answers2

23

I believe you're looking for this:

task stopServer(dependsOn: war, type: Exec) {
     commandLine "pkill", " -9", "tomcat"
}

The main difference is very subtle - I just deleted two characters. The << is gone from the task definition. The other difference is that the commandLine expects the executable to be passed in separately from the arguments to it.

I removed the << because of an important idea in gradle: the build lifecycle. There's configuration and execution phases (that's not all, but it's enough to explain this).

The << is like saying doLast - it adds the closure you pass to the end of the actions (the execution phase) for this task. So that means here, it's going to try and execute the command like normal (it's an Exec object, after all), and only then, once it's executed, will it call your block - the block setting commandLine. So when it's executing, execCommand really is null, and would be until your block was run. This is the heart of your problem.

Without the << (also known as left-shift), that same block runs during the configuration phase. So the exec command gets set before it runs, and it works.

Ram Patra
  • 16,266
  • 13
  • 66
  • 81
Paul Phillips
  • 6,093
  • 24
  • 34
  • I tried your solution but no luck, I am getting this error `> A problem occurred starting process 'command 'pkill -9 java''` – Ram Patra Nov 23 '14 at 17:48
  • 2
    There was another error in the commandLine syntax. Arguments have to be separated from the executable. I updated with the edit. – Paul Phillips Nov 23 '14 at 17:49
  • Your solution works for example `commandLine 'catalina.sh', 'run'` but not for `commandLine 'pkill', '-9', 'tomcat'`. Any reasons? – Ram Patra Nov 23 '14 at 18:05
  • 1
    It is most likely a problem with the shell command you're trying to run if one works and the other doesn't. Try running that command yourself in the shell and see if it works. Or run gradle with --debug or --stacktrace – Paul Phillips Nov 23 '14 at 18:08
  • I must say, this is a great answer. Have searched everywhere but couldn't get myself clear before this. Thanks! – Ram Patra Nov 23 '14 at 18:16
  • Is there a way to catch the exception as in java, so that the build doesn't fail if it fails to execute `pkill`? – Ram Patra Nov 23 '14 at 18:28
  • I doubt you can catch the exception, but what you can do is tell gradle to ignore the exit value with `ignoreExitValue true` in the task definition. – Paul Phillips Nov 23 '14 at 18:48
  • This answer is out-of-date with more recent versions of gradle. `commandLine` accepts the command and the arguments together. Here's a link to the docs: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Exec.html#org.gradle.api.tasks.Exec:commandLine – Marty Neal Sep 28 '18 at 18:20
  • How to execute this command in task ./gradlew app:connectedAndroidTest \ -Pandroid.testInstrumentationRunnerArguments.class=com.example.android.testing.blueprint.ui.espresso.EspressoTest – YLS Apr 05 '21 at 23:41
3

Here is another solution that works well for the same error if you have a standalone exec task that you want to run from the commandline but do not want to run in Android Studio as part of your build.

This will always run the configuration of "myExecTask" but will only execute doMyExecTask when it is explicitly run via "gradle myExecTask"

/**
 * Actually run exec task in doLast phase
 */
task doMyExecTask << {
    def hasProperties = project.hasProperty('SOME_PROPERTY');

    if (hasProperties) {
        myExecTask.commandLine "echo", "$SOME_PROPERTY"
    } else {
        println "ERROR: Unable to run task. Missing properties."
    }
}

/**
 * Configure exec task, this always runs
 */
task myExecTask(type: Exec) {
    dependsOn doMyExecTask
    workingDir 'path/to/executable'
}
Justin Fiedler
  • 6,478
  • 3
  • 21
  • 25