20260530 行为保持源码治理重构
This commit is contained in:
144
src/cli/output.rs
Normal file
144
src/cli/output.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
use std::io::BufWriter;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::audit::AuditReportV2;
|
||||
use crate::ccr::canonical_vrp_prefix;
|
||||
|
||||
use super::{PostValidationShared, RunStageTiming};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(super) enum ReportJsonFormat {
|
||||
Pretty,
|
||||
Compact,
|
||||
}
|
||||
|
||||
pub(super) fn write_json(
|
||||
path: &Path,
|
||||
report: &AuditReportV2,
|
||||
format: ReportJsonFormat,
|
||||
) -> Result<(), String> {
|
||||
let f = std::fs::File::create(path)
|
||||
.map_err(|e| format!("create report file failed: {}: {e}", path.display()))?;
|
||||
let writer = BufWriter::new(f);
|
||||
match format {
|
||||
ReportJsonFormat::Pretty => serde_json::to_writer_pretty(writer, report),
|
||||
ReportJsonFormat::Compact => serde_json::to_writer(writer, report),
|
||||
}
|
||||
.map_err(|e| format!("write report json failed: {e}"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(super) struct CompareViewTaskOutput {
|
||||
pub(super) build_ms: Option<u64>,
|
||||
pub(super) write_ms: Option<u64>,
|
||||
}
|
||||
|
||||
pub(super) fn run_compare_view_task(
|
||||
shared: &PostValidationShared,
|
||||
vrps_csv_out_path: Option<&Path>,
|
||||
vaps_csv_out_path: Option<&Path>,
|
||||
trust_anchor: &str,
|
||||
) -> Result<CompareViewTaskOutput, String> {
|
||||
let mut build_ms = None;
|
||||
let mut write_ms = None;
|
||||
if let (Some(vrps_path), Some(vaps_path)) = (vrps_csv_out_path, vaps_csv_out_path) {
|
||||
let started = std::time::Instant::now();
|
||||
build_ms = Some(0);
|
||||
write_direct_vrp_csv(vrps_path, shared.vrps.as_ref(), trust_anchor)?;
|
||||
write_direct_vap_csv(vaps_path, shared.aspas.as_ref(), trust_anchor)?;
|
||||
write_ms = Some(started.elapsed().as_millis() as u64);
|
||||
eprintln!(
|
||||
"wrote compare views: vrps={} vaps={}",
|
||||
vrps_path.display(),
|
||||
vaps_path.display()
|
||||
);
|
||||
}
|
||||
Ok(CompareViewTaskOutput { build_ms, write_ms })
|
||||
}
|
||||
|
||||
fn write_direct_vrp_csv(
|
||||
path: &Path,
|
||||
vrps: &[crate::validation::objects::Vrp],
|
||||
trust_anchor: &str,
|
||||
) -> Result<(), String> {
|
||||
if let Some(parent) = path.parent() {
|
||||
std::fs::create_dir_all(parent)
|
||||
.map_err(|e| format!("create parent dirs failed: {}: {e}", parent.display()))?;
|
||||
}
|
||||
let file = std::fs::File::create(path)
|
||||
.map_err(|e| format!("create file failed: {}: {e}", path.display()))?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
use std::io::Write;
|
||||
let trust_anchor = trust_anchor.to_ascii_lowercase();
|
||||
writeln!(writer, "ASN,IP Prefix,Max Length,Trust Anchor").map_err(|e| e.to_string())?;
|
||||
for vrp in vrps {
|
||||
writeln!(
|
||||
writer,
|
||||
"AS{},{},{},{}",
|
||||
vrp.asn,
|
||||
canonical_vrp_prefix(&vrp.prefix),
|
||||
vrp.max_length,
|
||||
trust_anchor
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_direct_vap_csv(
|
||||
path: &Path,
|
||||
aspas: &[crate::validation::objects::AspaAttestation],
|
||||
trust_anchor: &str,
|
||||
) -> Result<(), String> {
|
||||
if let Some(parent) = path.parent() {
|
||||
std::fs::create_dir_all(parent)
|
||||
.map_err(|e| format!("create parent dirs failed: {}: {e}", parent.display()))?;
|
||||
}
|
||||
let file = std::fs::File::create(path)
|
||||
.map_err(|e| format!("create file failed: {}: {e}", path.display()))?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
use std::io::Write;
|
||||
let trust_anchor = trust_anchor.to_ascii_lowercase();
|
||||
writeln!(writer, "Customer ASN,Providers,Trust Anchor").map_err(|e| e.to_string())?;
|
||||
for aspa in aspas {
|
||||
let mut providers = aspa.provider_as_ids.clone();
|
||||
providers.sort_unstable();
|
||||
providers.dedup();
|
||||
let providers = providers
|
||||
.into_iter()
|
||||
.map(|asn| format!("AS{asn}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(";");
|
||||
writeln!(
|
||||
writer,
|
||||
"AS{},{},{}",
|
||||
aspa.customer_as_id, providers, trust_anchor
|
||||
)
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn write_stage_timing(
|
||||
report_json_path: Option<&Path>,
|
||||
stage_timing: &RunStageTiming,
|
||||
) -> Result<(), String> {
|
||||
if let Some(path) = report_json_path
|
||||
&& let Some(parent) = path.parent()
|
||||
{
|
||||
let stage_timing_path = parent.join("stage-timing.json");
|
||||
std::fs::write(
|
||||
&stage_timing_path,
|
||||
serde_json::to_vec_pretty(stage_timing).map_err(|e| e.to_string())?,
|
||||
)
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
"write stage timing failed: {}: {e}",
|
||||
stage_timing_path.display()
|
||||
)
|
||||
})?;
|
||||
eprintln!("analysis: wrote {}", stage_timing_path.display());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
1592
src/cli/tests.rs
Normal file
1592
src/cli/tests.rs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user