Skip to content

Commit c2f1796

Browse files
committed
rename actions to ProcessActionsLines and remove unnecessary heap allocation
1 parent 62e52c3 commit c2f1796

File tree

4 files changed

+104
-74
lines changed

4 files changed

+104
-74
lines changed

src/cmd/actions.rs

Lines changed: 0 additions & 63 deletions
This file was deleted.

src/cmd/mod.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
//! Command execution and sandboxing.
22
3-
mod actions;
3+
mod process_lines_actions;
44
mod sandbox;
55

6-
pub use actions::Actions;
6+
pub use process_lines_actions::ProcessLinesActions;
77
pub use sandbox::*;
88

99
use crate::native;
1010
use crate::workspace::Workspace;
1111
use failure::{Error, Fail};
1212
use futures::{future, Future, Stream};
1313
use log::{error, info};
14+
use process_lines_actions::InnerState;
1415
use std::convert::AsRef;
1516
use std::env::consts::EXE_SUFFIX;
1617
use std::ffi::{OsStr, OsString};
@@ -127,7 +128,7 @@ pub struct Command<'w, 'pl> {
127128
binary: Binary,
128129
args: Vec<OsString>,
129130
env: Vec<(OsString, OsString)>,
130-
process_lines: Option<&'pl mut dyn FnMut(&str, &mut Actions)>,
131+
process_lines: Option<&'pl mut dyn FnMut(&str, &mut ProcessLinesActions)>,
131132
cd: Option<PathBuf>,
132133
timeout: Option<Duration>,
133134
no_output_timeout: Option<Duration>,
@@ -251,7 +252,7 @@ impl<'w, 'pl> Command<'w, 'pl> {
251252
/// # Ok(())
252253
/// # }
253254
/// ```
254-
pub fn process_lines(mut self, f: &'pl mut dyn FnMut(&str, &mut Actions)) -> Self {
255+
pub fn process_lines(mut self, f: &'pl mut dyn FnMut(&str, &mut ProcessLinesActions)) -> Self {
255256
self.process_lines = Some(f);
256257
self
257258
}
@@ -482,7 +483,7 @@ impl OutputKind {
482483

483484
fn log_command(
484485
mut cmd: StdCommand,
485-
mut process_lines: Option<&mut dyn FnMut(&str, &mut Actions)>,
486+
mut process_lines: Option<&mut dyn FnMut(&str, &mut ProcessLinesActions)>,
486487
capture: bool,
487488
timeout: Option<Duration>,
488489
no_output_timeout: Option<Duration>,
@@ -514,7 +515,7 @@ fn log_command(
514515
.map(|line| (OutputKind::Stderr, line));
515516

516517
let start = Instant::now();
517-
let mut actions = Actions::new();
518+
let mut actions = ProcessLinesActions::new();
518519

519520
let output = stdout
520521
.select(stderr)
@@ -536,11 +537,15 @@ fn log_command(
536537
return future::err(Error::from(CommandError::Timeout(timeout.as_secs())));
537538
}
538539

539-
actions.next_input(&line);
540540
if let Some(f) = &mut process_lines {
541541
f(&line, &mut actions);
542542
}
543-
let lines = actions.take_lines();
543+
// this is done here to avoid duplicating the output line
544+
let lines = match actions.take_lines() {
545+
InnerState::Removed => Vec::new(),
546+
InnerState::Original => vec![line],
547+
InnerState::Replaced(new_lines) => new_lines,
548+
};
544549

545550
if log_output {
546551
for line in &lines {

src/cmd/process_lines_actions.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use std::default::Default;
2+
3+
#[cfg_attr(test, derive(Debug, PartialEq))]
4+
pub(super) enum InnerState {
5+
Removed,
6+
Original,
7+
Replaced(Vec<String>),
8+
}
9+
10+
impl Default for InnerState {
11+
fn default() -> Self {
12+
InnerState::Original
13+
}
14+
}
15+
16+
/// Represents actions that are available while reading live output from a process.
17+
///
18+
/// This will be available inside the function you provide to [`Command::process_lines`](struct.Command.html#method.process_lines)
19+
pub struct ProcessLinesActions {
20+
state: InnerState,
21+
}
22+
23+
impl<'a> ProcessLinesActions {
24+
pub(super) fn new() -> Self {
25+
ProcessLinesActions {
26+
state: InnerState::default(),
27+
}
28+
}
29+
30+
pub(super) fn take_lines(&mut self) -> InnerState {
31+
std::mem::take(&mut self.state)
32+
}
33+
34+
/// Replace last read line from output with the lines provided.
35+
///
36+
/// The new lines will be logged instead of the original line.
37+
pub fn replace_with_lines(&mut self, new_lines: impl Iterator<Item = &'a str>) {
38+
self.state = InnerState::Replaced(new_lines.map(|str| str.to_string()).collect());
39+
}
40+
41+
/// Remove last read line from output.
42+
///
43+
/// This means that the line will not be logged.
44+
pub fn remove_line(&mut self) {
45+
self.state = InnerState::Removed;
46+
}
47+
}
48+
49+
#[cfg(test)]
50+
mod test {
51+
use super::InnerState;
52+
use super::ProcessLinesActions;
53+
#[test]
54+
fn test_replace() {
55+
let mut actions = ProcessLinesActions::new();
56+
57+
actions.replace_with_lines("ipsum".split("\n"));
58+
assert_eq!(
59+
actions.take_lines(),
60+
InnerState::Replaced(vec!["ipsum".to_string()])
61+
);
62+
63+
actions.replace_with_lines("lorem ipsum dolor".split(" "));
64+
assert_eq!(
65+
actions.take_lines(),
66+
InnerState::Replaced(vec![
67+
"lorem".to_string(),
68+
"ipsum".to_string(),
69+
"dolor".to_string()
70+
])
71+
);
72+
73+
// assert last input is discarded
74+
assert_eq!(actions.take_lines(), InnerState::Original);
75+
}
76+
77+
#[test]
78+
fn test_remove() {
79+
let mut actions = ProcessLinesActions::new();
80+
actions.remove_line();
81+
assert_eq!(actions.take_lines(), InnerState::Removed);
82+
}
83+
84+
#[test]
85+
fn test_no_actions() {
86+
let mut actions = ProcessLinesActions::new();
87+
assert_eq!(actions.take_lines(), InnerState::Original);
88+
}
89+
}

src/crates/git.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::CrateTrait;
2-
use crate::cmd::Actions;
3-
use crate::cmd::Command;
2+
use crate::cmd::{Command, ProcessLinesActions};
43
use crate::prepare::PrepareError;
54
use crate::Workspace;
65
use failure::{Error, ResultExt};
@@ -84,7 +83,7 @@ impl CrateTrait for GitRepo {
8483
// fata: credential helper '{path}' told us to quit
8584
//
8685
let mut private_repository = false;
87-
let mut detect_private_repositories = |line: &str, _actions: &mut Actions| {
86+
let mut detect_private_repositories = |line: &str, _actions: &mut ProcessLinesActions| {
8887
if line.starts_with("fatal: credential helper") && line.ends_with("told us to quit") {
8988
private_repository = true;
9089
}

0 commit comments

Comments
 (0)