[go: up one dir, main page]

cargo-deny 0.8.5

Cargo plugin to help you manage large dependency graphs
Documentation
#![allow(unused_macros, dead_code)]

use anyhow::{Context, Error};
use cargo_deny::{
    diag::{CargoSpans, ErrorSink, Files, KrateSpans},
    CheckCtx,
};

pub fn get_test_data_krates(name: &str) -> Result<cargo_deny::Krates, Error> {
    let project_dir = std::path::Path::new("./tests/test_data").join(name);

    let mut metadata_cmd = krates::Cmd::new();
    metadata_cmd.current_dir(&project_dir);

    krates::Builder::new()
        .build(metadata_cmd, krates::NoneFilter)
        .context("failed to build crate graph")
}

pub fn gather_diagnostics<
    C: serde::de::DeserializeOwned + Default + cargo_deny::UnvalidatedConfig<ValidCfg = VC>,
    VC: Send,
    R: FnOnce(CheckCtx<'_, VC>, CargoSpans, ErrorSink) + Send,
>(
    krates: cargo_deny::Krates,
    test_name: &str,
    cfg: Option<&str>,
    timeout: Option<std::time::Duration>,
    runner: R,
) -> Result<Vec<serde_json::Value>, Error> {
    let (spans, content, hashmap) = KrateSpans::synthesize(&krates);
    let mut files = Files::new();

    let spans_id = files.add(format!("{}/Cargo.lock", test_name), content);

    let spans = KrateSpans::with_spans(spans, spans_id);

    let (config, cfg_id) = match cfg {
        Some(cfg) => {
            let config: C = toml::from_str(cfg).context("failed to deserialize test config")?;

            let cfg_id = files.add(format!("{}.toml", test_name), cfg.to_owned());

            (config, cfg_id)
        }
        None => (
            C::default(),
            files.add(format!("{}.toml", test_name), "".to_owned()),
        ),
    };

    let mut newmap = CargoSpans::new();
    for (key, val) in hashmap {
        let cargo_id = files.add(val.0, val.1);
        newmap.insert(key, (cargo_id, val.2));
    }

    let mut cfg_diags = Vec::new();
    let cfg = config.validate(cfg_id, &mut cfg_diags);

    if cfg_diags
        .iter()
        .any(|d| d.severity >= cargo_deny::diag::Severity::Error)
    {
        anyhow::anyhow!("encountered errors validating config: {:#?}", cfg_diags);
    }

    let (tx, rx) = crossbeam::channel::unbounded();

    let (_, gathered) = rayon::join(
        || {
            let ctx = cargo_deny::CheckCtx {
                krates: &krates,
                krate_spans: &spans,
                cfg,
                serialize_extra: true,
            };
            runner(ctx, newmap, ErrorSink::Channel(tx));
        },
        || {
            let mut diagnostics = Vec::new();

            match timeout {
                Some(timeout) => {
                    let trx = crossbeam::channel::after(timeout);
                    loop {
                        crossbeam::select! {
                            recv(rx) -> msg => {
                                if let Ok(pack) = msg {
                                    diagnostics.extend(pack.into_iter().map(|d| cargo_deny::diag::diag_to_json(d, &files, None)));
                                } else {
                                    // Yay, the sender was dopped (i.e. check was finished)
                                    break;
                                }
                            }
                            recv(trx) -> _ => {
                                anyhow::bail!("Timed out after {:?}", timeout);
                            }
                        }
                    }
                }
                None => {
                    while let Ok(pack) = rx.recv() {
                        diagnostics.extend(
                            pack.into_iter()
                                .map(|d| cargo_deny::diag::diag_to_json(d, &files, None)),
                        );
                    }
                }
            }

            Ok(diagnostics)
        },
    );

    gathered
}

macro_rules! field_eq {
    ($obj:expr, $field:expr, $expected:expr) => {
        $obj.pointer($field) == Some(&serde_json::json!($expected))
    };
}

macro_rules! assert_field_eq {
    ($obj:expr, $field:expr, $expected:expr) => {
        assert_eq!($obj.pointer($field), Some(&serde_json::json!($expected)));
    };
}