Xcodebuild - Process output

Hi,

Overview:

  • I am trying to execute an xcodebuild command from Swift code using Process()
  • I am using Pipe for process.standardOutput

What is working:

  • When I execute the xcodebuild command to create an archive, I am able to get the output as a Swift String using the code mentioned below.

Problem:

  • When I try to execute the following command through my swift code, I am not able to capture the output as a Swift String
    xcodebuild -exportArchive -archivePath <archive path> -exportOptionsPlist <options plist path>
  • However when the above command is executed on the command line it does print some progress.

What I have found:

  • outputHandle.readabilityHandler closure is called often, however pipe.availableData is empty

Questions:

  • Is the upload script actually not using the standard output ?
  • How can I capture the output for the upload script as a Swift String ?
  • Or am I missing something, is there any other way to capture the progress ?

Code:

let process = Process()
process.launchPath = "/bin/zsh"
process.arguments = ["-c", command]
process.terminationHandler = terminationHandler

let outputPipe = Pipe()
process.standardOutput = outputPipe

let outputHandle = outputPipe.fileHandleForReading
outputHandle.waitForDataInBackgroundAndNotify()

var output = ""

outputHandle.readabilityHandler = { pipe in
    
    guard let currentOutput = String(data: pipe.availableData, encoding: .utf8) else {
        print("Error decoding data: \(pipe.availableData)")
        return
    }
    
    guard !currentOutput.isEmpty else {
        return
    }
    
    output = output + currentOutput + "\n"
    
    if debug {
        DispatchQueue.main.async {
            print(currentOutput)
        }
    }
}

Thanks.

hey @somu - I don't have any solid answers to the underlying questions, but I do have a suggestion that might help illuminate one:

When you're invoking via a shell, you can redirect the STDOUT and STDERR as streams explicitly, so that if Xcodebuild it isn't pushing to STDOUT, but to STDERR then you can collapse those streams together to make it seem as though it does.

The code to do this on the shell is somecommand 2>&1 - where 2> is indicating redirect to STDERR and &1 means "to the STDOUT" (>1 is STDOUT in this setup). I'm reasonably sure this'll work in ZSH, but I picked this up from SH and BASH days, so there may be some differences there, but there should at least be a way to do it.

You can also do a quick experiment with this to see what's going to STDOUT and STDERR explicitly:

somecommand 1>./stdout.txt 2>./stderr.txt will dump the output from STDOUT into ./stdout.txt and STDERR to ./stderr.txt respectively, which can then be inspected to see what's what and where output it going.

2 Likes

@Joseph_Heck Thank you so much !!!! It was writing the progress to the error file.

1 Like