use crate::{
deps::{
scan::{self, RequiredDetails},
AccumulativeCrateDetails,
},
opts::{CrateSelector, CrateVerify, CrateVerifyCommon, WotOpts},
Repo,
};
use anyhow::{bail, Result};
use crev_data::proof;
use serde::{Deserialize, Serialize};
use std::{collections::HashSet, io};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Details {
pub verified: bool,
pub loc: Option<u64>,
pub geiger_count: Option<u64>,
pub has_custom_build: bool,
pub unmaintained: bool,
}
impl From<AccumulativeCrateDetails> for Details {
fn from(details: AccumulativeCrateDetails) -> Self {
Details {
verified: details.verified,
loc: details.loc,
geiger_count: details.geiger_count,
has_custom_build: details.has_custom_build,
unmaintained: details.is_unmaintained,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct CrateInfoDepOutput {
pub details: Details,
pub recursive_details: Details,
pub dependencies: Vec<proof::PackageVersionId>,
pub rev_dependencies: Vec<proof::PackageVersionId>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct CrateInfoOutput {
pub package: proof::PackageVersionId,
#[serde(flatten)]
pub deps: Option<CrateInfoDepOutput>,
pub alternatives: HashSet<proof::PackageId>,
}
pub fn get_crate_deps_info(
pkg_id: cargo::core::PackageId,
common_opts: CrateVerifyCommon,
required_details: &RequiredDetails,
) -> Result<CrateInfoDepOutput> {
let args = CrateVerify {
common: common_opts,
..Default::default()
};
let scanner = scan::Scanner::new(CrateSelector::default(), &args)?;
let mut events = scanner.run(required_details);
let stats = events
.find(|stats| stats.info.id == pkg_id)
.expect("result");
Ok(CrateInfoDepOutput {
details: stats.details().accumulative_own.clone().into(),
recursive_details: stats.details().accumulative_recursive.clone().into(),
dependencies: stats.details().dependencies.clone(),
rev_dependencies: stats.details().rev_dependencies.clone(),
})
}
pub fn get_crate_info(
root_crate: CrateSelector,
common_opts: CrateVerifyCommon,
wot_opts: WotOpts,
) -> Result<CrateInfoOutput> {
if root_crate.name.is_none() {
bail!("Crate selector required");
}
let local = crev_lib::Local::auto_create_or_open()?;
let db = local.load_db()?;
let trust_set = local.trust_set_for_id(
wot_opts.for_id.as_deref(),
&wot_opts.trust_params.clone().into(),
&db,
)?;
let repo = Repo::auto_open_cwd(common_opts.cargo_opts.clone())?;
let pkg_id = repo.find_pkgid_by_crate_selector(&root_crate)?;
let crev_pkg_id = crate::cargo_pkg_id_to_crev_pkg_id(&pkg_id);
Ok(CrateInfoOutput {
package: crev_pkg_id.clone(),
deps: if root_crate.unrelated {
None
} else {
Some(get_crate_deps_info(
pkg_id,
common_opts,
&RequiredDetails::none(),
)?)
},
alternatives: db
.get_pkg_alternatives(&crev_pkg_id.id)
.iter()
.filter(|(author, _)| trust_set.is_trusted(author))
.map(|(_, id)| id)
.cloned()
.collect(),
})
}
pub fn print_crate_info(
root_crate: CrateSelector,
args: CrateVerifyCommon,
wot_opts: WotOpts,
) -> Result<()> {
let info = get_crate_info(root_crate, args, wot_opts)?;
serde_yaml::to_writer(io::stdout(), &info)?;
println!();
Ok(())
}