fn cmd_diff()

in src/main.rs [2051:2177]


fn cmd_diff(out: &Arc<dyn Out>, cfg: &Config, sub_args: &DiffArgs) -> Result<(), miette::Report> {
    let version1 = &sub_args.version1;
    let version2 = &sub_args.version2;
    let package = &*sub_args.package;

    let to_compare = {
        let network = Network::acquire(cfg);
        let store = Store::acquire(cfg, network.as_ref(), false)?;
        let cache = Cache::acquire(cfg)?;

        // Record this command for magic in `vet certify`
        cache.set_last_fetch(FetchCommand::Diff {
            package: package.to_owned(),
            version1: version1.clone(),
            version2: version2.clone(),
        });

        // Determine the fetch mode to use. We'll need to do a local diff if the
        // selected version has a git revision.
        let mode = cache.select_fetch_mode(
            sub_args.mode,
            version1.git_rev.is_some() || version2.git_rev.is_some(),
        );

        if mode != FetchMode::Local {
            let url = match mode {
                FetchMode::Sourcegraph => {
                    format!(
                        "https://sourcegraph.com/crates/{package}/-/compare/v{version1}...v{version2}?visible=7000"
                    )
                }
                FetchMode::DiffRs => {
                    format!("https://diff.rs/{package}/{version1}/{version2}/")
                }
                FetchMode::Local => unreachable!(),
            };
            tokio::runtime::Handle::current()
                .block_on(prompt_criteria_eulas(
                    out,
                    cfg,
                    network.as_ref(),
                    &store,
                    package,
                    Some(version1),
                    version2,
                    Some(&url),
                ))
                .into_diagnostic()?;

            open::that(&url).into_diagnostic().wrap_err_with(|| {
                format!("Couldn't open {url} in your browser, try --mode=local?")
            })?;

            writeln!(out, "\nUse |cargo vet certify| to record your audit.");

            return Ok(());
        }

        tokio::runtime::Handle::current().block_on(async {
            // NOTE: don't `try_join` everything as we don't want to abort the
            // prompt to the user if the download fails while it is being shown, as
            // that could be disorienting.
            let (to_compare, eulas) = tokio::join!(
                async {
                    let (pkg1, pkg2) = tokio::try_join!(
                        cache.fetch_package(&cfg.metadata, network.as_ref(), package, version1),
                        cache.fetch_package(&cfg.metadata, network.as_ref(), package, version2)
                    )?;
                    let (_, to_compare) = cache
                        .diffstat_package(
                            &pkg1,
                            &pkg2,
                            version1.git_rev.is_some() || version2.git_rev.is_some(),
                        )
                        .await?;
                    Ok::<_, FetchAndDiffError>(to_compare)
                },
                prompt_criteria_eulas(
                    out,
                    cfg,
                    network.as_ref(),
                    &store,
                    package,
                    Some(version1),
                    version2,
                    None,
                )
            );
            eulas.into_diagnostic()?;
            to_compare.into_diagnostic()
        })?
    };

    writeln!(out);

    // Start a pager to show the output from our diff invocations. This will
    // fall back to just printing to `stdout` if no pager is available or we're
    // not piped to a terminal.
    let mut pager = Pager::new(&**out).into_diagnostic()?;

    for (from, to) in to_compare {
        let output = std::process::Command::new("git")
            .arg("-c")
            .arg("core.safecrlf=false")
            .arg("diff")
            .arg(if pager.use_color() {
                "--color=always"
            } else {
                "--color=never"
            })
            .arg("--no-index")
            .arg("--ignore-cr-at-eol")
            .arg(&from)
            .arg(&to)
            .stdout(Stdio::piped())
            .output()
            .map_err(CommandError::CommandFailed)
            .into_diagnostic()?;
        io::Write::write_all(&mut pager, &output.stdout).into_diagnostic()?;
    }

    pager.wait().into_diagnostic()?;

    writeln!(out, "\nUse |cargo vet certify| to record your audit.");

    Ok(())
}