use {
super::{
ShellInstall,
util,
},
crate::{
conf,
errors::*,
},
directories::UserDirs,
std::{
fs,
path::PathBuf,
process::Command,
},
termimad::mad_print_inline,
};
const NAME: &str = "powershell";
const VERSION: &str = "1";
const PS_FUNC: &str = r#"
# https://github.com/Canop/broot/issues/460#issuecomment-1303005689
Function br {
$args = $args -join ' '
$cmd_file = New-TemporaryFile
try {
$process = Start-Process -FilePath 'broot.exe' `
-ArgumentList "--outcmd $($cmd_file.FullName) $args" `
-NoNewWindow -PassThru -WorkingDirectory $PWD
Wait-Process -InputObject $process #Faster than Start-Process -Wait
If ($process.ExitCode -eq 0) {
$cmd = Get-Content $cmd_file
If ($cmd -ne $null) { Invoke-Expression -Command $cmd }
} Else {
Write-Host "`n" # Newline to tidy up broot unexpected termination
Write-Error "broot.exe exited with error code $($process.ExitCode)"
}
} finally {
Remove-Item $cmd_file
}
}
"#;
pub fn get_script() -> &'static str {
PS_FUNC
}
fn get_link_path() -> PathBuf {
conf::dir().join("launcher").join(NAME).join("br.ps1")
}
fn get_script_path() -> PathBuf {
conf::app_dirs()
.data_dir()
.join("launcher")
.join(NAME)
.join(VERSION)
}
fn get_profile(exe: &str) -> Option<PathBuf> {
let output = Command::new(exe)
.args(["-NoProfile", "-NoLogo", "-Command", "Write-Output", "$profile"])
.output()
.ok()?;
if !output.status.success() {
return None;
}
let s = String::from_utf8_lossy(&output.stdout).trim().to_string();
if s.is_empty() {
None
} else {
Some(PathBuf::from(s))
}
}
#[allow(unreachable_code, unused_variables)]
pub fn install(si: &mut ShellInstall) -> Result<(), ShellInstallError> {
info!("install {NAME}");
#[cfg(unix)]
{
debug!("Shell install not supported for PowerShell on unix-based systems.");
return Ok(());
}
let Some(user_dir) = UserDirs::new() else {
warn!("Could not find user directory.");
return Ok(());
};
let Some(document_dir) = user_dir.document_dir() else {
warn!("Could not find user documents directory.");
return Ok(());
};
let script_path = get_script_path();
si.write_script(&script_path, PS_FUNC)?;
let link_path = get_link_path();
si.create_link(&link_path, &script_path)?;
let escaped_path = link_path.to_string_lossy().replace('\'', "''");
let source_line = format!(". '{}'", escaped_path);
let sourcing_path = get_profile("pwsh")
.or_else(|| get_profile("powershell"))
.unwrap_or_else(|| document_dir.join("WindowsPowerShell").join("Microsoft.PowerShell_profile.ps1"));
if !sourcing_path.exists() {
debug!("Creating missing PowerShell profile file.");
if let Some(parent) = sourcing_path.parent() {
fs::create_dir_all(parent).context(&|| format!("creating {parent:?} directory"))?;
}
fs::File::create(&sourcing_path).context(&|| format!("creating {sourcing_path:?}"))?;
}
let sourcing_path_str = sourcing_path.to_string_lossy();
if util::file_contains_line(&sourcing_path, &source_line)? {
mad_print_inline!(
&si.skin,
"`$0` already patched, no change made.\n",
&sourcing_path_str,
);
} else {
util::append_to_file(&sourcing_path, format!("\n{source_line}\n"))?;
mad_print_inline!(&si.skin, "`$0` successfully patched.\n", &sourcing_path_str,);
}
si.done = true;
Ok(())
}