Trimming of stuff to get into the snapshotting mood

This commit is contained in:
Lucien Greathouse
2018-12-12 13:56:11 -08:00
parent ee0a5cada3
commit b732c43274
4 changed files with 52 additions and 68 deletions

View File

@@ -76,9 +76,10 @@ impl Imfs {
if self.is_within_roots(parent_path) && self.get(parent_path).is_none() { if self.is_within_roots(parent_path) && self.get(parent_path).is_none() {
self.path_created(parent_path)?; self.path_created(parent_path)?;
} }
} else {
ImfsItem::read_from_disk(self, path)?;
} }
ImfsItem::read_from_disk(self, path)?;
Ok(()) Ok(())
} }
@@ -90,9 +91,10 @@ impl Imfs {
if self.is_within_roots(parent_path) && self.get(parent_path).is_none() { if self.is_within_roots(parent_path) && self.get(parent_path).is_none() {
self.path_created(parent_path)?; self.path_created(parent_path)?;
} }
} else {
ImfsItem::read_from_disk(self, path)?;
} }
ImfsItem::read_from_disk(self, path)?;
Ok(()) Ok(())
} }

View File

@@ -10,7 +10,7 @@ struct PathMapNode<T> {
} }
/// A map from paths to instance IDs, with a bit of additional data that enables /// A map from paths to instance IDs, with a bit of additional data that enables
/// removing a path and all of its child paths from the tree in constant time. /// removing a path and all of its child paths from the tree more quickly.
#[derive(Debug)] #[derive(Debug)]
pub struct PathMap<T> { pub struct PathMap<T> {
nodes: HashMap<PathBuf, PathMapNode<T>>, nodes: HashMap<PathBuf, PathMapNode<T>>,

View File

@@ -122,28 +122,12 @@ pub fn construct_oneoff_tree(project: &Project, imfs: &Imfs) -> RbxTree {
construct_initial_tree(project, imfs) construct_initial_tree(project, imfs)
} }
struct ConstructContext<'a> {
imfs: &'a Imfs,
path_id_tree: PathMap<RbxId>,
ids_to_project_paths: HashMap<RbxId, String>,
}
fn construct_initial_tree( fn construct_initial_tree(
project: &Project, project: &Project,
imfs: &Imfs, imfs: &Imfs,
) -> RbxTree { ) -> RbxTree {
let path_id_tree = PathMap::new();
let ids_to_project_paths = HashMap::new();
let mut context = ConstructContext {
imfs,
path_id_tree,
ids_to_project_paths,
};
let snapshot = construct_project_node( let snapshot = construct_project_node(
&mut context, imfs,
"",
&project.name, &project.name,
&project.tree, &project.tree,
); );
@@ -152,37 +136,30 @@ fn construct_initial_tree(
} }
fn construct_project_node<'a>( fn construct_project_node<'a>(
context: &mut ConstructContext<'a>, imfs: &'a Imfs,
instance_path: &str,
instance_name: &'a str, instance_name: &'a str,
project_node: &'a ProjectNode, project_node: &'a ProjectNode,
) -> RbxSnapshotInstance<'a> { ) -> RbxSnapshotInstance<'a> {
match project_node { match project_node {
ProjectNode::Instance(node) => { ProjectNode::Instance(node) => {
construct_instance_node(context, &instance_path, instance_name, node) construct_instance_node(imfs, instance_name, node)
}, },
ProjectNode::SyncPoint(node) => { ProjectNode::SyncPoint(node) => {
construct_sync_point_node(context, instance_name, &node.path) snapshot_instances_from_imfs(imfs, &node.path)
.expect("Could not reify nodes from Imfs")
}, },
} }
} }
fn construct_instance_node<'a>( fn construct_instance_node<'a>(
context: &mut ConstructContext<'a>, imfs: &'a Imfs,
instance_path: &str,
instance_name: &'a str, instance_name: &'a str,
project_node: &'a InstanceProjectNode, project_node: &'a InstanceProjectNode,
) -> RbxSnapshotInstance<'a> { ) -> RbxSnapshotInstance<'a> {
let mut children = Vec::new(); let mut children = Vec::new();
for (child_name, child_project_node) in &project_node.children { for (child_name, child_project_node) in &project_node.children {
let child_path = if instance_path.is_empty() { children.push(construct_project_node(imfs, child_name, child_project_node));
child_name.clone()
} else {
format!("{}/{}", instance_path, child_name)
};
children.push(construct_project_node(context, &child_path, child_name, child_project_node));
} }
RbxSnapshotInstance { RbxSnapshotInstance {
@@ -190,6 +167,7 @@ fn construct_instance_node<'a>(
name: Cow::Borrowed(instance_name), name: Cow::Borrowed(instance_name),
properties: HashMap::new(), properties: HashMap::new(),
children, children,
update_trigger_paths: Vec::new(),
} }
} }
@@ -200,28 +178,33 @@ enum FileType {
ClientScript, ClientScript,
} }
fn classify_file(file: &ImfsFile) -> Option<FileType> { fn get_trailing<'a>(input: &'a str, trailer: &str) -> Option<&'a str> {
let file_name = file.path.file_name()?.to_str()?; if input.ends_with(trailer) {
let end = input.len().saturating_sub(trailer.len());
if file_name.ends_with(".server.lua") { Some(&input[..end])
Some(FileType::ServerScript)
} else if file_name.ends_with(".client.lua") {
Some(FileType::ClientScript)
} else if file_name.ends_with(".lua") {
Some(FileType::ModuleScript)
} else { } else {
None None
} }
} }
fn construct_sync_point_node<'a>( fn classify_file(file: &ImfsFile) -> Option<(&str, FileType)> {
context: &mut ConstructContext<'a>, let file_name = file.path.file_name()?.to_str()?;
instance_name: &'a str,
file_path: &Path, if let Some(instance_name) = get_trailing(file_name, ".server.lua") {
) -> RbxSnapshotInstance<'a> { Some((instance_name, FileType::ServerScript))
match context.imfs.get(&file_path) { } else if let Some(instance_name) = get_trailing(file_name, ".client.lua") {
Some(ImfsItem::File(file)) => { Some((instance_name, FileType::ClientScript))
let file_type = classify_file(file).unwrap(); // TODO: Don't die here! } else if let Some(instance_name) = get_trailing(file_name, ".lua") {
Some((instance_name, FileType::ModuleScript))
} else {
None
}
}
fn snapshot_instances_from_imfs<'a>(imfs: &'a Imfs, imfs_path: &Path) -> Option<RbxSnapshotInstance<'a>> {
match imfs.get(imfs_path)? {
ImfsItem::File(file) => {
let (instance_name, file_type) = classify_file(file)?;
let class_name = match file_type { let class_name = match file_type {
FileType::ModuleScript => "ModuleScript", FileType::ModuleScript => "ModuleScript",
@@ -229,47 +212,44 @@ fn construct_sync_point_node<'a>(
FileType::ClientScript => "LocalScript", FileType::ClientScript => "LocalScript",
}; };
let contents = str::from_utf8(&file.contents).unwrap(); let contents = str::from_utf8(&file.contents)
.expect("File did not contain UTF-8 data, which is required for scripts.");
let mut properties = HashMap::new(); let mut properties = HashMap::new();
properties.insert("Source".to_string(), RbxSnapshotValue::String(Cow::Borrowed(contents))); properties.insert(String::from("Source"), RbxSnapshotValue::String(Cow::Borrowed(contents)));
let instance = RbxSnapshotInstance { Some(RbxSnapshotInstance {
class_name: Cow::Borrowed(class_name),
name: Cow::Borrowed(instance_name), name: Cow::Borrowed(instance_name),
class_name: Cow::Borrowed(class_name),
properties, properties,
children: Vec::new(), children: Vec::new(),
}; update_trigger_paths: vec![file.path.clone()],
})
instance
}, },
Some(ImfsItem::Directory(directory)) => { ImfsItem::Directory(directory) => {
let init_path = directory.path.join("init.lua"); let init_path = directory.path.join("init.lua");
let mut instance = if directory.children.contains(&init_path) { let mut instance = if directory.children.contains(&init_path) {
construct_sync_point_node(context, instance_name, &init_path) snapshot_instances_from_imfs(imfs, &init_path)?
} else { } else {
RbxSnapshotInstance { RbxSnapshotInstance {
class_name: Cow::Borrowed("Folder"), class_name: Cow::Borrowed("Folder"),
name: Cow::Borrowed(instance_name), name: Cow::Borrowed(""), // Assigned later in the method
properties: HashMap::new(), properties: HashMap::new(),
children: Vec::new(), children: Vec::new(),
update_trigger_paths: vec![directory.path.clone()],
} }
}; };
instance.name = Cow::Borrowed(directory.path.file_name()?.to_str()?);
for child_path in &directory.children { for child_path in &directory.children {
if child_path != &init_path { if child_path != &init_path {
let child_instance_name = match context.imfs.get(child_path).unwrap() { instance.children.push(snapshot_instances_from_imfs(imfs, child_path)?);
ImfsItem::File(_) => child_path.file_stem().unwrap().to_str().unwrap(),
ImfsItem::Directory(_) => child_path.file_name().unwrap().to_str().unwrap(),
};
instance.children.push(construct_sync_point_node(context, child_instance_name, child_path));
} }
} }
instance Some(instance)
}, },
None => panic!("Couldn't read {} from disk", file_path.display()),
} }
} }

View File

@@ -2,6 +2,7 @@ use std::{
str, str,
borrow::Cow, borrow::Cow,
collections::HashMap, collections::HashMap,
path::PathBuf,
}; };
use rbx_tree::{RbxTree, RbxId, RbxInstance, RbxValue}; use rbx_tree::{RbxTree, RbxId, RbxInstance, RbxValue};
@@ -11,6 +12,7 @@ pub struct RbxSnapshotInstance<'a> {
pub class_name: Cow<'a, str>, pub class_name: Cow<'a, str>,
pub properties: HashMap<String, RbxSnapshotValue<'a>>, pub properties: HashMap<String, RbxSnapshotValue<'a>>,
pub children: Vec<RbxSnapshotInstance<'a>>, pub children: Vec<RbxSnapshotInstance<'a>>,
pub update_trigger_paths: Vec<PathBuf>,
} }
pub enum RbxSnapshotValue<'a> { pub enum RbxSnapshotValue<'a> {