How to specify in Gradle an `#OutputDirectory` for an `Exec` task? - gradle

I have the following:
task cloneProtobuf(type: Exec) {
workingDir "${rootProject.buildDir}/github.com/google"
commandLine 'git', 'clone', 'https://github.com/google/protobuf.git'
enabled = { -> !new File(workingDir, "protobuf/.git").isDirectory() }()
doFirst {
mkdir workingDir
}
}
Rather than explicitly setting enabled and having gradle indicate that the task was SKIPPED, I would rather have gradle consider that if the protobuf directory already exists, the task is UP-TO-DATE. How can this be done?

Instead of enable/disable a task, please register a task output, then gradle will be aware itself if a task is up-to-date or not. Please have a look at the example below which you can find helpful:
task mk(type: Exec) {
def output = project.file('mk')
outputs.dir output
commandLine 'mkdir', output
workingDir '.'
}
If you run gradle mk twice, the task will execute only once.

Related

how to play audio in gradle.kts? [duplicate]

I have a gradle build setup at the beginning of which I want to execute a shellscript in a subdirectory that prepares my environment.
task build << {
}
task preBuild << {
println 'do prebuild stuff:'
}
task myPrebuildTask(type: Exec) {
workingDir "$projectDir/mySubDir"
commandLine './myScript.sh'
}
build.dependsOn preBuild
preBuild.dependsOn myPrebuildTask
However, when I execute the task either by calling gradle myPrebuildTask or by simply building the project, the following error occurs:
> A problem occurred starting process 'command './myScript.sh''
Unfortunately, thats all I get.
I have also tried the following - same error.
commandLine 'sh mySubDir/myScript.sh'
I use Gradle 1.10 (needed by Android) on Windows, inside a Cygwin shell. Any ideas?
use
commandLine 'sh', './myScript.sh'
your script itself is not a program itself, that's why you have to declare 'sh' as the program and the path to your script as an argument.
A more generic way of writing the exec task, but portable for Windows/Linux, if you are invoking a command file on the PATH:
task myPrebuildTask(type: Exec) {
workingDir "$projectDir/mySubDir"
if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) {
commandLine 'cmd', '/c', 'mycommand'
} else {
commandLine 'sh', '-c', 'mycommand'
}
}
This doesn't directly address the use case for the OP (since there is script file in the working directory), but the title of the question is more generic (and drew me here), so it could help someone maybe.
unfortunately options with commandLine not worked for me in any way and my friend find other way with executable
executable "./myScript.sh"
and full task would be
task startScript() {
doLast {
exec {
executable "./myScript.sh"
}
}
}
This works for me in my Android project
preBuild.doFirst {
println("Executing myScript")
def proc = "mySubDir/myScript.sh".execute()
proc.waitForProcessOutput(System.out, System.err)
}
See here for explanation:
How to make System command calls in Java/Groovy?
This is a solution for Kotlin DSL (build.gradle.kts) derived from Charlie Lee's answer:
task<Exec>("MyTask") {
doLast {
commandLine("git")
.args("rev-parse", "--verify", "--short", "HEAD")
.workingDir(rootProject.projectDir)
}
}
Another approach using the Java standard ProcessBuilder API:
tasks.create("MyTask") {
val command = "git rev-parse --verify --short HEAD"
doLast {
val process = ProcessBuilder()
.command(command.split(" "))
.directory(rootProject.projectDir)
.redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT)
.start()
process.waitFor(60, TimeUnit.SECONDS)
val result = process.inputStream.bufferedReader().readText()
println(result)
}
}
For more information see:
How to run a command line command with Kotlin DSL in Gradle 6.1.1?
How to invoke external command from within Kotlin code?
for kotlin gradle you can use
Runtime.getRuntime().exec("./my_script.sh")
I copied my shell scipt to /usr/local/bin with +x permission and used it as just another command:
commandLine 'my_script.sh'

Gradle zip task neither failing nor working

I'm trying to create a custom Gradle 4.3.1 task that will:
Run ./gradlew build which produces a build/libs/myapp.jar artifact; then
Creates a myapp-1.0.zip ZIP file whose contents include:
build/libs/myapp.jar; and
./AppGuide.md; and
./app-config.json
Here's my best attempt:
task zipMeUp(type: Zip) {
String zipName = 'myapp-1.0.zip'
doFirst {
tasks.build
}
from 'build/libs/myapp.jar'
from 'AppGuide.md'
from 'app-config.json'
into zipName
}
When I run this (./gradlew zipMeUp) I get the following output:
HarveyZ:myapp myuser$ ./gradlew zipMeUp
BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
But nothing actually seems to happen (no myapp-1.0.zip file in the directory). Any idea what the fix/solution is?
Don't use doFirst, use dependsOn
task zipMeUp(type:Zip, dependsOn :[build]) {
String zipName = 'myapp-1.0.zip'
from 'build/libs/myapp.jar'
from 'AppGuide.md'
from 'app-config.json'
version = "1.0"
baseName = "myapp"
}

Gradle clean erasing my file prior to ZIP task execution

I have the following simple task in my build:
task generateFile << {
def file = new File("$buildDir/setclasspath.sh")
file.text = "sample"
outputs.file(file)
}
task createDistro(type: Zip, dependsOn: ['copyDependencies','packageEnvironments','jar', 'generateFile']) <<{
from generateClasspathScript {
fileMode = 0755
into 'bin'
}
}
When I run gradle clean build I see the following output:
Cannot call TaskOutputs.file(Object) on task ':generateFile' after task has started execution. Check the configuration of task ':generateFile' as you may have misused '<<' at task declaration
How do I declare the task file creation outputs as an input to the zip task while also ensuring they happen in the execution phase?
If I leave off the << then the clean task wipes the generated file before the ZIP can use it. If I keep them, I get the above error.
It's the opposite as what is being suggested in the comments. You are trying to set the outputs in execution phase. The correct way to do what you are probably trying to do is for example:
task generateFile {
def file = new File("$buildDir/setclasspath.sh")
outputs.file(file)
doLast {
file.text = "sample"
}
}

Unable to create a Gradle task rule with an Exec task

I'm trying to write a task rule to create a series of tasks that checkout various svn repository locations. Here is my rule:
tasks.addRule("Pattern: svnCheckout&ltClassifier> - Checks out the indicated svn repo") { String taskName ->
if(taskName.startsWith('svnCheckout')) {
task(name: taskName, type: Exec) {
String classifier = taskName - 'svnCheckout'
String svnDir = svnRepoUrl //defined elsewhere
switch(classifier) {
case 'SourceTrunk':
svnDir += 'branches/CleanBuild/trunk'
break
case 'AutoInstaller':
svnDir += 'Tools/AutoInstaller'
break
case 'ContentAutomation':
svnDir += 'Tools/ContentAutomation'
break
case 'InternalTools':
svnDir += 'Tools/Internal'
break
default:
throw new GradleException("Invalid svnCheckout classifier '$classifier'")
}
String svnCommand = "svn co $svnDir --trust-server-cert"
//commandLine 'cmd', '/c', "$svnCommand"
commandLine 'cmd', '/c/', "echo 'Task created'"
workingDir = "$workspace"
}
}
}
I then try to run the task 'svnCheckoutSourceTrunk' with this command:
gradlew -Pworkspace="." svnCheckoutSourceTrunk
which fails with the error
FAILURE: Could not determine which tasks to execute.
* What went wrong:
Task 'svnCheckoutSourceTrunk' not found in root project 'GradleScripts'.
* Try:
Run gradlew tasks to get a list of available tasks.
BUILD FAILED
Anyone see what I'm doing wrong? I put some println statements around the first few lines, and the execution is getting past the if statement, but it's not getting inside the task declaration.
The syntax used for declaring the task(s) is incorrect. (Not sure why it's not giving an error.) The first positional argument always need to be the task name:
task(taskName, type: Exec) { ... }
In a build script, this will also work:
task "$taskName"(type: Exec) { ... }

Gradle: Output file not up to date if parsed from standardOutput

I have had problems with that the Exec task in gradle have problems with the up-to-date check if the output files is captured from standardOutput.
I have tried to simplify the example as much as possible:
task printToOutputFile(type: Exec) {
inputs.file file("file1") // not relevant for this example
outputs.file file("file2")
commandLine = ["echo", "1234"]
standardOutput = new FileOutputStream("file2")
}
When rerunning this task I expect it to be UP-TO-DATE but it is not.
How can I make the UP-TO-DATE check work when using the standardOutput as outputs?
What I have tried:
Closing and/or Flushing the stream in an doLast block.
the problem is, that the line
standardOutput = new FileOutputStream("file2")
changes the lastModified attribute of file2. To get the up-to-date check working, you have to move this assignment to the execution phase. You can do this by putting this assignment in a doFirst block. The following snippet should do the trick:
task printToOutputFile(type: Exec) {
inputs.file file("file1") // not relevant for this example
outputs.file file("file2")
commandLine = ["echo", "1234"]
doFirst{
standardOutput = new FileOutputStream("file2")
}
}
cheers,
René

Resources