use std::ffi::OsString;
use std::path::PathBuf;
use kernel::AxError;
use super::family::GECKO;
use super::table::{CHROMEDRIVER, MSEDGEDRIVER, PYTHON_WASI, REQUIREMENTS, SHELL};
use super::{Absence, Fault, Machine, PATIENCE, Platform, Presence, ThisMachine, Version};
pub(crate) const ENGINE_CARRIED: bool = cfg!(feature = "sandbox");
pub(crate) fn components_dir() -> Option<PathBuf> {
match accounting::home::Home::detect() {
Ok(home) => Some(home.components()),
Err(_) => None,
}
}
const USER_BINS: [&str; 4] = [".cargo/bin", ".elan/bin", ".local/bin", ".bun/bin"];
pub(crate) fn search_path() -> OsString {
let inherited = std::env::var_os("PATH").unwrap_or_default();
let mut dirs: Vec<PathBuf> = std::env::split_paths(&inherited).collect();
let home = accounting::home::Home::detect()
.map(|home| home.path().to_path_buf())
.into_iter()
.flat_map(|home| USER_BINS.map(|bin| home.join(bin)));
let links = std::env::var_os("LOCALAPPDATA").map(|local| {
PathBuf::from(local)
.join("Microsoft")
.join("WinGet")
.join("Links")
});
for dir in home.chain(links) {
if !dirs.contains(&dir) {
dirs.push(dir);
}
}
match std::env::join_paths(dirs) {
Ok(joined) => joined,
Err(_unjoinable) => inherited,
}
}
pub(crate) fn find_program(program: &str) -> Option<PathBuf> {
super::on_search_path(&search_path(), program)
}
pub(crate) fn install_log(item: &str) -> PathBuf {
std::env::temp_dir()
.join("sprawling-install")
.join(format!("{item}.log"))
}
pub(crate) fn firefox() -> Presence {
look(GECKO)
}
pub(crate) fn chromedriver() -> Presence {
let driver = look(CHROMEDRIVER);
match driver.usable() {
true => driver,
false => match look(MSEDGEDRIVER) {
second if second.usable() => second,
_ => driver,
},
}
}
pub(crate) fn python_wasm() -> Presence {
look(PYTHON_WASI)
}
pub(crate) fn shell() -> Presence {
look(SHELL)
}
pub(crate) fn usable_python_wasm() -> Option<PathBuf> {
usable_path(&python_wasm())
}
pub(crate) fn usable_shell() -> Option<PathBuf> {
usable_path(&shell())
}
fn usable_path(presence: &Presence) -> Option<PathBuf> {
if !presence.usable() {
return None;
}
presence.at().map(std::path::Path::to_path_buf)
}
pub(super) fn built(carried: bool) -> Presence {
if !carried {
return Presence::Absent(Absence::NotInThisBuild);
}
let at = std::env::current_exe().unwrap_or_else(|_| PathBuf::from("this binary"));
match execution_engine() {
Ok(_) => Presence::Present {
at,
version: Version::Said("wasmtime".to_owned()),
},
Err(err) => Presence::Broken {
at,
fault: Fault::WillNotStart(err.to_string()),
},
}
}
#[cfg(feature = "sandbox")]
pub(crate) fn execution_engine() -> Result<Box<dyn runtime::Sandbox>, AxError> {
Ok(Box::new(runtime::WasmtimeSandbox::new()?))
}
#[cfg(not(feature = "sandbox"))]
pub(crate) fn execution_engine() -> Result<Box<dyn runtime::Sandbox>, AxError> {
Ok(Box::new(runtime::AbsentSandbox))
}
fn look(name: &str) -> Presence {
let machine = ThisMachine::new(Platform::current(), PATIENCE);
REQUIREMENTS
.iter()
.find(|requirement| requirement.name == name)
.map_or(Presence::Absent(Absence::NotOnSearchPath), |requirement| {
machine.look(requirement)
})
}