use std::path::Path;
use crate::payload::ArchivePayload;
pub const EVERGREEN_PREFIX: &str = "webview2";
const EVERGREEN_INSTALLER_STEM: &str = "microsoftedgewebview2runtimeinstaller";
pub fn evergreen_carried(payload: &ArchivePayload) -> bool {
evergreen_entry(payload).is_some()
}
fn evergreen_entry(payload: &ArchivePayload) -> Option<std::path::PathBuf> {
payload
.entries()
.iter()
.map(|entry| &entry.path)
.find(|path| {
path.starts_with(Path::new(EVERGREEN_PREFIX))
&& path.file_name().is_some_and(|name| {
name.to_string_lossy()
.to_lowercase()
.starts_with(EVERGREEN_INSTALLER_STEM)
})
&& path
.extension()
.is_some_and(|ext| ext.eq_ignore_ascii_case("exe"))
})
.cloned()
}
pub fn evergreen_cache(product: &str) -> Option<std::path::PathBuf> {
std::env::var_os("LOCALAPPDATA")
.map(std::path::PathBuf::from)
.map(|local| local.join("shun").join(product).join("webview2"))
}
pub fn stage_evergreen(payload: &ArchivePayload, cache: &Path) -> Option<std::path::PathBuf> {
let entry = evergreen_entry(payload)?;
if payload
.extract_prefix(cache, Path::new(EVERGREEN_PREFIX), &mut |_| {})
.is_err()
{
return None;
}
let staged = cache.join(&entry);
staged.is_file().then_some(staged)
}
#[cfg(windows)]
pub fn run_evergreen_silent(installer: &Path) -> std::io::Result<std::process::ExitStatus> {
use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
let args = ["/silent", "/install"];
match std::process::Command::new(installer)
.args(args)
.creation_flags(CREATE_NO_WINDOW)
.status()
{
Ok(status) => Ok(status),
Err(err) if err.raw_os_error() == Some(740) => {
let exe = installer.display().to_string().replace('\'', "''");
let script = format!(
"Start-Process -FilePath '{exe}' -ArgumentList '{}' -Verb RunAs -Wait",
args.join("','")
);
std::process::Command::new("powershell")
.args(["-NoProfile", "-Command", &script])
.creation_flags(CREATE_NO_WINDOW)
.status()
}
Err(err) => Err(err),
}
}
#[cfg(not(windows))]
pub fn run_evergreen_silent(_installer: &Path) -> std::io::Result<std::process::ExitStatus> {
Err(std::io::Error::new(
std::io::ErrorKind::Unsupported,
"the Evergreen installer only exists on Windows",
))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::payload::pack_directory;
fn packed(dir: &Path) -> ArchivePayload {
ArchivePayload::from_bytes(&pack_directory(dir).expect("packs")).expect("decodes")
}
#[test]
fn evergreen_is_found_under_the_payload_prefix() {
let dir = std::env::temp_dir().join(format!("shun-wv2-found-{}", std::process::id()));
let inner = dir.join(EVERGREEN_PREFIX);
std::fs::create_dir_all(&inner).unwrap();
std::fs::write(
inner.join("MicrosoftEdgeWebView2RuntimeInstallerX64.exe"),
b"MZ",
)
.unwrap();
let payload = packed(&dir);
let _ = std::fs::remove_dir_all(&dir);
assert!(evergreen_carried(&payload));
assert_eq!(
evergreen_entry(&payload),
Some(Path::new("webview2/MicrosoftEdgeWebView2RuntimeInstallerX64.exe").to_path_buf())
);
}
#[test]
fn evergreen_match_is_case_insensitive_but_name_gated() {
let dir = std::env::temp_dir().join(format!("shun-wv2-case-{}", std::process::id()));
let inner = dir.join(EVERGREEN_PREFIX);
std::fs::create_dir_all(&inner).unwrap();
std::fs::write(
inner.join("MICROSOFTEDGEWEBVIEW2RUNTIMEINSTALLERARM64.EXE"),
b"MZ",
)
.unwrap();
std::fs::write(inner.join("license.txt"), b"eula").unwrap();
let payload = packed(&dir);
let _ = std::fs::remove_dir_all(&dir);
assert!(evergreen_carried(&payload));
assert_eq!(
evergreen_entry(&payload)
.unwrap()
.to_string_lossy()
.to_lowercase(),
"webview2/microsoftedgewebview2runtimeinstallerarm64.exe"
);
}
#[test]
fn evergreen_outside_the_prefix_is_ignored() {
let dir = std::env::temp_dir().join(format!("shun-wv2-outside-{}", std::process::id()));
std::fs::create_dir_all(dir.join("tools")).unwrap();
std::fs::write(
dir.join("tools/MicrosoftEdgeWebView2RuntimeInstallerX64.exe"),
b"MZ",
)
.unwrap();
let payload = packed(&dir);
let _ = std::fs::remove_dir_all(&dir);
assert!(!evergreen_carried(&payload));
}
#[test]
fn evergreen_staging_extracts_the_installer() {
let dir = std::env::temp_dir().join(format!("shun-wv2-stage-{}", std::process::id()));
let inner = dir.join(EVERGREEN_PREFIX);
std::fs::create_dir_all(&inner).unwrap();
std::fs::write(
inner.join("MicrosoftEdgeWebView2RuntimeInstallerX64.exe"),
b"MZ-payload",
)
.unwrap();
let payload = packed(&dir);
let _ = std::fs::remove_dir_all(&dir);
let cache = std::env::temp_dir().join(format!("shun-wv2-cache-{}", std::process::id()));
let staged = stage_evergreen(&payload, &cache);
assert_eq!(
staged.as_deref(),
Some(
cache
.join(EVERGREEN_PREFIX)
.join("MicrosoftEdgeWebView2RuntimeInstallerX64.exe")
.as_path()
)
);
assert_eq!(
std::fs::read(staged.unwrap()).unwrap(),
b"MZ-payload".to_vec()
);
let _ = std::fs::remove_dir_all(&cache);
}
#[test]
fn staging_without_a_carried_installer_is_none() {
let dir = std::env::temp_dir().join(format!("shun-wv2-bare-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("app.exe"), b"MZ").unwrap();
let payload = packed(&dir);
let _ = std::fs::remove_dir_all(&dir);
let cache =
std::env::temp_dir().join(format!("shun-wv2-bare-cache-{}", std::process::id()));
assert_eq!(stage_evergreen(&payload, &cache), None);
assert!(!cache.join(EVERGREEN_PREFIX).exists());
}
}