printable_shell_command/
command.rs

1use std::{ffi::OsStr, process::Command, str::Utf8Error};
2
3use crate::{
4    FormattingOptions, ShellPrintable, print_builder::PrintBuilder,
5    shell_printable::ShellPrintableWithOptions,
6};
7
8pub(crate) fn add_arg_from_command_lossy(print_builder: &mut PrintBuilder, arg: &OsStr) {
9    print_builder.add_single_arg(&arg.to_string_lossy());
10}
11
12pub(crate) fn add_arg_from_command(
13    print_builder: &mut PrintBuilder,
14    arg: &OsStr,
15) -> Result<(), Utf8Error> {
16    print_builder.add_single_arg(TryInto::<&str>::try_into(arg)?);
17    Ok(())
18}
19
20impl ShellPrintableWithOptions for Command {
21    fn printable_invocation_string_lossy_with_options(
22        &self,
23        formatting_options: FormattingOptions,
24    ) -> String {
25        let mut print_builder = PrintBuilder::new(formatting_options);
26        print_builder.add_program_name(&self.get_program().to_string_lossy());
27        for arg in self.get_args() {
28            add_arg_from_command_lossy(&mut print_builder, arg);
29        }
30        print_builder.get()
31    }
32
33    fn printable_invocation_string_with_options(
34        &self,
35        formatting_options: FormattingOptions,
36    ) -> Result<String, Utf8Error> {
37        let mut print_builder = PrintBuilder::new(formatting_options);
38        print_builder.add_program_name(TryInto::<&str>::try_into(self.get_program())?);
39        for arg in self.get_args() {
40            add_arg_from_command(&mut print_builder, arg)?;
41        }
42        Ok(print_builder.get())
43    }
44}
45
46impl ShellPrintable for Command {
47    fn printable_invocation_string(&self) -> Result<String, Utf8Error> {
48        self.printable_invocation_string_with_options(Default::default())
49    }
50
51    fn printable_invocation_string_lossy(&self) -> String {
52        self.printable_invocation_string_lossy_with_options(Default::default())
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use std::process::Command;
59
60    use crate::ShellPrintable;
61
62    #[test]
63    fn echo() -> Result<(), String> {
64        let mut command = Command::new("echo");
65        command.args(["#hi"]);
66        // Not printed by tests, but we can at least check this doesn't panic.
67        let _ = command.print_invocation();
68
69        assert_eq!(
70            command.printable_invocation_string().unwrap(),
71            "echo \\
72  '#hi'"
73        );
74        Ok(())
75    }
76}