-
Notifications
You must be signed in to change notification settings - Fork 28
Allow callers to run a subprocess and provide low and high water marks when using SequenceOutput to emit standard output and standard error as soon as it arrives. #40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 15 commits
7324ac4
7b6899c
9b173ab
ab43ae4
10aa523
aa903ad
bb57bf2
955e9c9
5f2df5f
4bac06a
ae0de61
d65f2ce
c8fe778
4de3d79
30876f5
ff7ae12
48b97f2
d94a9c6
888666b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -405,6 +405,7 @@ extension TrackedFileDescriptor { | |
} | ||
} | ||
) | ||
|
||
return .init(dispatchIO, closeWhenDone: self.closeWhenDone) | ||
} | ||
} | ||
|
@@ -414,37 +415,42 @@ extension DispatchIO { | |
#if SubprocessSpan | ||
@available(SubprocessSpan, *) | ||
#endif | ||
internal func readChunk(upToLength maxLength: Int) async throws -> AsyncBufferSequence.Buffer? { | ||
return try await withCheckedThrowingContinuation { continuation in | ||
var buffer: DispatchData = .empty | ||
self.read( | ||
offset: 0, | ||
length: maxLength, | ||
queue: .global() | ||
) { done, data, error in | ||
if error != 0 { | ||
continuation.resume( | ||
throwing: SubprocessError( | ||
code: .init(.failedToReadFromSubprocess), | ||
underlyingError: .init(rawValue: error) | ||
) | ||
) | ||
return | ||
} | ||
if let data = data { | ||
if buffer.isEmpty { | ||
buffer = data | ||
} else { | ||
buffer.append(data) | ||
} | ||
} | ||
if done { | ||
if !buffer.isEmpty { | ||
continuation.resume(returning: AsyncBufferSequence.Buffer(data: buffer)) | ||
} else { | ||
continuation.resume(returning: nil) | ||
} | ||
} | ||
internal func readChunk(upToLength maxLength: Int, continuation: AsyncBufferSequence.Iterator.Stream.Continuation) { | ||
self.read( | ||
offset: 0, | ||
length: maxLength, | ||
queue: .global() | ||
) { done, data, error in | ||
if error != 0 { | ||
continuation.finish(throwing: SubprocessError( | ||
code: .init(.failedToReadFromSubprocess), | ||
underlyingError: .init(rawValue: error) | ||
)) | ||
return | ||
} | ||
|
||
// Treat empty data and nil as the same | ||
let buffer = data.map { $0.isEmpty ? nil : $0 } ?? nil | ||
let status: AsyncBufferSequence.StreamStatus | ||
|
||
switch (buffer, done) { | ||
case (.some(let data), false): | ||
status = .data(AsyncBufferSequence.Buffer(data: data)) | ||
|
||
case (.some(let data), true): | ||
status = .endOfChunk(AsyncBufferSequence.Buffer(data: data)) | ||
|
||
case (nil, false): | ||
fatalError("Unexpectedly received no data from DispatchIO with it indicating it is not done.") | ||
|
||
case (nil, true): | ||
status = .endOfFile | ||
} | ||
|
||
continuation.yield(status) | ||
|
||
if done { | ||
continuation.finish() | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of setting using a switch (buffer, done) {
case (.some(let data), false):
continuation.yield(AsyncBufferSequence.Buffer(data: data))
case (.some(let data), true):
continuation.yield(AsyncBufferSequence.Buffer(data: data))
continuation.finish() // Finish the stream now
case (nil, false):
fatalError("Unexpectedly received no data from DispatchIO with it indicating it is not done.")
case (nil, true):
continuation.finish() // Finish the stream
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @iCharlesHu Simplified this. |
||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
streamIterator
returnedAsyncThrowingStream<Buffer>
here you can just return it directly.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iCharlesHu Yes, simplified this.