mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-23 22:25:26 +00:00
Flatten snapshot middleware to be much simpler (#324)
* First take at flattening middleware for simpler code and better perf * Undo debug prints * Fix using wrong path in snapshot_from_vfs * Disable some broken tests * Re-enable (mistakenly?) disabled CSV test * Fix some tests * Update project file tests * Fix benchmark
This commit is contained in:
committed by
GitHub
parent
bdd1afea57
commit
486b067567
@@ -1,6 +1,6 @@
|
||||
use std::{borrow::Cow, collections::HashMap, path::Path};
|
||||
|
||||
use memofs::{IoResultExt, Vfs};
|
||||
use memofs::Vfs;
|
||||
use rbx_reflection::{get_class_descriptor, try_resolve_value};
|
||||
|
||||
use crate::{
|
||||
@@ -10,92 +10,61 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use super::{
|
||||
error::SnapshotError,
|
||||
middleware::{SnapshotInstanceResult, SnapshotMiddleware},
|
||||
snapshot_from_vfs,
|
||||
};
|
||||
use super::{error::SnapshotError, middleware::SnapshotInstanceResult, snapshot_from_vfs};
|
||||
|
||||
/// Handles snapshots for:
|
||||
/// * Files ending in `.project.json`
|
||||
/// * Folders containing a file named `default.project.json`
|
||||
pub struct SnapshotProject;
|
||||
pub fn snapshot_project(
|
||||
context: &InstanceContext,
|
||||
vfs: &Vfs,
|
||||
path: &Path,
|
||||
) -> SnapshotInstanceResult {
|
||||
let project = Project::load_from_slice(&vfs.read(path)?, path)
|
||||
.map_err(|err| SnapshotError::malformed_project(err, path))?;
|
||||
|
||||
impl SnapshotMiddleware for SnapshotProject {
|
||||
fn from_vfs(context: &InstanceContext, vfs: &Vfs, path: &Path) -> SnapshotInstanceResult {
|
||||
let meta = vfs.metadata(path)?;
|
||||
let mut context = context.clone();
|
||||
|
||||
if meta.is_dir() {
|
||||
let project_path = path.join("default.project.json");
|
||||
let rules = project.glob_ignore_paths.iter().map(|glob| PathIgnoreRule {
|
||||
glob: glob.clone(),
|
||||
base_path: project.folder_location().to_path_buf(),
|
||||
});
|
||||
|
||||
match vfs.metadata(&project_path).with_not_found()? {
|
||||
// TODO: Do we need to muck with the relevant paths if we're a
|
||||
// project file within a folder? Should the folder path be the
|
||||
// relevant path instead of the project file path?
|
||||
Some(_meta) => return SnapshotProject::from_vfs(context, vfs, &project_path),
|
||||
None => return Ok(None),
|
||||
}
|
||||
}
|
||||
context.add_path_ignore_rules(rules);
|
||||
|
||||
if !path.to_string_lossy().ends_with(".project.json") {
|
||||
// This isn't a project file, so it's not our job.
|
||||
return Ok(None);
|
||||
}
|
||||
// TODO: If this project node is a path to an instance that Rojo doesn't
|
||||
// understand, this may panic!
|
||||
let mut snapshot =
|
||||
snapshot_project_node(&context, path, &project.name, &project.tree, vfs, None)?.unwrap();
|
||||
|
||||
let project = Project::load_from_slice(&vfs.read(path)?, path)
|
||||
.map_err(|err| SnapshotError::malformed_project(err, path))?;
|
||||
// Setting the instigating source to the project file path is a little
|
||||
// coarse.
|
||||
//
|
||||
// Ideally, we'd only snapshot the project file if the project file
|
||||
// actually changed. Because Rojo only has the concept of one
|
||||
// relevant path -> snapshot path mapping per instance, we pick the more
|
||||
// conservative approach of snapshotting the project file if any
|
||||
// relevant paths changed.
|
||||
snapshot.metadata.instigating_source = Some(path.to_path_buf().into());
|
||||
|
||||
let mut context = context.clone();
|
||||
// Mark this snapshot (the root node of the project file) as being
|
||||
// related to the project file.
|
||||
//
|
||||
// We SHOULD NOT mark the project file as a relevant path for any
|
||||
// nodes that aren't roots. They'll be updated as part of the project
|
||||
// file being updated.
|
||||
snapshot.metadata.relevant_paths.push(path.to_path_buf());
|
||||
|
||||
let rules = project.glob_ignore_paths.iter().map(|glob| PathIgnoreRule {
|
||||
glob: glob.clone(),
|
||||
base_path: project.folder_location().to_path_buf(),
|
||||
});
|
||||
|
||||
context.add_path_ignore_rules(rules);
|
||||
|
||||
// Snapshotting a project should always return an instance, so this
|
||||
// unwrap is safe.
|
||||
let mut snapshot = snapshot_project_node(
|
||||
&context,
|
||||
project.folder_location(),
|
||||
&project.name,
|
||||
&project.tree,
|
||||
vfs,
|
||||
None,
|
||||
)?
|
||||
.unwrap();
|
||||
|
||||
// Setting the instigating source to the project file path is a little
|
||||
// coarse.
|
||||
//
|
||||
// Ideally, we'd only snapshot the project file if the project file
|
||||
// actually changed. Because Rojo only has the concept of one
|
||||
// relevant path -> snapshot path mapping per instance, we pick the more
|
||||
// conservative approach of snapshotting the project file if any
|
||||
// relevant paths changed.
|
||||
snapshot.metadata.instigating_source = Some(path.to_path_buf().into());
|
||||
|
||||
// Mark this snapshot (the root node of the project file) as being
|
||||
// related to the project file.
|
||||
//
|
||||
// We SHOULD NOT mark the project file as a relevant path for any
|
||||
// nodes that aren't roots. They'll be updated as part of the project
|
||||
// file being updated.
|
||||
snapshot.metadata.relevant_paths.push(path.to_path_buf());
|
||||
|
||||
Ok(Some(snapshot))
|
||||
}
|
||||
Ok(Some(snapshot))
|
||||
}
|
||||
|
||||
pub fn snapshot_project_node(
|
||||
context: &InstanceContext,
|
||||
project_folder: &Path,
|
||||
project_path: &Path,
|
||||
instance_name: &str,
|
||||
node: &ProjectNode,
|
||||
vfs: &Vfs,
|
||||
parent_class: Option<&str>,
|
||||
) -> SnapshotInstanceResult {
|
||||
let project_folder = project_path.parent().unwrap();
|
||||
|
||||
let name = Cow::Owned(instance_name.to_owned());
|
||||
let mut class_name = node
|
||||
.class_name
|
||||
@@ -191,7 +160,7 @@ pub fn snapshot_project_node(
|
||||
for (child_name, child_project_node) in &node.children {
|
||||
if let Some(child) = snapshot_project_node(
|
||||
context,
|
||||
project_folder,
|
||||
project_path,
|
||||
child_name,
|
||||
child_project_node,
|
||||
vfs,
|
||||
@@ -223,7 +192,7 @@ pub fn snapshot_project_node(
|
||||
}
|
||||
|
||||
metadata.instigating_source = Some(InstigatingSource::ProjectNode(
|
||||
project_folder.to_path_buf(),
|
||||
project_path.to_path_buf(),
|
||||
instance_name.to_string(),
|
||||
node.clone(),
|
||||
parent_class.map(|name| name.to_owned()),
|
||||
@@ -239,6 +208,7 @@ pub fn snapshot_project_node(
|
||||
}))
|
||||
}
|
||||
|
||||
// #[cfg(feature = "broken-tests")]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@@ -246,6 +216,7 @@ mod test {
|
||||
use maplit::hashmap;
|
||||
use memofs::{InMemoryFs, VfsSnapshot};
|
||||
|
||||
#[ignore = "Functionality moved to root snapshot middleware"]
|
||||
#[test]
|
||||
fn project_from_folder() {
|
||||
let _ = env_logger::try_init();
|
||||
@@ -269,7 +240,7 @@ mod test {
|
||||
let mut vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot =
|
||||
SnapshotProject::from_vfs(&InstanceContext::default(), &mut vfs, Path::new("/foo"))
|
||||
snapshot_project(&InstanceContext::default(), &mut vfs, Path::new("/foo"))
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
|
||||
@@ -298,7 +269,7 @@ mod test {
|
||||
|
||||
let mut vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot = SnapshotProject::from_vfs(
|
||||
let instance_snapshot = snapshot_project(
|
||||
&InstanceContext::default(),
|
||||
&mut vfs,
|
||||
Path::new("/foo/hello.project.json"),
|
||||
@@ -315,9 +286,9 @@ mod test {
|
||||
|
||||
let mut imfs = InMemoryFs::new();
|
||||
imfs.load_snapshot(
|
||||
"/foo",
|
||||
VfsSnapshot::dir(hashmap! {
|
||||
"default.project.json" => VfsSnapshot::file(r#"
|
||||
"/foo.project.json",
|
||||
VfsSnapshot::file(
|
||||
r#"
|
||||
{
|
||||
"name": "resolved-properties",
|
||||
"tree": {
|
||||
@@ -330,17 +301,20 @@ mod test {
|
||||
}
|
||||
}
|
||||
}
|
||||
"#),
|
||||
}),
|
||||
"#,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot =
|
||||
SnapshotProject::from_vfs(&InstanceContext::default(), &mut vfs, Path::new("/foo"))
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
let instance_snapshot = snapshot_project(
|
||||
&InstanceContext::default(),
|
||||
&mut vfs,
|
||||
Path::new("/foo.project.json"),
|
||||
)
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
|
||||
insta::assert_yaml_snapshot!(instance_snapshot);
|
||||
}
|
||||
@@ -351,9 +325,9 @@ mod test {
|
||||
|
||||
let mut imfs = InMemoryFs::new();
|
||||
imfs.load_snapshot(
|
||||
"/foo",
|
||||
VfsSnapshot::dir(hashmap! {
|
||||
"default.project.json" => VfsSnapshot::file(r#"
|
||||
"/foo.project.json",
|
||||
VfsSnapshot::file(
|
||||
r#"
|
||||
{
|
||||
"name": "unresolved-properties",
|
||||
"tree": {
|
||||
@@ -363,17 +337,20 @@ mod test {
|
||||
}
|
||||
}
|
||||
}
|
||||
"#),
|
||||
}),
|
||||
"#,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot =
|
||||
SnapshotProject::from_vfs(&InstanceContext::default(), &mut vfs, Path::new("/foo"))
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
let instance_snapshot = snapshot_project(
|
||||
&InstanceContext::default(),
|
||||
&mut vfs,
|
||||
Path::new("/foo.project.json"),
|
||||
)
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
|
||||
insta::assert_yaml_snapshot!(instance_snapshot);
|
||||
}
|
||||
@@ -384,9 +361,9 @@ mod test {
|
||||
|
||||
let mut imfs = InMemoryFs::new();
|
||||
imfs.load_snapshot(
|
||||
"/foo",
|
||||
VfsSnapshot::dir(hashmap! {
|
||||
"default.project.json" => VfsSnapshot::file(r#"
|
||||
"/foo.project.json",
|
||||
VfsSnapshot::file(
|
||||
r#"
|
||||
{
|
||||
"name": "children",
|
||||
"tree": {
|
||||
@@ -397,17 +374,20 @@ mod test {
|
||||
}
|
||||
}
|
||||
}
|
||||
"#),
|
||||
}),
|
||||
"#,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot =
|
||||
SnapshotProject::from_vfs(&InstanceContext::default(), &mut vfs, Path::new("/foo"))
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
let instance_snapshot = snapshot_project(
|
||||
&InstanceContext::default(),
|
||||
&mut vfs,
|
||||
Path::new("/foo.project.json"),
|
||||
)
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
|
||||
insta::assert_yaml_snapshot!(instance_snapshot);
|
||||
}
|
||||
@@ -435,10 +415,13 @@ mod test {
|
||||
|
||||
let mut vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot =
|
||||
SnapshotProject::from_vfs(&InstanceContext::default(), &mut vfs, Path::new("/foo"))
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
let instance_snapshot = snapshot_project(
|
||||
&InstanceContext::default(),
|
||||
&mut vfs,
|
||||
Path::new("/foo/default.project.json"),
|
||||
)
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
|
||||
insta::assert_yaml_snapshot!(instance_snapshot);
|
||||
}
|
||||
@@ -473,10 +456,13 @@ mod test {
|
||||
|
||||
let mut vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot =
|
||||
SnapshotProject::from_vfs(&InstanceContext::default(), &mut vfs, Path::new("/foo"))
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
let instance_snapshot = snapshot_project(
|
||||
&InstanceContext::default(),
|
||||
&mut vfs,
|
||||
Path::new("/foo/default.project.json"),
|
||||
)
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
|
||||
insta::assert_yaml_snapshot!(instance_snapshot);
|
||||
}
|
||||
@@ -515,10 +501,13 @@ mod test {
|
||||
|
||||
let mut vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot =
|
||||
SnapshotProject::from_vfs(&InstanceContext::default(), &mut vfs, Path::new("/foo"))
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
let instance_snapshot = snapshot_project(
|
||||
&InstanceContext::default(),
|
||||
&mut vfs,
|
||||
Path::new("/foo/default.project.json"),
|
||||
)
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
|
||||
insta::assert_yaml_snapshot!(instance_snapshot);
|
||||
}
|
||||
@@ -562,10 +551,13 @@ mod test {
|
||||
|
||||
let mut vfs = Vfs::new(imfs);
|
||||
|
||||
let instance_snapshot =
|
||||
SnapshotProject::from_vfs(&InstanceContext::default(), &mut vfs, Path::new("/foo"))
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
let instance_snapshot = snapshot_project(
|
||||
&InstanceContext::default(),
|
||||
&mut vfs,
|
||||
Path::new("/foo/default.project.json"),
|
||||
)
|
||||
.expect("snapshot error")
|
||||
.expect("snapshot returned no instances");
|
||||
|
||||
insta::assert_yaml_snapshot!(instance_snapshot);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user