diff --git a/mps-cli-py/src/mpscli/model/builder/SModelBuilderBinaryPersistency.py b/mps-cli-py/src/mpscli/model/builder/SModelBuilderBinaryPersistency.py new file mode 100644 index 0000000..aebcb7f --- /dev/null +++ b/mps-cli-py/src/mpscli/model/builder/SModelBuilderBinaryPersistency.py @@ -0,0 +1,56 @@ +from mpscli.model.builder.SModelBuilderBase import SModelBuilderBase +import uuid + + +class SModelBuilderBinaryPersistency(SModelBuilderBase): + + # the following constants are taked from the MPS sources found at: + # https://github.com/JetBrains/MPS/blob/f9075b2832077358fd85a15a52bba76a9dad07a3/core/persistence/source/jetbrains/mps/persistence/binary/BinaryPersistence.java#L82 + HEADER_START = 0x91ABABA9 + STREAM_ID_V2 = 0x00000400 + + # https://github.com/JetBrains/MPS/blob/f9075b2832077358fd85a15a52bba76a9dad07a3/core/kernel/source/jetbrains/mps/util/io/ModelOutputStream.java + MODELREF_INDEX = 9 + MODELID_REGULAR = 0x28 + + def build(self, path_to_model): + print("Building binary persistency model from:", path_to_model) + with open(path_to_model, mode='rb') as file: + fileContent = file.read() + header = int.from_bytes(fileContent[:4], byteorder='big') + if header != self.HEADER_START: + raise ValueError("Invalid file format") + streamId = int.from_bytes(fileContent[4:8], byteorder='big') + if streamId != self.STREAM_ID_V2: + raise ValueError("Unsupported stream ID") + modelRef = self.readModelReference(fileContent, 8) + # Implement the binary persistency model building logic here + pass + + + + def readModelReference(self, fileContent, pos): + modelRefIndex = int.from_bytes(fileContent[pos:pos+2], byteorder='big') + if modelRefIndex != self.MODELREF_INDEX: + return self.readModelId(fileContent, pos+2) + pass + + def readModelId(self, fileContent, pos): + print("Reading Model ID at position:", pos) + modelId = int.from_bytes(fileContent[pos:pos+1], byteorder='big') + if modelId == self.MODELID_REGULAR: + return self.readUUID(fileContent, pos+1) + else: + print(f"Error: unhandled model ID type: 0x{modelId:X}") + return None + + + def readUUID(self, fileContent, pos): + headBits = self.readLong(fileContent, pos) + tailBits = self.readLong(fileContent, pos + 8) + uuid_val = uuid.UUID(int=(headBits << 64) | tailBits) + print("------------ UUID:", uuid_val) + return (headBits, tailBits) + + def readLong(self, fileContent, pos): + return int.from_bytes(fileContent[pos:pos+8], byteorder='big') \ No newline at end of file diff --git a/mps-cli-py/src/mpscli/model/builder/SSolutionBuilder.py b/mps-cli-py/src/mpscli/model/builder/SSolutionBuilder.py index b50d345..ad57266 100644 --- a/mps-cli-py/src/mpscli/model/builder/SSolutionBuilder.py +++ b/mps-cli-py/src/mpscli/model/builder/SSolutionBuilder.py @@ -3,7 +3,7 @@ from mpscli.model.SSolution import SSolution from mpscli.model.builder.SModelBuilderDefaultPersistency import SModelBuilderDefaultPersistency from mpscli.model.builder.SModelBuilderFilePerRootPersistency import SModelBuilderFilePerRootPersistency - +from mpscli.model.builder.SModelBuilderBinaryPersistency import SModelBuilderBinaryPersistency class SSolutionBuilder: @@ -20,6 +20,8 @@ def build_solution(self, path_to_msd_file): for path_to_model in path_to_models_dir.iterdir(): if path_to_model.is_dir(): builder = SModelBuilderFilePerRootPersistency() + elif path_to_model.suffix == ".mpb": + builder = SModelBuilderBinaryPersistency() else: builder = SModelBuilderDefaultPersistency() model = builder.build(path_to_model) diff --git a/mps-cli-py/tests/test_binary_persistency_low_level_access.py b/mps-cli-py/tests/test_binary_persistency_low_level_access.py new file mode 100644 index 0000000..c1319fb --- /dev/null +++ b/mps-cli-py/tests/test_binary_persistency_low_level_access.py @@ -0,0 +1,18 @@ + +from mpscli.model.builder.SModelBuilderBinaryPersistency import SModelBuilderBinaryPersistency +from tests.test_base import TestBase + + +class TestBinaryPersistencyLowLevelAccess(TestBase): + + def testReadModelId(self): + path_to_model = "../mps_test_projects/mps_cli_binary_persistency_generated_low_level_access_test_data/mps.cli.lanuse.library_top.binary_persistency.authors_top.mpb" + with open(path_to_model, mode='rb') as file: + fileContent = file.read() + binaryPersistencyReader = SModelBuilderBinaryPersistency() + modelId = binaryPersistencyReader.readModelId(fileContent, 9) + + self.assertEqual('cf91f372-8bfd-44b8-8e34-024eb23e64a8', modelId) + # Test reading model reference + pass + diff --git a/mps-cli-py/tests/test_nodes.py b/mps-cli-py/tests/test_nodes.py index da31f10..12a9031 100644 --- a/mps-cli-py/tests/test_nodes.py +++ b/mps-cli-py/tests/test_nodes.py @@ -11,7 +11,9 @@ class TestNodes(TestBase): ('mps_cli_lanuse_default_persistency', 'mps.cli.lanuse.library_top.default_persistency.authors_top'), ('mps_cli_lanuse_binary', - 'mps.cli.lanuse.library_top.authors_top')]) + 'mps.cli.lanuse.library_top.authors_top'), + ('mps_cli_binary_persistency_generated', + 'mps.cli.lanuse_binary_persistency.library_top.authors_top')]) def test_build_root_nodes(self, test_data_location, library_top_authors_top_model_name): """ Test the building of root nodes diff --git a/mps-cli-rs/Cargo.lock b/mps-cli-rs/Cargo.lock index 3a21c1a..f9f2123 100644 --- a/mps-cli-rs/Cargo.lock +++ b/mps-cli-rs/Cargo.lock @@ -236,6 +236,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -279,6 +291,16 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.155" @@ -326,7 +348,9 @@ dependencies = [ name = "mps-cli" version = "0.1.0" dependencies = [ + "byteorder", "roxmltree", + "uuid", "walkdir", "zip", ] @@ -389,6 +413,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.8.5" @@ -416,7 +446,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -425,6 +455,12 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "same-file" version = "1.0.6" @@ -539,6 +575,17 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "uuid" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "version_check" version = "0.9.5" @@ -561,6 +608,60 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +dependencies = [ + "unicode-ident", +] + [[package]] name = "winapi" version = "0.3.9" @@ -592,6 +693,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + [[package]] name = "zeroize" version = "1.8.1" diff --git a/mps-cli-rs/Cargo.toml b/mps-cli-rs/Cargo.toml index b1ad443..9fa532f 100644 --- a/mps-cli-rs/Cargo.toml +++ b/mps-cli-rs/Cargo.toml @@ -17,6 +17,8 @@ std = [] walkdir = "2.5.0" roxmltree = "0.20.0" zip = "2.1.5" +byteorder = "1.5.0" +uuid = { version = "1.19.0", features = ["v4"] } [profile.release] lto = "fat" diff --git a/mps-cli-rs/src/builder/mod.rs b/mps-cli-rs/src/builder/mod.rs index 1fffceb..ba05776 100644 --- a/mps-cli-rs/src/builder/mod.rs +++ b/mps-cli-rs/src/builder/mod.rs @@ -4,5 +4,8 @@ mod ssolution_builder; mod smodel_builder_base; mod smodel_builder_default_persistency; mod smodel_builder_file_per_root_persistency; +mod smodel_builder_binary_persistency; +mod smodel_builder_binary_persistency_utils; +mod smodel_builder_binary_persistency_constants; mod slanguage_builder; mod node_id_utils; diff --git a/mps-cli-rs/src/builder/node_id_utils.rs b/mps-cli-rs/src/builder/node_id_utils.rs index b7cdfc5..e4c9519 100644 --- a/mps-cli-rs/src/builder/node_id_utils.rs +++ b/mps-cli-rs/src/builder/node_id_utils.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -struct NodeIdEncodingUtils { +pub(crate) struct NodeIdEncodingUtils { my_index_chars : String, min_char : u8, my_char_to_value : HashMap, @@ -24,7 +24,8 @@ impl NodeIdEncodingUtils { my_char_to_value : my_char_to_value, } } - + // transforms from a string representing java friendly base 64 encoding + // a string representing its decimal encoding pub(crate) fn decode(&self, uid_string : String) -> String { let mut res = 0; let bytes = uid_string.as_bytes(); @@ -41,6 +42,38 @@ impl NodeIdEncodingUtils { return res.to_string(); } + // transforms from a string representing a decimal number to + // a string representing its java friendly base 64 encoding + pub(crate) fn encode(&self, uid_string : String) -> String { + let uid_number = match uid_string.parse::() { + Ok(val) => val, + Err(_) => return String::from("Invalid decimal input"), + }; + + let mut num = uid_number; + let mut res_size = 0; + while num > 0 { + res_size += 1; + num /= 64; + } + if res_size == 0 { + res_size = 1; + } + let mut res: Vec = Vec::with_capacity(res_size as usize); + + let mut num = uid_number; + while num > 0 { + let pos = num % 64; + let crt_char= self.my_index_chars.chars().nth(pos as usize).unwrap(); + res.push(crt_char); + num /= 64; + } + + res.reverse(); + let res: String = res.into_iter().collect(); + return res; + } + } #[cfg(test)] @@ -52,5 +85,6 @@ mod tests { let node_id_utils = NodeIdEncodingUtils::new(); assert_eq!("5731700211660045983", node_id_utils.decode(String::from("4Yb5JA31NUv"))); + assert_eq!("4Yb5JA31NUv", node_id_utils.encode(String::from("5731700211660045983"))); } } \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_base.rs b/mps-cli-rs/src/builder/smodel_builder_base.rs index a4c0ef2..bae129e 100644 --- a/mps-cli-rs/src/builder/smodel_builder_base.rs +++ b/mps-cli-rs/src/builder/smodel_builder_base.rs @@ -31,7 +31,7 @@ impl SModelBuilderCache { } } - fn get_model(&mut self, name : String, uuid : String) -> Rc> { + pub(crate) fn get_model(&mut self, name : String, uuid : String) -> Rc> { if let Some(model) = self.index_2_model.get(&uuid) { Rc::clone(&model) } else { diff --git a/mps-cli-rs/src/builder/smodel_builder_binary_persistency.rs b/mps-cli-rs/src/builder/smodel_builder_binary_persistency.rs new file mode 100644 index 0000000..1073093 --- /dev/null +++ b/mps-cli-rs/src/builder/smodel_builder_binary_persistency.rs @@ -0,0 +1,444 @@ +use std::{cell::RefCell, collections::HashMap, io::Read, path::PathBuf, rc::Rc}; + +use crate::model::sconcept::{SConcept, SContainmentLink, SProperty, SReferenceLink}; +use crate::model::{slanguage::SLanguage, smodel::SModel}; +use crate::model::snode::SNode; +use super::{slanguage_builder::SLanguageBuilder, smodel_builder_base::{SModelBuilderCache}}; +use std::io::Cursor; +use byteorder::{BigEndian, ReadBytesExt}; +use crate::builder::smodel_builder_binary_persistency_constants::*; +use crate::builder::smodel_builder_binary_persistency_utils::*; +use super::slanguage_builder::{get_or_build_language}; +use crate::builder::node_id_utils::NodeIdEncodingUtils; + +pub(crate) fn build_model<'a>(mpb_file: PathBuf, + language_id_to_slanguage: &'a mut HashMap, + language_builder : &mut SLanguageBuilder, + model_builder_cache : &mut SModelBuilderCache) -> Rc> { + let ext = mpb_file.extension(); + if !ext.is_some_and(|e| e.eq_ignore_ascii_case("mpb")) { + panic!("expected file with extension .mpb but found '{}'", mpb_file.to_str().unwrap()); + } + + println!(".........reading file: {}", mpb_file.to_str().unwrap()); + + let file = std::fs::File::open(mpb_file.clone()); + if file.is_err() { + panic!("error while opening the file '{}'", mpb_file.to_str().unwrap()); + } + + let mut buffer = Vec::new(); + file.unwrap().read_to_end(&mut buffer).expect("failed to read file as binary"); + + let mut cursor: Cursor<&Vec> = Cursor::new(&buffer); + + let mut my_model_refs= Vec::>>::new(); + let mut my_strings= Vec::::new(); + + let mut crt_model : Rc> = read_model_header(&mut cursor, &mpb_file, &mut my_model_refs, &mut my_strings, model_builder_cache); + + load_model_properties(&mut cursor, &mpb_file, model_builder_cache, language_builder, language_id_to_slanguage, crt_model.clone(), &mut my_strings); + + advance_cursor_until_after(&mut cursor, MODEL_START); + read_children(&mut cursor, None, model_builder_cache, &mut my_strings, crt_model.clone()); + + return crt_model; +} + + +pub(crate) fn read_children(cursor: &mut Cursor<&Vec>, parent : Option>, model_builder_cache : &mut SModelBuilderCache, my_strings: &mut Vec, model : Rc>) { + let child_count : u32 = cursor.read_u32::().expect("failed to read u32 child count"); + println!("...child count: {}", child_count); + for _ in 0..child_count { + let rootNode: Rc = read_node(cursor, parent.clone(), model_builder_cache, my_strings, model.clone()); + if parent.is_none() { + model.borrow_mut().root_nodes.push(rootNode); + } + } +} + + +pub(crate) fn read_node(cursor: &mut Cursor<&Vec>, parent : Option>, model_builder_cache : &mut SModelBuilderCache, my_strings: &mut Vec, model : Rc>) -> Rc { + let node_id_utils : NodeIdEncodingUtils = NodeIdEncodingUtils::new(); + + let concept_index: u16 = cursor.read_u16::().expect("failed to read u16 concept index"); + let concept: &Rc = model_builder_cache.index_2_concept.get(&concept_index.to_string()).expect("concept not found by index"); + + let mut nodeid: String = read_node_id(cursor, my_strings); + + nodeid = node_id_utils.encode(nodeid); + let mut node= SNode::new(nodeid.clone(), concept.clone(), None); + println!("...node: {} - {}", nodeid, concept.name); + + let aggregation_index : u16 = cursor.read_u16::().expect("failed to read u16 aggregation index"); + + let open_curly: char = cursor.read_u8().expect("failed to read u8") as char; + if open_curly != '{' { + panic!("bad stream, no '{{'"); + } + + let properties_count : u16 = cursor.read_u16::().expect("failed to read u16 properties count"); + println!("...properties count: {}", properties_count); + for _ in 0..properties_count { + let property_index: u16 = cursor.read_u16::().expect("failed to read u16"); + let property: &Rc = model_builder_cache.index_2_property.get(&property_index.to_string()).expect("property not found by index"); + let property_value = read_string(cursor, my_strings); + println!("......property: {} - {}", property.name, property_value); + node.add_property(property, property_value); + } + + let user_objects_count : u16 = cursor.read_u16::().expect("failed to read u16 user-objects count"); + if user_objects_count !=0 { + panic!("user-objects are not supported yet"); + } + + let references_count : u16 = cursor.read_u16::().expect("failed to read u16 references count"); + println!("...references count: {}", references_count); + for _ in 0..references_count { + let reference_index: u16 = cursor.read_u16::().expect("failed to read u16"); + let reference: &Rc = model_builder_cache.index_2_reference_link.get(&reference_index.to_string()).expect("reference not found by index"); + + let kind : u8 = cursor.read_u8().expect("failed to read u8"); + if kind != 1 && kind != 2 && kind != 3 { + panic!("unknown reference kind: {}", kind); + } + if kind == 1 { + let mut reference_nodeid = read_node_id(cursor, my_strings); + reference_nodeid = node_id_utils.encode(reference_nodeid); + println!("......reference node id: {}", reference_nodeid); + let mut target_model_kind: u8 = cursor.read_u8().expect("failed to read u8"); + if (target_model_kind != REF_OTHER_MODEL && target_model_kind != REF_THIS_MODEL) { + panic!("unknown target model kind: {}", target_model_kind); + } + let mut model_ref_id : String; + if (target_model_kind == REF_OTHER_MODEL) { + model_ref_id = read_model_reference(cursor, model_builder_cache); + } else { // THIS_MODEL + model_ref_id = model.borrow().uuid.clone(); + } + + let resolve_info = read_string(cursor, my_strings); + node.add_reference(reference, model_ref_id.clone(), reference_nodeid.clone(), Some(resolve_info.clone())); + println!("......reference: {} - {}@{} - resolveInfo: {}", reference.name, model_ref_id, reference_nodeid, resolve_info); + } else { + panic!("reference kinds 2 and 3 are not supported yet"); + } + } + + let node_rc : Rc ; + if let Some(parent) = parent { + let link: &Rc = model_builder_cache.index_2_containment_link.get(&aggregation_index.to_string()).expect("link not found by index"); + node.role_in_parent = Some(link.name.clone()); + node_rc = Rc::new(node); + parent.add_child(link.clone(), node_rc.clone()); + } else { + node_rc = Rc::new(node); + } + + read_children(cursor, Some(node_rc.clone()), model_builder_cache, my_strings, model); + + let closed_curly: char = cursor.read_u8().expect("failed to read u8") as char; + if closed_curly != '}' { + panic!("bad stream, no '}}'"); + } + + return node_rc; +} + +// ToDo: we currently only SKIP over module references +pub(crate) fn read_module_reference(cursor: &mut Cursor<&Vec>, my_strings: &mut Vec) { + let c = cursor.read_u8().expect("failed to read u8"); + if c == NULL { + // do nothing + } else if c == MODULEREF_NAMEONLY { + read_string(cursor, my_strings); + } else if c == MODULEREF_INDEX { + cursor.read_u32::().expect("failed to read u32"); + // we do nothing with this information + } else if c == MODULEREF_MODULEID { + let c = cursor.read_u8().expect("failed to read u8"); + if c == NULL { + // do nothing + } else if c == MODULEID_REGULAR { + read_uuid(cursor); + } else if c == MODULEID_FOREIGN { + read_string(cursor, my_strings); + } + } else { + panic!("unknown model reference format 0x{:X}", c); + } +} + +pub(crate) fn read_model_reference(cursor: &mut Cursor<&Vec>, model_builder_cache : &SModelBuilderCache) -> String { + let c = cursor.read_u8().expect("failed to read u8"); + if c == MODELREF_INDEX { + let model_index: u32 = cursor.read_u32::().expect("failed to read u32"); + println!("......model reference by index: {}", model_index); + return model_builder_cache.index_2_imported_model_uuid.get(&model_index.to_string()).expect("model id not found by index").to_string(); + } else { + panic!("unexpected model reference format 0x{:X}", c); + } +} + +pub(crate) fn read_and_add_model_reference(cursor: &mut Cursor<&Vec>, model_builder_cache : &mut SModelBuilderCache, my_strings: &mut Vec, index : String) -> (String, String) { + let c = cursor.read_u8().expect("failed to read u8"); + if c == MODELREF_INDEX { + panic!("unexpected MODELREF_INDEX when reading and adding model reference"); + } + + let mut model_id = read_model_id(cursor); + let _model_name = read_string(cursor, my_strings); + read_module_reference(cursor, my_strings); + model_builder_cache.index_2_imported_model_uuid.insert(index.clone(), model_id.clone()); + println!("......imported model: {} - {}", model_id, _model_name); + println!("......imported model reference added at index: {}", index); + return (model_id, _model_name); +} + +pub(crate) fn read_node_id(cursor: &mut Cursor<&Vec>, my_strings: &mut Vec) -> String { + let mut nodeid: String = "".to_string(); + let c : u8 = cursor.read_u8().expect("failed to read u8"); + if c == NODEID_LONG { + let long_id: u64 = cursor.read_u64::().expect("failed to read u64"); + nodeid = format!("{}", long_id); + } else if c == NODEID_STRING { + nodeid = read_string(cursor, my_strings); + } + return nodeid; +} + +// BinaryPersistency::loadModelProperties +pub(crate) fn load_model_properties(cursor: &mut Cursor<&Vec>, + mpb_file: &PathBuf, + model_builder_cache: &mut SModelBuilderCache, + language_builder : &mut SLanguageBuilder, + language_id_to_slanguage: &mut HashMap, + model : Rc>, + my_strings: &mut Vec) { + advance_cursor_until_after(cursor, REGISTRY_START); + load_registry(cursor, model_builder_cache, my_strings,language_builder, language_id_to_slanguage); + advance_cursor_until_after(cursor, REGISTRY_END); + + //BinaryPersistence::loadUsedLanguages + let used_languages_count = cursor.read_u16::().expect("failed to read u16 used languages count"); + println!("...languages count: {}", used_languages_count); + for _ in 0..used_languages_count { + let lang_id = read_uuid(cursor); + let lang_name = read_string(cursor, my_strings); + println!("...used language: {} - {}", lang_id, lang_name); + // we do nothing with this information + } + + //engaged in generation + load_module_ref_list(cursor, my_strings); + //used devkits + load_module_ref_list(cursor, my_strings); + + //BinaryPersistence::loadImports + let imports_count : u32 = cursor.read_u32::().expect("failed to read u32 imports count"); + println!("...imports count: {}", imports_count); + for import_index in 0..imports_count { + //TODO: FIXME we use "import_index + 1" since the first element is the current model + read_and_add_model_reference(cursor, model_builder_cache, my_strings, (import_index + 1).to_string()); + } + +} + +//BinaryPersistence::loadModuleRefList +pub(crate) fn load_module_ref_list(cursor: &mut Cursor<&Vec>, my_strings: &mut Vec) { + let modules_ref_count : u16 = cursor.read_u16::().expect("failed to read u16 modules ref count"); + println!("...modules ref count: {}", modules_ref_count); + for _ in 0..modules_ref_count { + read_module_reference(cursor, my_strings) + } +} + +pub(crate) fn load_registry(cursor: &mut Cursor<&Vec>, + model_builder_cache: &mut SModelBuilderCache, + my_strings: &mut Vec, + language_builder : &mut SLanguageBuilder, + language_id_to_slanguage: &mut HashMap) { + let lan_count : u16 = cursor.read_u16::().expect("failed to read u16 language count"); + println!("...language count: {}", lan_count); + let mut concept_index: u32 = 0; + let mut property_index: u32 = 0; + let mut reference_link_index: u32 = 0; + let mut aggregation_link_index: u32 = 0; + for _ in 0..lan_count { + let lan_id = read_uuid(cursor); + let lan_name = read_string(cursor, my_strings); + + let lang = get_or_build_language(&lan_id.to_string(), &lan_name.to_string(), language_id_to_slanguage); + println!("...language: {} - {}", lan_id, lan_name); + + let concept_count : u16 = cursor.read_u16::().expect("failed to read u16 concept count"); + println!("...concept count: {}", concept_count); + for _ in 0..concept_count { + let concept_id = cursor.read_u64::().expect("failed to read u64 concept id"); + let concept_name = read_string(cursor, my_strings); + + // not used + let flags = cursor.read_u8().expect("failed to read u8 flags"); + let stub_token = cursor.read_u8().expect("failed to read u8 stubToken"); + print!("...concept flags: 0x{:X}, stubToken: 0x{:X}", flags, stub_token); + + let full_concept_name = format!("{}.structure.{}", lan_name, concept_name); + let conc = language_builder.get_or_create_concept(lang, concept_id.to_string().as_str(), full_concept_name.as_str()); + model_builder_cache.index_2_concept.insert(concept_index.to_string(), Rc::clone(&conc)); + concept_index += 1; + println!("......concept: {} - {}", conc.name, concept_name); + + let property_count : u16 = cursor.read_u16::().expect("failed to read u16 property count"); + println!("...property count: {}", property_count); + for _ in 0..property_count { + let prop_id = cursor.read_u64::().expect("failed to read u64 property id"); + let prop_name = read_string(cursor, my_strings); + let _prop = language_builder.get_or_create_property(Rc::clone(&conc), prop_id.to_string(), prop_name); + model_builder_cache.index_2_property.insert(property_index.to_string(), Rc::clone(&_prop)); + property_index += 1; + println!("......property: {} - {}", prop_id, _prop.name); + } + + let association_count : u16 = cursor.read_u16::().expect("failed to read u16 association count"); + println!("...association count: {}", association_count); + for _ in 0..association_count { + let link_id = cursor.read_u64::().expect("failed to read u64 link id"); + let link_name = read_string(cursor, my_strings); + let _link = language_builder.get_or_create_reference(Rc::clone(&conc), link_id.to_string(), link_name); + model_builder_cache.index_2_reference_link.insert(reference_link_index.to_string(), Rc::clone(&_link)); + reference_link_index += 1; + println!("......property: {} - {}", link_id, _link.name); + + } + + let aggregation_count : u16 = cursor.read_u16::().expect("failed to read u16 aggregation count"); + println!("...aggregation count: {}", aggregation_count); + for _ in 0..aggregation_count { + let link_id = cursor.read_u64::().expect("failed to read u64 link id"); + let link_name = read_string(cursor, my_strings); + let unordered = cursor.read_u8().expect("failed to read u8 unordered") != 0; + let _link = language_builder.get_or_create_child(Rc::clone(&conc), link_id.to_string(), link_name); + model_builder_cache.index_2_containment_link.insert(aggregation_link_index.to_string(), Rc::clone(&_link)); + aggregation_link_index += 1; + println!("......aggregation link: {} - {}", link_id, _link.name); + } + } + } +} + +pub(crate) fn read_model_header(cursor: &mut Cursor<&Vec>, + mpb_file: &PathBuf, + my_model_refs: &mut Vec>>, + my_strings: &mut Vec, + model_builder_cache: &mut SModelBuilderCache) -> Rc> { + + let crt_model : Rc>; + let header = cursor.read_u32::().expect("failed to read u32 header"); + if !(header == HEADER_START) { + panic!("unexpected header: 0x{:X} in file {}", header, mpb_file.to_str().unwrap()); + } + let stream_id = cursor.read_u32::().expect("failed to read u32 streamId"); + if stream_id != STREAM_ID { + panic!("unexpected stream ID: 0x{:X} in file {}", stream_id, mpb_file.to_str().unwrap()); + } + + let crt_byte= cursor.read_u8().expect("failed to read u8 crtByte"); + if crt_byte == NULL { + panic!("unexpected byte NULL but model_ref in file {}", mpb_file.to_str().unwrap()); + } else if crt_byte == MODELREF_INDEX { + let index = cursor.read_u32::().expect("failed to read u32 modelRefIndex") as usize; + crt_model = my_model_refs[index].clone(); + } else { + let model_id = read_model_id(cursor); + let model_name = read_string(cursor, my_strings); + crt_model = model_builder_cache.get_model(model_name.clone(), model_id.clone()); + println!("...model: {} - {}", model_id, model_name); + model_builder_cache.index_2_imported_model_uuid.insert("0".to_string(), model_id.clone()); + + advance_cursor_until_after(cursor, HEADER_END); + + my_model_refs.push(crt_model.clone()); + } + + return crt_model; +} + +pub(crate) fn read_model_id(cursor: &mut Cursor<&Vec>) -> String { + let c = cursor.read_u8().expect("failed to read u8"); + if c == NULL { + return "".to_string(); + } else if c == MODELID_REGULAR { + let uuid = read_uuid(cursor); + let model_id = format!("r:{}", uuid); + return model_id; + } else { + panic!("unknown id format 0x{:X}", c); + } +} + +#[cfg(test)] +mod tests { + use byteorder::WriteBytesExt; + use uuid::Uuid; + +use super::*; + + #[test] + fn test_read_model_header_regular_model() { + let model_name = "TestModel"; + let model_id = "31323334-3536-3738-3334-323334326565"; + + let mut buf = Vec::new(); + // HEADER_START + buf.write_u32::(HEADER_START).unwrap(); + // STREAM_ID + buf.write_u32::(STREAM_ID).unwrap(); + + // Not NULL, not MODELREF_INDEX, so use MODELID_REGULAR + buf.write_u8(MODELID_REGULAR).unwrap(); + // use MODELID_REGULAR (not MODELID_FOREIGN, or MODELID_STRING) + buf.write_u8(MODELID_REGULAR).unwrap(); + // Write UUID (simulate) + let uuid = Uuid::parse_str(&model_id).unwrap(); + let uuid_bytes = uuid.as_bytes(); + buf.extend_from_slice(uuid_bytes); + // Write model name as string (simulate) + buf.write_u8(2).unwrap(); // 1 means string taken from index, we use 2 + let name_bytes = model_name.as_bytes(); + buf.write_u16::(name_bytes.len() as u16).unwrap(); + buf.extend_from_slice(name_bytes); + // HEADER_END + buf.write_u32::(HEADER_END).unwrap(); + // Next byte after model + buf.write_u8(0xAA).unwrap(); + + let mut cursor = Cursor::new(&buf); + let mpb_file = PathBuf::from("test.mpb"); + let mut my_model_refs = Vec::>>::new(); + let mut my_strings = Vec::::new(); + let mut cache = SModelBuilderCache::new(); + + let model_rc = read_model_header(&mut cursor, &mpb_file, &mut my_model_refs, &mut my_strings, &mut cache); + + let model = model_rc.borrow(); + assert_eq!(model.name, model_name); + assert_eq!(model.uuid, format!("r:{}", model_id)); + } + + #[test] + #[should_panic(expected = "unexpected header: 0xDEADBEEF in file test.mpb")] + fn test_read_model_header_invalid_header() { + let mut buf = Vec::new(); + buf.write_u32::(0xDEADBEEF).unwrap(); // Invalid header + buf.write_u32::(STREAM_ID).unwrap(); + buf.write_u8(MODELID_REGULAR).unwrap(); + let mut cursor = Cursor::new(&buf); + + let mpb_file = PathBuf::from("test.mpb"); + let mut my_model_refs = Vec::>>::new(); + let mut my_strings = Vec::::new(); + let mut cache = SModelBuilderCache::new(); + + let _ = read_model_header(&mut cursor, &mpb_file, &mut my_model_refs, &mut my_strings, &mut cache); + } +} diff --git a/mps-cli-rs/src/builder/smodel_builder_binary_persistency_constants.rs b/mps-cli-rs/src/builder/smodel_builder_binary_persistency_constants.rs new file mode 100644 index 0000000..cef5724 --- /dev/null +++ b/mps-cli-rs/src/builder/smodel_builder_binary_persistency_constants.rs @@ -0,0 +1,35 @@ + +// the following constants are taken from +// https://github.com/JetBrains/MPS/blob/f9075b2832077358fd85a15a52bba76a9dad07a3/core/persistence/source/jetbrains/mps/persistence/binary/BinaryPersistence.java +pub const HEADER_START : u32 = 0x91ABABA9; +pub const HEADER_END : u32 = 0xabababab; +pub const STREAM_ID_V2 : u32 = 0x00000400; +pub const STREAM_ID : u32 = STREAM_ID_V2; + +pub const REGISTRY_START : u32 = 0x5a5a5a5a; +pub const REGISTRY_END : u32 = 0xa5a5a5a5; + +pub const MODEL_START:u32 = 0xbabababa; + +// the following constants are taken from +// https://github.com/JetBrains/MPS/blob/f9075b2832077358fd85a15a52bba76a9dad07a3/core/kernel/source/jetbrains/mps/util/io/ModelOutputStream.java +pub const NULL: u8 = 0x70; +pub const MODELREF_INDEX: u8 = 9; +pub const MODELID_REGULAR: u8 = 0x28; +pub const CONCEPT_INDEX: u8 = 0x33; +pub const NODEID_STRING: u8 = 0x17; +pub const NODEID_LONG: u8 = 0x18; +pub const PROPERTY: u8 = 0x34; +pub const PROPERTY_INDEX: u8 = 0x35; + +pub const MODULEID_FOREIGN: u8 = 0x47; +pub const MODULEID_REGULAR: u8 = 0x48; +pub const MODULEREF_MODULEID: u8 = 0x17; +pub const MODULEREF_NAMEONLY: u8 = 0x18; +pub const MODULEREF_INDEX: u8 = 0x19; + + +// the following constants are taken from +// https://github.com/JetBrains/MPS/blob/master/core/persistence/source/jetbrains/mps/persistence/binary/BareNodeWriter.java +pub const REF_THIS_MODEL: u8 = 17; +pub const REF_OTHER_MODEL: u8 = 18; \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodel_builder_binary_persistency_utils.rs b/mps-cli-rs/src/builder/smodel_builder_binary_persistency_utils.rs new file mode 100644 index 0000000..3ce773d --- /dev/null +++ b/mps-cli-rs/src/builder/smodel_builder_binary_persistency_utils.rs @@ -0,0 +1,59 @@ +use std::io::{Cursor, Read}; +use byteorder::{BigEndian, ReadBytesExt}; +use uuid::Uuid; +use crate::builder::smodel_builder_binary_persistency_constants::*; + + +pub(crate) fn read_uuid(cursor: &mut Cursor<&Vec>) -> String { + let head_bits = cursor.read_u64::().expect("failed to read u64 head_bits"); + let tail_bits = cursor.read_u64::().expect("failed to read u64 tail_bits"); + return Uuid::from_u64_pair(head_bits, tail_bits).as_hyphenated().to_string(); +} + +pub(crate) fn read_string(cursor: &mut Cursor<&Vec>, my_strings: &mut Vec) -> String { + let c = cursor.read_u8().expect("failed to read u8"); + if c == NULL { + return "".to_string(); + } else if c == 1 { + let index = cursor.read_u32::().expect("failed to read u32") as usize; + return my_strings[index].clone(); + } + + let string_size = cursor.read_u16::().expect("failed to read u32") as usize; + println!(".........reading string of size: {}", string_size); + + let mut sb = String::new(); + let mut buf = vec![0u8; string_size]; + cursor.read_exact(&mut buf).expect("failed to read string bytes"); + sb.push_str(&String::from_utf8_lossy(&buf)); + my_strings.push(sb.clone()); + + println!(".........reading string: {}", sb); + return sb; + } + + pub(crate) fn advance_cursor_until_after(cursor: &mut Cursor<&Vec>, marker: u32) { + let mut current_pos = cursor.position(); + let end_pos = cursor.get_ref().len() as u64; + + while current_pos < end_pos { + let byte = cursor.read_u8().expect("failed to read u8"); + // Read 4 bytes and compare to marker (u32) + if current_pos + 4 <= end_pos { + let mut buf = [0u8; 4]; + buf[0] = byte; + cursor.read_exact(&mut buf[1..]).expect("failed to read marker bytes"); + let found = u32::from_be_bytes(buf); + if found == marker { + return; + } else { + // Move back 3 bytes to check next possible 4-byte window + cursor.set_position(cursor.position() - 3); + current_pos = cursor.position(); + } + } else { + break; + } + current_pos += 1; + } + } \ No newline at end of file diff --git a/mps-cli-rs/src/builder/smodules_repository_builder.rs b/mps-cli-rs/src/builder/smodules_repository_builder.rs index 12b8978..5d794b3 100644 --- a/mps-cli-rs/src/builder/smodules_repository_builder.rs +++ b/mps-cli-rs/src/builder/smodules_repository_builder.rs @@ -1,11 +1,8 @@ use std::collections::HashMap; -use std::fs::File; -use std::io::Error; use std::path::PathBuf; use std::time::Instant; use walkdir::WalkDir; -use zip::ZipArchive; use crate::builder::slanguage_builder::SLanguageBuilder; use crate::builder::smodel_builder_base::SModelBuilderCache; diff --git a/mps-cli-rs/src/builder/ssolution_builder.rs b/mps-cli-rs/src/builder/ssolution_builder.rs index fd40143..b34d46a 100644 --- a/mps-cli-rs/src/builder/ssolution_builder.rs +++ b/mps-cli-rs/src/builder/ssolution_builder.rs @@ -7,8 +7,10 @@ use walkdir::WalkDir; use crate::builder::smodel_builder_file_per_root_persistency; use crate::builder::smodel_builder_default_persistency; +use crate::builder::smodel_builder_binary_persistency; use crate::builder::slanguage_builder::SLanguageBuilder; use crate::model::slanguage::SLanguage; +use crate::model::smodel; use crate::model::ssolution::SSolution; use super::smodel_builder_base::SModelBuilderCache; @@ -27,8 +29,10 @@ pub(crate) fn build_solution<'a>(path_buf_to_msd_file: &PathBuf, language_id_to_ let path = model_entry.unwrap().into_path(); let model = if path.is_dir() { smodel_builder_file_per_root_persistency::build_model(path, language_id_to_slanguage, language_builder, model_builder_cache) - } else { + } else if path.extension().is_some_and(|e| e.eq_ignore_ascii_case("mps")) { smodel_builder_default_persistency::build_model(path, language_id_to_slanguage, language_builder, model_builder_cache) + } else { + smodel_builder_binary_persistency::build_model(path, language_id_to_slanguage, language_builder, model_builder_cache) }; models.push(model) } diff --git a/mps-cli-rs/tests/binary_persistency_tests.rs b/mps-cli-rs/tests/binary_persistency_tests.rs new file mode 100644 index 0000000..bfda8f4 --- /dev/null +++ b/mps-cli-rs/tests/binary_persistency_tests.rs @@ -0,0 +1,9 @@ +mod model_completeness_tests; +use mps_cli::build_repo_from_directory; + +#[test] +fn test_build_repository() { + let path = "../mps_test_projects/mps_cli_binary_persistency_generated/"; + let repo = build_repo_from_directory(path.to_string()); + model_completeness_tests::check_model_completeness(&repo, "mps.cli.lanuse.library_top.binary_persistency", "mps.cli.lanuse.library_second.binary_persistency"); +} \ No newline at end of file diff --git a/mps-cli-rs/tests/binary_persistency_utils_tests.rs b/mps-cli-rs/tests/binary_persistency_utils_tests.rs new file mode 100644 index 0000000..bfda8f4 --- /dev/null +++ b/mps-cli-rs/tests/binary_persistency_utils_tests.rs @@ -0,0 +1,9 @@ +mod model_completeness_tests; +use mps_cli::build_repo_from_directory; + +#[test] +fn test_build_repository() { + let path = "../mps_test_projects/mps_cli_binary_persistency_generated/"; + let repo = build_repo_from_directory(path.to_string()); + model_completeness_tests::check_model_completeness(&repo, "mps.cli.lanuse.library_top.binary_persistency", "mps.cli.lanuse.library_second.binary_persistency"); +} \ No newline at end of file diff --git a/mps-cli-rs/tests/model_completeness_tests.rs b/mps-cli-rs/tests/model_completeness_tests.rs index 86b26a3..5a17027 100644 --- a/mps-cli-rs/tests/model_completeness_tests.rs +++ b/mps-cli-rs/tests/model_completeness_tests.rs @@ -11,7 +11,7 @@ pub (crate) fn check_model_completeness(repo : &SRepository, library_top_solutio assert!(library_first_solution.find_model((library_top_solution_name.to_owned() + ".library_top").as_str()).is_some()); let library_top_model = repo.find_model_by_name((library_top_solution_name.to_owned() + ".library_top").as_str()).unwrap(); - let library_top_model : Ref = library_top_model.try_borrow().ok().unwrap(); + let library_top_model : Ref = library_top_model.try_borrow().ok().unwrap(); assert_eq!(library_top_model.root_nodes.len(), 2); let munich_library_root = library_top_model.root_nodes.iter().find(|r| r.get_property("name") == Some(String::from("munich_library"))); assert!(munich_library_root.is_some()); @@ -38,6 +38,8 @@ pub (crate) fn check_model_completeness(repo : &SRepository, library_top_solutio assert_eq!(mark_twain.resolve_info, "Mark Twain"); if library_top_solution_name.contains("default_persistency") { assert_eq!(mark_twain.model_id, "r:ca00da79-915e-4bdb-9c30-11a341daf779"); + } else if library_top_solution_name.contains("binary_persistency") { + assert_eq!(mark_twain.model_id, "r:cf91f372-8bfd-44b8-8e34-024eb23e64a8"); } else { assert_eq!(mark_twain.model_id, "r:ec5f093b-9d83-43a1-9b41-b5952da8b1ed"); } diff --git a/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.landefs.library-src.jar b/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.landefs.library-src.jar new file mode 100644 index 0000000..3dcec65 Binary files /dev/null and b/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.landefs.library-src.jar differ diff --git a/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.landefs.people-src.jar b/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.landefs.people-src.jar new file mode 100644 index 0000000..59e147b Binary files /dev/null and b/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.landefs.people-src.jar differ diff --git a/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.lanuse.library_second.binary_persistency-src.jar b/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.lanuse.library_second.binary_persistency-src.jar new file mode 100644 index 0000000..7cf85da Binary files /dev/null and b/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.lanuse.library_second.binary_persistency-src.jar differ diff --git a/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.lanuse.library_top.binary_persistency-src.jar b/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.lanuse.library_top.binary_persistency-src.jar new file mode 100644 index 0000000..e6aebc4 Binary files /dev/null and b/mps_test_projects/mps_cli_binary_persistency_generated/mps.cli.lanuse.library_top.binary_persistency-src.jar differ diff --git a/mps_test_projects/mps_cli_binary_persistency_generated_low_level_access_test_data/mps.cli.lanuse.library_top.binary_persistency.authors_top.mpb b/mps_test_projects/mps_cli_binary_persistency_generated_low_level_access_test_data/mps.cli.lanuse.library_top.binary_persistency.authors_top.mpb new file mode 100644 index 0000000..27fcefa Binary files /dev/null and b/mps_test_projects/mps_cli_binary_persistency_generated_low_level_access_test_data/mps.cli.lanuse.library_top.binary_persistency.authors_top.mpb differ diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/.mps/.gitignore b/mps_test_projects/mps_cli_binary_persistency_sources/.mps/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/.mps/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/.mps/migration.xml b/mps_test_projects/mps_cli_binary_persistency_sources/.mps/migration.xml new file mode 100644 index 0000000..74b8df6 --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/.mps/migration.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/.mps/modules.xml b/mps_test_projects/mps_cli_binary_persistency_sources/.mps/modules.xml new file mode 100644 index 0000000..c5ae371 --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/.mps/modules.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/.mps/vcs.xml b/mps_test_projects/mps_cli_binary_persistency_sources/.mps/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/.mps/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/Readme.md b/mps_test_projects/mps_cli_binary_persistency_sources/Readme.md new file mode 100644 index 0000000..52cc4af --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/Readme.md @@ -0,0 +1,3 @@ +This project contains the solutions used to create and package the library example in binary persistency format. + +- `mps_cli_lanuse_binary_persistency.build` - build solution which when ran generated in the 'build' directory the models in binary persistency diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_second.binary_persistency/models/mps.cli.lanuse.library_second.binary_persistency.library_top.mps b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_second.binary_persistency/models/mps.cli.lanuse.library_second.binary_persistency.library_top.mps new file mode 100644 index 0000000..56d2796 --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_second.binary_persistency/models/mps.cli.lanuse.library_second.binary_persistency.library_top.mps @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_second.binary_persistency/mps.cli.lanuse.library_second.binary_persistency.msd b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_second.binary_persistency/mps.cli.lanuse.library_second.binary_persistency.msd new file mode 100644 index 0000000..ccc69d4 --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_second.binary_persistency/mps.cli.lanuse.library_second.binary_persistency.msd @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + 7c712852-79e9-4a66-9752-404fe92e52e3(mps.cli.lanuse.library_top.binary_persistency) + + + + + + + + + + + + + diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_top.binary_persistency/models/mps.cli.lanuse.library_top.binary_persistency.authors_top.mps b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_top.binary_persistency/models/mps.cli.lanuse.library_top.binary_persistency.authors_top.mps new file mode 100644 index 0000000..975a0a3 --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_top.binary_persistency/models/mps.cli.lanuse.library_top.binary_persistency.authors_top.mps @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_top.binary_persistency/models/mps.cli.lanuse.library_top.binary_persistency.library_top.mps b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_top.binary_persistency/models/mps.cli.lanuse.library_top.binary_persistency.library_top.mps new file mode 100644 index 0000000..44f49ef --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_top.binary_persistency/models/mps.cli.lanuse.library_top.binary_persistency.library_top.mps @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_top.binary_persistency/mps.cli.lanuse.library_top.binary_persistency.msd b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_top.binary_persistency/mps.cli.lanuse.library_top.binary_persistency.msd new file mode 100644 index 0000000..2ba4d14 --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps.cli.lanuse.library_top.binary_persistency/mps.cli.lanuse.library_top.binary_persistency.msd @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps_cli_lanuse_binary_persistency.build/models/mps_cli_lanuse_binary_persistency.build.mps b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps_cli_lanuse_binary_persistency.build/models/mps_cli_lanuse_binary_persistency.build.mps new file mode 100644 index 0000000..14297b6 --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps_cli_lanuse_binary_persistency.build/models/mps_cli_lanuse_binary_persistency.build.mps @@ -0,0 +1,481 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps_cli_lanuse_binary_persistency.build/mps_cli_lanuse_binary_persistency.build.msd b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps_cli_lanuse_binary_persistency.build/mps_cli_lanuse_binary_persistency.build.msd new file mode 100644 index 0000000..e41e1fd --- /dev/null +++ b/mps_test_projects/mps_cli_binary_persistency_sources/solutions/mps_cli_lanuse_binary_persistency.build/mps_cli_lanuse_binary_persistency.build.msd @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + 422c2909-59d6-41a9-b318-40e6256b250f(jetbrains.mps.ide.build) + + + + + + + + + + + + diff --git a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/generator/templates/mps.cli.landefs.library.generator.templates@generator.mps b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/generator/templates/mps.cli.landefs.library.generator.templates@generator.mps index 78b31ea..05a0542 100644 --- a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/generator/templates/mps.cli.landefs.library.generator.templates@generator.mps +++ b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/generator/templates/mps.cli.landefs.library.generator.templates@generator.mps @@ -12,7 +12,7 @@ - + diff --git a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/models/mps.cli.landefs.library.behavior.mps b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/models/mps.cli.landefs.library.behavior.mps index 32f52c3..33b634c 100644 --- a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/models/mps.cli.landefs.library.behavior.mps +++ b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/models/mps.cli.landefs.library.behavior.mps @@ -2,7 +2,7 @@ - + diff --git a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/models/mps.cli.landefs.library.structure.mps b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/models/mps.cli.landefs.library.structure.mps index 6c651f8..2f7085c 100644 --- a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/models/mps.cli.landefs.library.structure.mps +++ b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/models/mps.cli.landefs.library.structure.mps @@ -48,7 +48,7 @@ - + diff --git a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/mps.cli.landefs.library.mpl b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/mps.cli.landefs.library.mpl index 0832d58..35cd23e 100644 --- a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/mps.cli.landefs.library.mpl +++ b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.library/mps.cli.landefs.library.mpl @@ -6,7 +6,7 @@ - + @@ -19,15 +19,15 @@ - + - + - + @@ -38,7 +38,7 @@ - + @@ -54,15 +54,14 @@ - a7aaae55-aa5e-4a05-b2d0-013745658efa(mps.cli.landefs.people) - + - + @@ -86,7 +85,7 @@ - + diff --git a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/generator/templates/mps.cli.landefs.people.generator.templates@generator.mps b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/generator/templates/mps.cli.landefs.people.generator.templates@generator.mps index 3d1ffee..9612231 100644 --- a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/generator/templates/mps.cli.landefs.people.generator.templates@generator.mps +++ b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/generator/templates/mps.cli.landefs.people.generator.templates@generator.mps @@ -12,7 +12,7 @@ - + diff --git a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/models/mps.cli.landefs.people.behavior.mps b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/models/mps.cli.landefs.people.behavior.mps index ff37250..d73e915 100644 --- a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/models/mps.cli.landefs.people.behavior.mps +++ b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/models/mps.cli.landefs.people.behavior.mps @@ -2,7 +2,7 @@ - + diff --git a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/models/mps.cli.landefs.people.structure.mps b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/models/mps.cli.landefs.people.structure.mps index fbc50e0..ee37343 100644 --- a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/models/mps.cli.landefs.people.structure.mps +++ b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/models/mps.cli.landefs.people.structure.mps @@ -31,7 +31,7 @@ - + diff --git a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/mps.cli.landefs.people.mpl b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/mps.cli.landefs.people.mpl index e9588cb..0f56da9 100644 --- a/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/mps.cli.landefs.people.mpl +++ b/mps_test_projects/mps_cli_landefs/languages/mps.cli.landefs.people/mps.cli.landefs.people.mpl @@ -6,7 +6,7 @@ - + @@ -19,15 +19,15 @@ - + - + - + @@ -38,7 +38,7 @@ - + @@ -54,12 +54,11 @@ - - + - + @@ -83,7 +82,7 @@ - + diff --git a/mps_test_projects/mps_cli_lanuse_default_persistency/.mps/vcs.xml b/mps_test_projects/mps_cli_lanuse_default_persistency/.mps/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/mps_test_projects/mps_cli_lanuse_default_persistency/.mps/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file