refactor(macos): centralize process pipe draining
This commit is contained in:
@@ -278,10 +278,7 @@ enum GatewayEnvironment {
|
|||||||
process.standardOutput = pipe
|
process.standardOutput = pipe
|
||||||
process.standardError = pipe
|
process.standardError = pipe
|
||||||
do {
|
do {
|
||||||
try process.run()
|
let data = try process.runAndReadToEnd(from: pipe)
|
||||||
// Read pipe before waitUntilExit to avoid potential deadlock
|
|
||||||
let data = pipe.fileHandleForReading.readToEndSafely()
|
|
||||||
process.waitUntilExit()
|
|
||||||
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
||||||
if elapsedMs > 500 {
|
if elapsedMs > 500 {
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
|
|||||||
@@ -72,11 +72,11 @@ enum LaunchAgentManager {
|
|||||||
let process = Process()
|
let process = Process()
|
||||||
process.launchPath = "/bin/launchctl"
|
process.launchPath = "/bin/launchctl"
|
||||||
process.arguments = args
|
process.arguments = args
|
||||||
process.standardOutput = Pipe()
|
let pipe = Pipe()
|
||||||
process.standardError = Pipe()
|
process.standardOutput = pipe
|
||||||
|
process.standardError = pipe
|
||||||
do {
|
do {
|
||||||
try process.run()
|
_ = try process.runAndReadToEnd(from: pipe)
|
||||||
process.waitUntilExit()
|
|
||||||
return process.terminationStatus
|
return process.terminationStatus
|
||||||
} catch {
|
} catch {
|
||||||
return -1
|
return -1
|
||||||
|
|||||||
@@ -16,12 +16,7 @@ enum Launchctl {
|
|||||||
process.standardOutput = pipe
|
process.standardOutput = pipe
|
||||||
process.standardError = pipe
|
process.standardError = pipe
|
||||||
do {
|
do {
|
||||||
try process.run()
|
let data = try process.runAndReadToEnd(from: pipe)
|
||||||
// Read pipe output BEFORE waitUntilExit to avoid deadlock.
|
|
||||||
// If the process writes enough to fill the pipe buffer (~64KB),
|
|
||||||
// it will block until someone reads. Reading first prevents this.
|
|
||||||
let data = pipe.fileHandleForReading.readToEndSafely()
|
|
||||||
process.waitUntilExit()
|
|
||||||
let output = String(data: data, encoding: .utf8) ?? ""
|
let output = String(data: data, encoding: .utf8) ?? ""
|
||||||
return Result(status: process.terminationStatus, output: output)
|
return Result(status: process.terminationStatus, output: output)
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -580,11 +580,10 @@ final class NodePairingApprovalPrompter {
|
|||||||
process.standardError = pipe
|
process.standardError = pipe
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try process.run()
|
_ = try process.runAndReadToEnd(from: pipe)
|
||||||
} catch {
|
} catch {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
process.waitUntilExit()
|
|
||||||
return process.terminationStatus == 0
|
return process.terminationStatus == 0
|
||||||
}.value
|
}.value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,10 +203,7 @@ actor PortGuardian {
|
|||||||
proc.standardOutput = pipe
|
proc.standardOutput = pipe
|
||||||
proc.standardError = Pipe()
|
proc.standardError = Pipe()
|
||||||
do {
|
do {
|
||||||
try proc.run()
|
let data = try proc.runAndReadToEnd(from: pipe)
|
||||||
// Read pipe before waitUntilExit to avoid potential deadlock
|
|
||||||
let data = pipe.fileHandleForReading.readToEndSafely()
|
|
||||||
proc.waitUntilExit()
|
|
||||||
guard !data.isEmpty else { return nil }
|
guard !data.isEmpty else { return nil }
|
||||||
return String(data: data, encoding: .utf8)?
|
return String(data: data, encoding: .utf8)?
|
||||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
|||||||
11
apps/macos/Sources/Clawdbot/Process+PipeRead.swift
Normal file
11
apps/macos/Sources/Clawdbot/Process+PipeRead.swift
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension Process {
|
||||||
|
/// Runs the process and drains the given pipe before waiting to avoid blocking on full buffers.
|
||||||
|
func runAndReadToEnd(from pipe: Pipe) throws -> Data {
|
||||||
|
try self.run()
|
||||||
|
let data = pipe.fileHandleForReading.readToEndSafely()
|
||||||
|
self.waitUntilExit()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -133,10 +133,7 @@ enum RuntimeLocator {
|
|||||||
process.standardError = pipe
|
process.standardError = pipe
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try process.run()
|
let data = try process.runAndReadToEnd(from: pipe)
|
||||||
// Read pipe before waitUntilExit to avoid potential deadlock
|
|
||||||
let data = pipe.fileHandleForReading.readToEndSafely()
|
|
||||||
process.waitUntilExit()
|
|
||||||
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
let elapsedMs = Int(Date().timeIntervalSince(start) * 1000)
|
||||||
if elapsedMs > 500 {
|
if elapsedMs > 500 {
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
|
|||||||
Reference in New Issue
Block a user