isothrum-runner 1.0.1

The Isothrum runner: executes the run manifest Isoloom writes next to a target's files (lifecycle, state and locks, drivers, checks, events).
Documentation
//! Where an operation runs: this host's operating system and the run's Vagrant provider. A step,
//! a tool, a param or a slot narrowed to some hosts or providers concerns only those.

use std::collections::BTreeSet;

use isoloom_manifest::{HostOs, Provider};

/// Where an operation runs: the host's operating system and the run's Vagrant provider. A step,
/// tool, param or slot narrowed to some hosts or providers concerns only those.
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct Scope {
    /// This host.
    pub(crate) host: HostOs,
    /// The run's provider, when it has one (`${run.provider}`).
    pub(crate) provider: Option<String>,
}

impl Scope {
    /// Whether something for `hosts` and `providers` (empty: every one) concerns this scope.
    pub(crate) fn admits(&self, hosts: &BTreeSet<HostOs>, providers: &BTreeSet<Provider>) -> bool {
        let host = hosts.is_empty() || hosts.contains(&self.host);
        let provider = providers.is_empty() || self.provider.as_deref().is_some_and(|p| providers.iter().any(|q| provider_id(*q) == p));
        host && provider
    }
}

/// A Vagrant provider's id, as the manifest writes it (`vmware_desktop`).
pub(crate) fn provider_id(p: Provider) -> String {
    serde_json::to_value(p).ok().and_then(|v| v.as_str().map(str::to_owned)).unwrap_or_default()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn a_scope_admits_what_names_its_host_and_provider_or_names_none() {
        let esxi = Scope {
            host: HostOs::Macos,
            provider: Some("vmware_esxi".into()),
        };
        let (any_host, any_provider) = (BTreeSet::new(), BTreeSet::new());
        assert!(esxi.admits(&any_host, &any_provider));
        assert!(esxi.admits(&BTreeSet::from([HostOs::Macos]), &BTreeSet::from([Provider::VmwareEsxi])));
        assert!(!esxi.admits(&BTreeSet::from([HostOs::Windows]), &any_provider));
        assert!(!esxi.admits(&any_host, &BTreeSet::from([Provider::Virtualbox])));
        let no_provider = Scope {
            host: HostOs::Linux,
            provider: None,
        };
        assert!(!no_provider.admits(&any_host, &BTreeSet::from([Provider::Virtualbox])));
        assert_eq!(provider_id(Provider::VmwareDesktop), "vmware_desktop");
    }
}