use eyre::Result;
use serde::Serialize;
use crate::config::Config;
use crate::system::services_common::ServiceState;
use crate::system::user_services::{self, UserServiceRequest};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub(crate) enum Watcher {
Running,
ServiceNotWatching,
DeclaredNotRunning,
NotDeclared,
}
impl Watcher {
pub(crate) fn as_str(self) -> &'static str {
match self {
Self::Running => "running",
Self::ServiceNotWatching => "running but not watching this store",
Self::DeclaredNotRunning => "declared but not running",
Self::NotDeclared => "not declared",
}
}
}
pub(crate) async fn watcher() -> Result<Watcher> {
let running = crate::system::history::watch::runtime::is_running(
&crate::system::history::store::state_dir(),
);
if running {
return Ok(Watcher::Running);
}
let config = Config::get().await?;
let declared = crate::system::services_common::compose_user_declarations(&config)?
.values()
.any(|(declaration, _)| {
declaration.builtin.as_deref() == Some("history-watch")
&& declaration.state != ServiceState::Absent
});
if !declared {
return Ok(Watcher::NotDeclared);
}
for request in declared_watchers(&config) {
match user_services::is_process_running(&request).await {
Ok(true) => return Ok(Watcher::ServiceNotWatching),
Ok(false) => {}
Err(err) => debug!(
"history: could not ask the service manager about {}: {err:#}",
request.name
),
}
}
Ok(Watcher::DeclaredNotRunning)
}
fn declared_watchers(config: &Config) -> Vec<UserServiceRequest> {
user_services::requests_from_config(config)
.unwrap_or_default()
.into_iter()
.filter(user_services::stale_history_watcher)
.collect()
}
pub(crate) fn advice(state: Watcher) -> &'static str {
match state {
Watcher::Running => "edits are saved automatically",
Watcher::ServiceNotWatching => {
"the history service is running but is not watching this store (its process predates this mise version, or uses a different MISE_STATE_DIR): restart it with `mise bootstrap services apply`"
}
Watcher::DeclaredNotRunning => {
"the history watcher is declared but not running: run `mise bootstrap services apply`"
}
Watcher::NotDeclared => {
"automatic capture is inactive: declare `[bootstrap.services.mise-history] builtin = \"history-watch\"` and run `mise bootstrap`; until then edits are saved by `mise dot save` or `mise dot watch --once`"
}
}
}
pub(crate) async fn report() {
match watcher().await {
Ok(Watcher::Running) => {
info!("history: watcher running; autosave-enabled files are saved automatically")
}
Ok(state) => warn!("history: {}", advice(state)),
Err(err) => {
warn!("history: could not determine whether edits are saved automatically: {err:#}")
}
}
}