mirror of
https://github.com/rust-lang/cargo
synced 2024-10-30 12:35:34 +00:00
Auto merge of #9586 - tmiasko:lines, r=alexcrichton
Avoid quadratic complexity when splitting output into lines When searching for newlines in a process output keep track which part of buffer was already examined to avoid processing the same data again and again.
This commit is contained in:
commit
9a3c162dc3
1 changed files with 33 additions and 26 deletions
|
@ -243,47 +243,54 @@ impl ProcessBuilder {
|
||||||
.stdin(Stdio::null());
|
.stdin(Stdio::null());
|
||||||
|
|
||||||
let mut callback_error = None;
|
let mut callback_error = None;
|
||||||
|
let mut stdout_pos = 0;
|
||||||
|
let mut stderr_pos = 0;
|
||||||
let status = (|| {
|
let status = (|| {
|
||||||
let mut child = cmd.spawn()?;
|
let mut child = cmd.spawn()?;
|
||||||
let out = child.stdout.take().unwrap();
|
let out = child.stdout.take().unwrap();
|
||||||
let err = child.stderr.take().unwrap();
|
let err = child.stderr.take().unwrap();
|
||||||
read2(out, err, &mut |is_out, data, eof| {
|
read2(out, err, &mut |is_out, data, eof| {
|
||||||
|
let pos = if is_out {
|
||||||
|
&mut stdout_pos
|
||||||
|
} else {
|
||||||
|
&mut stderr_pos
|
||||||
|
};
|
||||||
let idx = if eof {
|
let idx = if eof {
|
||||||
data.len()
|
data.len()
|
||||||
} else {
|
} else {
|
||||||
match data.iter().rposition(|b| *b == b'\n') {
|
match data[*pos..].iter().rposition(|b| *b == b'\n') {
|
||||||
Some(i) => i + 1,
|
Some(i) => *pos + i + 1,
|
||||||
None => return,
|
None => {
|
||||||
|
*pos = data.len();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
{
|
|
||||||
// scope for new_lines
|
let new_lines = &data[..idx];
|
||||||
let new_lines = if capture_output {
|
|
||||||
let dst = if is_out { &mut stdout } else { &mut stderr };
|
for line in String::from_utf8_lossy(new_lines).lines() {
|
||||||
let start = dst.len();
|
if callback_error.is_some() {
|
||||||
let data = data.drain(..idx);
|
break;
|
||||||
dst.extend(data);
|
}
|
||||||
&dst[start..]
|
let callback_result = if is_out {
|
||||||
|
on_stdout_line(line)
|
||||||
} else {
|
} else {
|
||||||
&data[..idx]
|
on_stderr_line(line)
|
||||||
};
|
};
|
||||||
for line in String::from_utf8_lossy(new_lines).lines() {
|
if let Err(e) = callback_result {
|
||||||
if callback_error.is_some() {
|
callback_error = Some(e);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
let callback_result = if is_out {
|
|
||||||
on_stdout_line(line)
|
|
||||||
} else {
|
|
||||||
on_stderr_line(line)
|
|
||||||
};
|
|
||||||
if let Err(e) = callback_result {
|
|
||||||
callback_error = Some(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !capture_output {
|
|
||||||
data.drain(..idx);
|
if capture_output {
|
||||||
|
let dst = if is_out { &mut stdout } else { &mut stderr };
|
||||||
|
dst.extend(new_lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.drain(..idx);
|
||||||
|
*pos = 0;
|
||||||
})?;
|
})?;
|
||||||
child.wait()
|
child.wait()
|
||||||
})()
|
})()
|
||||||
|
|
Loading…
Reference in a new issue