forked from rojo-rbx/rojo
Upgrade to rbx_dom_weak 2.0 (#377)
* Mostly mechanical port bits * Almost there * It builds again! * Turn on all the code again * Tests compiling but not passing * Stub work for value resolution * Implement resolution minus enums and derived properties * Implement property descriptor resolution * Update referent snapshots * Update unions test project Using a place file instead of a model yields better error messages in Roblox Studio. * Add easy shortcut to testing with local rbx-dom * Update rbx-dom * Add enum resolution * Update init.meta.json to use UnresolvedValue * Expand value resolution support, add test * Filter SharedString values from web API * Add 'property' builder method to InstanceSnapshot * Change InstanceSnapshot/InstanceBuilder boundary * Fix remove_file crash * rustfmt * Update to latest rbx_dom_lua * Update dependencies, including rbx_dom_weak * Update to latest rbx-dom * Update dependencies * Update rbx-dom, fixing more bugs * Remove experimental warning on binary place builds * Remove unused imports
This commit is contained in:
committed by
GitHub
parent
b84aab0960
commit
59ef5f05ea
@@ -3,7 +3,6 @@ use std::{collections::BTreeMap, path::Path};
|
||||
use anyhow::Context;
|
||||
use maplit::hashmap;
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use rbx_dom_weak::RbxValue;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||
@@ -30,9 +29,7 @@ pub fn snapshot_csv(
|
||||
.name(instance_name)
|
||||
.class_name("LocalizationTable")
|
||||
.properties(hashmap! {
|
||||
"Contents".to_owned() => RbxValue::String {
|
||||
value: table_contents,
|
||||
},
|
||||
"Contents".to_owned() => table_contents.into(),
|
||||
})
|
||||
.metadata(
|
||||
InstanceMetadata::new()
|
||||
@@ -41,8 +38,8 @@ pub fn snapshot_csv(
|
||||
);
|
||||
|
||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||
metadata.apply_all(&mut snapshot);
|
||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, meta_path)?;
|
||||
metadata.apply_all(&mut snapshot)?;
|
||||
}
|
||||
|
||||
Ok(Some(snapshot))
|
||||
|
||||
@@ -60,8 +60,8 @@ pub fn snapshot_dir(context: &InstanceContext, vfs: &Vfs, path: &Path) -> Snapsh
|
||||
);
|
||||
|
||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||
let mut metadata = DirectoryMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||
metadata.apply_all(&mut snapshot);
|
||||
let mut metadata = DirectoryMetadata::from_slice(&meta_contents, meta_path)?;
|
||||
metadata.apply_all(&mut snapshot)?;
|
||||
}
|
||||
|
||||
Ok(Some(snapshot))
|
||||
|
||||
@@ -3,7 +3,6 @@ use std::path::Path;
|
||||
use anyhow::Context;
|
||||
use maplit::hashmap;
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use rbx_dom_weak::RbxValue;
|
||||
|
||||
use crate::{
|
||||
lua_ast::{Expression, Statement},
|
||||
@@ -26,9 +25,7 @@ pub fn snapshot_json(
|
||||
let as_lua = json_to_lua(value).to_string();
|
||||
|
||||
let properties = hashmap! {
|
||||
"Source".to_owned() => RbxValue::String {
|
||||
value: as_lua,
|
||||
},
|
||||
"Source".to_owned() => as_lua.into(),
|
||||
};
|
||||
|
||||
let meta_path = path.with_file_name(format!("{}.meta.json", instance_name));
|
||||
@@ -45,8 +42,8 @@ pub fn snapshot_json(
|
||||
);
|
||||
|
||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||
metadata.apply_all(&mut snapshot);
|
||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, meta_path)?;
|
||||
metadata.apply_all(&mut snapshot)?;
|
||||
}
|
||||
|
||||
Ok(Some(snapshot))
|
||||
|
||||
@@ -2,11 +2,12 @@ use std::{borrow::Cow, collections::HashMap, path::Path};
|
||||
|
||||
use anyhow::Context;
|
||||
use memofs::Vfs;
|
||||
use rbx_dom_weak::UnresolvedRbxValue;
|
||||
use rbx_reflection::try_resolve_value;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::snapshot::{InstanceContext, InstanceSnapshot};
|
||||
use crate::{
|
||||
resolution::UnresolvedValue,
|
||||
snapshot::{InstanceContext, InstanceSnapshot},
|
||||
};
|
||||
|
||||
use super::middleware::SnapshotInstanceResult;
|
||||
|
||||
@@ -20,7 +21,10 @@ pub fn snapshot_json_model(
|
||||
let instance: JsonModel = serde_json::from_slice(&contents)
|
||||
.with_context(|| format!("File is not a valid JSON model: {}", path.display()))?;
|
||||
|
||||
let mut snapshot = instance.core.into_snapshot(instance_name.to_owned());
|
||||
let mut snapshot = instance
|
||||
.core
|
||||
.into_snapshot(instance_name.to_owned())
|
||||
.with_context(|| format!("Could not load JSON model: {}", path.display()))?;
|
||||
|
||||
snapshot.metadata = snapshot
|
||||
.metadata
|
||||
@@ -58,36 +62,32 @@ struct JsonModelCore {
|
||||
children: Vec<JsonModelInstance>,
|
||||
|
||||
#[serde(default = "HashMap::new", skip_serializing_if = "HashMap::is_empty")]
|
||||
properties: HashMap<String, UnresolvedRbxValue>,
|
||||
properties: HashMap<String, UnresolvedValue>,
|
||||
}
|
||||
|
||||
impl JsonModelCore {
|
||||
fn into_snapshot(self, name: String) -> InstanceSnapshot {
|
||||
fn into_snapshot(self, name: String) -> anyhow::Result<InstanceSnapshot> {
|
||||
let class_name = self.class_name;
|
||||
|
||||
let children = self
|
||||
.children
|
||||
.into_iter()
|
||||
.map(|child| child.core.into_snapshot(child.name))
|
||||
.collect();
|
||||
let mut children = Vec::with_capacity(self.children.len());
|
||||
for child in self.children {
|
||||
children.push(child.core.into_snapshot(child.name)?);
|
||||
}
|
||||
|
||||
let properties = self
|
||||
.properties
|
||||
.into_iter()
|
||||
.map(|(key, value)| {
|
||||
try_resolve_value(&class_name, &key, &value).map(|resolved| (key, resolved))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>, _>>()
|
||||
.expect("TODO: Handle rbx_reflection errors");
|
||||
let mut properties = HashMap::with_capacity(self.properties.len());
|
||||
for (key, unresolved) in self.properties {
|
||||
let value = unresolved.resolve(&class_name, &key)?;
|
||||
properties.insert(key, value);
|
||||
}
|
||||
|
||||
InstanceSnapshot {
|
||||
Ok(InstanceSnapshot {
|
||||
snapshot_id: None,
|
||||
metadata: Default::default(),
|
||||
name: Cow::Owned(name),
|
||||
class_name: Cow::Owned(class_name),
|
||||
properties,
|
||||
children,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ use std::{path::Path, str};
|
||||
use anyhow::Context;
|
||||
use maplit::hashmap;
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use rbx_dom_weak::RbxValue;
|
||||
|
||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||
|
||||
@@ -38,9 +37,7 @@ pub fn snapshot_lua(context: &InstanceContext, vfs: &Vfs, path: &Path) -> Snapsh
|
||||
.name(instance_name)
|
||||
.class_name(class_name)
|
||||
.properties(hashmap! {
|
||||
"Source".to_owned() => RbxValue::String {
|
||||
value: contents_str,
|
||||
},
|
||||
"Source".to_owned() => contents_str.into(),
|
||||
})
|
||||
.metadata(
|
||||
InstanceMetadata::new()
|
||||
@@ -50,8 +47,8 @@ pub fn snapshot_lua(context: &InstanceContext, vfs: &Vfs, path: &Path) -> Snapsh
|
||||
);
|
||||
|
||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||
metadata.apply_all(&mut snapshot);
|
||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, meta_path)?;
|
||||
metadata.apply_all(&mut snapshot)?;
|
||||
}
|
||||
|
||||
Ok(Some(snapshot))
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use std::{borrow::Cow, collections::HashMap, path::Path};
|
||||
use std::{borrow::Cow, collections::HashMap, path::PathBuf};
|
||||
|
||||
use anyhow::Context;
|
||||
use rbx_dom_weak::UnresolvedRbxValue;
|
||||
use rbx_reflection::try_resolve_value;
|
||||
use anyhow::{format_err, Context};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::snapshot::InstanceSnapshot;
|
||||
use crate::{resolution::UnresolvedValue, snapshot::InstanceSnapshot};
|
||||
|
||||
/// Represents metadata in a sibling file with the same basename.
|
||||
///
|
||||
@@ -18,17 +16,23 @@ pub struct AdjacentMetadata {
|
||||
pub ignore_unknown_instances: Option<bool>,
|
||||
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub properties: HashMap<String, UnresolvedRbxValue>,
|
||||
pub properties: HashMap<String, UnresolvedValue>,
|
||||
|
||||
#[serde(skip)]
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
impl AdjacentMetadata {
|
||||
pub fn from_slice(slice: &[u8], path: &Path) -> anyhow::Result<Self> {
|
||||
serde_json::from_slice(slice).with_context(|| {
|
||||
pub fn from_slice(slice: &[u8], path: PathBuf) -> anyhow::Result<Self> {
|
||||
let mut meta: Self = serde_json::from_slice(slice).with_context(|| {
|
||||
format!(
|
||||
"File contained malformed .meta.json data: {}",
|
||||
path.display()
|
||||
)
|
||||
})
|
||||
})?;
|
||||
|
||||
meta.path = path;
|
||||
Ok(meta)
|
||||
}
|
||||
|
||||
pub fn apply_ignore_unknown_instances(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||
@@ -37,23 +41,24 @@ impl AdjacentMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_properties(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||
let class_name = &snapshot.class_name;
|
||||
pub fn apply_properties(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
||||
let path = &self.path;
|
||||
|
||||
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, unresolved) in self.properties.drain() {
|
||||
let value = unresolved
|
||||
.resolve(&snapshot.class_name, &key)
|
||||
.with_context(|| format!("error applying meta file {}", path.display()))?;
|
||||
|
||||
for (key, value) in source_properties {
|
||||
snapshot.properties.insert(key, value);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn apply_all(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||
pub fn apply_all(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
||||
self.apply_ignore_unknown_instances(snapshot);
|
||||
self.apply_properties(snapshot);
|
||||
self.apply_properties(snapshot)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Add method to allow selectively applying parts of metadata and
|
||||
@@ -71,37 +76,50 @@ pub struct DirectoryMetadata {
|
||||
pub ignore_unknown_instances: Option<bool>,
|
||||
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub properties: HashMap<String, UnresolvedRbxValue>,
|
||||
pub properties: HashMap<String, UnresolvedValue>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub class_name: Option<String>,
|
||||
|
||||
#[serde(skip)]
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
impl DirectoryMetadata {
|
||||
pub fn from_slice(slice: &[u8], path: &Path) -> anyhow::Result<Self> {
|
||||
serde_json::from_slice(slice).with_context(|| {
|
||||
pub fn from_slice(slice: &[u8], path: PathBuf) -> anyhow::Result<Self> {
|
||||
let mut meta: Self = serde_json::from_slice(slice).with_context(|| {
|
||||
format!(
|
||||
"File contained malformed init.meta.json data: {}",
|
||||
path.display()
|
||||
)
|
||||
})
|
||||
})?;
|
||||
|
||||
meta.path = path;
|
||||
Ok(meta)
|
||||
}
|
||||
|
||||
pub fn apply_all(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||
pub fn apply_all(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
||||
self.apply_ignore_unknown_instances(snapshot);
|
||||
self.apply_class_name(snapshot);
|
||||
self.apply_properties(snapshot);
|
||||
self.apply_class_name(snapshot)?;
|
||||
self.apply_properties(snapshot)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply_class_name(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||
fn apply_class_name(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
||||
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.");
|
||||
return Err(format_err!(
|
||||
"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);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply_ignore_unknown_instances(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||
@@ -110,17 +128,17 @@ impl DirectoryMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_properties(&mut self, snapshot: &mut InstanceSnapshot) {
|
||||
let class_name = &snapshot.class_name;
|
||||
fn apply_properties(&mut self, snapshot: &mut InstanceSnapshot) -> anyhow::Result<()> {
|
||||
let path = &self.path;
|
||||
|
||||
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, unresolved) in self.properties.drain() {
|
||||
let value = unresolved
|
||||
.resolve(&snapshot.class_name, &key)
|
||||
.with_context(|| format!("error applying meta file {}", path.display()))?;
|
||||
|
||||
for (key, value) in source_properties {
|
||||
snapshot.properties.insert(key, value);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{borrow::Cow, collections::HashMap, path::Path};
|
||||
|
||||
use anyhow::Context;
|
||||
use memofs::Vfs;
|
||||
use rbx_reflection::{get_class_descriptor, try_resolve_value};
|
||||
use rbx_reflection::ClassTag;
|
||||
|
||||
use crate::{
|
||||
project::{Project, ProjectNode},
|
||||
@@ -140,9 +140,9 @@ pub fn snapshot_project_node(
|
||||
// Members of DataModel with names that match known services are
|
||||
// probably supposed to be those services.
|
||||
|
||||
let descriptor = get_class_descriptor(&name)?;
|
||||
let descriptor = rbx_reflection_database::get().classes.get(&name)?;
|
||||
|
||||
if descriptor.is_service() {
|
||||
if descriptor.tags.contains(&ClassTag::Service) {
|
||||
return Some(name.clone());
|
||||
}
|
||||
} else if parent_class == "StarterPlayer" {
|
||||
@@ -171,11 +171,18 @@ pub fn snapshot_project_node(
|
||||
}
|
||||
}
|
||||
|
||||
for (key, value) in &node.properties {
|
||||
let resolved_value = try_resolve_value(&class_name, key, value)
|
||||
.expect("TODO: Properly handle value resolution errors");
|
||||
for (key, unresolved) in &node.properties {
|
||||
let value = unresolved
|
||||
.clone()
|
||||
.resolve(&class_name, key)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Unresolvable property in project at path {}",
|
||||
project_path.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
properties.insert(key.clone(), resolved_value);
|
||||
properties.insert(key.clone(), value);
|
||||
}
|
||||
|
||||
// If the user specified $ignoreUnknownInstances, overwrite the existing
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::{collections::HashMap, path::Path};
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Context;
|
||||
use memofs::Vfs;
|
||||
use rbx_dom_weak::{RbxInstanceProperties, RbxTree};
|
||||
|
||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||
|
||||
@@ -14,18 +13,11 @@ pub fn snapshot_rbxm(
|
||||
path: &Path,
|
||||
instance_name: &str,
|
||||
) -> SnapshotInstanceResult {
|
||||
let mut temp_tree = RbxTree::new(RbxInstanceProperties {
|
||||
name: "DataModel".to_owned(),
|
||||
class_name: "DataModel".to_owned(),
|
||||
properties: HashMap::new(),
|
||||
});
|
||||
|
||||
let root_id = temp_tree.get_root_id();
|
||||
rbx_binary::decode(&mut temp_tree, root_id, vfs.read(path)?.as_slice())
|
||||
let temp_tree = rbx_binary::from_reader_default(vfs.read(path)?.as_slice())
|
||||
.with_context(|| format!("Malformed rbxm file: {}", path.display()))?;
|
||||
|
||||
let root_instance = temp_tree.get_instance(root_id).unwrap();
|
||||
let children = root_instance.get_children_ids();
|
||||
let root_instance = temp_tree.root();
|
||||
let children = root_instance.children();
|
||||
|
||||
if children.len() == 1 {
|
||||
let snapshot = InstanceSnapshot::from_tree(&temp_tree, children[0])
|
||||
|
||||
@@ -19,8 +19,8 @@ pub fn snapshot_rbxmx(
|
||||
let temp_tree = rbx_xml::from_reader(vfs.read(path)?.as_slice(), options)
|
||||
.with_context(|| format!("Malformed rbxm file: {}", path.display()))?;
|
||||
|
||||
let root_instance = temp_tree.get_instance(temp_tree.get_root_id()).unwrap();
|
||||
let children = root_instance.get_children_ids();
|
||||
let root_instance = temp_tree.root();
|
||||
let children = root_instance.children();
|
||||
|
||||
if children.len() == 1 {
|
||||
let snapshot = InstanceSnapshot::from_tree(&temp_tree, children[0])
|
||||
|
||||
@@ -14,7 +14,7 @@ name: foo
|
||||
class_name: IntValue
|
||||
properties:
|
||||
Value:
|
||||
Type: Int32
|
||||
Type: Int64
|
||||
Value: 5
|
||||
children:
|
||||
- snapshot_id: ~
|
||||
|
||||
@@ -3,7 +3,6 @@ use std::{path::Path, str};
|
||||
use anyhow::Context;
|
||||
use maplit::hashmap;
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use rbx_dom_weak::RbxValue;
|
||||
|
||||
use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
|
||||
|
||||
@@ -21,9 +20,7 @@ pub fn snapshot_txt(
|
||||
.to_owned();
|
||||
|
||||
let properties = hashmap! {
|
||||
"Value".to_owned() => RbxValue::String {
|
||||
value: contents_str,
|
||||
},
|
||||
"Value".to_owned() => contents_str.into(),
|
||||
};
|
||||
|
||||
let meta_path = path.with_file_name(format!("{}.meta.json", instance_name));
|
||||
@@ -40,8 +37,8 @@ pub fn snapshot_txt(
|
||||
);
|
||||
|
||||
if let Some(meta_contents) = vfs.read(&meta_path).with_not_found()? {
|
||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, &meta_path)?;
|
||||
metadata.apply_all(&mut snapshot);
|
||||
let mut metadata = AdjacentMetadata::from_slice(&meta_contents, meta_path)?;
|
||||
metadata.apply_all(&mut snapshot)?;
|
||||
}
|
||||
|
||||
Ok(Some(snapshot))
|
||||
|
||||
Reference in New Issue
Block a user