110 lines
3.4 KiB
Rust
110 lines
3.4 KiB
Rust
//! Utility functions for the test harness.
|
|
|
|
use anyhow::Result;
|
|
use descape::UnescapeExt;
|
|
|
|
/// Get the OS ID from /etc/os-release file.
|
|
/// Returns the value of the ID field, which is the canonical OS identifier.
|
|
/// For example: "ubuntu", "opensuse-tumbleweed", "fedora", etc.
|
|
pub fn get_host_os_id() -> Option<String> {
|
|
os_release::OsRelease::new().ok().and_then(|info| {
|
|
if info.id.is_empty() {
|
|
None
|
|
} else {
|
|
Some(info.id)
|
|
}
|
|
})
|
|
}
|
|
|
|
/// Reads and processes the expectrl log output.
|
|
#[cfg(unix)]
|
|
pub fn read_expectrl_log(log: Vec<u8>) -> Result<String> {
|
|
let output_str = String::from_utf8(log)?;
|
|
let output: String = output_str
|
|
.lines()
|
|
.filter(|line| line.starts_with("read:"))
|
|
.map(|line| {
|
|
line.strip_prefix("read: \"")
|
|
.unwrap()
|
|
.strip_suffix('"')
|
|
.unwrap()
|
|
})
|
|
.collect();
|
|
|
|
Ok(output)
|
|
}
|
|
|
|
/// Makes expectrl output human-readable by unescaping and stripping ANSI codes.
|
|
pub fn make_expectrl_output_readable<S: AsRef<str>>(output: S) -> String {
|
|
// Unescape the escaping done by expectrl's logging mechanism.
|
|
let unescaped = output.as_ref().to_unescaped().unwrap().to_string();
|
|
|
|
// Remove VT escape sequences.
|
|
strip_ansi_escapes::strip_str(unescaped)
|
|
}
|
|
|
|
/// Writes a diff between two strings to a writer.
|
|
pub fn write_diff(
|
|
writer: &mut impl std::io::Write,
|
|
indent: usize,
|
|
left: &str,
|
|
right: &str,
|
|
) -> Result<()> {
|
|
use colored::Colorize;
|
|
|
|
let indent_str = " ".repeat(indent);
|
|
|
|
let diff = diff::lines(left, right);
|
|
for d in diff {
|
|
let formatted = match d {
|
|
diff::Result::Left(l) => std::format!("{indent_str}- {l}").red(),
|
|
diff::Result::Both(l, _) => std::format!("{indent_str} {l}").bright_black(),
|
|
diff::Result::Right(r) => std::format!("{indent_str}+ {r}").green(),
|
|
};
|
|
|
|
writeln!(writer, "{formatted}")?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Resolves the first element of the given launcher token list to an absolute path.
|
|
///
|
|
/// This is needed because the test harness clears env vars (including `PATH`)
|
|
/// before spawning child processes, so a launcher binary referenced by name
|
|
/// (e.g., `wasmtime`) would fail to resolve at exec time.
|
|
pub fn resolve_launcher_path(tokens: &mut [String]) -> Result<()> {
|
|
let Some(first) = tokens.first() else {
|
|
return Ok(());
|
|
};
|
|
if std::path::Path::new(first.as_str()).is_absolute() {
|
|
return Ok(());
|
|
}
|
|
let resolved = std::env::var_os("PATH")
|
|
.into_iter()
|
|
.flat_map(|p| std::env::split_paths(&p).collect::<Vec<_>>())
|
|
.map(|d| d.join(first.as_str()))
|
|
.find(|p| p.is_file())
|
|
.ok_or_else(|| anyhow::anyhow!("could not resolve launcher binary '{first}' in PATH"))?;
|
|
tokens[0] = resolved.to_string_lossy().into_owned();
|
|
Ok(())
|
|
}
|
|
|
|
/// Gets the bash version string from the given bash path.
|
|
pub fn get_bash_version_str(bash_path: &std::path::Path) -> Result<String> {
|
|
use anyhow::Context;
|
|
|
|
let output = std::process::Command::new(bash_path)
|
|
.arg("--norc")
|
|
.arg("--noprofile")
|
|
.arg("-c")
|
|
.arg("echo -n ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}.${BASH_VERSINFO[2]}")
|
|
.output()
|
|
.context("failed to retrieve bash version")?
|
|
.stdout;
|
|
|
|
let ver_str = String::from_utf8(output)?;
|
|
|
|
Ok(ver_str)
|
|
}
|