Skip to content

Commit a6a6a22

Browse files
committed
Fix hang when merging stderr with stdout
1 parent abd49a7 commit a6a6a22

File tree

2 files changed

+18
-13
lines changed

2 files changed

+18
-13
lines changed

Sources/Subprocess/PipeConfiguration.swift

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,7 @@ extension PipeConfiguration {
294294
group.addTask {
295295
let errorReadFileDescriptor = createIODescriptor(from: sharedErrorPipe.readEnd, closeWhenDone: true)
296296
let errorReadEnd = errorReadFileDescriptor.createIOChannel()
297-
298297
let stderr = try await self.error.captureOutput(from: errorReadEnd)
299-
300298
return .stderr(stderr)
301299
}
302300

@@ -342,12 +340,10 @@ extension PipeConfiguration {
342340
let originalResult = try await Subprocess.run(
343341
configuration,
344342
input: self.input,
345-
output: .fileDescriptor(writeEnd, closeAfterSpawningProcess: false),
343+
output: .fileDescriptor(writeEnd, closeAfterSpawningProcess: true),
346344
error: .combineWithOutput
347345
)
348346

349-
try writeEnd.close()
350-
351347
taskResult = PipelineTaskResult.success(
352348
0,
353349
SendableCollectedResult(
@@ -471,12 +467,10 @@ extension PipeConfiguration {
471467
let originalResult = try await Subprocess.run(
472468
configuration,
473469
input: .fileDescriptor(readEnd, closeAfterSpawningProcess: true),
474-
output: .fileDescriptor(writeEnd, closeAfterSpawningProcess: false),
470+
output: .fileDescriptor(writeEnd, closeAfterSpawningProcess: true),
475471
error: .combineWithOutput
476472
)
477473

478-
try writeEnd.close()
479-
480474
taskResult = PipelineTaskResult.success(
481475
i,
482476
SendableCollectedResult(

Tests/SubprocessTests/PipeConfigurationTests.swift

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ func pipe(
3030
return [PipeStage(configuration: configurable.configuration, options: options)]
3131
}
3232

33+
extension [PipeStage] {
34+
func stage(
35+
_ configurable: any Configurable,
36+
options: ProcessStageOptions = .default
37+
) -> [PipeStage] {
38+
return self.stage(configurable.configuration, options: options)
39+
}
40+
}
41+
3342
/// Pipe operator for stage arrays with Configuration
3443
func | (
3544
left: [PipeStage],
@@ -237,6 +246,8 @@ struct PipeConfigurationTests {
237246
@Test func testBasicPipeConfiguration() async throws {
238247
let config = pipe(
239248
Echo("Hello World")
249+
).stage(
250+
Cat()
240251
).finally(
241252
output: .string(limit: .max),
242253
error: .discarded
@@ -342,7 +353,7 @@ struct PipeConfigurationTests {
342353
let processConfig =
343354
pipe(
344355
Echo("Test Message")
345-
) |> .string(limit: .max)
356+
) | Cat() |> .string(limit: .max)
346357

347358
let result = try await processConfig.run()
348359
#expect(result.standardOutput?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) == "Test Message")
@@ -868,19 +879,19 @@ struct PipeConfigurationTests {
868879
.name("powershell.exe"),
869880
arguments: Arguments(["-Command", "'shell stdout'; [Console]::Error.WriteLine('shell stderr')"]),
870881
options: .mergeErrors
871-
) |> (
882+
) | Grep("shell") |> (
872883
output: .string(limit: .max),
873-
error: .string(limit: .max)
884+
error: .discarded
874885
)
875886
#else
876887
let config =
877888
pipe(
878889
.name("sh"),
879890
arguments: ["-c", "echo 'shell stdout'; echo 'shell stderr' >&2"],
880891
options: .mergeErrors
881-
) |> (
892+
) | Grep("shell") |> (
882893
output: .string(limit: .max),
883-
error: .string(limit: .max)
894+
error: .discarded
884895
)
885896
#endif
886897

0 commit comments

Comments
 (0)