cargo-workspace2 0.2.2

A tool to query and manage complex cargo workspaces
Documentation
use super::{Constraint, DepConstraint};
use crate::models::{CrateId, DepGraph};
use std::collections::BTreeSet;

/// Execute a simple set query
pub(crate) fn set(crates: &Vec<String>, g: &DepGraph) -> Vec<CrateId> {
    crates
        .iter()
        .filter_map(|name| match g.find_crate(name) {
            None => {
                eprintln!("[ERROR]: Unable to find crate: `{}`", name);
                None
            }
            some => some,
        })
        .collect()
}

/// Execute a search query on the dependency graph
pub(crate) fn deps(mut deps: Vec<DepConstraint>, g: &DepGraph) -> Vec<CrateId> {
    // Parse the anchor point (first crate)
    let DepConstraint {
        ref _crate,
        ref constraint,
    } = deps.remove(0);
    let init_id = get_crate_error(_crate, g);

    // Get it's dependents
    let mut dependents: BTreeSet<_> = match constraint {
        Constraint::Initial(true) => g.get_dependents(init_id).into_iter().collect(),
        Constraint::Initial(false) => g
            .get_all()
            .iter()
            .filter(|c| c.has_dependency(init_id))
            .map(|c| c.id)
            .collect(),
        _ => {
            eprintln!("Invalid initial constraint! Only `<` and `!<` are allowed!");
            std::process::exit(2);
        }
    };

    // Then loop over all other constraints and subtract crates from
    // the dependents set until all constraints are met.
    deps.reverse();
    while let Some(dc) = deps.pop() {
        let DepConstraint {
            ref _crate,
            ref constraint,
        } = dc;

        let id = get_crate_error(_crate, g);
        let ldeps = g.get_dependents(id);
        dependents = apply_constraint(dependents, ldeps, constraint);
    }

    dependents.into_iter().collect()
}

fn get_crate_error(_crate: &String, g: &DepGraph) -> CrateId {
    match g.find_crate(&_crate.trim().to_string()) {
        Some(id) => id,
        None => {
            eprintln!("[ERROR]: Crate `{}` not found in workspace!", _crate);
            std::process::exit(2);
        }
    }
}

fn apply_constraint(
    init: BTreeSet<CrateId>,
    cmp: Vec<CrateId>,
    cnd: &Constraint,
) -> BTreeSet<CrateId> {
    let cmp: BTreeSet<CrateId> = cmp.into_iter().collect();
    let init = init.into_iter();
    match cnd {
        Constraint::And(true) => init.filter(|id| cmp.contains(id)).collect(),
        Constraint::And(false) => init.filter(|id| !cmp.contains(id)).collect(),
        Constraint::Or => init.chain(cmp.into_iter()).collect(),
        _ => todo!(),
    }
}