@@ -143,45 +143,46 @@ struct ReadStdoutFailOnError {
143
143
read : std:: process:: ChildStdout ,
144
144
}
145
145
146
+ impl ReadStdoutFailOnError {
147
+ fn swap_err_if_present_in_stderr ( & self , wanted : usize , res : std:: io:: Result < usize > ) -> std:: io:: Result < usize > {
148
+ match self . recv . try_recv ( ) . ok ( ) {
149
+ Some ( err) => Err ( err) ,
150
+ None => match res {
151
+ Ok ( n) if n == wanted => Ok ( n) ,
152
+ Ok ( n) => {
153
+ // TODO: fix this
154
+ // When parsing refs this seems to happen legitimately
155
+ // (even though we read packet lines only and should always know exactly how much to read)
156
+ // Maybe this still happens in `read_exact()` as sometimes we just don't get enough bytes
157
+ // despite knowing how many.
158
+ // To prevent deadlock, we have to set a timeout which slows down legitimate parts of the protocol.
159
+ // This code was specifically written to make the `cargo` test-suite pass, and we can reduce
160
+ // the timeouts even more once there is a native ssh transport that is used by `cargo`, it will
161
+ // be able to handle these properly.
162
+ // Alternatively, one could implement something like `read2` to avoid blocking on stderr entirely.
163
+ self . recv
164
+ . recv_timeout ( std:: time:: Duration :: from_millis ( 5 ) )
165
+ . ok ( )
166
+ . map_or ( Ok ( n) , Err )
167
+ }
168
+ Err ( err) => Err ( self . recv . recv ( ) . ok ( ) . unwrap_or ( err) ) ,
169
+ } ,
170
+ }
171
+ }
172
+ }
173
+
174
+ impl std:: io:: Read for ReadStdoutFailOnError {
175
+ fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
176
+ let res = self . read . read ( buf) ;
177
+ self . swap_err_if_present_in_stderr ( buf. len ( ) , res)
178
+ }
179
+ }
180
+
146
181
fn supervise_stderr (
147
182
ssh_kind : ssh:: ProgramKind ,
148
183
stderr : std:: process:: ChildStderr ,
149
184
stdout : std:: process:: ChildStdout ,
150
185
) -> ReadStdoutFailOnError {
151
- impl ReadStdoutFailOnError {
152
- fn swap_err_if_present_in_stderr ( & self , wanted : usize , res : std:: io:: Result < usize > ) -> std:: io:: Result < usize > {
153
- match self . recv . try_recv ( ) . ok ( ) {
154
- Some ( err) => Err ( err) ,
155
- None => match res {
156
- Ok ( n) if n == wanted => Ok ( n) ,
157
- Ok ( n) => {
158
- // TODO: fix this
159
- // When parsing refs this seems to happen legitimately
160
- // (even though we read packet lines only and should always know exactly how much to read)
161
- // Maybe this still happens in `read_exact()` as sometimes we just don't get enough bytes
162
- // despite knowing how many.
163
- // To prevent deadlock, we have to set a timeout which slows down legitimate parts of the protocol.
164
- // This code was specifically written to make the `cargo` test-suite pass, and we can reduce
165
- // the timeouts even more once there is a native ssh transport that is used by `cargo`, it will
166
- // be able to handle these properly.
167
- // Alternatively, one could implement something like `read2` to avoid blocking on stderr entirely.
168
- self . recv
169
- . recv_timeout ( std:: time:: Duration :: from_millis ( 5 ) )
170
- . ok ( )
171
- . map_or ( Ok ( n) , Err )
172
- }
173
- Err ( err) => Err ( self . recv . recv ( ) . ok ( ) . unwrap_or ( err) ) ,
174
- } ,
175
- }
176
- }
177
- }
178
- impl std:: io:: Read for ReadStdoutFailOnError {
179
- fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
180
- let res = self . read . read ( buf) ;
181
- self . swap_err_if_present_in_stderr ( buf. len ( ) , res)
182
- }
183
- }
184
-
185
186
let ( send, recv) = std:: sync:: mpsc:: sync_channel ( 1 ) ;
186
187
std:: thread:: Builder :: new ( )
187
188
. name ( "supervise ssh stderr" . into ( ) )
0 commit comments