watchexec_supervisor/command/
conversions.rs

1use std::fmt;
2
3use process_wrap::tokio::{KillOnDrop, TokioCommandWrap};
4use tokio::process::Command as TokioCommand;
5use tracing::trace;
6
7use super::{Command, Program, SpawnOptions};
8
9impl Command {
10	/// Obtain a [`process_wrap::tokio::TokioCommandWrap`].
11	pub fn to_spawnable(&self) -> TokioCommandWrap {
12		trace!(program=?self.program, "constructing command");
13
14		let cmd = match &self.program {
15			Program::Exec { prog, args, .. } => {
16				let mut c = TokioCommand::new(prog);
17				c.args(args);
18				c
19			}
20
21			Program::Shell {
22				shell,
23				args,
24				command,
25			} => {
26				let mut c = TokioCommand::new(shell.prog.clone());
27
28				// Avoid quoting issues on Windows by using raw_arg everywhere
29				#[cfg(windows)]
30				{
31					for opt in &shell.options {
32						c.raw_arg(opt);
33					}
34					if let Some(progopt) = &shell.program_option {
35						c.raw_arg(progopt);
36					}
37					c.raw_arg(command);
38					for arg in args {
39						c.raw_arg(arg);
40					}
41				}
42
43				#[cfg(not(windows))]
44				{
45					c.args(shell.options.clone());
46					if let Some(progopt) = &shell.program_option {
47						c.arg(progopt);
48					}
49					c.arg(command);
50					for arg in args {
51						c.arg(arg);
52					}
53				}
54
55				c
56			}
57		};
58
59		let mut cmd = TokioCommandWrap::from(cmd);
60		cmd.wrap(KillOnDrop);
61
62		match self.options {
63			#[cfg(unix)]
64			SpawnOptions { session: true, .. } => {
65				cmd.wrap(process_wrap::tokio::ProcessSession);
66			}
67			#[cfg(unix)]
68			SpawnOptions { grouped: true, .. } => {
69				cmd.wrap(process_wrap::tokio::ProcessGroup::leader());
70			}
71			#[cfg(windows)]
72			SpawnOptions { grouped: true, .. } | SpawnOptions { session: true, .. } => {
73				cmd.wrap(process_wrap::tokio::JobObject);
74			}
75			_ => {}
76		}
77
78		#[cfg(unix)]
79		if self.options.reset_sigmask {
80			cmd.wrap(process_wrap::tokio::ResetSigmask);
81		}
82
83		cmd
84	}
85}
86
87impl fmt::Display for Program {
88	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89		match self {
90			Self::Exec { prog, args, .. } => {
91				write!(f, "{}", prog.display())?;
92				for arg in args {
93					write!(f, " {arg}")?;
94				}
95
96				Ok(())
97			}
98			Self::Shell { command, .. } => {
99				write!(f, "{command}")
100			}
101		}
102	}
103}
104
105impl fmt::Display for Command {
106	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107		write!(f, "{}", self.program)
108	}
109}