use crate::cratemap::CrateMap;
use cargo_tally::arena::Slice;
use cargo_tally::id::{CrateId, VersionId};
use cargo_tally::version::Version;
use cargo_tally::{DbDump, Dependency};
use semver::{Comparator, Op};
use std::cmp;
use std::collections::btree_map::{BTreeMap as Map, Entry};
pub(crate) fn clean(db_dump: &mut DbDump, crates: &CrateMap) {
let mut crate_max_version: Map<CrateId, &Version> = Map::new();
let mut dependencies_per_version: Map<VersionId, Vec<&mut Dependency>> = Map::new();
for dep in &mut db_dump.dependencies {
dependencies_per_version
.entry(dep.version_id)
.or_insert_with(Vec::new)
.push(dep);
}
for rel in &db_dump.releases {
match crate_max_version.entry(rel.crate_id) {
Entry::Vacant(entry) => {
entry.insert(&rel.num);
}
Entry::Occupied(entry) => {
let entry = entry.into_mut();
*entry = cmp::max(entry, &rel.num);
}
}
let mut no_dependencies = Vec::new();
let dependencies = dependencies_per_version
.get_mut(&rel.id)
.unwrap_or(&mut no_dependencies);
let mut i = 0;
while let Some(dep) = dependencies.get_mut(i) {
if !crate_max_version.contains_key(&dep.crate_id) {
if crate::trace::VERBOSE {
eprintln!(
"unresolved dep {} {} on {} {}",
crates.name(rel.crate_id).unwrap(),
rel.num,
crates.name(dep.crate_id).unwrap(),
dep.req,
);
}
dependencies.remove(i);
continue;
}
let max_version = crate_max_version[&dep.crate_id];
let mut incompatible_version = Version(semver::Version {
major: 0,
minor: 0,
patch: 0,
pre: semver::Prerelease::EMPTY,
build: semver::BuildMetadata::EMPTY,
});
if max_version.major > 0 {
incompatible_version.major = max_version.major + 1;
} else if max_version.minor > 0 {
incompatible_version.minor = max_version.minor + 1;
} else {
incompatible_version.patch = max_version.patch + 1;
};
if dep.req.matches(&incompatible_version) {
dep.req.comparators = Slice::new(&[Comparator {
op: Op::Caret,
major: max_version.major,
minor: Some(max_version.minor),
patch: Some(max_version.patch),
pre: semver::Prerelease::EMPTY,
}]);
}
i += 1;
}
}
}