Gradle构建脚本未执行CMD中curl命令,请求排查原因
问题分析与解决:Gradle脚本未实际执行curl和tar命令
问题场景
编写了用于测试项目构建的Gradle构建脚本,预期当系统未安装指定版本(2201.6.0)的Ballerina包时,自动下载并解压该依赖包。执行脚本后控制台日志显示curl和tar命令已执行且退出值为0,但build目录中未出现下载的文件。
原build.gradle中checkBallerinaDist任务代码
task checkBallerinaDist(type: Exec) { def fileName = "ballerina-${ballerinaLangVersion}-swan-lake" def downloadLink = "https://dist.ballerina.io/downloads/${ballerinaLangVersion}/${fileName}.zip" workingDir project.buildDir if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine 'cmd', '/c', 'bal', '--version' } else { commandLine 'bash', 'bal', '--version' } standardOutput = new ByteArrayOutputStream() ignoreExitValue = true doLast { String output = standardOutput.toString().trim() println "Ballerina distribution check result: $output" standardOutput = System.out if (executionResult.get().exitValue != 0 || !output.contains(ballerinaLangVersion)) { println "Ballerina distribution not found. Downloading..." if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine 'cmd', '/c', 'curl', '-o', fileName + '.zip', downloadLink, '--progress-bar' println "Curl command executed" println "Command line: ${commandLine}" println "Working directory: ${workingDir}" println "Exit value: ${executionResult.get().exitValue}" commandLine 'cmd', '/c', 'tar', '-xf', fileName + '.zip' println "Tar command executed" println "Command line: ${commandLine}" println "Working directory: ${workingDir}" println "Exit value: ${executionResult.get().exitValue}" } else { // TODO: Handle this for Linux } System.setProperty("ballerina.home", "${project.buildDir}/${fileName}") } else { println "Ballerina distribution already exists" System.setProperty("ballerina.home", "${System.getenv("BALLERINA_HOME")}/distributions/ballerina-${ballerinaLangVersion}") } } } test { dependsOn checkBallerinaDist doFirst { println "Ballerina distribution path: ${System.getProperty("ballerina.home")}" systemProperties = [ "target.dir" : project.buildDir, "ballerina.home": System.getProperty("ballerina.home") ] } testLogging { showStackTraces = true showStandardStreams = true } useTestNG { suites "src/test/resources/testng.xml" } finalizedBy jacocoTestReport }
执行日志
> Task :gateway-native:checkBallerinaDist Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 Ballerina distribution check result: Ballerina 2201.5.0 (Swan Lake Update 5) Language specification 2022R4 Update Tool 1.3.14 Ballerina distribution not found. Downloading... Curl command executed Command line: [cmd, /c, curl, -o, ballerina-2201.6.0-swan-lake.zip, https://dist.ballerina.io/downloads/2201.6.0/ballerina-2201.6.0-swan-lake.zip, --progress-bar] Working directory: D:\graphql-federation-gateway\native\build Exit value: 0 Tar command executed Command line: [cmd, /c, tar, -xf, ballerina-2201.6.0-swan-lake.zip] Working directory: D:\graphql-federation-gateway\native\build Exit value: 0 > Task :gateway-native:test Ballerina distribution path: D:\graphql-federation-gateway\native\build/ballerina-2201.6.0-swan-lake
问题根源
doLast块中修改commandLine不会触发命令执行
Exec任务的commandLine是在配置阶段就确定要执行的命令,doLast属于执行阶段的回调,此时任务的主命令(bal --version)已经执行完毕。你在doLast里修改commandLine只是改变了变量值,并没有实际调用执行这些新命令。错误的退出值来源
日志里打印的Exit value: 0是之前bal --version命令的退出值,不是curl或tar命令的执行结果,这导致你误以为curl和tar真的运行成功了。
修复方案
在doLast块中,不要修改commandLine,而是用Gradle提供的exec方法直接执行curl和tar命令,这样才能真正触发命令运行。修改后的checkBallerinaDist任务代码如下:
task checkBallerinaDist(type: Exec) { def fileName = "ballerina-${ballerinaLangVersion}-swan-lake" def downloadLink = "https://dist.ballerina.io/downloads/${ballerinaLangVersion}/${fileName}.zip" workingDir project.buildDir if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine 'cmd', '/c', 'bal', '--version' } else { commandLine 'bash', '-c', 'bal --version' // 修正原Linux命令的错误 } standardOutput = new ByteArrayOutputStream() ignoreExitValue = true doLast { String output = standardOutput.toString().trim() println "Ballerina distribution check result: $output" if (executionResult.get().exitValue != 0 || !output.contains(ballerinaLangVersion)) { println "Ballerina distribution not found. Downloading..." if (Os.isFamily(Os.FAMILY_WINDOWS)) { // 用exec方法执行curl命令 exec { commandLine 'cmd', '/c', 'curl', '-o', "${fileName}.zip", downloadLink, '--progress-bar' workingDir project.buildDir } println "Curl command executed successfully" // 用exec方法执行tar命令 exec { commandLine 'cmd', '/c', 'tar', '-xf', "${fileName}.zip" workingDir project.buildDir } println "Tar command executed successfully" } else { // Linux下的实现,同样用exec方法 exec { commandLine 'bash', '-c', "curl -o ${fileName}.zip ${downloadLink} --progress-bar" workingDir project.buildDir } exec { commandLine 'bash', '-c', "tar -xf ${fileName}.zip" workingDir project.buildDir } } System.setProperty("ballerina.home", "${project.buildDir}/${fileName}") } else { println "Ballerina distribution already exists" System.setProperty("ballerina.home", "${System.getenv("BALLERINA_HOME")}/distributions/ballerina-${ballerinaLangVersion}") } } }
补充说明
- 用
exec方法可以在执行阶段直接运行外部命令,每个exec块都会独立执行并返回自己的执行结果,若需要强制检查命令是否成功,可添加ignoreExitValue = false(默认值即为false,命令失败会抛出异常)。 - 原Linux分支的
commandLine 'bash', 'bal', '--version'存在错误,应该改为bash -c 'bal --version',否则bash会把bal当作脚本文件名执行,上述代码已一并修正。
内容的提问来源于stack exchange,提问作者Mohamed Ishad
相关产品推荐
相关产品推荐

