Run the command with optional stdin buffer, returning an error if the command does not exit successfully.
(self, stdin: Option<&[u8]>)
| 122 | |
| 123 | /// Run the command with optional stdin buffer, returning an error if the command does not exit successfully. |
| 124 | pub(crate) fn run_with_stdin_buf(self, stdin: Option<&[u8]>) -> Result<()> { |
| 125 | self.pre_run_output(); |
| 126 | let description = self.description; |
| 127 | let mut cmd = self.cmd; |
| 128 | let mut output = None; |
| 129 | if self.quiet_output { |
| 130 | let tmpf = tempfile::tempfile()?; |
| 131 | cmd.stdout(Stdio::from(tmpf.try_clone()?)); |
| 132 | cmd.stderr(Stdio::from(tmpf.try_clone()?)); |
| 133 | output = Some(tmpf); |
| 134 | } |
| 135 | tracing::debug!("exec: {cmd:?}"); |
| 136 | let st = if let Some(stdin_value) = stdin { |
| 137 | cmd.stdin(Stdio::piped()); |
| 138 | let mut child = cmd.spawn()?; |
| 139 | // SAFETY: We used piped for stdin |
| 140 | let mut stdin = child.stdin.take().unwrap(); |
| 141 | // If this was async, we could avoid spawning a thread here |
| 142 | std::thread::scope(|s| { |
| 143 | s.spawn(move || stdin.write_all(stdin_value)) |
| 144 | .join() |
| 145 | .map_err(|e| anyhow::anyhow!("Failed to spawn thread: {e:?}"))? |
| 146 | .context("Failed to write to cryptsetup stdin") |
| 147 | })?; |
| 148 | child.wait()? |
| 149 | } else { |
| 150 | cmd.status()? |
| 151 | }; |
| 152 | tracing::trace!("{st:?}"); |
| 153 | if !st.success() { |
| 154 | if let Some(mut output) = output { |
| 155 | output.seek(std::io::SeekFrom::Start(0))?; |
| 156 | let mut stderr = std::io::stderr().lock(); |
| 157 | std::io::copy(&mut output, &mut stderr)?; |
| 158 | } |
| 159 | anyhow::bail!("Task {description} failed: {st:?}"); |
| 160 | } |
| 161 | Ok(()) |
| 162 | } |
| 163 | |
| 164 | /// Like [`Task::run`], but return stdout. |
| 165 | pub(crate) fn read(self) -> Result<String> { |
no test coverage detected