You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Returns a the read end of a pipe that will stream everything from the stream reader.
37
+
38
+
The data will be read from the stream and sent along to the pipe.
39
+
At most `maxCacheSize` bytes will be kept in memory from the stream (assuming the stream does not have a bigger internal cache).
40
+
41
+
If at any point reading from the stream fails, an error is logged and the write end of the pipe is closed, effectively ending the data sent in the read end.
42
+
43
+
- Important: If the fd is sent to a subprocess, the fd must be closed after the subprocess is launched. */
Conf.logger?.error("Failed closing write end of fd for pipe to swift; pipe might stay open forever.", metadata:["errno":"\(errno)","errno-str":"\(Errno(rawValue: errno).localizedDescription)"])
try reader.peekData(size: reader.currentStreamReadPosition - reader.currentReadPosition, allowReadingLess:false,{ bytes in
62
+
let(writtenNow, readError)={
63
+
guard bytes.count >0else{
64
+
return(0,Int32(0))
65
+
}
66
+
67
+
varret:Int
68
+
repeat{
69
+
Conf.logger?.trace("Trying to write on write end of pipe.", metadata:["bytes_count":"\(bytes.count)"])
70
+
ret =Darwin.write(fh.fileDescriptor, bytes.baseAddress!, bytes.count)
71
+
}while ret ==-1 && errno == EINTR
72
+
return(ret, errno)
73
+
}()
74
+
75
+
if writtenNow >0{
76
+
do{try reader.readData(size: writtenNow, allowReadingLess:false,{ _ in /*nop: we only update the current read position.*/ })}
77
+
catch{Conf.logger?.critical("Invalid StreamReader (or internal logic error)! Reading from the stream failed but the data should already be in the buffer.")}
78
+
}elseif writtenNow <0{
79
+
if[EAGAIN, EWOULDBLOCK].contains(readError){
80
+
/* We ignore the write error and let the writeabilityHandler call us back (let’s hope it will!). */
81
+
Conf.logger?.debug("Failed write end of fd for pipe to swift with temporary error (EAGAIN or EWOULDBLOCK). We wait for the writeabilityHandler to be called again.", metadata:["errno":"\(readError)","errno-str":"\(Errno(rawValue: readError).localizedDescription)"])
82
+
}else{
83
+
Conf.logger?.error("Failed writing in fd for pipe. We close the stream now.", metadata:["errno":"\(readError)","errno-str":"\(Errno(rawValue: readError).localizedDescription)"])
84
+
closeFH()
85
+
}
86
+
}
87
+
88
+
if reader.streamHasReachedEOF, reader.currentReadPosition == reader.currentStreamReadPosition {
89
+
/* We have reached the end of the stream; let’s close the stream! */
90
+
Conf.logger?.trace("Closing write end of pipe fd.")
91
+
closeFH()
92
+
}
93
+
})
94
+
}catch{
95
+
Conf.logger?.error("Failed reading from the stream for writing to pipe. Bailing.", metadata:["error":"\(error)"])
Copy file name to clipboardExpand all lines: Sources/ProcessInvocation/ProcessInvocation.swift
+39-42Lines changed: 39 additions & 42 deletions
Original file line number
Diff line number
Diff line change
@@ -40,9 +40,9 @@ import CMacroExports
40
40
Some signals are forwarded by default.
41
41
42
42
IMHO the signal forwarding method, though a bit more complex (in this case, a lot of the complexity is hidden by this object),
43
-
is better than using the same PGID than the parent for the child.
43
+
is better than using the same PGID than the parent for the child.
44
44
In a shell, if a long running process is launched from a bash script, and said bash script is killed using a signal
45
-
(but from another process sending a signal, not from the tty), the child won’t be killed!
45
+
(but from another process sending a signal, not from the tty), the child won’t be killed!
46
46
Using signal forwarding, it will.
47
47
48
48
Some interesting links:
@@ -62,10 +62,10 @@ import CMacroExports
62
62
It is true on the `main` branch though (2021-04-01).
63
63
64
64
- Important: All of the `additionalOutputFileDescriptors` are closed when the end of their respective stream are reached
65
-
(i.e. the function takes “ownership” of the file descriptors).
65
+
(i.e. the function takes “ownership” of the file descriptors).
66
66
Maybe later we’ll add an option not to close at end of the stream.
67
67
Additionally on Linux the fds will be set non-blocking
68
-
(clients should not care as they have given up ownership of the fd, but it’s still good to know IMHO).
68
+
(clients should not care as they have given up ownership of the fd, but it’s still good to know IMHO).
69
69
70
70
- Important: AFAICT the absolute ref for `PATH` resolution is [from exec function in FreeBSD source](https://opensource.apple.com/source/Libc/Libc-1439.100.3/gen/FreeBSD/exec.c.auto.html) (end of file).
71
71
Sadly `Process` does not report the actual errors and seem to always report “File not found” errors when the executable cannot be run.
@@ -140,9 +140,9 @@ public struct ProcessInvocation : AsyncSequence {
fileDescriptorsToSend:[FileDescriptor /* Value in **child** */:FileDescriptor /* Value in **parent** */]=[:],
@@ -266,7 +266,7 @@ public struct ProcessInvocation : AsyncSequence {
266
266
self.workingDirectory = workingDirectory
267
267
self.environment = environment
268
268
269
-
self.stdin=stdin
269
+
self.stdinRedirect=stdinRedirect
270
270
self.stdoutRedirect = stdoutRedirect
271
271
self.stderrRedirect = stderrRedirect
272
272
@@ -391,8 +391,9 @@ public struct ProcessInvocation : AsyncSequence {
391
391
You retrieve the process and a dispatch group you can wait on to be notified when the process and all of its outputs are done.
392
392
You can also set the termination handler of the process, but you should wait on the dispatch group to be sure all of the outputs have finished streaming. */
0 commit comments