Exec task failing to perform process, no error


(Steve Cohen) #1

Gradle Version: 3.1 (and earlier)
Operating System and JVM version:
Red Hat Enterprise Linux Server release 6.7 (Santiago)

java version "1.8.0_77"
Java™ SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot™ 64-Bit Server VM (build 25.77-b03, mixed mode)

Is this a regression? If yes, which version of Gradle do you know it last worked for?
No

NOTE: I have updated this post. The previous version was based on a run where the code was not as stated below.

I have defined a simple exec task. It deletes everything in a directory that is outside of the build tree.

        Task nativeClean = project.tasks.create('nativeClean', Exec) {
            // does not depend on anything, must be manually invoked.
            workingDir nativeDir
            commandLine 'rm', '-rfv', "*"
        }    

If I then run the task

$ gradlew nativeClean -i

I see that the task does execute but the contents of nativeDir remain undeleted:

Starting process 'command 'rm''. Working directory: /usr/local/openssl Command: rm -rfv *
Successfully started process 'command 'rm''
:openssl64:nativeClean (Thread[Daemon worker Thread 18,5,main]) completed. Took 0.02 secs.

If it were some sort of permissions error, say, I would expect an exception to be thrown. But I tried forcing that by changing the permissions, and the results were the same.

I think the process is starting but never actually executing. It only says it’s started the process. It’s as if gradle isn’t waiting for the process to complete.


(Steve Cohen) #2

Okay, I don’t know what to try next. It certainly seems like Gradle thinks it’s performing the rm but nothing is happening. Nothing I try is giving me any visibility into this situation.

I’ve rewritten the task to provide as much info as possible:

        Task nativeClean = project.tasks.create('nativeClean', Exec) {
            // does not depend on anything, must be manually invoked.
            workingDir nativeDir
            commandLine 'rm', '-rfv', "*"
            standardOutput = new ByteArrayOutputStream()
            errorOutput = new ByteArrayOutputStream()
            ext.stdout = {
                return standardOutput.toString()
            }
            ext.stderr = {
                return errorOutput.toString()
            }
            doLast {
                println "rm output:" + ext.stdout()
                println "rm error output:" + ext.stderr()
            }
        }        

Now running under debug logging, it still looks like everything is working - yet nothing gets deleted:

12:33:02.801 [LIFECYCLE] [class org.gradle.internal.buildevents.TaskExecutionLogger] :openssl64:nativeClean
12:33:02.801 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Starting to execute task ':openssl64:nativeClean'
12:33:02.801 [DEBUG] [org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter] Determining if task ':openssl64:nativeClean' is up-to-date
12:33:02.801 [INFO] [org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter] Executing task ':openssl64:nativeClean' (up-to-date check took 0.0 secs) due to:
  Task has not declared any outputs.
12:33:02.801 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter] Executing actions for task ':openssl64:nativeClean'.
12:33:02.801 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process 'command 'rm''. Working directory: /usr/local/openssl Command: rm -rfv *
12:33:02.801 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Environment for process 'command 'rm'': {... (edited)`
}, LS_COLORS=, HOME=/home/sc1478, SHLVL=1}
12:33:02.801 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Changing state to: STARTING
12:33:02.802 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Waiting until process started: command 'rm'.
12:33:02.804 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Changing state to: STARTED
12:33:02.806 [DEBUG] [org.gradle.process.internal.ExecHandleRunner] waiting until streams are handled...
12:33:02.806 [INFO] [org.gradle.process.internal.DefaultExecHandle] Successfully started process 'command 'rm''
12:33:02.808 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Changing state to: SUCCEEDED
12:33:02.808 [DEBUG] [org.gradle.process.internal.DefaultExecHandle] Process 'command 'rm'' finished with exit value 0 (state: SUCCEEDED)
12:33:02.808 [QUIET] [system.out] rm output:
12:33:02.808 [QUIET] [system.out] rm error output:
12:33:02.808 [DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Finished executing task ':openssl64:nativeClean'

(davidmichaelkarr) #3

It seems possible that the “*” is not being globbed, as I don’t think this is executing through through a command line shell. You could verify this by changing the argument to a single file name that you know will exist. If that “works”, I’m still not sure what the proper solution is.


(Steve Cohen) #4

Thank you, David, good call! That is the issue.

Now what to do about it? That is the $64K question.

I’m pretty sure I could use the Delete task instead of Exec with a properly constructed collection of Files. But is it true that globs are not properly processible by Exec? Is there a way around this?


(Steve Cohen) #5

Delete seems to have another issue with confusion about UP-TO-DATE-ness.

With the task now defined as

        Task nativeClean = project.tasks.create('nativeClean', Delete) {
            File nativeRoot = new File(nativeDir)
            // everything under /usr/local/openssl, not including /usr/local/openssl itself
            FileCollection natives = project.files(nativeRoot).filter{ File f ->
                !(f.equals(nativeRoot))
            }
            delete natives
            outputs.upToDateWhen {
                FileTree tree = project.fileTree(dir: nativeDir)
                tree.files.size() <=1
            }
        }        

we can see that upToDateWhen functions correctly but Gradle still finds it up-to-date:

:openssl64:nativeClean (Thread[Daemon worker Thread 33,5,main]) started.
:openssl64:nativeClean
Executing task ':openssl64:nativeClean' (up-to-date check took 0.01 secs) due to:
  Task.upToDateWhen is false.
:openssl64:nativeClean UP-TO-DATE
:openssl64:nativeClean (Thread[Daemon worker Thread 33,5,main]) completed. Took 0.012 secs.

First it says upToDateWhen is false, then it UP-TO-DATEs it anyway.

Fortunately, this simple suggestion from Stack Overflow works and is properly evaluated for up-to-dateness.:

Task nativeClean = project.tasks.create('nativeClean', Exec) {
    // does not depend on anything, must be manually invoked.
    workingDir nativeDir
    commandLine 'bash', '-c', "/bin/rm -rf *"
}