212 lines
7.6 KiB
Rust
212 lines
7.6 KiB
Rust
use std::path::{Path, PathBuf};
|
|
use std::sync::LazyLock;
|
|
use std::{env, path};
|
|
|
|
use anyhow::{anyhow, Result};
|
|
use galaxyui::{AppContext, SingletonEntity};
|
|
|
|
use crate::system::SystemInfo;
|
|
use crate::util::path::{file_exists_and_is_executable, resolve_executable};
|
|
|
|
const KASPERSKY_PROCESS_NAME: &str = "avp";
|
|
const PWSH_EXE: &str = "pwsh.exe";
|
|
const POWERSHELL_EXE: &str = "powershell.exe";
|
|
const WSL_EXE: &str = "wsl.exe";
|
|
|
|
static POWERSHELL_7_PATH: LazyLock<Option<PathBuf>> = LazyLock::new(find_powershell_7_path);
|
|
static POWERSHELL_5_PATH: LazyLock<Option<PathBuf>> = LazyLock::new(find_powershell_5_path);
|
|
static WSL_PATH: LazyLock<Option<PathBuf>> = LazyLock::new(find_wsl_path);
|
|
|
|
/// Returns the location which Warp was installed to.
|
|
#[cfg(feature = "local_fs")]
|
|
pub fn install_dir() -> Result<path::PathBuf> {
|
|
let current_exe = env::current_exe()?;
|
|
current_exe
|
|
.parent()
|
|
.map(ToOwned::to_owned)
|
|
.ok_or(anyhow!("Unable to get install dir"))
|
|
}
|
|
|
|
/// Returns the path to the PowerShell 7 executable on the user's machine, if we
|
|
/// were able to find one.
|
|
pub fn powershell_7_path() -> Option<&'static PathBuf> {
|
|
POWERSHELL_7_PATH.as_ref()
|
|
}
|
|
|
|
/// Returns the path to the PowerShell 5 executable on the user's machine, if we
|
|
/// were able to find one.
|
|
pub fn powershell_5_path() -> Option<&'static PathBuf> {
|
|
POWERSHELL_5_PATH.as_ref()
|
|
}
|
|
|
|
/// Returns the path to the a PowerShell 7 or PowerShell 5 executable on the
|
|
/// user's machine, if we were able to find one. Prefers PowerShell 7.
|
|
pub fn any_powershell_path() -> Option<&'static PathBuf> {
|
|
if let Some(path) = POWERSHELL_7_PATH.as_ref() {
|
|
return Some(path);
|
|
}
|
|
POWERSHELL_5_PATH.as_ref()
|
|
}
|
|
|
|
/// Returns the path to the WSL executable on the user's machine, if we were able
|
|
/// to find one.
|
|
pub fn wsl_path() -> Option<&'static PathBuf> {
|
|
WSL_PATH.as_ref()
|
|
}
|
|
|
|
/// Searches the user's system for a PowerShell 7 executable and returns the
|
|
/// full path to the executable.
|
|
fn find_powershell_7_path() -> Option<PathBuf> {
|
|
for install_path in powershell_7_install_paths() {
|
|
let exe_path = install_path.join(PWSH_EXE);
|
|
if file_exists_and_is_executable(&exe_path) {
|
|
return Some(exe_path);
|
|
}
|
|
}
|
|
|
|
// Check if the executable is in the PATH.
|
|
let resolved_executable = resolve_executable(PWSH_EXE).map(|path| path.into_owned());
|
|
if resolved_executable.is_some() {
|
|
return resolved_executable;
|
|
}
|
|
|
|
log::warn!("Failed to find pwsh.exe on system");
|
|
None
|
|
}
|
|
|
|
/// Searches the user's system for a PowerShell 5 executable and returns the
|
|
/// full path to the executable.
|
|
fn find_powershell_5_path() -> Option<PathBuf> {
|
|
// Check the default install location.
|
|
let exe_path = powershell_5_install_path().join(POWERSHELL_EXE);
|
|
if file_exists_and_is_executable(&exe_path) {
|
|
return Some(exe_path);
|
|
}
|
|
|
|
// Check if the executable is in the PATH.
|
|
let resolved_executable = resolve_executable(POWERSHELL_EXE).map(|path| path.into_owned());
|
|
if resolved_executable.is_some() {
|
|
return resolved_executable;
|
|
}
|
|
|
|
log::warn!("Failed to find powershell.exe on system");
|
|
None
|
|
}
|
|
|
|
fn find_wsl_path() -> Option<PathBuf> {
|
|
// Check the default install location.
|
|
let system_root = std::env::var("SYSTEMROOT")
|
|
.map(PathBuf::from)
|
|
.unwrap_or_else(|_| Path::new("C:").join("Windows"));
|
|
let wsl_path = system_root.join("System32").join(WSL_EXE);
|
|
if file_exists_and_is_executable(&wsl_path) {
|
|
return Some(wsl_path);
|
|
}
|
|
|
|
// Check if the executable is in the PATH.
|
|
let resolved_executable = resolve_executable(WSL_EXE).map(|path| path.into_owned());
|
|
if resolved_executable.is_some() {
|
|
return resolved_executable;
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
/// Returns the default location where the PowerShell 5 executable
|
|
/// is usually installed.
|
|
pub fn powershell_5_install_path() -> PathBuf {
|
|
let system_root = std::env::var("SYSTEMROOT")
|
|
.map(PathBuf::from)
|
|
.unwrap_or_else(|_| Path::new("C:").join("Windows"));
|
|
system_root
|
|
.join("System32")
|
|
.join("WindowsPowerShell")
|
|
.join("v1.0")
|
|
}
|
|
|
|
/// Returns the default locations where the PowerShell 7 executable
|
|
/// is usually installed.
|
|
///
|
|
/// The locations to search have been adapted from Windows Terminal:
|
|
/// https://github.com/microsoft/terminal/blob/e1be2f4c73b8a8d55e07a9499a72d7b943ac3fe7/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp#L264-L286
|
|
///
|
|
/// Adapted under the MIT License, Copyright (c) Microsoft Corporation. See app/assets/windows/LICENSE-WINDOWS-TERMINAL.
|
|
pub fn powershell_7_install_paths() -> impl Iterator<Item = PathBuf> {
|
|
powershell_7_program_files_paths()
|
|
.chain(dotnet_tools_path())
|
|
.chain(scoop_shims_path())
|
|
.chain(microsoft_store_app_path())
|
|
}
|
|
|
|
fn powershell_7_program_files_paths() -> impl Iterator<Item = PathBuf> {
|
|
let program_files = env::var("PROGRAMFILES")
|
|
.map(PathBuf::from)
|
|
.unwrap_or_else(|_| Path::new("C:").join("Program Files"));
|
|
let program_files_paths = find_powershell_7_program_files_paths(program_files);
|
|
|
|
// On 64 bit systems, check the "Program Files (x86)" directory.
|
|
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
|
|
let program_files_paths = {
|
|
let program_files_x86 = env::var("PROGRAMFILES(X86)")
|
|
.map(PathBuf::from)
|
|
.unwrap_or_else(|_| Path::new("C:").join("Program Files (x86)"));
|
|
program_files_paths.chain(find_powershell_7_program_files_paths(program_files_x86))
|
|
};
|
|
|
|
// On ARM64 systems, check the "Program Files (Arm)" directory.
|
|
#[cfg(target_arch = "aarch64")]
|
|
let program_files_paths = {
|
|
let program_files_arm = env::var("PROGRAMFILES(ARM)")
|
|
.map(PathBuf::from)
|
|
.unwrap_or_else(|_| Path::new("C:").join("Program Files (Arm)"));
|
|
program_files_paths.chain(find_powershell_7_program_files_paths(program_files_arm))
|
|
};
|
|
|
|
program_files_paths
|
|
}
|
|
|
|
/// Given a Program Files directory, return the possible install locations for
|
|
/// the PowerShell 7 executable within that directory.
|
|
fn find_powershell_7_program_files_paths(program_files: PathBuf) -> impl Iterator<Item = PathBuf> {
|
|
// We could be more robust in our search by iterating over all subdirectories
|
|
// of `{directory}/PowerShell`, but this simplifies the logic and it's highly
|
|
// unlikely that users would have versions other than the hardcoded ones here.
|
|
["7", "7-preview"]
|
|
.into_iter()
|
|
.map(move |version| program_files.join("PowerShell").join(version))
|
|
}
|
|
|
|
fn dotnet_tools_path() -> Option<PathBuf> {
|
|
env::var("USERPROFILE")
|
|
.map(PathBuf::from)
|
|
.map(|user_profile| user_profile.join(".dotnet").join("tools"))
|
|
.ok()
|
|
}
|
|
|
|
fn scoop_shims_path() -> Option<PathBuf> {
|
|
env::var("USERPROFILE")
|
|
.map(PathBuf::from)
|
|
.map(|user_profile| user_profile.join("scoop").join("shims"))
|
|
.ok()
|
|
}
|
|
|
|
fn microsoft_store_app_path() -> Option<PathBuf> {
|
|
let windows_base_dirs = directories::BaseDirs::new()?;
|
|
let mut microsoft_store_app_path = PathBuf::from(windows_base_dirs.data_local_dir());
|
|
microsoft_store_app_path.push("Microsoft");
|
|
microsoft_store_app_path.push("WindowsApps");
|
|
Some(microsoft_store_app_path)
|
|
}
|
|
|
|
/// Determines if Kaspersky is currently running by checking if there is a
|
|
/// process with the name "avp" running.
|
|
pub fn is_kaspersky_running(ctx: &mut AppContext) -> bool {
|
|
SystemInfo::handle(ctx).update(ctx, |system_info, _| {
|
|
system_info.refresh_all_processes();
|
|
system_info
|
|
.processes_by_name(KASPERSKY_PROCESS_NAME)
|
|
.next()
|
|
.is_some()
|
|
})
|
|
}
|