rattler_build_core 0.1.0

Core library for rattler-build
Documentation
use std::collections::HashMap;

use rattler_build_recipe::stage1::requirements::IgnoreRunExports;
use rattler_conda_types::{
    MatchSpec, PackageName, ParseMatchSpecError, ParseStrictness, package::RunExportsJson,
};

use super::resolved_dependencies::{DependencyInfo, RunExportDependency};

/// Filtered run export result
#[derive(Debug, Default, Clone)]
pub struct FilteredRunExports {
    pub noarch: Vec<DependencyInfo>,
    pub strong: Vec<DependencyInfo>,
    pub strong_constraints: Vec<DependencyInfo>,
    pub weak: Vec<DependencyInfo>,
    pub weak_constraints: Vec<DependencyInfo>,
}

/// Filter run exports based on ignore lists
pub fn filter_run_exports(
    ignore_run_exports: &IgnoreRunExports,
    run_export_map: &HashMap<PackageName, RunExportsJson>,
    from_env: &str,
) -> Result<FilteredRunExports, ParseMatchSpecError> {
    let mut run_export_map = run_export_map.clone();
    run_export_map.retain(|name, _| !ignore_run_exports.from_package.contains(name));

    let mut filtered_run_exports = FilteredRunExports::default();

    let to_specs = |strings: &Vec<String>| -> Result<Vec<MatchSpec>, ParseMatchSpecError> {
        use rattler_conda_types::PackageNameMatcher;
        strings
            .iter()
            // We have to parse these as lenient as they come from packages
            .map(|s| MatchSpec::from_str(s, ParseStrictness::Lenient))
            .filter_map(|result| match result {
                Ok(spec) => {
                    let should_include = spec.name.as_ref().is_some_and(|matcher| {
                        match matcher {
                            PackageNameMatcher::Exact(name) => {
                                !ignore_run_exports.by_name.contains(name)
                            }
                            _ => true, // Include non-exact matchers
                        }
                    });
                    if should_include { Some(Ok(spec)) } else { None }
                }
                Err(e) => Some(Err(e)),
            })
            .collect()
    };

    let as_dependency = |spec: MatchSpec, name: &PackageName| -> DependencyInfo {
        DependencyInfo::RunExport(RunExportDependency {
            spec,
            from: from_env.to_string(),
            source_package: name.as_normalized().to_string(),
        })
    };

    for (name, run_export) in run_export_map.iter() {
        if ignore_run_exports.from_package.contains(name) {
            continue;
        }

        filtered_run_exports.noarch.extend(
            to_specs(&run_export.noarch)?
                .into_iter()
                .map(|d| as_dependency(d, name)),
        );
        filtered_run_exports.strong.extend(
            to_specs(&run_export.strong)?
                .into_iter()
                .map(|d| as_dependency(d, name)),
        );
        filtered_run_exports.strong_constraints.extend(
            to_specs(&run_export.strong_constrains)?
                .into_iter()
                .map(|d| as_dependency(d, name)),
        );
        filtered_run_exports.weak.extend(
            to_specs(&run_export.weak)?
                .into_iter()
                .map(|d| as_dependency(d, name)),
        );
        filtered_run_exports.weak_constraints.extend(
            to_specs(&run_export.weak_constrains)?
                .into_iter()
                .map(|d| as_dependency(d, name)),
        );
    }

    Ok(filtered_run_exports)
}