SwiftSlash
                                
                                
                                
                                    SwiftSlash copied to clipboard
                            
                            
                            
                        Recommended way to print stdout and stderr to the console in real time
I'd like to allow commands that I call with SwiftSlash to print stdout and stderr to the console like if they were being run directly in a shell. Is there a way built into SwiftSlash for me to do this? Or do you have a recommendation on how best to accomplish this?
My current method of accomplishing this is to create a task group which with two tasks run in parallel:
let processInterface = ProcessInterface(command: command)
try await processInterface.launch()
await withTaskGroup(of: Void.self) { group in
    group.addTask(priority: .high) {
        for await chunk in await processInterface.stdout {
            guard let string = String(data: chunk, encoding: .utf8) else { continue }
            print(string)
        }
    }
    group.addTask(priority: .high) {
        for await chunk in await processInterface.stderr {
            guard let string = String(data: chunk, encoding: .utf8) else { continue }
            print(string)
        }
    }
}
This does work, but the output is not streamed in real time. It gets printed to the console in short bursts. It also sometimes gets printed out of order.
Here's a gif showing what I mean, using a download with curl, first run directly, then run via a Swift Package using SwiftShell:
This is the Swift package that was being run: SwiftSlashExample.zip
Any tips or ideas?
I'd love if there were an option on ProcessInterface or something where I could just say "also print stdout and/or stderr to the console".
I like this idea. Let me see what I can come up with.
@hisaac as far as tips for current release, I don’t have any that can improve your situation yet. The batching/timing issue is a deeply rooted symptom that I will address in the next major cycle. My absolute deadline for v4 is when Swift 6 is released, however, I’m currently feeling good about the development trajectory and feel it could easily be done this year.
Stay tuned.
Sounds good, I look forward to seeing what you come up with for version 4!
I ran across something that might be of use here: An environment variable called NSUnbufferedIO.
I first noticed it in Realm's build script here: https://github.com/realm/realm-swift/blob/6b992e508b1fab07d47775f2fd7485fd5f110893/build.sh#L121
And after a quick search, I found some information about it in an NSHipster article:
Although unlikely, you may come across a situation where you want logging to
stdoutto be unbuffered (ensuring that the output has been written before continuing). You can set that with theNSUnbufferedIOenvironment variable. If set toYES, Foundation will use unbuffered I/O forstdout(stderris unbuffered by default).
I don't know if that's helpful here, but it made me think of this conversation, and that it might be a useful nugget.
I hope SwiftSlash v4 is coming along nicely! 👋