#
cargo/ops/cargo_report/
util.rs

    1//! Common utilities for `cargo report` commands.
    2
    3use std::ffi::OsStr;
    4use std::path::PathBuf;
    5
    6use crate::CargoResult;
    7use crate::GlobalContext;
    8use crate::core::Workspace;
    9use crate::core::compiler::CompileMode;
    10use crate::util::BuildLogger;
    11use crate::util::log_message::Target;
    12use crate::util::logger::RunId;
    13
    14/// Lists log files by calling a callback for each valid log file.
    15///
    16/// * Yield log files from new to old
    17/// * If in a workspace, select only the log files associated with the workspace
    18pub fn list_log_files(
    19    gctx: &GlobalContext,
    20    ws: Option<&Workspace<'_>>,
    21) -> CargoResult<Box<dyn Iterator<Item = (PathBuf, RunId)>>> {
    22    let log_dir = gctx.home().join("log");
    23    let log_dir = log_dir.as_path_unlocked();
    24
    25    if !log_dir.exists() {
    26        return Ok(Box::new(std::iter::empty()));
    27    }
    28
    29    let walk = walkdir::WalkDir::new(log_dir)
    30        .follow_links(true)
    31        .sort_by(|a, b| a.file_name().cmp(b.file_name()).reverse())
    32        .min_depth(1)
    33        .max_depth(1)
    34        .into_iter()
    35        .filter_map(|entry| {
    36            let entry = entry.ok()?;
    37            let path = entry.path();
    38
    39            // We only accept JSONL/NDJSON files.
    40            if !entry.file_type().is_file() {
    41                return None;
    42            }
    43            if entry.path().extension() != Some(OsStr::new("jsonl")) {
    44                return None;
    45            }
    46
    47            // ...and the file name must follow RunId format
    48            let run_id = path.file_stem()?.to_str()?.parse::<RunId>().ok()?;
    49            Some((path.to_path_buf(), run_id))
    50        });
    51
    52    let ws_run_id = ws.map(BuildLogger::generate_run_id);
    53
    54    let walk = walk.filter(move |(_, id)| {
    55        ws_run_id
    56            .as_ref()
    57            .map_or(true, |ws_id| id.same_workspace(ws_id))
    58    });
    59
    60    Ok(Box::new(walk))
    61}
    62
    63pub fn find_log_file(
    64    gctx: &GlobalContext,
    65    ws: Option<&Workspace<'_>>,
    66    id: Option<&RunId>,
    67) -> CargoResult<Option<(std::path::PathBuf, RunId)>> {
    68    match id {
    69        Some(requested_id) => {
    70            for (path, run_id) in list_log_files(gctx, ws)? {
    71                if run_id.to_string() == requested_id.to_string() {
    72                    return Ok(Some((path, run_id)));
    73                }
    74            }
    75            Ok(None)
    76        }
    77        None => Ok(list_log_files(gctx, ws)?.next()),
    78    }
    79}
    80
    81pub fn unit_target_description(target: &Target, mode: CompileMode) -> String {
    82    // This is pretty similar to how the current `core::compiler::timings`
    83    // renders `core::manifest::Target`. However, our target is
    84    // a simplified type so we cannot reuse the same logic here.
    85    let mut target_str =
    86        if target.kind == "lib" && matches!(mode, CompileMode::Build | CompileMode::Check { .. }) {
    87            // Special case for brevity, since most dependencies hit this path.
    88            "".to_string()
    89        } else if target.kind == "build-script" {
    90            " build-script".to_string()
    91        } else {
    92            format!(r#" {} "{}""#, target.name, target.kind)
    93        };
    94
    95    match mode {
    96        CompileMode::Test => target_str.push_str(" (test)"),
    97        CompileMode::Build => {}
    98        CompileMode::Check { test: true } => target_str.push_str(" (check-test)"),
    99        CompileMode::Check { test: false } => target_str.push_str(" (check)"),
    100        CompileMode::Doc { .. } => target_str.push_str(" (doc)"),
    101        CompileMode::Doctest => target_str.push_str(" (doc test)"),
    102        CompileMode::Docscrape => target_str.push_str(" (doc scrape)"),
    103        CompileMode::RunCustomBuild => target_str.push_str(" (run)"),
    104    }
    105
    106    target_str
    107}