use super::*;
#[derive(Deserialize)]
struct Lockfile {
version: Option<u64>,
package: Option<Vec<LockedPackage>>,
}
#[derive(Deserialize)]
struct LockedPackage {
name: String,
version: String,
source: Option<String>,
}
pub(super) fn collect(
root: &Path,
lockfiles: &mut BTreeSet<String>,
unreadable: &mut Vec<String>,
unsupported: &mut Vec<String>,
add: &mut impl FnMut(&'static str, String, String, &Path),
) {
for file in walk(root, &["Cargo.lock"]) {
let relative = rel(root, &file);
lockfiles.insert(relative.clone());
let parsed = fs::read_to_string(&file)
.ok()
.and_then(|text| toml::from_str::<Lockfile>(&text).ok());
let Some(lock) = parsed else {
unreadable.push(relative);
continue;
};
if (lock.package.is_none() && lock.version.is_none())
|| lock
.version
.is_some_and(|version| !(1..=4).contains(&version))
|| lock.package.as_ref().is_some_and(|packages| {
packages
.iter()
.any(|package| package.name.is_empty() || !is_version(&package.version))
})
{
unreadable.push(relative);
continue;
}
for package in lock.package.unwrap_or_default() {
match package.source.as_deref() {
None => {}
Some("registry+https://github.com/rust-lang/crates.io-index") => {
add("crates.io", package.name, package.version, &file);
}
Some(_) => {
unsupported.push(format!("{}@{} ({relative})", package.name, package.version))
}
}
}
}
unsupported.sort();
unsupported.dedup();
}