//! Run once against the frozen schema-6 library, never regenerate with schema7. use oa_core::{source_project::*, *}; use serde::Serialize; use serde::ser::{SerializeStruct, Serializer}; use std::{collections::BTreeSet, fs, path::Path}; struct Project5<'a>(&'a Project); struct Diagram5<'a>(&'a Diagram); impl Serialize for Project5<'_> { fn serialize(&self, serializer: S) -> Result { let p = self.0; let diagrams: std::collections::BTreeMap<_, _> = p.diagrams.iter().map(|(id, d)| (id, Diagram5(d))).collect(); let mut s = serializer.serialize_struct("Project", 10)?; s.serialize_field("schema_version", &5u32)?; s.serialize_field("id", &p.id)?; s.serialize_field("alias", &p.alias)?; s.serialize_field("name", &p.name)?; s.serialize_field("description", &p.description)?; s.serialize_field("elements", &p.elements)?; s.serialize_field("relations", &p.relations)?; s.serialize_field("diagrams", &diagrams)?; s.serialize_field("artifact_links", &p.artifact_links)?; s.serialize_field("traces", &p.traces)?; s.end() } } impl Serialize for Diagram5<'_> { fn serialize(&self, serializer: S) -> Result { let d = self.0; let mut s = serializer.serialize_struct("Diagram", 8)?; s.serialize_field("id", &d.id)?; s.serialize_field("alias", &d.alias)?; s.serialize_field("name", &d.name)?; s.serialize_field("description", &d.description)?; s.serialize_field("layer", &d.layer)?; s.serialize_field("projection", &d.projection)?; s.serialize_field("nodes", &d.nodes)?; s.serialize_field("routes", &d.routes)?; s.end() } } fn alias(p: &Project, name: &str) -> Id { p.elements .values() .find(|e| e.alias == name) .map(|e| e.id) .or_else(|| p.relations.values().find(|e| e.alias == name).map(|e| e.id)) .unwrap() } fn main() { assert_eq!( SCHEMA_VERSION, 6, "fixture writer must use historical core6 library" ); let out = Path::new("crates/oa-desktop/src/recovery/fixtures"); fs::create_dir_all(out).unwrap(); let original = persistence::decode(&fs::read("examples/release1/model.json").unwrap()).unwrap(); for schema in [5, 6] { let mut p = original.clone(); if schema == 5 { let mut removed: BTreeSet<_> = p .elements .values() .filter(|e| e.kind() == Kind::ExchangeCategory) .map(|e| e.id) .collect(); removed.extend( p.relations .values() .filter(|r| r.kind() == RelationKind::CommunicationMean) .map(|r| r.id), ); removed.extend( p.relations .values() .filter(|r| { r.kind() == RelationKind::ExchangeAllocation && removed.contains(&r.source()) }) .map(|r| r.id) .collect::>(), ); p.elements.retain(|id, _| !removed.contains(id)); p.relations.retain(|id, _| !removed.contains(id)); p.traces .retain(|_, t| !removed.contains(&t.oa) && !removed.contains(&t.sa)); for d in p.diagrams.values_mut() { d.view_options = Default::default(); } let assess = alias(&p, "oa_assess"); let repair = alias(&p, "oa_repair"); let request = alias(&p, "oa_repair_request"); for name in ["oa_conversation", "oa_full_scenario"] { let id = alias(&p, name); let Some(SharedBody::Scenario { viewpoint, .. }) = p.elements.get_mut(&id).unwrap().shared_mut() else { panic!() }; *viewpoint = ScenarioViewpoint::OperationalActivity; } for (name, work) in [ ("oa_caller", assess), ("oa_responder", repair), ("oa_outer_controller", assess), ("oa_outer_technician", repair), ] { let id = alias(&p, name); let Some(SharedBody::Lifeline { represented }) = p.elements.get_mut(&id).unwrap().shared_mut() else { panic!() }; *represented = Some(work); } for name in ["oa_call", "oa_reply"] { let id = alias(&p, name); let Some(SharedBody::Occurrence { body: OccurrenceBody::Exchange { exchange, .. }, .. }) = p.elements.get_mut(&id).unwrap().shared_mut() else { panic!() }; *exchange = Some(request); } } let issues = validation::validate(&p); assert!( !issues .iter() .any(|i| i.severity == validation::Severity::Error), "{issues:?}" ); let mut bundle = format_bundle(&p); if schema == 5 { let block = " view_options {\n coverage \"All\";\n exchange_labels \"Name\";\n hidden_edges [];\n participant_categories \"All\";\n relation_kinds \"All\";\n work_categories \"All\";\n work_contexts \"All\";\n };\n"; let mut removed = 0; for text in bundle.files.values_mut() { removed += text.matches(block).count(); *text = text.replace(block, ""); } assert_eq!(removed, p.diagrams.len()); } let entry = bundle.files.get_mut(&bundle.entry).unwrap(); *entry = entry.replacen( "arcadia 6;", &format!("// Frozen legacy recovery input 雨.\r\narcadia // profile\r\n {schema};"), 1, ); let compiled = compile_bundle(&bundle, ProjectLimits::default()).unwrap(); assert_eq!(compiled.decoded.project, p); let bytes = if schema == 5 { serde_json::to_vec(&Project5(&p)).unwrap() } else { serde_json::to_vec(&p).unwrap() }; assert_eq!(persistence::decode(&bytes).unwrap(), p); fs::write(out.join(format!("source{schema}-model.json")), &bytes).unwrap(); fs::write( out.join(format!("source{schema}-bundle.json")), serde_json::to_string_pretty(&bundle).unwrap() + "\n", ) .unwrap(); let hash = bytes.iter().fold(0xcbf29ce484222325u64, |h, b| { (h ^ u64::from(*b)).wrapping_mul(0x100000001b3) }); println!( "source{schema}: files={}, elements={}, relations={}, traces={}, fingerprint={hash:016x}", bundle.files.len(), p.elements.len(), p.relations.len(), p.traces.len() ); } }