userd 0.2.0

A user daemon, managing services and regular running of jobs, in user space.
#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum Trigger {
    Every {
        #[serde(with = "humantime_serde")]
        duration: std::time::Duration,
    },
}

fn default_false() -> bool {
    false
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum ContentCheck {
    Contains { value: String },
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum UpdateCheck {
    Watch,
    Every {
        #[serde(with = "humantime_serde")]
        duration: std::time::Duration,
    },
}

fn default_update_check() -> UpdateCheck {
    UpdateCheck::Watch
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum Condition {
    File {
        filename: std::path::PathBuf,
        #[serde(default = "default_false")]
        negate: bool,
        check: ContentCheck,
        #[serde(default = "default_update_check")]
        update_check: UpdateCheck,
    },
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub(crate) struct Task {
    pub(crate) name: String,
    pub(crate) triggers: Vec<Trigger>,
    pub(crate) command: String,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub(crate) struct Service {
    pub(crate) name: String,
    pub(crate) conditions: Vec<Condition>,
    pub(crate) restart_triggers: Vec<Trigger>,
    pub(crate) command: String,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub(crate) struct Config {
    pub(crate) tasks: Vec<Task>,
    pub(crate) services: Vec<Service>,
}