Xcode runs swift script with gradle process but in terminal it hangs with no output

I have this fascinating problem that when I ran a process in a swift commandline tool in xcode it triggers gradle, or gradlew (both have the problem), and it shows output. The same thing ran from commandline does not output anything.

I found 1 post on stackoverflow mentioning that maybe the deamon is not started. I added my question there to. But maybe somebody here could point me in the right direction?

    let gradlew = try <#projectdir#>.file(named: "gradlew")
    let process = Process()
    process.executableURL = URL(fileURLWithPath: "/bin/bash")
    process.currentDirectoryURL = chameleonKotlin.url
         
    process.arguments = ["-c", "\(gradlew.path) tasks"]
          
    try process.run()
    process.waitUntilExit()
    
    guard process.terminationStatus == 0 else {
        throw Error.cannotPublisKotlin
    }

how is the output configured for the Process?

1 Like

In my example I do not configure it and leave it to standardOut and error. This seams to be the problem indeed.

altering the script to pipe both stdErr and stdOut fixed the issue. Although I do not quite understand why this would halt the deamon from starting?? :thinking: I do the same for other processes, like swift build, and then it works just fine without a pipe.

Anyway if you are using Zollerboy1/SwiftCommand: A wrapper around Foundation.Process, inspired by Rust's std::process::Command. you could use the following code and then it should work.

let gradle = try File(path: <#path to gradle#>/.gradle/wrapper/dists/gradle-8.2-bin/bbg7u40eoinfdyxsxr3z4i7ta/gradle-8.2/bin/gradle")
      let output = try await Command(executablePath: gradle.filePath)
        .setCWD(<#currentDir#>)
      // do to a weird gradle deamon hang we have to capture the output or gradle will not start running
        .setStderr(.pipe)
        .setStdout(.pipe)
        .setEnvVariables(ProcessInfo.processInfo.environment)
        .setEnvVariable(key: "ANDROID_HOME", value: androidSDK.path)
        .addArgument("tasks")
        .output
      
      logger.notice("\(output.stdout)")
      logger.notice("\(output.stderr ?? "[no stderr output]")")

I would still be interested in understanding why the output configuration would matter?

It’s common for CLI tools to check whether they’re being run on a proper terminal or not and change their output accordingly. You’d have to look in the Gradle documentation to see if there’s a way to override this inference. If you want to be sure this is the thing, you can try running Gradle from your shell using the techniques described here:

1 Like