Skip to main content

pray_core/
environment.rs

1use crate::manifest::{Manifest, ManifestPackage};
2use crate::{PrayError, PrayResult};
3use std::collections::BTreeSet;
4
5pub fn package_matches_environment(groups: &[String], environment: Option<&str>) -> bool {
6    if groups.is_empty() {
7        return true;
8    }
9    let Some(selected) = environment else {
10        return false;
11    };
12    groups.iter().any(|group| group == selected)
13}
14
15pub fn collect_group_names(manifest: &Manifest) -> BTreeSet<String> {
16    manifest
17        .packages
18        .iter()
19        .flat_map(|package| package.groups.iter().cloned())
20        .collect()
21}
22
23pub fn validate_environment(manifest: &Manifest, environment: Option<&str>) -> PrayResult<()> {
24    let Some(selected) = environment else {
25        return Ok(());
26    };
27    if selected.is_empty() {
28        return Err(PrayError::Resolution(
29            "environment name cannot be empty".to_string(),
30        ));
31    }
32    let known_groups = collect_group_names(manifest);
33    if known_groups.is_empty() {
34        return Err(PrayError::Resolution(format!(
35            "unknown environment {selected}; Prayfile defines no groups"
36        )));
37    }
38    if !known_groups.contains(selected) {
39        let mut names: Vec<String> = known_groups.into_iter().collect();
40        names.sort();
41        return Err(PrayError::Resolution(format!(
42            "unknown environment {selected}; available groups are {}",
43            names.join(", ")
44        )));
45    }
46    Ok(())
47}
48
49pub fn packages_for_render<'a>(
50    packages: &'a [crate::resolve::ResolvedPackage],
51    environment: Option<&str>,
52) -> Vec<&'a crate::resolve::ResolvedPackage> {
53    packages
54        .iter()
55        .filter(|package| package_matches_environment(&package.declaration.groups, environment))
56        .collect()
57}
58
59pub fn should_render_package(declaration: &ManifestPackage, environment: Option<&str>) -> bool {
60    package_matches_environment(&declaration.groups, environment)
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use crate::manifest::ManifestPackage;
67
68    fn package_with_groups(groups: &[&str]) -> ManifestPackage {
69        ManifestPackage {
70            name: "sample/base".to_string(),
71            groups: groups.iter().map(|group| (*group).to_string()).collect(),
72            ..ManifestPackage::default()
73        }
74    }
75
76    #[test]
77    fn ungrouped_packages_always_render() {
78        let package = package_with_groups(&[]);
79        assert!(should_render_package(&package, None));
80        assert!(should_render_package(&package, Some("development")));
81    }
82
83    #[test]
84    fn grouped_packages_render_only_for_selected_environment() {
85        let package = package_with_groups(&["development", "test"]);
86        assert!(!should_render_package(&package, None));
87        assert!(should_render_package(&package, Some("development")));
88        assert!(should_render_package(&package, Some("test")));
89        assert!(!should_render_package(&package, Some("production")));
90    }
91}