explicit.rs raw

use std::path::PathBuf;

use anyhow::Result;

use super::metadata::resolve_packages;
use super::{Project, ProjectSource, SourceKind};

/// The projects named in the config, by `add`, by `scan`, or by hand.
///
/// This is where everything grunk knows about ends up, bar the handful cargo
/// happens to have recorded itself. Nothing is here by accident: a project is
/// on this list because someone put it there.
pub struct Explicit {
    package_dirs: Vec<PathBuf>,
}

impl Explicit {
    pub fn new(package_dirs: Vec<PathBuf>) -> Self {
        Self { package_dirs }
    }
}

impl ProjectSource for Explicit {
    fn kind(&self) -> SourceKind {
        SourceKind::Explicit
    }

    fn projects(&self, warnings: &mut Vec<String>) -> Result<Vec<Project>> {
        // Unlike a path install, an entry here was typed deliberately, so a
        // path that has gone missing is worth saying out loud rather than
        // quietly dropping — it means the config has gone stale.
        let mut dirs = Vec::new();
        for dir in &self.package_dirs {
            if dir.is_dir() {
                dirs.push(dir.clone());
            } else {
                warnings.push(format!(
                    "explicit: {} no longer exists; `cargo grunk remove {}` to forget it",
                    dir.display(),
                    dir.display()
                ));
            }
        }

        Ok(resolve_packages(self.kind(), dirs, warnings))
    }
}