use std::path::{Path, PathBuf};
use std::process::Command;
use kernel::{AxCode, AxError, Interpreter};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Shell {
Absent,
Missing { asked: Interpreter },
Found {
program: PathBuf,
interpreter: Interpreter,
},
}
impl Shell {
pub(super) fn command(&self, text: &str) -> Result<(Command, String), AxError> {
match self {
Shell::Absent => Err(AxError::failure(
AxCode::ToolUnavailable,
"run shell",
"no shell interpreter was found",
)
.with_recovery("use the program arm with an explicit executable")),
Shell::Missing { asked } => Err(missing(*asked)),
Shell::Found {
program,
interpreter,
} => {
let mut command = Command::new(program);
command.args(flags(*interpreter)).arg(text);
Ok((command, interpreter_name(program)))
}
}
}
pub(super) fn statement(&self) -> String {
match self {
Shell::Absent | Shell::Missing { .. } => String::new(),
Shell::Found { program, .. } => {
format!(" A shell line runs under {}.", interpreter_name(program))
}
}
}
}
fn flags(interpreter: Interpreter) -> &'static [&'static str] {
match interpreter {
Interpreter::System if cfg!(windows) => &["/C"],
Interpreter::System => &["-c"],
Interpreter::Pwsh => &["-NoLogo", "-NoProfile", "-NonInteractive", "-Command"],
}
}
fn missing(asked: Interpreter) -> AxError {
match asked {
Interpreter::System => AxError::failure(
AxCode::ToolUnavailable,
"run shell",
"this machine's own shell is missing or does not start",
)
.with_recovery(
"use the program arm with an explicit executable; `sprawling doctor` names what is \
wrong with the shell",
),
Interpreter::Pwsh => AxError::failure(
AxCode::ToolUnavailable,
"run shell",
"this building runs shell lines under PowerShell 7 (pwsh), and this machine has no \
pwsh 7 on its search path",
)
.with_recovery(
"install PowerShell 7, or set `[sandbox] interpreter = \"system\"` in this building's \
CONFIG.toml",
),
}
}
pub(super) fn interpreter_name(program: &Path) -> String {
program
.file_stem()
.unwrap_or(program.as_os_str())
.to_string_lossy()
.to_lowercase()
}