fn ensure_config_gitignore() {
const REQUIRED: &[&str] = &[
"*.pid",
"*.log",
"*.local.*",
"*.compiled.*",
"schedule.compailed.cron",
".compailed.cron",
"run.sh",
"cache/",
];
let gitignore = crate::paths::config_gitignore_path();
let existing = std::fs::read_to_string(&gitignore).unwrap_or_default();
let lines: Vec<&str> = existing.lines().collect();
let missing: Vec<&str> = REQUIRED
.iter()
.copied()
.filter(|pat| !lines.iter().any(|line| line.trim() == *pat))
.collect();
if missing.is_empty() {
return;
}
let mut content = existing;
if !content.is_empty() && !content.ends_with('\n') {
content.push('\n');
}
for pattern in &missing {
content.push_str(pattern);
content.push('\n');
}
let _ = std::fs::write(&gitignore, &content);
}
pub fn clear_pid_file() {
let _ = std::fs::remove_file(crate::paths::pid_file());
}
pub(crate) fn read_pid_file() -> Option<u32> {
let pid = std::fs::read_to_string(crate::paths::pid_file())
.ok()?
.trim()
.parse()
.ok()?;
if process_is_alive(pid) {
Some(pid)
} else {
clear_pid_file();
None
}
}
#[cfg(unix)]
fn process_is_alive(pid: u32) -> bool {
if pid > i32::MAX as u32 {
return false;
}
std::process::Command::new("kill")
.args(["-0", &pid.to_string()])
.output()
.is_ok_and(|out| out.status.success())
}
#[cfg(not(unix))]
fn process_is_alive(_pid: u32) -> bool {
true
}
pub(super) fn paths_daemon_log() -> String {
crate::paths::daemon_log_file().display().to_string()
}
pub(crate) fn is_running() -> bool {
matches!(http_request("GET", "/api/v1/health"), Ok(200))
}
const WAIT_POLL_INTERVAL: Duration = Duration::from_millis(200);
#[cfg(test)]
#[path = "system_tests.rs"]
mod cli_system_tests;