-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async output? #11
Comments
I would love to see this added to ShellOut! 👍 It would also make async scripting with Marathon possible, which would be a big win. Would be happy to accept a PR adding this feature. |
Got PR for this here |
Edit, the original sounded a bit douchy in the second read. This PR seems to work well on Linux, is it possible to get it to work with Marathon? Thanks for the PR @rob-nash . |
Glad someone finds it useful @lf-araujo no worries mate 👍 |
Any progress? It doesn't look like anyone made a progress update in years. |
This is the closer way to a kind of workaround I found so far: @discardableResult func shellOut(
to command: ShellOutCommand,
arguments: [String] = [],
at path: String = ".",
process: Process = .init(),
errorHandle: FileHandle? = nil,
liveOutput: @escaping (String) -> Void
) throws -> String {
let temporaryOutputURL = FileManager.default.temporaryDirectory.appendingPathComponent(
"shellout_live_output.temp"
)
if FileManager.default.fileExists(atPath: temporaryOutputURL.absoluteString) {
try FileManager.default.removeItem(at: temporaryOutputURL)
}
try Data().write(to: temporaryOutputURL)
let outputHandle = try FileHandle(forWritingTo: temporaryOutputURL)
#if DEBUG
print("To read live output file directly in a terminal")
print("tail -f \(temporaryOutputURL.path)")
#endif
outputHandle.waitForDataInBackgroundAndNotify()
let subscription = NotificationCenter.default.publisher(for: NSNotification.Name.NSFileHandleDataAvailable)
.tryReduce("", { alreadyDisplayedContent, _ in
let content = try String(contentsOf: temporaryOutputURL)
liveOutput(String(content[alreadyDisplayedContent.endIndex...]))
outputHandle.waitForDataInBackgroundAndNotify()
return content
})
.sink(receiveCompletion: {
switch $0 {
case let .failure(error):
print("Content of live output cannot be read: \(error)")
case .finished: break
}
}, receiveValue: { _ in })
let output = try shellOut(to: command, at: path, process: process, outputHandle: outputHandle, errorHandle: errorHandle)
subscription.cancel()
try FileManager.default.removeItem(at: temporaryOutputURL)
return output
} Usage in my script: try shellOut(
to: .iOSTest(
scheme: projectName,
simulatorName: device.simulatorName,
derivedDataPath: derivedDataPath,
testPlan: planName
)
) { print($0) } // I'm printing everything, but here you can filter what you really want to print out. I know this is far from being nice, and there is certainly a way to do better. If you have better approach, I'm all ears. I guess this PR will fix the issue once for all: #30. In the meanwhile, it's good to have a workaround for some scripts I guess. (I also know that I'm ignoring the live error output, it's only because for my case, I don't need it for my case). |
I've skimmed the code and it appears you don't provide any way to get the output of a command as it comes through the pipe. Is this something you'd consider adding? I guess it would provide a "data received" callback argument or something?
The text was updated successfully, but these errors were encountered: