diff options
| author | Tommaso Negri <me@tommasongr.com> | 2026-07-27 16:18:34 +0200 |
|---|---|---|
| committer | Tommaso Negri <me@tommasongr.com> | 2026-07-27 16:18:34 +0200 |
| commit | 535b42a7b8304340182ca1367aa42f047eb06bff (patch) | |
| tree | 88e15512f874a00886fc7b97861feb5e92c6aaf5 /Sources/phbar/Models/Runner.swift | |
| parent | 6d165c74a5a6b471c155b12ab15ef833d6b2aa36 (diff) | |
| download | bar-535b42a7b8304340182ca1367aa42f047eb06bff.tar.gz bar-535b42a7b8304340182ca1367aa42f047eb06bff.zip | |
scaffold basic structure
Diffstat (limited to 'Sources/phbar/Models/Runner.swift')
| -rw-r--r-- | Sources/phbar/Models/Runner.swift | 45 |
1 files changed, 45 insertions, 0 deletions
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 + } +} |
