|  | use super::env::{CommandEnv, CommandEnvs}; | 
|  | pub use crate::ffi::OsString as EnvKey; | 
|  | use crate::ffi::{OsStr, OsString}; | 
|  | use crate::num::NonZero; | 
|  | use crate::path::Path; | 
|  | use crate::process::StdioPipes; | 
|  | use crate::sys::fs::File; | 
|  | use crate::sys::pipe::AnonPipe; | 
|  | use crate::sys::unsupported; | 
|  | use crate::{fmt, io}; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  | // Command | 
|  | //////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | pub struct Command { | 
|  | program: OsString, | 
|  | args: Vec<OsString>, | 
|  | env: CommandEnv, | 
|  |  | 
|  | cwd: Option<OsString>, | 
|  | stdin: Option<Stdio>, | 
|  | stdout: Option<Stdio>, | 
|  | stderr: Option<Stdio>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug)] | 
|  | pub enum Stdio { | 
|  | Inherit, | 
|  | Null, | 
|  | MakePipe, | 
|  | ParentStdout, | 
|  | ParentStderr, | 
|  | #[allow(dead_code)] // This variant exists only for the Debug impl | 
|  | InheritFile(File), | 
|  | } | 
|  |  | 
|  | impl Command { | 
|  | pub fn new(program: &OsStr) -> Command { | 
|  | Command { | 
|  | program: program.to_owned(), | 
|  | args: vec![program.to_owned()], | 
|  | env: Default::default(), | 
|  | cwd: None, | 
|  | stdin: None, | 
|  | stdout: None, | 
|  | stderr: None, | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn arg(&mut self, arg: &OsStr) { | 
|  | self.args.push(arg.to_owned()); | 
|  | } | 
|  |  | 
|  | pub fn env_mut(&mut self) -> &mut CommandEnv { | 
|  | &mut self.env | 
|  | } | 
|  |  | 
|  | pub fn cwd(&mut self, dir: &OsStr) { | 
|  | self.cwd = Some(dir.to_owned()); | 
|  | } | 
|  |  | 
|  | pub fn stdin(&mut self, stdin: Stdio) { | 
|  | self.stdin = Some(stdin); | 
|  | } | 
|  |  | 
|  | pub fn stdout(&mut self, stdout: Stdio) { | 
|  | self.stdout = Some(stdout); | 
|  | } | 
|  |  | 
|  | pub fn stderr(&mut self, stderr: Stdio) { | 
|  | self.stderr = Some(stderr); | 
|  | } | 
|  |  | 
|  | pub fn get_program(&self) -> &OsStr { | 
|  | &self.program | 
|  | } | 
|  |  | 
|  | pub fn get_args(&self) -> CommandArgs<'_> { | 
|  | let mut iter = self.args.iter(); | 
|  | iter.next(); | 
|  | CommandArgs { iter } | 
|  | } | 
|  |  | 
|  | pub fn get_envs(&self) -> CommandEnvs<'_> { | 
|  | self.env.iter() | 
|  | } | 
|  |  | 
|  | pub fn get_current_dir(&self) -> Option<&Path> { | 
|  | self.cwd.as_ref().map(|cs| Path::new(cs)) | 
|  | } | 
|  |  | 
|  | pub fn spawn( | 
|  | &mut self, | 
|  | _default: Stdio, | 
|  | _needs_stdin: bool, | 
|  | ) -> io::Result<(Process, StdioPipes)> { | 
|  | unsupported() | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn output(_cmd: &mut Command) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> { | 
|  | unsupported() | 
|  | } | 
|  |  | 
|  | impl From<AnonPipe> for Stdio { | 
|  | fn from(pipe: AnonPipe) -> Stdio { | 
|  | pipe.diverge() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<io::Stdout> for Stdio { | 
|  | fn from(_: io::Stdout) -> Stdio { | 
|  | Stdio::ParentStdout | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<io::Stderr> for Stdio { | 
|  | fn from(_: io::Stderr) -> Stdio { | 
|  | Stdio::ParentStderr | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<File> for Stdio { | 
|  | fn from(file: File) -> Stdio { | 
|  | Stdio::InheritFile(file) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl fmt::Debug for Command { | 
|  | // show all attributes | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | if f.alternate() { | 
|  | let mut debug_command = f.debug_struct("Command"); | 
|  | debug_command.field("program", &self.program).field("args", &self.args); | 
|  | if !self.env.is_unchanged() { | 
|  | debug_command.field("env", &self.env); | 
|  | } | 
|  |  | 
|  | if self.cwd.is_some() { | 
|  | debug_command.field("cwd", &self.cwd); | 
|  | } | 
|  |  | 
|  | if self.stdin.is_some() { | 
|  | debug_command.field("stdin", &self.stdin); | 
|  | } | 
|  | if self.stdout.is_some() { | 
|  | debug_command.field("stdout", &self.stdout); | 
|  | } | 
|  | if self.stderr.is_some() { | 
|  | debug_command.field("stderr", &self.stderr); | 
|  | } | 
|  |  | 
|  | debug_command.finish() | 
|  | } else { | 
|  | if let Some(ref cwd) = self.cwd { | 
|  | write!(f, "cd {cwd:?} && ")?; | 
|  | } | 
|  | if self.env.does_clear() { | 
|  | write!(f, "env -i ")?; | 
|  | // Altered env vars will be printed next, that should exactly work as expected. | 
|  | } else { | 
|  | // Removed env vars need the command to be wrapped in `env`. | 
|  | let mut any_removed = false; | 
|  | for (key, value_opt) in self.get_envs() { | 
|  | if value_opt.is_none() { | 
|  | if !any_removed { | 
|  | write!(f, "env ")?; | 
|  | any_removed = true; | 
|  | } | 
|  | write!(f, "-u {} ", key.to_string_lossy())?; | 
|  | } | 
|  | } | 
|  | } | 
|  | // Altered env vars can just be added in front of the program. | 
|  | for (key, value_opt) in self.get_envs() { | 
|  | if let Some(value) = value_opt { | 
|  | write!(f, "{}={value:?} ", key.to_string_lossy())?; | 
|  | } | 
|  | } | 
|  | if self.program != self.args[0] { | 
|  | write!(f, "[{:?}] ", self.program)?; | 
|  | } | 
|  | write!(f, "{:?}", self.args[0])?; | 
|  |  | 
|  | for arg in &self.args[1..] { | 
|  | write!(f, " {:?}", arg)?; | 
|  | } | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] | 
|  | #[non_exhaustive] | 
|  | pub struct ExitStatus(); | 
|  |  | 
|  | impl ExitStatus { | 
|  | pub fn exit_ok(&self) -> Result<(), ExitStatusError> { | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | pub fn code(&self) -> Option<i32> { | 
|  | Some(0) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl fmt::Display for ExitStatus { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | write!(f, "<dummy exit status>") | 
|  | } | 
|  | } | 
|  |  | 
|  | pub struct ExitStatusError(!); | 
|  |  | 
|  | impl Clone for ExitStatusError { | 
|  | fn clone(&self) -> ExitStatusError { | 
|  | self.0 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Copy for ExitStatusError {} | 
|  |  | 
|  | impl PartialEq for ExitStatusError { | 
|  | fn eq(&self, _other: &ExitStatusError) -> bool { | 
|  | self.0 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Eq for ExitStatusError {} | 
|  |  | 
|  | impl fmt::Debug for ExitStatusError { | 
|  | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | self.0 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Into<ExitStatus> for ExitStatusError { | 
|  | fn into(self) -> ExitStatus { | 
|  | self.0 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl ExitStatusError { | 
|  | pub fn code(self) -> Option<NonZero<i32>> { | 
|  | self.0 | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | 
|  | pub struct ExitCode(u8); | 
|  |  | 
|  | impl ExitCode { | 
|  | pub const SUCCESS: ExitCode = ExitCode(0); | 
|  | pub const FAILURE: ExitCode = ExitCode(1); | 
|  |  | 
|  | pub fn as_i32(&self) -> i32 { | 
|  | self.0 as i32 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<u8> for ExitCode { | 
|  | fn from(code: u8) -> Self { | 
|  | Self(code) | 
|  | } | 
|  | } | 
|  |  | 
|  | pub struct Process(!); | 
|  |  | 
|  | impl Process { | 
|  | pub fn id(&self) -> u32 { | 
|  | self.0 | 
|  | } | 
|  |  | 
|  | pub fn kill(&mut self) -> io::Result<()> { | 
|  | self.0 | 
|  | } | 
|  |  | 
|  | pub fn wait(&mut self) -> io::Result<ExitStatus> { | 
|  | self.0 | 
|  | } | 
|  |  | 
|  | pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { | 
|  | self.0 | 
|  | } | 
|  | } | 
|  |  | 
|  | pub struct CommandArgs<'a> { | 
|  | iter: crate::slice::Iter<'a, OsString>, | 
|  | } | 
|  |  | 
|  | impl<'a> Iterator for CommandArgs<'a> { | 
|  | type Item = &'a OsStr; | 
|  | fn next(&mut self) -> Option<&'a OsStr> { | 
|  | self.iter.next().map(|os| &**os) | 
|  | } | 
|  | fn size_hint(&self) -> (usize, Option<usize>) { | 
|  | self.iter.size_hint() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<'a> ExactSizeIterator for CommandArgs<'a> { | 
|  | fn len(&self) -> usize { | 
|  | self.iter.len() | 
|  | } | 
|  | fn is_empty(&self) -> bool { | 
|  | self.iter.is_empty() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<'a> fmt::Debug for CommandArgs<'a> { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | f.debug_list().entries(self.iter.clone()).finish() | 
|  | } | 
|  | } |