use std::path::PathBuf;
use crate::view::NodeId;
use super::Workspace;
use super::id_index::NodeAddress;
use super::path_helpers::file_basename;
impl Workspace {
pub(super) fn compute_diff_summary(&self) -> Vec<crate::view::DiffItem> {
use crate::view::{DiffItem, DiffKind};
let mut out = Vec::new();
for (rs_idx, rule_set) in self.config.service.rule_sets.iter().enumerate() {
let path = PathBuf::from(rule_set.file_path.as_str());
let rendered = crate::toml_writer::render_rule_set_toml(rule_set);
let baseline_text = self.baseline_files.get(&path);
let baseline_matches = baseline_text
.map(|s| s.as_str() == rendered.as_str())
.unwrap_or(false);
if baseline_matches {
continue;
}
if let Some(baseline) = baseline_text {
self.append_per_rule_diff(rs_idx, rule_set, baseline, &mut out);
} else {
if let Some(rs_id) = self.ids.id_for(NodeAddress::RuleSet { rule_set: rs_idx }) {
out.push(DiffItem {
kind: DiffKind::Added,
target: rs_id,
summary: format!(
"rule set #{} ({}): rules={}",
rs_idx + 1,
file_basename(&path),
rule_set.rules.len(),
),
});
}
}
}
let root_rendered = crate::toml_writer::render_apimock_toml(&self.config);
let root_baseline_matches = self
.baseline_files
.get(&self.root_path)
.map(|s| s.as_str() == root_rendered.as_str())
.unwrap_or(false);
if !root_baseline_matches {
if let Some(root_id) = self.ids.id_for(NodeAddress::Root) {
out.push(DiffItem {
kind: DiffKind::Updated,
target: root_id,
summary: format!(
"{}: listener / log / service",
file_basename(&self.root_path)
),
});
}
}
out
}
fn append_per_rule_diff(
&self,
rs_idx: usize,
rule_set: &apimock_routing::RuleSet,
baseline_text: &str,
out: &mut Vec<crate::view::DiffItem>,
) {
use crate::view::{DiffItem, DiffKind};
use toml::Value;
let baseline_value: Value = match toml::from_str(baseline_text) {
Ok(v) => v,
Err(_) => return, };
let baseline_rules: &[Value] = match baseline_value
.get("rules")
.and_then(|v| v.as_array())
{
Some(arr) => arr.as_slice(),
None => &[],
};
let cur_len = rule_set.rules.len();
let base_len = baseline_rules.len();
let common = cur_len.min(base_len);
for rule_idx in 0..common {
let cur_rendered = rule_to_string(&rule_set.rules[rule_idx]);
let base_rendered = toml::to_string_pretty(&baseline_rules[rule_idx])
.unwrap_or_default();
if cur_rendered == base_rendered {
continue;
}
let target = self
.ids
.id_for(NodeAddress::Rule {
rule_set: rs_idx,
rule: rule_idx,
})
.unwrap_or_else(NodeId::new);
out.push(DiffItem {
kind: DiffKind::Updated,
target,
summary: format!(
"rule #{} in rule set #{}",
rule_idx + 1,
rs_idx + 1
),
});
}
for rule_idx in common..cur_len {
let target = self
.ids
.id_for(NodeAddress::Rule {
rule_set: rs_idx,
rule: rule_idx,
})
.unwrap_or_else(NodeId::new);
out.push(DiffItem {
kind: DiffKind::Added,
target,
summary: format!(
"added rule #{} in rule set #{}",
rule_idx + 1,
rs_idx + 1
),
});
}
for rule_idx in common..base_len {
out.push(DiffItem {
kind: DiffKind::Removed,
target: NodeId::new(),
summary: format!(
"removed rule #{} from rule set #{}",
rule_idx + 1,
rs_idx + 1
),
});
}
}
}
fn rule_to_string(rule: &apimock_routing::Rule) -> String {
let table = crate::toml_writer::rule_table(rule);
toml::to_string_pretty(&toml::Value::Table(table)).unwrap_or_default()
}