macOS: split AppMain into focused modules
This commit is contained in:
45
apps/macos/Sources/Clawdis/ShellRunner.swift
Normal file
45
apps/macos/Sources/Clawdis/ShellRunner.swift
Normal file
@@ -0,0 +1,45 @@
|
||||
import ClawdisIPC
|
||||
import Foundation
|
||||
|
||||
enum ShellRunner {
|
||||
static func run(command: [String], cwd: String?, env: [String: String]?, timeout: Double?) async -> Response {
|
||||
guard !command.isEmpty else { return Response(ok: false, message: "empty command") }
|
||||
|
||||
let process = Process()
|
||||
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
|
||||
process.arguments = command
|
||||
if let cwd { process.currentDirectoryURL = URL(fileURLWithPath: cwd) }
|
||||
if let env { process.environment = env }
|
||||
|
||||
let stdoutPipe = Pipe()
|
||||
let stderrPipe = Pipe()
|
||||
process.standardOutput = stdoutPipe
|
||||
process.standardError = stderrPipe
|
||||
|
||||
do {
|
||||
try process.run()
|
||||
} catch {
|
||||
return Response(ok: false, message: "failed to start: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
let waitTask = Task.detached { () -> (Int32, Data, Data) in
|
||||
process.waitUntilExit()
|
||||
let out = stdoutPipe.fileHandleForReading.readDataToEndOfFile()
|
||||
let err = stderrPipe.fileHandleForReading.readDataToEndOfFile()
|
||||
return (process.terminationStatus, out, err)
|
||||
}
|
||||
|
||||
if let timeout, timeout > 0 {
|
||||
let nanos = UInt64(timeout * 1_000_000_000)
|
||||
try? await Task.sleep(nanoseconds: nanos)
|
||||
if process.isRunning {
|
||||
process.terminate()
|
||||
return Response(ok: false, message: "timeout")
|
||||
}
|
||||
}
|
||||
|
||||
let (status, out, err) = await waitTask.value
|
||||
let combined = out.isEmpty ? err : out
|
||||
return Response(ok: status == 0, message: status == 0 ? nil : "exit \(status)", payload: combined)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user