use anyhow::{bail, Result};
use laterite_core::config::{BackendConfig, DatabaseConfig};
use serde::Deserialize;
use sqlx::any::AnyPoolOptions;
use crate::new::is_writable;
use crate::project::Project;
#[derive(Deserialize)]
struct Config {
database: DatabaseConfig,
#[serde(default)]
backend: BackendConfig,
}
pub async fn run() -> Result<()> {
let project = Project::locate()?;
println!(
"Checking the Laterite application at {}:\n",
project.root.display()
);
let config: Config = match project.load() {
Ok(config) => {
report(true, "Configuration loads");
config
}
Err(err) => {
report(false, "Configuration loads");
println!(" {err}");
bail!("cannot continue without a valid configuration");
}
};
let mut ok = true;
let tz_ok = config.backend.timezone.parse::<chrono_tz::Tz>().is_ok();
ok &= check(
&format!("Timezone '{}' is valid", config.backend.timezone),
tz_ok,
);
let storage = project.root.join("storage");
ok &= check(
"storage/ is writable",
storage.is_dir() && is_writable(&storage),
);
sqlx::any::install_default_drivers();
let pool = AnyPoolOptions::new()
.max_connections(1)
.connect(&config.database.url)
.await;
match &pool {
Ok(_) => ok &= check("Database is reachable", true),
Err(err) => {
report(false, "Database is reachable");
println!(" {err}");
ok = false;
}
}
if let Ok(pool) = &pool {
for table in ["backend_users", "settings"] {
let exists = sqlx::query(&format!("select 1 from {table} where 1 = 0"))
.fetch_optional(pool)
.await
.is_ok();
ok &= check(&format!("Table '{table}' exists"), exists);
}
}
match crate::plugin::manifest_in_sync(&project.root) {
Ok(Some(true)) => ok &= check("plugins-manifest is in sync", true),
Ok(Some(false)) => {
ok &= check("plugins-manifest is in sync (run `lat plugin sync`)", false)
}
Ok(None) => {} Err(err) => {
report(false, "plugins-manifest is in sync");
println!(" {err}");
ok = false;
}
}
println!();
if ok {
println!("All checks passed.");
Ok(())
} else {
bail!("some checks failed; see above");
}
}
fn check(label: &str, pass: bool) -> bool {
report(pass, label);
pass
}
fn report(pass: bool, label: &str) {
println!(" {} {label}", if pass { '\u{2713}' } else { '\u{2717}' });
}