From 535b42a7b8304340182ca1367aa42f047eb06bff Mon Sep 17 00:00:00 2001 From: Tommaso Negri Date: Mon, 27 Jul 2026 16:18:34 +0200 Subject: scaffold basic structure --- Sources/phbar/Models/Runner.swift | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Sources/phbar/Models/Runner.swift (limited to 'Sources/phbar/Models/Runner.swift') diff --git a/Sources/phbar/Models/Runner.swift b/Sources/phbar/Models/Runner.swift new file mode 100644 index 0000000..a98d34a --- /dev/null +++ b/Sources/phbar/Models/Runner.swift @@ -0,0 +1,45 @@ +import Foundation + +/// Runs a shell command and returns its stdout as cells (one per line). +/// +/// Blocking — always call from a background context (e.g. `Task.detached`). +enum Runner { + static func run(_ command: String, env: [String: String] = [:]) -> [String] { + let process = Process() + process.executableURL = URL(fileURLWithPath: "/bin/sh") + process.arguments = ["-c", command] + + var environment = ProcessInfo.processInfo.environment + environment.merge(env) { _, new in new } + process.environment = environment + + let stdout = Pipe() + let stderr = Pipe() + process.standardOutput = stdout + process.standardError = stderr + + guard let _ = try? process.run() else { + return ["(error)"] + } + + let data = stdout.fileHandleForReading.readDataToEndOfFile() + let errData = stderr.fileHandleForReading.readDataToEndOfFile() + process.waitUntilExit() + + if process.terminationStatus != 0 { + let reason = String(data: errData, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) + FileHandle.standardError.write("phbar: `\(command)` failed: \(reason ?? "exit \(process.terminationStatus)")\n".data(using: .utf8)!) + } + + return parse(String(data: data, encoding: .utf8) ?? "") + } + + /// Split output into cells: one per line. A single trailing newline (from a + /// final `\n`) is dropped; blank lines elsewhere are kept so a script can + /// emit intentional gaps. + static func parse(_ text: String) -> [String] { + var lines = text.components(separatedBy: "\n") + if lines.last == "" { lines.removeLast() } + return lines + } +} -- cgit v1.2.3