Gradle basic task help

I am new to gradle, but have used a lot of other build tools like Rake, fabric and of course make.

I have a task defined like this:

task abc (type:Exec) {

  String clientDir = project.buildscript.sourceFile.getParent()

  String version = new File("${clientDir}/Assets/Resources/version.txt").text
  String buildDir = "${clientDir}/Build/${version}"

  commandLine "/bin/customtool", "${buildDir}/artifact" 
}

version.txt does exist yet and is generated by another step in the build process.

When I try to build another task that is not dependent on this one, I still get an error:

$ gradle othertask

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/amrox/Code/project/build.gradle' line: 75

* What went wrong:
A problem occurred evaluating project ':client'.
> /Users/amrox/Code/project/Assets/Resources/version.txt (No such file or directory)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

I don’t understand why gradle is doing this. The task should fail if the version.txt file doesn’t exist when it’s run, the task isn’t being executed. I guess gradle does something during the evaluation phase?

Any help would be appreciated. I’m just trying to get something simple done quickly.

All of the body of your task is executed during the evaluation phase. You want that to execute during the execution phase, so you should surround all of your present task body with a “doLast { }” wrapper.

Gradle has three different build phases it goes through.

new File("${clientDir}/Assets/Resources/version.txt").text gets evaluated during the ‘configuration’ phase.

A few suggestions. I think this is equivalent (and still broken):

task abc (type:Exec) {
  String version = file("Assets/Resources/version.txt").text
  String artifactDir = file("Build/${version}/artifact").absolutePath

  commandLine "/bin/customtool", artifactDir
}

Project has lots of useful methods available like file() that turns paths into relative paths to the project directory. project.buildscript.sourceFile.getParent() should be equivalent to projectDir unless you’re explicitly using a build file from another directory (then I’m not sure).

If your ‘version.txt’ file is produced by another Gradle task, you’ll need to be sure to have a dependency between them.

The way I’d recommend wrapping your customtool is to use a custom task. Exec is OK if the inputs are fairly fixed and simple. You can unit test it and given more meaningful names to the properties. I’d try something like (typed, but not tested):

class CustomToolTask extends DefaultTask {
  @Input
  public String getVersion() {
     project.file("Assets/Resources/version.txt").text
  }

  @InputFile
  public File getInputArtifact() {
     project.file("Build/${version}/artifact")
  }

  @TaskAction 
  public void perform() {
     project.exec {
        commandLine "/bin/customtool", inputArtifact.absolutePath
     }
  }
}

task abc(type: CustomToolTask) {}