Running command line is not correct in Gradle - gradle

Following is my code:
task encodeFile(type: Exec) {
workingDir dirName
def files = file(dirName).listFiles()
files.each { File file ->
if (file.isFile()) {
println " *** $file.name *** "
def tmpName = "tmp$file.name"
println " === $tmpName"
commandLine "cmd", "/c native2ascii $file.name $tmpName"
commandLine "cmd", "/c del $file.name"
commandLine "cmd", "/c move $tmpName $file.name"
// commandLine "cmd", "/c move $file.name $tmpName"
println " === $file.name is moved"
println "----------------------------------"
// """executable "native2ascii" "$file.name" "$tmpName""""".execute()
}
}
}
I'm trying to encode all the files under the specified folder for localization. But when I ran the code above, only the last file is changed as expected. I printed some messages and all the files are iterated.
Does anyone know what happens here?

Yes, the last iteration of each invoked on files object sets the configuration up and wins - you can change the order of files passed to verify it.
native2ascii task is built-in gradle by default, you can try e.g.:
task n2a {
doLast {
ant.native2ascii(
src : project.file('n2a-src'),
dest : project.file('n2a-dest')
)
}
}
It seems that there's no need to do it via Exec task.

For me this is working properly:
processResources {
"*.properties, *.txt".split(",").each {pattern ->
filesMatching ("**/" + pattern.trim ()) {
filter {
it
.replace ('${projectVersion}', project.version)
.replace ('${projectName}', project.name)
}
}
}
doLast {
if (file (processResources.destinationDir).exists()) {
ant.native2ascii (
src: "${processResources.destinationDir}",
dest: "${processResources.destinationDir}/../ascii",
includes: '**/*.properties',
)
copy {
from "${processResources.destinationDir}/../ascii"
into processResources.destinationDir
}
}
}
}

Related

Fill array/args programmatically in Groovy/Gradle

I am trying to fix the args-argument for the executing programm for this Gradle task:
task generateResources(type: JavaExec) {
group = 'build'
description = 'Generate resource bundle from excel file'
mainClass.set('com.project.MainClass')
ext {
destDir = ''
sourceFile = ''
isDir = false
setInputDir = { input ->
xlxsTree = fileTree(input).matching { include '*.xls' }
xlxsTree.files.each {
args[1] = "$it" //how can I add all matching files???
}
}
setOutput = { output ->
outputs.dir(output)
destDir = output
args[0] = destDir
}
}
setInputDir("${project.projectDir}\\src\\main\\resources\\properties")
setOutput("${project.buildDir}\\resources\\generatedProperties")
logging.captureStandardOutput LogLevel.INFO
onlyIf {
!sourceFile.empty
}
classpath = project.configurations.resbundles
doFirst {
args args
jvmArgs '-Dfile.encoding=ISO-8859-15'
}
The args-argument in doLast{} should contain all file paths ending with .xls, e. g. ["C:\...\src\main\resources\properties\destdir", "C:\...\resources\generatedProperties\file1", "C:\...\resources\generatedProperties\file2"].
My approach is not working at all, I just tried to make it compile for at least one input file.

Skipping task as it has no source files and no previous output files

This is my build.gradle which has three tasks (one for downloading the zip, one for unzipping it and other for executing the sh file). These tasks are dependent on each other. I am using Gradle 6. As these are dependent tasks I have used following command:
gradlew C
I get the error:
Skipping task 'B' as it has no source files and no previous output files.
build.gradle:
task A {
description = 'Rolls out new changes'
doLast {
def url = "https://${serverName}/xxx/try.zip"
def copiedZip = 'build/newdeploy/try.zip'
logger.lifecycle("Downloading $url...")
file('build/newdeploy').mkdirs()
ant.get(src: url, dest: copiedZip, verbose: true)
}
}
task B (type: Copy, dependsOn: 'A') {
doLast {
def zipFile = file('build/newdeploy/try.zip')
def outputDir = file("build/newdeploy")
from zipTree(zipFile)
into outputDir
}
}
task C (type: Exec, dependsOn: 'B') {
doLast {
workingDir 'build/newdeploy/try/bin'
executable 'sh'
args arguments, url
ext.output = { return standardOutput.toString() }
}
}
I tried following and it worked. Rather than adding a separate task to copy, added the copy function in the task A itself
task A {
description = 'Rolls out new changes'
doLast {
def url = "https://${serverName}/xxx/try.zip"
def copiedZip = 'build/newdeploy/try.zip'
logger.lifecycle("Downloading $url...")
file('build/newdeploy').mkdirs()
ant.get(src: url, dest: copiedZip, verbose: true)
def outputDir = file("build/newdeploy")
copy {
from zipTree(zipFile)
into outputDir
}
}
}
task C (type: Exec, dependsOn: 'A') {
doLast {
workingDir 'build/newdeploy/try/bin'
executable 'sh'
args arguments, url
ext.output = { return standardOutput.toString() }
}
}

Gradle zip task with lazy include property includes itself

Hi I got this zip task which works great:
def dir = new File("${projectDir.parentFile}/test/")
task testZip(type: Zip) {
from dir
destinationDirectory = dir
include 'toast/**'
archiveFileName = 'test.zip'
}
but then when I make the include property lazy (because I need to in my real case)
def dir = new File("${projectDir.parentFile}/test/")
task testZip(type: Zip) {
from dir
destinationDirectory = dir
include {
'toast/**'
}
archiveFileName = 'test.zip'
}
then it creates a zip that includes everything in the folder, (so the generated archive too). In this test case the inner zip is just corrupted (doesn't run infinitely) but in the real world case it does make an infinite zip. (Not sure why, maybe my best case has too few or small files). Either way the test case shows the problem, the generated zip contains a zip even though it should only contain the toast directory and all of its content.
How do I fix this? I need a lazy include because the directory I want to include is computed by other tasks. I get the exact same problem with Tar except it refuses to create the archive since it includes itself.
Using exclude '*.zip' is a dumb workaround which makes the archive include other folders I don't want. I only want to include a specific folder, lazyly.
Here's what the monster looks like in the real world case. I basically need to retrieve the version of the project from Java to then use that version to name the folders I'm packaging. (Making a libGDX game and packaging it with a jre using packr). The problematic tasks are 'makeArchive_' + platform.
String jumpaiVersion;
task fetchVersion(type: JavaExec) {
outputs.upToDateWhen { jumpaiVersion != null }
main = 'net.jumpai.Version'
classpath = sourceSets.main.runtimeClasspath
standardOutput new ByteArrayOutputStream()
doLast {
jumpaiVersion = standardOutput.toString().replaceAll("\\s+", "")
}
}
def names = [
'win64' : "Jumpai-%%VERSION%%-Windows-64Bit",
'win32' : "Jumpai-%%VERSION%%-Windows-32Bit",
'linux64' : "Jumpai-%%VERSION%%-Linux-64Bit",
'linux32' : "Jumpai-%%VERSION%%-Linux-32Bit",
'mac' : "Jumpai-%%VERSION%%-Mac.app"
]
def platforms = names.keySet() as String[]
def jdks = [
'win64' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-win_x64.zip',
'win32' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-win_i686.zip',
'linux64' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-linux_x64.tar.gz',
'linux32' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-linux_i686.tar.gz',
'mac' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-macosx_x64.zip'
]
def formats = [
'win64' : 'ZIP',
'win32' : 'ZIP',
'linux64' : 'TAR_GZ',
'linux32' : 'TAR_GZ',
'mac' : 'ZIP'
]
File jdksDir = new File(project.buildscript.sourceFile.parentFile.parentFile, 'out/jdks')
File gameJar = new File("${projectDir.parentFile}/desktop/build/libs/Jumpai.jar")
File gameData = new File("${projectDir.parentFile}/desktop/build/libs/Jumpai.data")
File packrDir = new File("${projectDir.parentFile}/out/packr/")
File minimalTmpDir = new File("${projectDir.parentFile}/desktop/build/libs/minimal-tmp")
task minimizeGameJar {
dependsOn ':desktop:dist'
doFirst {
minimalTmpDir.mkdirs()
copy {
from zipTree(gameJar)
into minimalTmpDir
}
for(file in minimalTmpDir.listFiles())
if(file.getName().contains("humble"))
file.delete()
}
}
task makeMinimal(type: Zip) {
dependsOn minimizeGameJar
dependsOn fetchVersion
from minimalTmpDir
include '**'
archiveFileName = provider {
"Jumpai-${->jumpaiVersion}-Minimal.jar"
}
destinationDir packrDir
doLast {
minimalTmpDir.deleteDir()
}
}
task copyGameJar(type: Copy) {
outputs.upToDateWhen { gameData.exists() }
dependsOn ':desktop:dist'
from gameJar.getAbsolutePath()
into gameData.getParentFile()
rename("Jumpai.jar", "Jumpai.data")
}
task setWindowsIcons(type: Exec) {
dependsOn fetchVersion
workingDir '.'
commandLine 'cmd', '/c', 'set_windows_icons.bat', "${->jumpaiVersion}"
}
for(platform in platforms) {
task("getJdk_" + platform) {
String url = jdks[platform]
File jdkDir = new File(jdksDir, platform + "-jdk")
File jdkFile = new File(jdkDir, url.split("/").last())
outputs.upToDateWhen { jdkFile.exists() }
doFirst {
if(!jdkDir.exists())
jdkDir.mkdirs()
if(jdkFile.exists())
{
println jdkFile.getName() + " is already present"
return
}
else
{
println "Downloading " + jdkFile.getName()
new URL(url).withInputStream {
i -> jdkFile.withOutputStream { it << i }
}
}
for(file in jdkDir.listFiles()) {
if(file.equals(jdkFile))
continue
if(file.isFile()) {
if (!file.delete())
println "ERROR: could not delete " + file.getAbsoluteFile()
} else if(!file.deleteDir())
println "ERROR: could not delete content of " + file.getAbsoluteFile()
}
if(url.endsWith(".tar.gz"))// don't mix up archive type of what we downloaded vs archive type of what we compress (in formats)
{
copy {
from tarTree(resources.gzip(jdkFile))
into jdkDir
}
}
else if(url.endsWith(".zip"))
{
copy {
from zipTree(jdkFile)
into jdkDir
}
}
}
}
File packrInDir = new File(packrDir, platform)
String platformRawName = names[platform]
task("packr_" + platform, type: JavaExec) {
outputs.upToDateWhen { new File(packrDir, platformRawName.replace("%%VERSION%%", jumpaiVersion)).exists() }
dependsOn fetchVersion
dependsOn copyGameJar
dependsOn 'getJdk_' + platform
main = 'com.badlogicgames.packr.Packr'
classpath = sourceSets.main.runtimeClasspath
args 'tools/res/packr_config/' + platform + '.json'
workingDir = project.buildscript.sourceFile.parentFile.parentFile
doLast {
File packrOutDir = new File(packrDir, platformRawName.replace("%%VERSION%%", jumpaiVersion));
packrOutDir.deleteDir()
if(packrOutDir.exists())
{
println "ERROR Could not delete packr output " + packrOutDir.getAbsolutePath()
return
}
if(!packrInDir.renameTo(packrOutDir))
println "ERROR Could not rename packr output dir for " + packrInDir.getName()
}
}
if(formats[platform] == 'ZIP')
{
task('makeArchive_' + platform, type: Zip) {
if(platform.contains("win"))
dependsOn setWindowsIcons
dependsOn fetchVersion
dependsOn 'packr_' + platform
from packrDir
destinationDirectory = packrDir
include {
platformRawName.replace("%%VERSION%%", jumpaiVersion) + "/"
}
archiveFileName = provider {
platformRawName.replace("%%VERSION%%", jumpaiVersion) + ".zip"
}
}
}
else if(formats[platform] == 'TAR_GZ')
{
task('makeArchive_' + platform, type: Tar) {
dependsOn 'packr_' + platform
from packrDir
destinationDirectory = packrDir
include {
platformRawName.replace("%%VERSION%%", jumpaiVersion) + '/**'
}
archiveFileName = provider {
platformRawName.replace("%%VERSION%%", jumpaiVersion) + ".tar.gz"
}
extension 'tar'
compression = Compression.GZIP
}
}
else
println 'Unsupported format for ' + platform
}
task deploy {
dependsOn makeMinimal
for(platform in platforms)
dependsOn 'makeArchive_' + platform
}
How do I fix this? I need a lazy include because the directory I want to include is computed by other tasks. I get the exact same problem with Tar except it refuses to create the archive since it includes itself.
You can get what you want by using the doFirst method and modifiying the tasks properties with the passed action.
task('makeArchive_' + platform, type: Zip) {
if(platform.contains("win"))
dependsOn setWindowsIcons
dependsOn fetchVersion
dependsOn 'packr_' + platform
from packrDir
destinationDirectory = packrDir
archiveFileName = provider {
platformRawName.replace("%%VERSION%%", jumpaiVersion) + ".zip"
}
doFirst {
def includeDir = platformRawName.replace("%%VERSION%%", jumpaiVersion)
// Include only files and directories from 'includeDir'
include {
it.relativePath.segments[ 0 ].equalsIgnoreCase(includeDir)
}
}
}
Please have also a look at this answer to a similar question. My solution is just a workaround. If you know your version at configuration phase you can achieve what you want more easily. Writing your own custom tasks or plugins can also help to clean up your build script.

Gradle - How to execute command line in doLast and get exit code?

task executeScript() {
doFirst {
exec {
ignoreExitValue true
commandLine "sh", "process.sh"
}
}
doLast {
if (execResult.exitValue == 0) {
print "Success"
} else {
print "Fail"
}
}
}
I'm getting the following error
> Could not get unknown property 'execResult' for task ':core:executeScript' of type org.gradle.api.DefaultTask.
If I move the commandLine to configuration part everything works fine. But I want commandLine to be in action block so it wont run every time we execute some other gradle tasks.
Use gradle type for your task
task executeScript(type : Exec) {
commandLine 'sh', 'process.sh'
ignoreExitValue true
doLast {
if(execResult.exitValue == 0) {
println "Success"
} else {
println "Fail"
}
}
}
This will work for you...
You can read more about the Exec task here
Alternative syntax to execute external command and get its return code:
doLast {
def process = "my command line".execute()
process.waitFor()
println "Exit code: " + process.exitValue()
}

Gradle task doLast if task fails

I want a clean build, where you can see exactly what happened, but all information is preserved - so essentially for every task, I want it to write the output to a file, and only display it if the task fails.
I've tried to achieve this in gradle - but am being defeated because doLast doesn't run if the task fails. Here's my "almost" working pattern:
task fakeTask( type: Exec ) {
standardOutput = new ByteArrayOutputStream()
commandLine 'cmd', '/c', 'silly'
doLast {
new File("build.log") << standardOutput.toString()
if (execResult.exitValue != 0) println standardOutput.toString()
}
}
is there any alternative to doLast that will run any time? Any other way of doing this? - especially as I want to do this for every single task I have?
this is my final solution:
tasks.withType( Exec ) {
standardOutput = new ByteArrayOutputStream()
ignoreExitValue = true
doLast {
new File("gradle.log") << standardOutput.toString()
if (execResult.exitValue != 0)
{
println standardOutput.toString()
throw new GradleException(commandLine.join(" ") + " returned exitcode of " + execResult.exitValue )
}
}
}
Add a ignoreExitValue true to your task definition to suppress throwing of an exception when the exit value is non-zero.
You can use the task graph as documented at https://docs.gradle.org/current/userguide/build_lifecycle.html#sec:task_execution to execute code after a task has run.
gradle.taskGraph.afterTask { task, state ->
if (task instanceof ExecTask && state.failure) {
file('gradle.log') << standardOutput.toString()
}
}

Resources