#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CheckState {
Pass,
Fail,
Warn,
Info,
}
#[derive(Debug, Clone)]
pub struct Check {
pub label: String,
pub state: CheckState,
pub value: String,
}
#[derive(Debug, Clone)]
pub struct Section {
pub title: String,
pub checks: Vec<Check>,
}
#[derive(Debug, Clone)]
pub struct Problem {
pub headline: String,
pub hints: Vec<String>,
pub fix: Option<Fix>,
}
#[derive(Debug, Clone)]
pub struct Fix {
pub description: String,
pub commands: Vec<FixCommand>,
pub requires_relogin: bool,
}
#[derive(Debug, Clone)]
pub struct FixCommand {
pub program: String,
pub args: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct Diagnosis {
pub sections: Vec<Section>,
pub problems: Vec<Problem>,
}
impl Check {
pub(crate) fn pass(label: &str, value: &str) -> Self {
Self {
label: label.to_string(),
state: CheckState::Pass,
value: value.to_string(),
}
}
pub(crate) fn fail(label: &str, value: &str) -> Self {
Self {
label: label.to_string(),
state: CheckState::Fail,
value: value.to_string(),
}
}
pub(crate) fn info(label: &str, value: &str) -> Self {
Self {
label: label.to_string(),
state: CheckState::Info,
value: value.to_string(),
}
}
}
impl Problem {
pub(crate) fn new(headline: impl Into<String>, hints: Vec<String>) -> Self {
Self {
headline: headline.into(),
hints,
fix: None,
}
}
pub fn with_fix(mut self, fix: Fix) -> Self {
self.fix = Some(fix);
self
}
}
impl Fix {
pub fn new(description: impl Into<String>, commands: Vec<FixCommand>) -> Self {
Self {
description: description.into(),
commands,
requires_relogin: false,
}
}
pub fn requires_relogin(mut self) -> Self {
self.requires_relogin = true;
self
}
}
impl FixCommand {
pub fn sudo(args: &[&str]) -> Self {
Self {
program: "sudo".to_string(),
args: args.iter().map(|a| a.to_string()).collect(),
}
}
pub fn display(&self) -> String {
let mut parts = Vec::with_capacity(self.args.len() + 1);
parts.push(self.program.as_str());
parts.extend(self.args.iter().map(String::as_str));
parts.join(" ")
}
}
impl Diagnosis {
pub fn is_healthy(&self) -> bool {
self.problems.is_empty()
}
}
pub fn diagnose() -> Diagnosis {
let mut sections = Vec::new();
let mut problems = Vec::new();
let (runtime, mut runtime_problems) = runtime_section();
sections.push(runtime);
problems.append(&mut runtime_problems);
let (host, mut host_problems) = host_section();
sections.push(host);
problems.append(&mut host_problems);
Diagnosis { sections, problems }
}
fn runtime_section() -> (Section, Vec<Problem>) {
let base = microsandbox_utils::resolve_home();
let bin_dir = base.join(microsandbox_utils::BIN_SUBDIR);
let lib_dir = base.join(microsandbox_utils::LIB_SUBDIR);
let os = std::env::consts::OS;
let msb_name = microsandbox_utils::msb_binary_filename(os);
let libkrunfw_name = microsandbox_utils::libkrunfw_filename(os);
let msb_ok = bin_dir.join(&msb_name).is_file();
let libkrunfw_ok = lib_dir.join(&libkrunfw_name).is_file();
let checks = vec![
Check::info("Install root", &base.display().to_string()),
if msb_ok {
Check::pass("msb", "present")
} else {
Check::fail("msb", "missing")
},
if libkrunfw_ok {
Check::pass("libkrunfw", "present")
} else {
Check::fail("libkrunfw", "missing")
},
];
let mut problems = Vec::new();
if !msb_ok || !libkrunfw_ok {
problems.push(Problem::new(
"microsandbox runtime is not fully installed",
vec![
format!("expected runtime files under {}", base.display()),
"install or repair them: msb self update".to_string(),
],
));
}
(
Section {
title: "Runtime".to_string(),
checks,
},
problems,
)
}
fn host_section() -> (Section, Vec<Problem>) {
#[cfg(target_os = "linux")]
{
super::linux::host_section()
}
#[cfg(target_os = "macos")]
{
super::macos::host_section()
}
#[cfg(target_os = "windows")]
{
super::windows::host_section()
}
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
{
unsupported_host_section()
}
}
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
fn unsupported_host_section() -> (Section, Vec<Problem>) {
let label = format!("{} {}", std::env::consts::OS, std::env::consts::ARCH);
(
Section {
title: "Host".to_string(),
checks: vec![Check::fail("Platform", &label)],
},
vec![Problem::new(
"this platform is not supported for local sandboxes",
vec!["local execution is supported on Linux, macOS (arm64), and Windows".to_string()],
)],
)
}