1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::models::{CargoCrate, CrateId, DepGraph};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{
    cmp::{self, Eq, Ord, PartialEq, PartialOrd},
    collections::BTreeSet,
    path::PathBuf,
};

static ID_CTR: AtomicUsize = AtomicUsize::new(0);

/// A crate in a cargo workspace
///
/// Has a name, path (stored as the offset of the root), and set of
/// dependencies inside the workspace.  To get the dependents of this
/// crate, query the dependency graph with the set of other crate IDs.
#[derive(Clone, Debug)]
pub struct Crate {
    /// Numeric Id of this crate
    pub id: CrateId,
    /// Package name, not the folder name
    pub name: String,
    /// Path offset of the workspace root
    pub cc: CargoCrate,
    /// List of dependencies this crate has inside this workspace
    pub dependencies: BTreeSet<CrateId>,
}

impl PartialEq for Crate {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Crate {}

impl Ord for Crate {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.id.cmp(&other.id)
    }
}

impl PartialOrd for Crate {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

/// Increment the monotonicly increasing Id
fn incr_id() -> usize {
    ID_CTR.fetch_add(1, Ordering::Relaxed)
}

impl Crate {
    pub fn new(cc: CargoCrate) -> Self {
        Self {
            id: incr_id(),
            name: cc.name(),
            cc,
            dependencies: BTreeSet::default(),
        }
    }

    /// Call this function once all crates have been loaded into scope
    pub fn process(&mut self, g: &DepGraph) {
        let deps: Vec<_> = self
            .cc
            .dependencies
            .iter()
            .filter_map(|d| g.find_crate(&d.name))
            .collect();

        deps.into_iter().for_each(|cid| self.add_dependency(cid));
    }

    /// Get the crate name
    pub fn name(&self) -> &String {
        &self.name
    }

    /// Get the crate path
    pub fn path(&self) -> &PathBuf {
        &self.cc.path
    }

    /// Get the current version
    pub fn version(&self) -> String {
        self.cc.version()
    }

    /// Add a dependency of this crate
    pub fn add_dependency(&mut self, id: CrateId) {
        self.dependencies.insert(id);
    }

    /// Check if this crate has a particular dependency
    pub fn has_dependency(&self, id: CrateId) -> bool {
        self.dependencies.contains(&id)
    }

    pub fn change_dependency(&mut self, dep: &String, new_ver: &String) {
        self.cc.change_dep(dep, new_ver);
    }

    /// Publish a new version of this crate
    pub fn publish(&mut self, new_version: String) {
        self.cc.set_version(new_version);
    }

    pub fn sync(&mut self) {
        self.cc.sync();
    }
}