logone 0.2.9

A command-line tool that parses Nix's --log-format json-internal output as standalone and crate library
Documentation
use crate::{logone, logone::LogStatus};
use anyhow::{anyhow, Result};
use serde_json::{Map, Value};

fn get_target_name(obj: &Map<String, Value>) -> String {
    let crate_name = obj
        .get("crate_name")
        .and_then(|v| v.as_str())
        .unwrap_or("")
        .to_string();

    let crate_type = obj
        .get("crate_type")
        .and_then(|v| v.as_str())
        .unwrap_or("")
        .to_string();

    if crate_type.is_empty() {
        crate_name.clone()
    } else {
        format!("{} {}", crate_name, crate_type)
    }
}

// echo "@cargo { \"type\":0, \"crate_name\":\"{{{crate_name}}}\", \"crate_type\":\"{{{crate_type}}}\", \"id\":\"{{{fullname}}}\" }"
pub fn handle_cargo_log_start(obj: &Map<String, Value>, logone: &mut logone::LogOne) -> Result<()> {
    let id = obj
        .get("id")
        .and_then(|v| v.as_u64())
        .ok_or_else(|| anyhow!("Missing id in log start"))?;

    // Create new log buffer for this id
    logone.cargo_log_buffers.insert(id, Vec::new());
    logone
        .cargo_log_buffers_state
        .insert(id, LogStatus::Started);

    let target_name = get_target_name(&obj);
    
    logone.target_add(target_name.clone())?;

    let msg: String = format!("   \x1b[32mCompiling\x1b[0m {}", target_name);

    logone.print_message(0, msg.as_str(), None);

    Ok(())
}

// @cargo {type: 2, id: $fullname, crate_name: $crate_name, crate_type: $crate_type, rustc_exit_code: ($exit_code|tonumber), rustc_messages: [ { rendered: "..." }, { rendered: "..." }, ... ]}
pub fn handle_cargo_log_rustc_exit(
    obj: &Map<String, Value>,
    logone: &mut logone::LogOne,
) -> Result<()> {
    //println!("{:#?}", obj);
    let id = obj
        .get("id")
        .and_then(|v| v.as_u64())
        .ok_or_else(|| anyhow!("Missing id in log phase"))?;

    let target_name = get_target_name(&obj);

    logone.target_remove(target_name.clone())?;

    let rustc_exit_code: u64 = obj.get("rustc_exit_code").and_then(|v| v.as_u64()).unwrap();

    let rendered_messages: Vec<String> = obj
        .get("rustc_messages")
        .and_then(|msgs| msgs.as_array())
        .map(|msgs| {
            msgs.iter()
                .filter_map(|msg| {
                    msg.as_object()
                        .and_then(|obj| obj.get("rendered"))
                        .and_then(|value| value.as_str())
                        .map(|s| s.to_string())
                })
                .collect()
        })
        .unwrap_or_else(Vec::new);

    //println!("{:#?}", rendered_messages);

    logone
        .cargo_log_buffers_state
        .insert(id, LogStatus::Started);
    match rustc_exit_code {
        0 => {
            logone
                .cargo_log_buffers_state
                .insert(id, LogStatus::FinishedWithSuccess);
        }
        _ => {
            logone
                .cargo_log_buffers_state
                .insert(id, LogStatus::FinishedWithError);
        }
    };

    if let Some(buffer) = logone.cargo_log_buffers.get_mut(&id) {
        for msg in rendered_messages.clone() {
            buffer.push(msg);
        }
    }

    if logone.level() == logone::LogLevel::Cargo {
        for msg in rendered_messages {
            let file: Option<&str> = None;
            logone.print_message(rustc_exit_code, msg.as_str(), file);
        }
    }

    Ok(())
}

// @cargo {type: 3, crate_name: $crate_name, crate_type: $crate_type, exit_code: ($exit_code|tonumber), messages: [ "a", "b", "c" ]}
pub fn handle_cargo_log_build_exit(
    obj: &Map<String, Value>,
    logone: &mut logone::LogOne,
) -> Result<()> {
    //println!("{:#?}", obj);
    let id = obj
        .get("id")
        .and_then(|v| v.as_u64())
        .ok_or_else(|| anyhow!("Missing id in log phase"))?;

    let target_name = get_target_name(&obj);

    logone.target_remove(target_name.clone())?;

    let exit_code: u64 = obj.get("exit_code").and_then(|v| v.as_u64()).unwrap();

    let messages: Vec<String> = obj
        .get("messages")
        .and_then(|msgs| msgs.as_array())
        .map(|msgs| {
            msgs.iter()
                .filter_map(|msg| msg.as_str().map(|s| s.to_string()))
                .collect()
        })
        .unwrap_or_else(Vec::new);

    // println!("{:#?}", messages);

    logone
        .cargo_log_buffers_state
        .insert(id, LogStatus::Started);
    match exit_code {
        0 => {
            logone
                .cargo_log_buffers_state
                .insert(id, LogStatus::FinishedWithSuccess);
        }
        _ => {
            logone
                .cargo_log_buffers_state
                .insert(id, LogStatus::FinishedWithError);
        }
    };

    if let Some(buffer) = logone.cargo_log_buffers.get_mut(&id) {
        for msg in messages.clone() {
            buffer.push(msg);
        }
    }

    if logone.level() == logone::LogLevel::Cargo {
        for msg in messages {
            let file: Option<&str> = None;
            logone.print_message(exit_code, msg.as_str(), file);
        }
    }

    Ok(())
}