From 2fb2342fd464d1586d1581b3d8d070492719bd6b Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Thu, 29 Aug 2019 17:13:36 -0700 Subject: [PATCH] Fix Lua snapshot code to work with children. It's also way easier to read now --- .../build-tests/init_with_children/init.lua | 1 + .../build-tests/init_with_children/other.lua | 1 + rojo-test/src/build_test.rs | 1 + .../build_test__init_with_children.snap | 20 +++ src/snapshot_middleware/lua.rs | 144 +++++++++++------- 5 files changed, 111 insertions(+), 56 deletions(-) create mode 100644 rojo-test/build-tests/init_with_children/init.lua create mode 100644 rojo-test/build-tests/init_with_children/other.lua create mode 100644 rojo-test/src/snapshots/build_test__init_with_children.snap diff --git a/rojo-test/build-tests/init_with_children/init.lua b/rojo-test/build-tests/init_with_children/init.lua new file mode 100644 index 00000000..1bdba462 --- /dev/null +++ b/rojo-test/build-tests/init_with_children/init.lua @@ -0,0 +1 @@ +-- init.lua \ No newline at end of file diff --git a/rojo-test/build-tests/init_with_children/other.lua b/rojo-test/build-tests/init_with_children/other.lua new file mode 100644 index 00000000..2cf052cf --- /dev/null +++ b/rojo-test/build-tests/init_with_children/other.lua @@ -0,0 +1 @@ +-- other.lua \ No newline at end of file diff --git a/rojo-test/src/build_test.rs b/rojo-test/src/build_test.rs index 2a8676b7..7a85d0df 100644 --- a/rojo-test/src/build_test.rs +++ b/rojo-test/src/build_test.rs @@ -24,6 +24,7 @@ gen_build_tests! { csv_in_folder, deep_nesting, gitkeep, + init_with_children, json_model_in_folder, json_model_legacy_name, module_in_folder, diff --git a/rojo-test/src/snapshots/build_test__init_with_children.snap b/rojo-test/src/snapshots/build_test__init_with_children.snap new file mode 100644 index 00000000..f35e6e2f --- /dev/null +++ b/rojo-test/src/snapshots/build_test__init_with_children.snap @@ -0,0 +1,20 @@ +--- +created: "2019-08-30T00:12:56.686707700Z" +creator: insta@0.10.1 +source: rojo-test/src/build_test.rs +expression: contents +--- + + + + init_with_children + -- init.lua + + + + other + -- other.lua + + + + diff --git a/src/snapshot_middleware/lua.rs b/src/snapshot_middleware/lua.rs index a2e86495..8ae12323 100644 --- a/src/snapshot_middleware/lua.rs +++ b/src/snapshot_middleware/lua.rs @@ -8,7 +8,10 @@ use crate::{ snapshot::InstanceSnapshot, }; -use super::middleware::{SnapshotFileResult, SnapshotInstanceResult, SnapshotMiddleware}; +use super::{ + dir::SnapshotDir, + middleware::{SnapshotFileResult, SnapshotInstanceResult, SnapshotMiddleware}, +}; pub struct SnapshotLua; @@ -19,64 +22,29 @@ impl SnapshotMiddleware for SnapshotLua { ) -> SnapshotInstanceResult<'static> { let file_name = entry.path().file_name().unwrap().to_string_lossy(); - if entry.is_directory() { - let module_init_path = entry.path().join("init.lua"); - if let Some(init_entry) = imfs.get(module_init_path).with_not_found()? { - if let Some(mut snapshot) = SnapshotLua::from_imfs(imfs, &init_entry)? { - snapshot.name = Cow::Owned(file_name.into_owned()); - - return Ok(Some(snapshot)); - } - } - - let server_init_path = entry.path().join("init.server.lua"); - if let Some(init_entry) = imfs.get(server_init_path).with_not_found()? { - if let Some(mut snapshot) = SnapshotLua::from_imfs(imfs, &init_entry)? { - snapshot.name = Cow::Owned(file_name.into_owned()); - - return Ok(Some(snapshot)); - } - } - - let client_init_path = entry.path().join("init.client.lua"); - if let Some(init_entry) = imfs.get(client_init_path).with_not_found()? { - if let Some(mut snapshot) = SnapshotLua::from_imfs(imfs, &init_entry)? { - snapshot.name = Cow::Owned(file_name.into_owned()); - - return Ok(Some(snapshot)); - } - } + // These paths alter their parent instance, so we don't need to turn + // them into a script instance here. + match &*file_name { + "init.lua" | "init.server.lua" | "init.client.lua" => return Ok(None), + _ => {} } - let (class_name, instance_name) = - if let Some(name) = match_trailing(&file_name, ".server.lua") { - ("Script", name) - } else if let Some(name) = match_trailing(&file_name, ".client.lua") { - ("LocalScript", name) - } else if let Some(name) = match_trailing(&file_name, ".lua") { - ("ModuleScript", name) + if entry.is_file() { + snapshot_lua_file(imfs, entry) + } else { + if let Some(snapshot) = snapshot_init(imfs, entry, "init.lua")? { + // An `init.lua` file turns its parent into a ModuleScript + Ok(Some(snapshot)) + } else if let Some(snapshot) = snapshot_init(imfs, entry, "init.server.lua")? { + // An `init.server.lua` file turns its parent into a Script + Ok(Some(snapshot)) + } else if let Some(snapshot) = snapshot_init(imfs, entry, "init.client.lua")? { + // An `init.client.lua` file turns its parent into a LocalScript + Ok(Some(snapshot)) } else { - return Ok(None); - }; - - let contents = entry.contents(imfs)?; - let contents_str = str::from_utf8(contents) - .expect("File content was not valid UTF-8") - .to_string(); - - let properties = hashmap! { - "Source".to_owned() => RbxValue::String { - value: contents_str, - }, - }; - - Ok(Some(InstanceSnapshot { - snapshot_id: None, - name: Cow::Owned(instance_name.to_owned()), - class_name: Cow::Borrowed(class_name), - properties, - children: Vec::new(), - })) + Ok(None) + } + } } fn from_instance(tree: &RbxTree, id: RbxId) -> SnapshotFileResult { @@ -91,6 +59,70 @@ impl SnapshotMiddleware for SnapshotLua { } } +/// Core routine for turning Lua files into snapshots. +fn snapshot_lua_file( + imfs: &mut Imfs, + entry: &ImfsEntry, +) -> SnapshotInstanceResult<'static> { + let file_name = entry.path().file_name().unwrap().to_string_lossy(); + + let (class_name, instance_name) = if let Some(name) = match_trailing(&file_name, ".server.lua") + { + ("Script", name) + } else if let Some(name) = match_trailing(&file_name, ".client.lua") { + ("LocalScript", name) + } else if let Some(name) = match_trailing(&file_name, ".lua") { + ("ModuleScript", name) + } else { + return Ok(None); + }; + + let contents = entry.contents(imfs)?; + let contents_str = str::from_utf8(contents) + .expect("File content was not valid UTF-8") + .to_string(); + + let properties = hashmap! { + "Source".to_owned() => RbxValue::String { + value: contents_str, + }, + }; + + Ok(Some(InstanceSnapshot { + snapshot_id: None, + name: Cow::Owned(instance_name.to_owned()), + class_name: Cow::Borrowed(class_name), + properties, + children: Vec::new(), + })) +} + +/// Attempts to snapshot an 'init' Lua script contained inside of a folder with +/// the given name. +/// +/// Scripts named `init.lua`, `init.server.lua`, or `init.client.lua` usurp +/// their parents, which acts similarly to `__init__.py` from the Python world. +fn snapshot_init( + imfs: &mut Imfs, + folder_entry: &ImfsEntry, + init_name: &str, +) -> SnapshotInstanceResult<'static> { + let init_path = folder_entry.path().join(init_name); + + if let Some(init_entry) = imfs.get(init_path).with_not_found()? { + if let Some(mut dir_snapshot) = SnapshotDir::from_imfs(imfs, folder_entry)? { + if let Some(mut init_snapshot) = snapshot_lua_file(imfs, &init_entry)? { + init_snapshot.name = dir_snapshot.name; + init_snapshot.children = dir_snapshot.children; + + return Ok(Some(init_snapshot)); + } + } + } + + Ok(None) +} + fn match_trailing<'a>(input: &'a str, trailer: &str) -> Option<&'a str> { if input.ends_with(trailer) { let end = input.len().saturating_sub(trailer.len());