helm_schema/output_pipeline/
format.rs1use std::collections::BTreeSet;
2use std::io::Write;
3
4use serde_json::Value;
5
6use crate::error::EngineResult;
7use crate::output_pipeline::JsonOutputFormat;
8
9pub const HELM_MAX_CHART_FILE_BYTES: usize = 5 * 1024 * 1024;
12
13#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
15pub struct FinalOutputMetrics {
16 pub serialized_bytes: usize,
18 pub objects: usize,
20 pub condition_nodes: usize,
22 pub unique_conditions: usize,
24 pub unique_then_payloads: usize,
26}
27
28#[tracing::instrument(skip_all, fields(format = ?format))]
37pub fn write_schema_json(
38 out: &mut impl Write,
39 schema: &Value,
40 format: JsonOutputFormat,
41) -> EngineResult<FinalOutputMetrics> {
42 let mut bytes = match format {
43 JsonOutputFormat::Compact => serde_json::to_vec(schema)?,
44 JsonOutputFormat::Pretty => {
45 let pretty = serde_json::to_vec_pretty(schema)?;
50 if pretty.len() >= HELM_MAX_CHART_FILE_BYTES {
51 serde_json::to_vec(schema)?
52 } else {
53 pretty
54 }
55 }
56 };
57 bytes.push(b'\n');
58 out.write_all(&bytes)?;
59 Ok(final_output_metrics(schema, bytes.len()))
60}
61
62fn final_output_metrics(schema: &Value, serialized_bytes: usize) -> FinalOutputMetrics {
63 fn visit(
64 value: &Value,
65 metrics: &mut FinalOutputMetrics,
66 conditions: &mut BTreeSet<String>,
67 then_payloads: &mut BTreeSet<String>,
68 ) {
69 match value {
70 Value::Object(object) => {
71 metrics.objects += 1;
72 if let Some(condition) = object.get("if") {
73 metrics.condition_nodes += 1;
74 conditions.insert(helm_schema_json_schema_walk::canonical_json_string(
75 condition,
76 ));
77 }
78 if let Some(then_payload) = object.get("then") {
79 then_payloads.insert(helm_schema_json_schema_walk::canonical_json_string(
80 then_payload,
81 ));
82 }
83 for child in object.values() {
84 visit(child, metrics, conditions, then_payloads);
85 }
86 }
87 Value::Array(items) => {
88 for item in items {
89 visit(item, metrics, conditions, then_payloads);
90 }
91 }
92 Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => {}
93 }
94 }
95
96 let mut metrics = FinalOutputMetrics {
97 serialized_bytes,
98 ..FinalOutputMetrics::default()
99 };
100 let mut conditions = BTreeSet::new();
101 let mut then_payloads = BTreeSet::new();
102 visit(schema, &mut metrics, &mut conditions, &mut then_payloads);
103 metrics.unique_conditions = conditions.len();
104 metrics.unique_then_payloads = then_payloads.len();
105 metrics
106}
107
108#[cfg(test)]
109#[path = "tests/format.rs"]
110mod tests;