use crate::command_prelude::*;
use anyhow::anyhow;
use cargo::core::compiler::future_incompat::{OnDiskReport, FUTURE_INCOMPAT_FILE};
use cargo::drop_eprint;
use cargo::util::CargoResultExt;
use std::io::Read;

pub fn cli() -> App {
    subcommand("describe-future-incompatibilities")
        .arg(
            opt(
                "id",
                "identifier of the report [generated by a Cargo command invocation",
            )
            .value_name("id")
            .required(true),
        )
        .about("Reports any crates which will eventually stop compiling")
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    if !config.nightly_features_allowed {
        return Err(anyhow!(
            "`cargo describe-future-incompatibilities` can only be used on the nightly channel"
        )
        .into());
    }

    let ws = args.workspace(config)?;
    let report_file = ws.target_dir().open_ro(
        FUTURE_INCOMPAT_FILE,
        ws.config(),
        "Future incompatible report",
    )?;

    let mut file_contents = String::new();
    report_file
        .file()
        .read_to_string(&mut file_contents)
        .chain_err(|| "failed to read report")?;
    let on_disk_report: OnDiskReport =
        serde_json::from_str(&file_contents).chain_err(|| "failed to load report")?;

    let id = args.value_of("id").unwrap();
    if id != on_disk_report.id {
        return Err(anyhow!(
            "Expected an id of `{}`, but `{}` was provided on the command line. \
             Your report may have been overwritten by a different one.",
            on_disk_report.id,
            id
        )
        .into());
    }

    drop_eprint!(config, "{}", on_disk_report.report);
    Ok(())
}
