@@ -5,29 +5,47 @@ pub use self::imp::read2;
55use std:: io;
66use std:: process:: { Child , Output } ;
77
8- pub fn read2_abbreviated ( mut child : Child ) -> io:: Result < Output > {
8+ pub fn read2_abbreviated ( mut child : Child , exclude_from_len : & [ String ] ) -> io:: Result < Output > {
99 use io:: Write ;
1010 use std:: mem:: replace;
1111
1212 const HEAD_LEN : usize = 160 * 1024 ;
1313 const TAIL_LEN : usize = 256 * 1024 ;
1414
1515 enum ProcOutput {
16- Full ( Vec < u8 > ) ,
16+ Full { bytes : Vec < u8 > , excluded_len : usize } ,
1717 Abbreviated { head : Vec < u8 > , skipped : usize , tail : Box < [ u8 ] > } ,
1818 }
1919
2020 impl ProcOutput {
21- fn extend ( & mut self , data : & [ u8 ] ) {
21+ fn extend ( & mut self , data : & [ u8 ] , exclude_from_len : & [ String ] ) {
2222 let new_self = match * self {
23- ProcOutput :: Full ( ref mut bytes) => {
23+ ProcOutput :: Full { ref mut bytes, ref mut excluded_len } => {
2424 bytes. extend_from_slice ( data) ;
25+
26+ // We had problems in the past with tests failing only in some environments,
27+ // due to the length of the base path pushing the output size over the limit.
28+ //
29+ // To make those failures deterministic across all environments we ignore known
30+ // paths when calculating the string length, while still including the full
31+ // path in the output. This could result in some output being larger than the
32+ // threshold, but it's better than having nondeterministic failures.
33+ for pattern in exclude_from_len {
34+ let pattern_bytes = pattern. as_bytes ( ) ;
35+ let matches = data
36+ . windows ( pattern_bytes. len ( ) )
37+ . filter ( |window| window == & pattern_bytes)
38+ . count ( ) ;
39+ * excluded_len += matches * pattern_bytes. len ( ) ;
40+ }
41+
2542 let new_len = bytes. len ( ) ;
26- if new_len <= HEAD_LEN + TAIL_LEN {
43+ if new_len. saturating_sub ( * excluded_len ) <= HEAD_LEN + TAIL_LEN {
2744 return ;
2845 }
29- let tail = bytes. split_off ( new_len - TAIL_LEN ) . into_boxed_slice ( ) ;
30- let head = replace ( bytes, Vec :: new ( ) ) ;
46+
47+ let mut head = replace ( bytes, Vec :: new ( ) ) ;
48+ let tail = head. split_off ( new_len - TAIL_LEN ) . into_boxed_slice ( ) ;
3149 let skipped = new_len - HEAD_LEN - TAIL_LEN ;
3250 ProcOutput :: Abbreviated { head, skipped, tail }
3351 }
@@ -47,7 +65,7 @@ pub fn read2_abbreviated(mut child: Child) -> io::Result<Output> {
4765
4866 fn into_bytes ( self ) -> Vec < u8 > {
4967 match self {
50- ProcOutput :: Full ( bytes) => bytes,
68+ ProcOutput :: Full { bytes, .. } => bytes,
5169 ProcOutput :: Abbreviated { mut head, skipped, tail } => {
5270 write ! ( & mut head, "\n \n <<<<<< SKIPPED {} BYTES >>>>>>\n \n " , skipped) . unwrap ( ) ;
5371 head. extend_from_slice ( & tail) ;
@@ -57,15 +75,15 @@ pub fn read2_abbreviated(mut child: Child) -> io::Result<Output> {
5775 }
5876 }
5977
60- let mut stdout = ProcOutput :: Full ( Vec :: new ( ) ) ;
61- let mut stderr = ProcOutput :: Full ( Vec :: new ( ) ) ;
78+ let mut stdout = ProcOutput :: Full { bytes : Vec :: new ( ) , excluded_len : 0 } ;
79+ let mut stderr = ProcOutput :: Full { bytes : Vec :: new ( ) , excluded_len : 0 } ;
6280
6381 drop ( child. stdin . take ( ) ) ;
6482 read2 (
6583 child. stdout . take ( ) . unwrap ( ) ,
6684 child. stderr . take ( ) . unwrap ( ) ,
6785 & mut |is_stdout, data, _| {
68- if is_stdout { & mut stdout } else { & mut stderr } . extend ( data) ;
86+ if is_stdout { & mut stdout } else { & mut stderr } . extend ( data, exclude_from_len ) ;
6987 data. clear ( ) ;
7088 } ,
7189 ) ?;
0 commit comments