use serde::Serialize;
use crate::errors;
use std::io::{self, Write};
use std::time::Duration;
pub fn is_json_mode() -> bool {
crate::runtime_flags::json_mode()
}
#[derive(Debug, Clone, Copy, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ProductStatus {
Success,
Failed,
Skipped,
Restored,
}
#[derive(Debug, Serialize)]
#[serde(tag = "event", rename_all = "snake_case")]
pub enum BuildEvent {
BuildStart {
total_products: usize,
},
ProductStart {
product: String,
processor: String,
},
ProductComplete {
product: String,
processor: String,
status: ProductStatus,
#[serde(skip_serializing_if = "Option::is_none")]
duration_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<String>,
},
BuildSummary {
total: usize,
success: usize,
failed: usize,
skipped: usize,
restored: usize,
duration_ms: u64,
#[serde(skip_serializing_if = "Vec::is_empty")]
errors: Vec<String>,
},
}
#[derive(Debug, Serialize)]
pub struct ProcessorFileEntry {
pub processor: String,
pub processor_type: String,
pub inputs: Vec<String>,
pub outputs: Vec<String>,
}
#[derive(Debug, Serialize)]
pub struct ProcessorListEntry {
pub name: String,
pub processor_type: String,
pub enabled: bool,
pub detected: bool,
pub batch: bool,
pub description: String,
}
#[derive(Debug, Serialize)]
pub struct ToolInstallMethodEntry {
pub method: String,
pub command: String,
}
#[derive(Debug, Serialize)]
pub struct ToolListEntry {
pub tool: String,
pub installed: bool,
pub runtime: String,
pub processors: Vec<String>,
pub install_methods: Vec<ToolInstallMethodEntry>,
}
#[derive(Debug, Serialize)]
pub struct ToolStatsOutput {
pub tools: Vec<ToolStat>,
pub runtimes: Vec<RuntimeStat>,
pub summary: StatsSummary,
}
#[derive(Debug, Serialize)]
pub struct ToolStat {
pub name: String,
pub installed: bool,
pub runtime: String,
pub processors: Vec<String>,
pub install_command: Option<String>,
}
#[derive(Debug, Serialize)]
pub struct RuntimeStat {
pub runtime: String,
pub total: usize,
pub installed: usize,
pub missing: usize,
}
#[derive(Debug, Serialize)]
pub struct StatsSummary {
pub total_tools: usize,
pub installed: usize,
pub missing: usize,
}
#[derive(Debug, Serialize)]
pub struct SlocLanguageEntry {
pub language: String,
pub files: usize,
pub blank: usize,
pub comment: usize,
pub code: usize,
}
#[derive(Debug, Serialize)]
pub struct SlocTotals {
pub files: usize,
pub blank: usize,
pub comment: usize,
pub code: usize,
}
#[derive(Debug, Serialize)]
pub struct SlocCocomoEstimate {
pub effort_person_months: f64,
pub schedule_months: f64,
pub people: f64,
pub cost: f64,
pub salary: u64,
}
#[derive(Debug, Serialize)]
pub struct SlocOutput {
pub languages: Vec<SlocLanguageEntry>,
pub total: SlocTotals,
#[serde(skip_serializing_if = "Option::is_none")]
pub cocomo: Option<SlocCocomoEstimate>,
}
pub fn emit(event: &BuildEvent) {
if !is_json_mode() {
return;
}
let json = serde_json::to_string(event).expect(errors::JSON_SERIALIZE);
let mut stdout = io::stdout().lock();
let _ = writeln!(stdout, "{}", json);
}
pub fn emit_build_start(total_products: usize) {
emit(&BuildEvent::BuildStart { total_products });
}
pub fn emit_product_start(product: &str, processor: &str) {
emit(&BuildEvent::ProductStart {
product: product.to_string(),
processor: processor.to_string(),
});
}
pub fn emit_product_complete(
product: &str,
processor: &str,
status: ProductStatus,
duration: Option<Duration>,
error: Option<&str>,
) {
emit(&BuildEvent::ProductComplete {
product: product.to_string(),
processor: processor.to_string(),
status,
duration_ms: duration.map(|d| d.as_millis() as u64),
error: error.map(|s| s.to_string()),
});
}
pub fn emit_build_summary(
total: usize,
success: usize,
failed: usize,
skipped: usize,
restored: usize,
duration: Duration,
errors: &[String],
) {
emit(&BuildEvent::BuildSummary {
total,
success,
failed,
skipped,
restored,
duration_ms: duration.as_millis() as u64,
errors: errors.to_vec(),
});
}