3
3
// For the full copyright and license information, please view the LICENSE
4
4
// file that was distributed with this source code.
5
5
6
- //spell-checker: ignore (linux) rlimit prlimit coreutil ggroups uchild uncaptured scmd SHLVL canonicalized
6
+ //spell-checker: ignore (linux) rlimit prlimit coreutil ggroups uchild uncaptured scmd SHLVL canonicalized openpty
7
7
8
8
#![ allow( dead_code) ]
9
9
@@ -38,7 +38,7 @@ use std::rc::Rc;
38
38
use std:: sync:: mpsc:: { self , RecvTimeoutError } ;
39
39
use std:: thread:: { sleep, JoinHandle } ;
40
40
use std:: time:: { Duration , Instant } ;
41
- use std:: { env, hint, thread , mem } ;
41
+ use std:: { env, hint, mem , thread } ;
42
42
use tempfile:: { Builder , TempDir } ;
43
43
44
44
static TESTS_DIR : & str = "tests" ;
@@ -1429,6 +1429,32 @@ impl UCommand {
1429
1429
}
1430
1430
}
1431
1431
1432
+ fn spawn_reader_thread (
1433
+ & self ,
1434
+ captured_output : Option < CapturedOutput > ,
1435
+ pty_fd_master : OwnedFd ,
1436
+ name : String ,
1437
+ ) -> Option < CapturedOutput > {
1438
+ if let Some ( mut captured_output_i) = captured_output {
1439
+ let fd = captured_output_i. try_clone ( ) . unwrap ( ) ;
1440
+
1441
+ let handle = std:: thread:: Builder :: new ( )
1442
+ . name ( name)
1443
+ . spawn ( move || {
1444
+ let mut buffer_out = String :: default ( ) ;
1445
+ Self :: read_string_from_pty ( pty_fd_master, & mut buffer_out) ;
1446
+ let mut out = std:: fs:: File :: from ( fd) ;
1447
+ out. write_all ( buffer_out. as_bytes ( ) ) . unwrap ( ) ;
1448
+ } )
1449
+ . unwrap ( ) ;
1450
+
1451
+ captured_output_i. reader_thread_handle = Some ( handle) ;
1452
+ Some ( captured_output_i)
1453
+ } else {
1454
+ None
1455
+ }
1456
+ }
1457
+
1432
1458
/// Build the `std::process::Command` and apply the defaults on fields which were not specified
1433
1459
/// by the user.
1434
1460
///
@@ -1448,7 +1474,14 @@ impl UCommand {
1448
1474
/// * `stderr_to_stdout`: `false`
1449
1475
/// * `bytes_into_stdin`: `None`
1450
1476
/// * `limits`: `None`.
1451
- fn build ( & mut self ) -> ( Command , Option < CapturedOutput > , Option < CapturedOutput > , Option < OwnedFd > ) {
1477
+ fn build (
1478
+ & mut self ,
1479
+ ) -> (
1480
+ Command ,
1481
+ Option < CapturedOutput > ,
1482
+ Option < CapturedOutput > ,
1483
+ Option < OwnedFd > ,
1484
+ ) {
1452
1485
if self . bin_path . is_some ( ) {
1453
1486
if let Some ( util_name) = & self . util_name {
1454
1487
self . args . push_front ( util_name. into ( ) ) ;
@@ -1562,7 +1595,6 @@ impl UCommand {
1562
1595
} ;
1563
1596
1564
1597
if self . terminal_simulation {
1565
-
1566
1598
let terminal_size = libc:: winsize {
1567
1599
ws_col : 80 ,
1568
1600
ws_row : 30 ,
@@ -1585,41 +1617,12 @@ impl UCommand {
1585
1617
1586
1618
stdin_pty = Some ( pi_master) ;
1587
1619
1588
- if let Some ( mut captured_stdout_i) = captured_stdout {
1589
- let fd = captured_stdout_i. try_clone ( ) . unwrap ( ) ;
1590
-
1591
- std:: thread:: Builder :: new ( )
1592
- . name ( "fwd_stdout" . to_string ( ) )
1593
- . spawn ( move ||{
1594
- let mut buffer_out = String :: default ( ) ;
1595
- Self :: read_string_from_pty ( po_master, & mut buffer_out) ;
1596
- let mut out = std:: fs:: File :: from ( fd) ;
1597
- out. write_all ( buffer_out. as_bytes ( ) ) . unwrap ( ) ;
1598
- //std::mem::forget(_pi_master); // _pi_master needs to be kept alive otherwise stdin.is_terminal() fails
1599
- } ) . unwrap ( ) ;
1600
-
1601
- captured_stdout = Some ( captured_stdout_i) ;
1602
- }
1603
-
1604
- if let Some ( mut captured_stderr_i) = captured_stderr {
1605
- let fd = captured_stderr_i. try_clone ( ) . unwrap ( ) ;
1606
-
1607
- std:: thread:: Builder :: new ( )
1608
- . name ( "fwd_stderr" . to_string ( ) )
1609
- . spawn ( move ||{
1610
- let mut buffer_out = String :: default ( ) ;
1611
- Self :: read_string_from_pty ( pe_master, & mut buffer_out) ;
1612
- let mut out = std:: fs:: File :: from ( fd) ;
1613
- out. write_all ( buffer_out. as_bytes ( ) ) . unwrap ( ) ;
1614
- } ) . unwrap ( ) ;
1615
-
1616
- captured_stderr = Some ( captured_stderr_i) ;
1617
- }
1620
+ captured_stdout =
1621
+ self . spawn_reader_thread ( captured_stdout, po_master, "stdout_reader" . to_string ( ) ) ;
1622
+ captured_stderr =
1623
+ self . spawn_reader_thread ( captured_stderr, pe_master, "stderr_reader" . to_string ( ) ) ;
1618
1624
1619
- command
1620
- . stdin ( pi_slave)
1621
- . stdout ( po_slave)
1622
- . stderr ( pe_slave) ;
1625
+ command. stdin ( pi_slave) . stdout ( po_slave) . stderr ( pe_slave) ;
1623
1626
}
1624
1627
1625
1628
( command, captured_stdout, captured_stderr, stdin_pty)
@@ -1631,10 +1634,7 @@ impl UCommand {
1631
1634
assert ! ( !self . has_run, "{}" , ALREADY_RUN ) ;
1632
1635
self . has_run = true ;
1633
1636
1634
- let ( mut command,
1635
- captured_stdout,
1636
- captured_stderr,
1637
- stdin_pty) = self . build ( ) ;
1637
+ let ( mut command, captured_stdout, captured_stderr, stdin_pty) = self . build ( ) ;
1638
1638
log_info ( "run" , self . to_string ( ) ) ;
1639
1639
1640
1640
let child = command. spawn ( ) . unwrap ( ) ;
@@ -1715,6 +1715,7 @@ impl std::fmt::Display for UCommand {
1715
1715
struct CapturedOutput {
1716
1716
current_file : File ,
1717
1717
output : tempfile:: NamedTempFile , // drop last
1718
+ reader_thread_handle : Option < thread:: JoinHandle < ( ) > > ,
1718
1719
}
1719
1720
1720
1721
impl CapturedOutput {
@@ -1723,6 +1724,7 @@ impl CapturedOutput {
1723
1724
Self {
1724
1725
current_file : output. reopen ( ) . unwrap ( ) ,
1725
1726
output,
1727
+ reader_thread_handle : None ,
1726
1728
}
1727
1729
}
1728
1730
@@ -1799,6 +1801,7 @@ impl Default for CapturedOutput {
1799
1801
Self {
1800
1802
current_file : file. reopen ( ) . unwrap ( ) ,
1801
1803
output : file,
1804
+ reader_thread_handle : None ,
1802
1805
}
1803
1806
}
1804
1807
}
@@ -1946,7 +1949,7 @@ impl UChild {
1946
1949
child : Child ,
1947
1950
captured_stdout : Option < CapturedOutput > ,
1948
1951
captured_stderr : Option < CapturedOutput > ,
1949
- stdin_pty : Option < OwnedFd >
1952
+ stdin_pty : Option < OwnedFd > ,
1950
1953
) -> Self {
1951
1954
Self {
1952
1955
raw : child,
@@ -2095,7 +2098,6 @@ impl UChild {
2095
2098
/// error.
2096
2099
#[ deprecated = "Please use wait() -> io::Result<CmdResult> instead." ]
2097
2100
pub fn wait_with_output ( mut self ) -> io:: Result < Output > {
2098
-
2099
2101
// some apps do not stop execution until their stdin gets closed.
2100
2102
// to prevent a endless waiting here, we close the stdin.
2101
2103
self . join ( ) ; // ensure that all pending async input is piped in
@@ -2107,7 +2109,8 @@ impl UChild {
2107
2109
let ( sender, receiver) = mpsc:: channel ( ) ;
2108
2110
let handle = thread:: Builder :: new ( )
2109
2111
. name ( "wait_with_output" . to_string ( ) )
2110
- . spawn ( move || sender. send ( child. wait_with_output ( ) ) ) . unwrap ( ) ;
2112
+ . spawn ( move || sender. send ( child. wait_with_output ( ) ) )
2113
+ . unwrap ( ) ;
2111
2114
2112
2115
match receiver. recv_timeout ( timeout) {
2113
2116
Ok ( result) => {
@@ -2139,9 +2142,17 @@ impl UChild {
2139
2142
} ;
2140
2143
2141
2144
if let Some ( stdout) = self . captured_stdout . as_mut ( ) {
2145
+ stdout
2146
+ . reader_thread_handle
2147
+ . take ( )
2148
+ . map ( |handle| handle. join ( ) . unwrap ( ) ) ;
2142
2149
output. stdout = stdout. output_bytes ( ) ;
2143
2150
}
2144
2151
if let Some ( stderr) = self . captured_stderr . as_mut ( ) {
2152
+ stderr
2153
+ . reader_thread_handle
2154
+ . take ( )
2155
+ . map ( |handle| handle. join ( ) . unwrap ( ) ) ;
2145
2156
output. stderr = stderr. output_bytes ( ) ;
2146
2157
}
2147
2158
@@ -2346,7 +2357,6 @@ impl UChild {
2346
2357
///
2347
2358
/// [`JoinHandle`]: std::thread::JoinHandle
2348
2359
pub fn pipe_in < T : Into < Vec < u8 > > > ( & mut self , content : T ) -> & mut Self {
2349
-
2350
2360
let ignore_stdin_write_error = self . ignore_stdin_write_error ;
2351
2361
let mut content: Vec < u8 > = content. into ( ) ;
2352
2362
if self . stdin_pty . is_some ( ) {
@@ -2369,7 +2379,8 @@ impl UChild {
2369
2379
Ok ( ( ) ) | Err ( _) => Ok ( ( ) ) ,
2370
2380
} ;
2371
2381
result
2372
- } ) . unwrap ( ) ;
2382
+ } )
2383
+ . unwrap ( ) ;
2373
2384
2374
2385
self . join_handle = Some ( join_handle) ;
2375
2386
self
0 commit comments