use super::{TestRepo, wt_bin, wt_command};
pub fn shell_binary(shell: &str) -> &str {
match shell {
"nushell" => "nu",
"powershell" => "pwsh",
"oil" => "osh",
_ => shell,
}
}
pub fn execute_shell_script(repo: &TestRepo, shell: &str, script: &str) -> String {
use portable_pty::CommandBuilder;
use std::io::Read;
let pair = super::open_pty();
let mut cmd = CommandBuilder::new(shell_binary(shell));
cmd.env_clear();
cmd.env("HOME", repo.home_path().to_string_lossy().to_string());
#[cfg(windows)]
cmd.env(
"USERPROFILE",
repo.home_path().to_string_lossy().to_string(),
);
#[cfg(unix)]
let default_path = "/usr/bin:/bin";
#[cfg(windows)]
let default_path = std::env::var("PATH").unwrap_or_default();
cmd.env(
"PATH",
std::env::var("PATH").unwrap_or_else(|_| default_path.to_string()),
);
cmd.env("USER", "testuser");
cmd.env("SHELL", shell_binary(shell));
for (key, value) in repo.test_env_vars() {
cmd.env(key, value);
}
match shell {
"bash" => {
cmd.arg("--noprofile");
cmd.arg("--norc");
}
"zsh" => {
cmd.arg("--no-globalrcs");
cmd.arg("-f");
}
"fish" => {
cmd.arg("--no-config");
}
"powershell" | "pwsh" => {
cmd.arg("-NoProfile");
}
"xonsh" => {
cmd.arg("--no-rc");
}
"nushell" | "nu" => {
cmd.arg("--no-config-file");
}
_ => {}
};
match shell {
"powershell" | "pwsh" => {
cmd.arg("-Command");
cmd.arg(script);
}
_ => {
cmd.arg("-c");
cmd.arg(script);
}
}
cmd.cwd(repo.root_path());
super::pass_coverage_env_to_pty_cmd(&mut cmd);
let mut child = pair.slave.spawn_command(cmd).unwrap();
drop(pair.slave);
let mut reader = pair.master.try_clone_reader().unwrap();
let mut buf = String::new();
reader.read_to_string(&mut buf).unwrap();
let status = child.wait().unwrap();
if !status.success() {
let exit_info = match status.exit_code() {
0 => "unknown error".to_string(),
code => format!("exit code {}", code),
};
panic!(
"Shell script failed ({}):\nshell: {}\noutput: {}",
exit_info, shell, buf
);
}
if buf.contains("command not found") || buf.contains("not defined") {
panic!(
"Shell integration error detected:\nshell: {}\noutput: {}",
shell, buf
);
}
buf.replace("\r\n", "\n")
}
pub fn generate_init_code(repo: &TestRepo, shell: &str) -> String {
let mut cmd = wt_command();
repo.configure_wt_cmd(&mut cmd);
let output = cmd
.args(["config", "shell", "init", shell])
.current_dir(repo.root_path())
.output()
.unwrap();
let stdout = String::from_utf8(output.stdout).unwrap();
let stderr = String::from_utf8_lossy(&output.stderr);
if !output.status.success() && stdout.trim().is_empty() {
panic!("Failed to generate init code:\nstderr: {}", stderr);
}
if stderr.contains("command not found") || stderr.contains("not defined") {
panic!(
"Init code contains errors:\nstderr: {}\nGenerated code:\n{}",
stderr, stdout
);
}
stdout
}
pub fn path_export_syntax(shell: &str, bin_path: &str) -> String {
match shell {
"fish" => format!(r#"set -x PATH {} $PATH"#, bin_path),
"nushell" => format!(r#"$env.PATH = ($env.PATH | prepend "{}")"#, bin_path),
"powershell" => format!(r#"$env:PATH = "{};$env:PATH""#, bin_path),
"elvish" => format!(r#"set E:PATH = {}:$E:PATH"#, bin_path),
"xonsh" => format!(r#"$PATH.insert(0, "{}")"#, bin_path),
_ => format!(r#"export PATH="{}:$PATH""#, bin_path),
}
}
pub fn wt_bin_dir() -> String {
wt_bin().parent().unwrap().to_string_lossy().to_string()
}