tv-anarchy/Sources/PlumTVCore/ProcessRunner.swift
Natalie e2977041aa feat: PlumTV — native macOS player with config-driven hosts
Phase 0/1: SwiftUI app (XcodeGen), PlumTVCore framework, player MVP.
- PlayerTarget protocol + VLCTarget (HTTP) and BlackTVTarget (ssh black-tv)
- config-driven hosts (~/.config/plumtv/hosts.json), seeded plum-vlc + black
- reliability: SSH ControlMaster (5s->~1s/poll), endpoint pinning (LAN->overlay),
  single-flight polling, keep-last-known on transient failure, debounced volume
- Hosts pane shows live connection state; Player has target picker + transport
- unit tests for status decoding

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 20:24:55 -07:00

33 lines
1.2 KiB
Swift

import Foundation
public struct ProcessResult: Sendable {
public let status: Int32
public let stdout: String
public let stderr: String
public var ok: Bool { status == 0 }
}
/// Minimal blocking command runner. Outputs here are tiny (a line of JSON), so
/// the read-to-EOF pattern is safe. Always call off the main thread.
public enum ProcessRunner {
public static func run(_ launchPath: String, _ args: [String]) -> ProcessResult {
let p = Process()
p.executableURL = URL(fileURLWithPath: launchPath)
p.arguments = args
let out = Pipe()
let err = Pipe()
p.standardOutput = out
p.standardError = err
do {
try p.run()
} catch {
return ProcessResult(status: -1, stdout: "", stderr: "spawn failed: \(error.localizedDescription)")
}
let o = out.fileHandleForReading.readDataToEndOfFile()
let e = err.fileHandleForReading.readDataToEndOfFile()
p.waitUntilExit()
return ProcessResult(status: p.terminationStatus,
stdout: String(decoding: o, as: UTF8.self),
stderr: String(decoding: e, as: UTF8.self))
}
}