Add init.meta.json support, untested

This commit is contained in:
Lucien Greathouse
2019-10-12 23:45:38 -07:00
parent b9ebed14a5
commit 1c6c1298d5
3 changed files with 86 additions and 6 deletions

View File

@@ -4,12 +4,13 @@ use rbx_dom_weak::{RbxId, RbxTree};
use crate::{
snapshot::{InstanceMetadata, InstanceSnapshot},
vfs::{DirectorySnapshot, Vfs, VfsEntry, VfsFetcher, VfsSnapshot},
vfs::{DirectorySnapshot, FsResultExt, Vfs, VfsEntry, VfsFetcher, VfsSnapshot},
};
use super::{
context::InstanceSnapshotContext,
error::SnapshotError,
meta_file::DirectoryMetadata,
middleware::{SnapshotFileResult, SnapshotInstanceResult, SnapshotMiddleware},
snapshot_from_instance, snapshot_from_vfs,
};
@@ -44,7 +45,9 @@ impl SnapshotMiddleware for SnapshotDir {
.ok_or_else(|| SnapshotError::file_name_bad_unicode(entry.path()))?
.to_string();
Ok(Some(InstanceSnapshot {
let meta_path = entry.path().join("init.meta.json");
let mut snapshot = InstanceSnapshot {
snapshot_id: None,
metadata: InstanceMetadata {
instigating_source: Some(entry.path().to_path_buf().into()),
@@ -55,7 +58,15 @@ impl SnapshotMiddleware for SnapshotDir {
class_name: Cow::Borrowed("Folder"),
properties: HashMap::new(),
children: snapshot_children,
}))
};
if let Some(meta_entry) = vfs.get(meta_path).with_not_found()? {
let meta_contents = meta_entry.contents(vfs)?;
let mut metadata = DirectoryMetadata::from_slice(&meta_contents);
metadata.apply_all(&mut snapshot);
}
Ok(Some(snapshot))
}
fn from_instance(tree: &RbxTree, id: RbxId) -> SnapshotFileResult {

View File

@@ -126,10 +126,17 @@ fn snapshot_init<F: VfsFetcher>(
if let Some(init_entry) = vfs.get(init_path).with_not_found()? {
if let Some(dir_snapshot) = SnapshotDir::from_vfs(context, vfs, folder_entry)? {
if let Some(mut init_snapshot) = snapshot_lua_file(vfs, &init_entry)? {
if dir_snapshot.class_name != "Folder" {
panic!(
"init.lua, init.server.lua, and init.client.lua can \
only be used if the instance produced by the parent \
directory would be a Folder."
);
}
init_snapshot.name = dir_snapshot.name;
init_snapshot.children = dir_snapshot.children;
// TODO: Metadata
// TODO: Validate directory class name is "Folder"
// TODO: Apply metadata from folder
return Ok(Some(init_snapshot));
}

View File

@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{borrow::Cow, collections::HashMap};
use rbx_dom_weak::UnresolvedRbxValue;
use rbx_reflection::try_resolve_value;
@@ -55,3 +55,65 @@ impl AdjacentMetadata {
// TODO: Add method to allow selectively applying parts of metadata and
// throwing errors if invalid parts are specified.
}
/// Represents metadata that affects the instance resulting from the containing
/// folder.
///
/// This is always sourced from a file named init.meta.json.
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DirectoryMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
pub ignore_unknown_instances: Option<bool>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub properties: HashMap<String, UnresolvedRbxValue>,
#[serde(skip_serializing_if = "Option::is_none")]
pub class_name: Option<String>,
}
impl DirectoryMetadata {
pub fn from_slice(slice: &[u8]) -> Self {
serde_json::from_slice(slice)
// TODO: Turn into error type
.expect("init.meta.json file was malformed")
}
pub fn apply_all(&mut self, snapshot: &mut InstanceSnapshot) {
self.apply_ignore_unknown_instances(snapshot);
self.apply_class_name(snapshot);
self.apply_properties(snapshot);
}
fn apply_class_name(&mut self, snapshot: &mut InstanceSnapshot) {
if let Some(class_name) = self.class_name.take() {
if snapshot.class_name != "Folder" {
// TODO: Turn into error type
panic!("className in init.meta.json can only be specified if the affected directory would turn into a Folder instance.");
}
snapshot.class_name = Cow::Owned(class_name);
}
}
fn apply_ignore_unknown_instances(&mut self, snapshot: &mut InstanceSnapshot) {
if let Some(ignore) = self.ignore_unknown_instances.take() {
snapshot.metadata.ignore_unknown_instances = ignore;
}
}
fn apply_properties(&mut self, snapshot: &mut InstanceSnapshot) {
let class_name = &snapshot.class_name;
let source_properties = self.properties.drain().map(|(key, value)| {
try_resolve_value(class_name, &key, &value)
.map(|resolved| (key, resolved))
.expect("TODO: Handle rbx_reflection errors")
});
for (key, value) in source_properties {
snapshot.properties.insert(key, value);
}
}
}