pray-core 1.8.1

Core library for Prayfile, the package manager for the language placed before inference
Documentation
use crate::manifest::{Manifest, ManifestPackage};
use crate::{PrayError, PrayResult};
use std::collections::BTreeSet;

pub fn package_matches_environment(groups: &[String], environment: Option<&str>) -> bool {
    if groups.is_empty() {
        return true;
    }
    let Some(selected) = environment else {
        return false;
    };
    groups.iter().any(|group| group == selected)
}

pub fn collect_group_names(manifest: &Manifest) -> BTreeSet<String> {
    manifest
        .packages
        .iter()
        .flat_map(|package| package.groups.iter().cloned())
        .collect()
}

pub fn validate_environment(manifest: &Manifest, environment: Option<&str>) -> PrayResult<()> {
    let Some(selected) = environment else {
        return Ok(());
    };
    if selected.is_empty() {
        return Err(PrayError::Resolution(
            "environment name cannot be empty".to_string(),
        ));
    }
    let known_groups = collect_group_names(manifest);
    if known_groups.is_empty() {
        return Err(PrayError::Resolution(format!(
            "unknown environment {selected}; Prayfile defines no groups"
        )));
    }
    if !known_groups.contains(selected) {
        let mut names: Vec<String> = known_groups.into_iter().collect();
        names.sort();
        return Err(PrayError::Resolution(format!(
            "unknown environment {selected}; available groups are {}",
            names.join(", ")
        )));
    }
    Ok(())
}

pub fn packages_for_render<'a>(
    packages: &'a [crate::resolve::ResolvedPackage],
    environment: Option<&str>,
) -> Vec<&'a crate::resolve::ResolvedPackage> {
    packages
        .iter()
        .filter(|package| package_matches_environment(&package.declaration.groups, environment))
        .collect()
}

pub fn should_render_package(declaration: &ManifestPackage, environment: Option<&str>) -> bool {
    package_matches_environment(&declaration.groups, environment)
}

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

    fn package_with_groups(groups: &[&str]) -> ManifestPackage {
        ManifestPackage {
            name: "sample/base".to_string(),
            groups: groups.iter().map(|group| (*group).to_string()).collect(),
            ..ManifestPackage::default()
        }
    }

    #[test]
    fn ungrouped_packages_always_render() {
        let package = package_with_groups(&[]);
        assert!(should_render_package(&package, None));
        assert!(should_render_package(&package, Some("development")));
    }

    #[test]
    fn grouped_packages_render_only_for_selected_environment() {
        let package = package_with_groups(&["development", "test"]);
        assert!(!should_render_package(&package, None));
        assert!(should_render_package(&package, Some("development")));
        assert!(should_render_package(&package, Some("test")));
        assert!(!should_render_package(&package, Some("production")));
    }
}