Line data Source code
1 : use anyhow::{ensure, Context, Result}; 2 : use std::{ 3 : ffi::{OsStr, OsString}, 4 : path::{Path, PathBuf}, 5 : process::{Command, Output}, 6 : }; 7 : 8 : #[allow(clippy::module_name_repetitions)] 9 : pub trait CommandExt { 10 : fn logged_output(&mut self, require_success: bool) -> Result<Output>; 11 : fn success(&mut self) -> Result<()>; 12 : } 13 : 14 : impl CommandExt for Command { 15 : #[cfg_attr(dylint_lib = "general", allow(non_local_effect_before_error_return))] 16 : #[cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))] 17 79 : fn logged_output(&mut self, require_success: bool) -> Result<Output> { 18 79 : log::debug!("{:?}", self.get_envs().collect::<Vec<_>>()); 19 79 : log::debug!("{:?}", self.get_current_dir()); 20 79 : log::debug!("{:?}", self); 21 : 22 : #[allow(clippy::disallowed_methods)] 23 79 : let output = self 24 79 : .output() 25 79 : .with_context(|| format!("Could not get output of `{self:?}`"))?; 26 : 27 79 : ensure!( 28 79 : !require_success || output.status.success(), 29 0 : "command failed: {:?}\nstdout: {:?}\nstderr: {:?}", 30 0 : self, 31 0 : std::str::from_utf8(&output.stdout).unwrap_or_default(), 32 0 : std::str::from_utf8(&output.stderr).unwrap_or_default() 33 : ); 34 : 35 79 : Ok(output) 36 79 : } 37 : 38 : // smoelius: Why not get the status by calling `self.output()`? Because we don't want stdout and 39 : // stderr to be captured. 40 : #[cfg_attr(dylint_lib = "general", allow(non_local_effect_before_error_return))] 41 : #[cfg_attr(dylint_lib = "overscoped_allow", allow(overscoped_allow))] 42 127 : fn success(&mut self) -> Result<()> { 43 127 : log::debug!("{:?}", self.get_envs().collect::<Vec<_>>()); 44 127 : log::debug!("{:?}", self.get_current_dir()); 45 127 : log::debug!("{:?}", self); 46 : 47 127 : let status = self 48 127 : .status() 49 127 : .with_context(|| format!("Could not get status of `{self:?}`"))?; 50 : 51 127 : ensure!(status.success(), "command failed: {:?}", self); 52 : 53 124 : Ok(()) 54 127 : } 55 : } 56 : 57 : #[allow(unused_variables)] 58 32 : pub fn driver(toolchain: &str, driver: &Path) -> Result<Command> { 59 32 : #[allow(unused_mut)] 60 32 : let mut command = Command::new(driver); 61 32 : #[cfg(windows)] 62 32 : { 63 32 : // MinerSebas: To succesfully determine the dylint driver Version on Windows, 64 32 : // it is neccesary to add some Libraries to the Path. 65 32 : let new_path = prepend_toolchain_path(toolchain)?; 66 32 : command.envs(vec![(crate::env::PATH, new_path)]); 67 32 : } 68 32 : Ok(command) 69 32 : } 70 : 71 0 : pub fn prepend_toolchain_path(toolchain: impl AsRef<Path>) -> Result<OsString> { 72 0 : let rustup_home = crate::env::var(crate::env::RUSTUP_HOME)?; 73 0 : prepend_path( 74 0 : Path::new(&rustup_home) 75 0 : .join("toolchains") 76 0 : .join(toolchain) 77 0 : .join("bin"), 78 0 : ) 79 0 : } 80 : 81 0 : pub fn prepend_path(path: impl AsRef<OsStr>) -> Result<OsString> { 82 0 : let old_path = crate::env::var(crate::env::PATH)?; 83 0 : let new_path = std::env::join_paths( 84 0 : std::iter::once(PathBuf::from(path.as_ref())).chain(std::env::split_paths(&old_path)), 85 0 : )?; 86 0 : Ok(new_path) 87 0 : }