nu_test_support/playground/
director.rs1use super::EnvironmentVariable;
2use super::nu_process::*;
3use std::ffi::OsString;
4use std::fmt;
5use std::fmt::Write;
6
7#[derive(Default, Debug)]
8pub struct Director {
9 pub cwd: Option<OsString>,
10 pub environment_vars: Vec<EnvironmentVariable>,
11 pub config: Option<OsString>,
12 pub pipeline: Option<Vec<String>>,
13 pub executable: Option<NuProcess>,
14}
15
16impl Director {
17 pub fn and_then(&mut self, commands: &str) -> &mut Self {
18 let commands = commands.to_string();
19
20 if let Some(ref mut pipeline) = self.pipeline {
21 pipeline.push(commands);
22 } else {
23 self.pipeline = Some(vec![commands]);
24 }
25
26 self
27 }
28
29 pub fn pipeline(&self, commands: &str) -> Self {
30 let mut director = Director {
31 pipeline: if commands.is_empty() {
32 None
33 } else {
34 Some(vec![commands.to_string()])
35 },
36 ..Default::default()
37 };
38
39 let mut process = NuProcess {
40 environment_vars: self.environment_vars.clone(),
41 ..Default::default()
42 };
43
44 if let Some(working_directory) = &self.cwd {
45 process.cwd(working_directory);
46 }
47
48 process.arg("--no-history");
49 if let Some(config_file) = self.config.as_ref() {
50 process.args(&[
51 "--config",
52 config_file.to_str().expect("failed to convert."),
53 ]);
54 }
55 process.args(&["--log-level", "info"]);
56
57 director.executable = Some(process);
58 director
59 }
60
61 pub fn executable(&self) -> Option<&NuProcess> {
62 if let Some(binary) = &self.executable {
63 Some(binary)
64 } else {
65 None
66 }
67 }
68}
69
70impl Executable for Director {
71 fn execute(&mut self) -> Result<Outcome, NuError> {
72 use std::process::Stdio;
73
74 match self.executable() {
75 Some(binary) => {
76 let mut commands = String::new();
77 if let Some(pipelines) = &self.pipeline {
78 for pipeline in pipelines {
79 if !commands.is_empty() {
80 commands.push_str("| ");
81 }
82 let _ = writeln!(commands, "{pipeline}");
83 }
84 }
85
86 let process = binary
87 .construct()
88 .stdout(Stdio::piped())
89 .stderr(Stdio::piped())
91 .arg("-c")
92 .arg(commands)
93 .spawn()
94 .expect("It should be possible to run tests");
95
96 process
97 .wait_with_output()
98 .map_err(|_| {
99 let reason = format!(
100 "could not execute process {} ({})",
101 binary, "No execution took place"
102 );
103
104 NuError {
105 desc: reason,
106 exit: None,
107 output: None,
108 }
109 })
110 .and_then(|process| {
111 let out =
112 Outcome::new(&read_std(&process.stdout), &read_std(&process.stderr));
113
114 match process.status.success() {
115 true => Ok(out),
116 false => Err(NuError {
117 desc: String::new(),
118 exit: Some(process.status),
119 output: Some(out),
120 }),
121 }
122 })
123 }
124 None => Err(NuError {
125 desc: String::from("err"),
126 exit: None,
127 output: None,
128 }),
129 }
130 }
131}
132
133impl fmt::Display for Director {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 write!(f, "director")
136 }
137}
138
139fn read_std(std: &[u8]) -> Vec<u8> {
140 let out = String::from_utf8_lossy(std);
141 let out = out.lines().collect::<Vec<_>>().join("\n");
142 let out = out.replace("\r\n", "");
143 out.replace('\n', "").into_bytes()
144}