mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-24 14:45:56 +00:00
Normalize metadata into metadata per instance and metadata per path (#107)
* Begin the metadata merge trek * Tidy up path metadata, entry API, begin implementing * Flesh out use of PathMap Entry API * Metadata per instance is a go * Tidy up naming for metadata per instance * SnapshotMetadata -> SnapshotContext
This commit is contained in:
committed by
GitHub
parent
4cfdc72c00
commit
bd3a4a719d
@@ -1,4 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
collections::hash_map,
|
||||||
path::{self, Path, PathBuf},
|
path::{self, Path, PathBuf},
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
};
|
};
|
||||||
@@ -31,6 +32,16 @@ impl<T> PathMap<T> {
|
|||||||
self.nodes.get(path).map(|v| &v.value)
|
self.nodes.get(path).map(|v| &v.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, path: &Path) -> Option<&mut T> {
|
||||||
|
self.nodes.get_mut(path).map(|v| &mut v.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entry<'a>(&'a mut self, path: PathBuf) -> Entry<'a, T> {
|
||||||
|
Entry {
|
||||||
|
internal: self.nodes.entry(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, path: PathBuf, value: T) {
|
pub fn insert(&mut self, path: PathBuf, value: T) {
|
||||||
if let Some(parent_path) = path.parent() {
|
if let Some(parent_path) = path.parent() {
|
||||||
if let Some(parent) = self.nodes.get_mut(parent_path) {
|
if let Some(parent) = self.nodes.get_mut(parent_path) {
|
||||||
@@ -106,3 +117,27 @@ impl<T> PathMap<T> {
|
|||||||
current_path
|
current_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Entry<'a, T> {
|
||||||
|
internal: hash_map::Entry<'a, PathBuf, PathMapNode<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Entry<'a, T> {
|
||||||
|
pub fn or_insert(self, value: T) -> &'a mut T {
|
||||||
|
&mut self.internal.or_insert(PathMapNode {
|
||||||
|
value,
|
||||||
|
children: HashSet::new(),
|
||||||
|
}).value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Entry<'a, T>
|
||||||
|
where T: Default
|
||||||
|
{
|
||||||
|
pub fn or_default(self) -> &'a mut T {
|
||||||
|
&mut self.internal.or_insert(PathMapNode {
|
||||||
|
value: Default::default(),
|
||||||
|
children: HashSet::new(),
|
||||||
|
}).value
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,15 +6,16 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
use rbx_tree::{RbxTree, RbxId};
|
use rbx_tree::{RbxTree, RbxId};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
project::{Project, InstanceProjectNodeMetadata},
|
project::Project,
|
||||||
message_queue::MessageQueue,
|
message_queue::MessageQueue,
|
||||||
imfs::{Imfs, ImfsItem},
|
imfs::{Imfs, ImfsItem},
|
||||||
path_map::PathMap,
|
path_map::PathMap,
|
||||||
rbx_snapshot::{SnapshotMetadata, snapshot_project_tree, snapshot_imfs_path},
|
rbx_snapshot::{SnapshotContext, snapshot_project_tree, snapshot_imfs_path},
|
||||||
snapshot_reconciler::{InstanceChanges, reify_root, reconcile_subtree},
|
snapshot_reconciler::{InstanceChanges, reify_root, reconcile_subtree},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,11 +23,25 @@ const INIT_SCRIPT: &str = "init.lua";
|
|||||||
const INIT_SERVER_SCRIPT: &str = "init.server.lua";
|
const INIT_SERVER_SCRIPT: &str = "init.server.lua";
|
||||||
const INIT_CLIENT_SCRIPT: &str = "init.client.lua";
|
const INIT_CLIENT_SCRIPT: &str = "init.client.lua";
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
|
pub struct MetadataPerPath {
|
||||||
|
pub instance_id: Option<RbxId>,
|
||||||
|
pub instance_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
|
pub struct MetadataPerInstance {
|
||||||
|
pub source_path: Option<PathBuf>,
|
||||||
|
pub ignore_unknown_instances: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct RbxSession {
|
pub struct RbxSession {
|
||||||
tree: RbxTree,
|
tree: RbxTree,
|
||||||
path_map: PathMap<RbxId>,
|
|
||||||
instance_metadata_map: HashMap<RbxId, InstanceProjectNodeMetadata>,
|
// TODO(#105): Change metadata_per_path to PathMap<Vec<MetadataPerPath>> for
|
||||||
sync_point_names: HashMap<PathBuf, String>,
|
// path aliasing.
|
||||||
|
metadata_per_path: PathMap<MetadataPerPath>,
|
||||||
|
metadata_per_instance: HashMap<RbxId, MetadataPerInstance>,
|
||||||
message_queue: Arc<MessageQueue<InstanceChanges>>,
|
message_queue: Arc<MessageQueue<InstanceChanges>>,
|
||||||
imfs: Arc<Mutex<Imfs>>,
|
imfs: Arc<Mutex<Imfs>>,
|
||||||
}
|
}
|
||||||
@@ -37,20 +52,18 @@ impl RbxSession {
|
|||||||
imfs: Arc<Mutex<Imfs>>,
|
imfs: Arc<Mutex<Imfs>>,
|
||||||
message_queue: Arc<MessageQueue<InstanceChanges>>,
|
message_queue: Arc<MessageQueue<InstanceChanges>>,
|
||||||
) -> RbxSession {
|
) -> RbxSession {
|
||||||
let mut sync_point_names = HashMap::new();
|
let mut metadata_per_path = PathMap::new();
|
||||||
let mut path_map = PathMap::new();
|
let mut metadata_per_instance = HashMap::new();
|
||||||
let mut instance_metadata_map = HashMap::new();
|
|
||||||
|
|
||||||
let tree = {
|
let tree = {
|
||||||
let temp_imfs = imfs.lock().unwrap();
|
let temp_imfs = imfs.lock().unwrap();
|
||||||
reify_initial_tree(&project, &temp_imfs, &mut path_map, &mut instance_metadata_map, &mut sync_point_names)
|
reify_initial_tree(&project, &temp_imfs, &mut metadata_per_path, &mut metadata_per_instance)
|
||||||
};
|
};
|
||||||
|
|
||||||
RbxSession {
|
RbxSession {
|
||||||
tree,
|
tree,
|
||||||
path_map,
|
metadata_per_path,
|
||||||
instance_metadata_map,
|
metadata_per_instance,
|
||||||
sync_point_names,
|
|
||||||
message_queue,
|
message_queue,
|
||||||
imfs,
|
imfs,
|
||||||
}
|
}
|
||||||
@@ -67,8 +80,7 @@ impl RbxSession {
|
|||||||
.expect("Path was outside in-memory filesystem roots");
|
.expect("Path was outside in-memory filesystem roots");
|
||||||
|
|
||||||
// Find the closest instance in the tree that currently exists
|
// Find the closest instance in the tree that currently exists
|
||||||
let mut path_to_snapshot = self.path_map.descend(root_path, path);
|
let mut path_to_snapshot = self.metadata_per_path.descend(root_path, path);
|
||||||
let &instance_id = self.path_map.get(&path_to_snapshot).unwrap();
|
|
||||||
|
|
||||||
// If this is a file that might affect its parent if modified, we
|
// If this is a file that might affect its parent if modified, we
|
||||||
// should snapshot its parent instead.
|
// should snapshot its parent instead.
|
||||||
@@ -81,12 +93,19 @@ impl RbxSession {
|
|||||||
|
|
||||||
trace!("Snapshotting path {}", path_to_snapshot.display());
|
trace!("Snapshotting path {}", path_to_snapshot.display());
|
||||||
|
|
||||||
let instance_name = self.sync_point_names.get(&path_to_snapshot)
|
let path_metadata = self.metadata_per_path.get(&path_to_snapshot).unwrap();
|
||||||
|
let instance_id = path_metadata.instance_id
|
||||||
|
.expect("Instance did not exist in tree");
|
||||||
|
|
||||||
|
// If this instance is a sync point, pull its name out of our
|
||||||
|
// per-path metadata store.
|
||||||
|
let instance_name = path_metadata.instance_name.as_ref()
|
||||||
.map(|value| Cow::Owned(value.to_owned()));
|
.map(|value| Cow::Owned(value.to_owned()));
|
||||||
let mut snapshot_meta = SnapshotMetadata {
|
|
||||||
sync_point_names: &mut self.sync_point_names,
|
let mut context = SnapshotContext {
|
||||||
|
metadata_per_path: &mut self.metadata_per_path,
|
||||||
};
|
};
|
||||||
let maybe_snapshot = snapshot_imfs_path(&imfs, &mut snapshot_meta, &path_to_snapshot, instance_name)
|
let maybe_snapshot = snapshot_imfs_path(&imfs, &mut context, &path_to_snapshot, instance_name)
|
||||||
.unwrap_or_else(|_| panic!("Could not generate instance snapshot for path {}", path_to_snapshot.display()));
|
.unwrap_or_else(|_| panic!("Could not generate instance snapshot for path {}", path_to_snapshot.display()));
|
||||||
|
|
||||||
let snapshot = match maybe_snapshot {
|
let snapshot = match maybe_snapshot {
|
||||||
@@ -103,8 +122,8 @@ impl RbxSession {
|
|||||||
&mut self.tree,
|
&mut self.tree,
|
||||||
instance_id,
|
instance_id,
|
||||||
&snapshot,
|
&snapshot,
|
||||||
&mut self.path_map,
|
&mut self.metadata_per_path,
|
||||||
&mut self.instance_metadata_map,
|
&mut self.metadata_per_instance,
|
||||||
&mut changes,
|
&mut changes,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -144,13 +163,13 @@ impl RbxSession {
|
|||||||
|
|
||||||
pub fn path_removed(&mut self, path: &Path) {
|
pub fn path_removed(&mut self, path: &Path) {
|
||||||
info!("Path removed: {}", path.display());
|
info!("Path removed: {}", path.display());
|
||||||
self.path_map.remove(path);
|
self.metadata_per_path.remove(path);
|
||||||
self.path_created_or_updated(path);
|
self.path_created_or_updated(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_renamed(&mut self, from_path: &Path, to_path: &Path) {
|
pub fn path_renamed(&mut self, from_path: &Path, to_path: &Path) {
|
||||||
info!("Path renamed from {} to {}", from_path.display(), to_path.display());
|
info!("Path renamed from {} to {}", from_path.display(), to_path.display());
|
||||||
self.path_map.remove(from_path);
|
self.metadata_per_path.remove(from_path);
|
||||||
self.path_created_or_updated(from_path);
|
self.path_created_or_updated(from_path);
|
||||||
self.path_created_or_updated(to_path);
|
self.path_created_or_updated(to_path);
|
||||||
}
|
}
|
||||||
@@ -159,38 +178,36 @@ impl RbxSession {
|
|||||||
&self.tree
|
&self.tree
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_instance_metadata(&self, id: RbxId) -> Option<&InstanceProjectNodeMetadata> {
|
pub fn get_instance_metadata(&self, id: RbxId) -> Option<&MetadataPerInstance> {
|
||||||
self.instance_metadata_map.get(&id)
|
self.metadata_per_instance.get(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_get_path_map(&self) -> &PathMap<RbxId> {
|
pub fn debug_get_metadata_per_path(&self) -> &PathMap<MetadataPerPath> {
|
||||||
&self.path_map
|
&self.metadata_per_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct_oneoff_tree(project: &Project, imfs: &Imfs) -> RbxTree {
|
pub fn construct_oneoff_tree(project: &Project, imfs: &Imfs) -> RbxTree {
|
||||||
let mut path_map = PathMap::new();
|
let mut metadata_per_path = PathMap::new();
|
||||||
let mut instance_metadata_map = HashMap::new();
|
let mut metadata_per_instance = HashMap::new();
|
||||||
let mut sync_point_names = HashMap::new();
|
reify_initial_tree(project, imfs, &mut metadata_per_path, &mut metadata_per_instance)
|
||||||
reify_initial_tree(project, imfs, &mut path_map, &mut instance_metadata_map, &mut sync_point_names)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reify_initial_tree(
|
fn reify_initial_tree(
|
||||||
project: &Project,
|
project: &Project,
|
||||||
imfs: &Imfs,
|
imfs: &Imfs,
|
||||||
path_map: &mut PathMap<RbxId>,
|
metadata_per_path: &mut PathMap<MetadataPerPath>,
|
||||||
instance_metadata_map: &mut HashMap<RbxId, InstanceProjectNodeMetadata>,
|
metadata_per_instance: &mut HashMap<RbxId, MetadataPerInstance>,
|
||||||
sync_point_names: &mut HashMap<PathBuf, String>,
|
|
||||||
) -> RbxTree {
|
) -> RbxTree {
|
||||||
let mut meta = SnapshotMetadata {
|
let mut context = SnapshotContext {
|
||||||
sync_point_names,
|
metadata_per_path,
|
||||||
};
|
};
|
||||||
let snapshot = snapshot_project_tree(imfs, &mut meta, project)
|
let snapshot = snapshot_project_tree(imfs, &mut context, project)
|
||||||
.expect("Could not snapshot project tree")
|
.expect("Could not snapshot project tree")
|
||||||
.expect("Project did not produce any instances");
|
.expect("Project did not produce any instances");
|
||||||
|
|
||||||
let mut changes = InstanceChanges::default();
|
let mut changes = InstanceChanges::default();
|
||||||
let tree = reify_root(&snapshot, path_map, instance_metadata_map, &mut changes);
|
let tree = reify_root(&snapshot, metadata_per_path, metadata_per_instance, &mut changes);
|
||||||
|
|
||||||
tree
|
tree
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,9 @@ use crate::{
|
|||||||
RbxSnapshotInstance,
|
RbxSnapshotInstance,
|
||||||
snapshot_from_tree,
|
snapshot_from_tree,
|
||||||
},
|
},
|
||||||
|
path_map::PathMap,
|
||||||
|
// TODO: Move MetadataPerPath into this module?
|
||||||
|
rbx_session::{MetadataPerPath, MetadataPerInstance},
|
||||||
};
|
};
|
||||||
|
|
||||||
const INIT_MODULE_NAME: &str = "init.lua";
|
const INIT_MODULE_NAME: &str = "init.lua";
|
||||||
@@ -36,8 +39,8 @@ const INIT_CLIENT_NAME: &str = "init.client.lua";
|
|||||||
|
|
||||||
pub type SnapshotResult<'a> = Result<Option<RbxSnapshotInstance<'a>>, SnapshotError>;
|
pub type SnapshotResult<'a> = Result<Option<RbxSnapshotInstance<'a>>, SnapshotError>;
|
||||||
|
|
||||||
pub struct SnapshotMetadata<'meta> {
|
pub struct SnapshotContext<'meta> {
|
||||||
pub sync_point_names: &'meta mut HashMap<PathBuf, String>,
|
pub metadata_per_path: &'meta mut PathMap<MetadataPerPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
@@ -80,34 +83,34 @@ impl fmt::Display for SnapshotError {
|
|||||||
|
|
||||||
pub fn snapshot_project_tree<'source>(
|
pub fn snapshot_project_tree<'source>(
|
||||||
imfs: &'source Imfs,
|
imfs: &'source Imfs,
|
||||||
metadata: &mut SnapshotMetadata,
|
context: &mut SnapshotContext,
|
||||||
project: &'source Project,
|
project: &'source Project,
|
||||||
) -> SnapshotResult<'source> {
|
) -> SnapshotResult<'source> {
|
||||||
snapshot_project_node(imfs, metadata, &project.tree, Cow::Borrowed(&project.name))
|
snapshot_project_node(imfs, context, &project.tree, Cow::Borrowed(&project.name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot_project_node<'source>(
|
fn snapshot_project_node<'source>(
|
||||||
imfs: &'source Imfs,
|
imfs: &'source Imfs,
|
||||||
metadata: &mut SnapshotMetadata,
|
context: &mut SnapshotContext,
|
||||||
node: &'source ProjectNode,
|
node: &'source ProjectNode,
|
||||||
instance_name: Cow<'source, str>,
|
instance_name: Cow<'source, str>,
|
||||||
) -> SnapshotResult<'source> {
|
) -> SnapshotResult<'source> {
|
||||||
match node {
|
match node {
|
||||||
ProjectNode::Instance(instance_node) => snapshot_instance_node(imfs, metadata, instance_node, instance_name),
|
ProjectNode::Instance(instance_node) => snapshot_instance_node(imfs, context, instance_node, instance_name),
|
||||||
ProjectNode::SyncPoint(sync_node) => snapshot_sync_point_node(imfs, metadata, sync_node, instance_name),
|
ProjectNode::SyncPoint(sync_node) => snapshot_sync_point_node(imfs, context, sync_node, instance_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot_instance_node<'source>(
|
fn snapshot_instance_node<'source>(
|
||||||
imfs: &'source Imfs,
|
imfs: &'source Imfs,
|
||||||
metadata: &mut SnapshotMetadata,
|
context: &mut SnapshotContext,
|
||||||
node: &'source InstanceProjectNode,
|
node: &'source InstanceProjectNode,
|
||||||
instance_name: Cow<'source, str>,
|
instance_name: Cow<'source, str>,
|
||||||
) -> SnapshotResult<'source> {
|
) -> SnapshotResult<'source> {
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
|
|
||||||
for (child_name, child_project_node) in &node.children {
|
for (child_name, child_project_node) in &node.children {
|
||||||
if let Some(child) = snapshot_project_node(imfs, metadata, child_project_node, Cow::Borrowed(child_name))? {
|
if let Some(child) = snapshot_project_node(imfs, context, child_project_node, Cow::Borrowed(child_name))? {
|
||||||
children.push(child);
|
children.push(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,18 +120,20 @@ fn snapshot_instance_node<'source>(
|
|||||||
name: instance_name,
|
name: instance_name,
|
||||||
properties: node.properties.clone(),
|
properties: node.properties.clone(),
|
||||||
children,
|
children,
|
||||||
source_path: None,
|
metadata: MetadataPerInstance {
|
||||||
metadata: Some(node.metadata.clone()),
|
source_path: None,
|
||||||
|
ignore_unknown_instances: node.metadata.ignore_unknown_instances,
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot_sync_point_node<'source>(
|
fn snapshot_sync_point_node<'source>(
|
||||||
imfs: &'source Imfs,
|
imfs: &'source Imfs,
|
||||||
metadata: &mut SnapshotMetadata,
|
context: &mut SnapshotContext,
|
||||||
node: &'source SyncPointProjectNode,
|
node: &'source SyncPointProjectNode,
|
||||||
instance_name: Cow<'source, str>,
|
instance_name: Cow<'source, str>,
|
||||||
) -> SnapshotResult<'source> {
|
) -> SnapshotResult<'source> {
|
||||||
let maybe_snapshot = snapshot_imfs_path(imfs, metadata, &node.path, Some(instance_name))?;
|
let maybe_snapshot = snapshot_imfs_path(imfs, context, &node.path, Some(instance_name))?;
|
||||||
|
|
||||||
// If the snapshot resulted in no instances, like if it targets an unknown
|
// If the snapshot resulted in no instances, like if it targets an unknown
|
||||||
// file or an empty model file, we can early-return.
|
// file or an empty model file, we can early-return.
|
||||||
@@ -138,40 +143,41 @@ fn snapshot_sync_point_node<'source>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Otherwise, we can log the name of the sync point we just snapshotted.
|
// Otherwise, we can log the name of the sync point we just snapshotted.
|
||||||
metadata.sync_point_names.insert(node.path.to_owned(), snapshot.name.clone().into_owned());
|
let path_meta = context.metadata_per_path.entry(node.path.to_owned()).or_default();
|
||||||
|
path_meta.instance_name = Some(snapshot.name.clone().into_owned());
|
||||||
|
|
||||||
Ok(Some(snapshot))
|
Ok(Some(snapshot))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snapshot_imfs_path<'source>(
|
pub fn snapshot_imfs_path<'source>(
|
||||||
imfs: &'source Imfs,
|
imfs: &'source Imfs,
|
||||||
metadata: &mut SnapshotMetadata,
|
context: &mut SnapshotContext,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
instance_name: Option<Cow<'source, str>>,
|
instance_name: Option<Cow<'source, str>>,
|
||||||
) -> SnapshotResult<'source> {
|
) -> SnapshotResult<'source> {
|
||||||
// If the given path doesn't exist in the in-memory filesystem, we consider
|
// If the given path doesn't exist in the in-memory filesystem, we consider
|
||||||
// that an error.
|
// that an error.
|
||||||
match imfs.get(path) {
|
match imfs.get(path) {
|
||||||
Some(imfs_item) => snapshot_imfs_item(imfs, metadata, imfs_item, instance_name),
|
Some(imfs_item) => snapshot_imfs_item(imfs, context, imfs_item, instance_name),
|
||||||
None => return Err(SnapshotError::DidNotExist(path.to_owned())),
|
None => return Err(SnapshotError::DidNotExist(path.to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot_imfs_item<'source>(
|
fn snapshot_imfs_item<'source>(
|
||||||
imfs: &'source Imfs,
|
imfs: &'source Imfs,
|
||||||
metadata: &mut SnapshotMetadata,
|
context: &mut SnapshotContext,
|
||||||
item: &'source ImfsItem,
|
item: &'source ImfsItem,
|
||||||
instance_name: Option<Cow<'source, str>>,
|
instance_name: Option<Cow<'source, str>>,
|
||||||
) -> SnapshotResult<'source> {
|
) -> SnapshotResult<'source> {
|
||||||
match item {
|
match item {
|
||||||
ImfsItem::File(file) => snapshot_imfs_file(file, instance_name),
|
ImfsItem::File(file) => snapshot_imfs_file(file, instance_name),
|
||||||
ImfsItem::Directory(directory) => snapshot_imfs_directory(imfs, metadata, directory, instance_name),
|
ImfsItem::Directory(directory) => snapshot_imfs_directory(imfs, context, directory, instance_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot_imfs_directory<'source>(
|
fn snapshot_imfs_directory<'source>(
|
||||||
imfs: &'source Imfs,
|
imfs: &'source Imfs,
|
||||||
metadata: &mut SnapshotMetadata,
|
context: &mut SnapshotContext,
|
||||||
directory: &'source ImfsDirectory,
|
directory: &'source ImfsDirectory,
|
||||||
instance_name: Option<Cow<'source, str>>,
|
instance_name: Option<Cow<'source, str>>,
|
||||||
) -> SnapshotResult<'source> {
|
) -> SnapshotResult<'source> {
|
||||||
@@ -187,19 +193,21 @@ fn snapshot_imfs_directory<'source>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
let mut snapshot = if directory.children.contains(&init_path) {
|
let mut snapshot = if directory.children.contains(&init_path) {
|
||||||
snapshot_imfs_path(imfs, metadata, &init_path, Some(snapshot_name))?.unwrap()
|
snapshot_imfs_path(imfs, context, &init_path, Some(snapshot_name))?.unwrap()
|
||||||
} else if directory.children.contains(&init_server_path) {
|
} else if directory.children.contains(&init_server_path) {
|
||||||
snapshot_imfs_path(imfs, metadata, &init_server_path, Some(snapshot_name))?.unwrap()
|
snapshot_imfs_path(imfs, context, &init_server_path, Some(snapshot_name))?.unwrap()
|
||||||
} else if directory.children.contains(&init_client_path) {
|
} else if directory.children.contains(&init_client_path) {
|
||||||
snapshot_imfs_path(imfs, metadata, &init_client_path, Some(snapshot_name))?.unwrap()
|
snapshot_imfs_path(imfs, context, &init_client_path, Some(snapshot_name))?.unwrap()
|
||||||
} else {
|
} else {
|
||||||
RbxSnapshotInstance {
|
RbxSnapshotInstance {
|
||||||
class_name: Cow::Borrowed("Folder"),
|
class_name: Cow::Borrowed("Folder"),
|
||||||
name: snapshot_name,
|
name: snapshot_name,
|
||||||
properties: HashMap::new(),
|
properties: HashMap::new(),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
source_path: Some(directory.path.to_owned()),
|
metadata: MetadataPerInstance {
|
||||||
metadata: None,
|
source_path: Some(directory.path.to_owned()),
|
||||||
|
ignore_unknown_instances: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -215,7 +223,7 @@ fn snapshot_imfs_directory<'source>(
|
|||||||
// them here.
|
// them here.
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(child) = snapshot_imfs_path(imfs, metadata, child_path, None)? {
|
if let Some(child) = snapshot_imfs_path(imfs, context, child_path, None)? {
|
||||||
snapshot.children.push(child);
|
snapshot.children.push(child);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -281,8 +289,10 @@ fn snapshot_lua_file<'source>(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
metadata: None,
|
metadata: MetadataPerInstance {
|
||||||
source_path: Some(file.path.to_path_buf()),
|
source_path: Some(file.path.to_path_buf()),
|
||||||
|
ignore_unknown_instances: false,
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,8 +327,10 @@ fn snapshot_txt_file<'source>(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
metadata: None,
|
metadata: MetadataPerInstance {
|
||||||
source_path: Some(file.path.to_path_buf()),
|
source_path: Some(file.path.to_path_buf()),
|
||||||
|
ignore_unknown_instances: false,
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,8 +360,10 @@ fn snapshot_csv_file<'source>(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
metadata: None,
|
metadata: MetadataPerInstance {
|
||||||
source_path: Some(file.path.to_path_buf()),
|
source_path: Some(file.path.to_path_buf()),
|
||||||
|
ignore_unknown_instances: false,
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use std::{
|
|||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
fmt,
|
fmt,
|
||||||
path::PathBuf,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use rbx_tree::{RbxTree, RbxId, RbxInstanceProperties, RbxValue};
|
use rbx_tree::{RbxTree, RbxId, RbxInstanceProperties, RbxValue};
|
||||||
@@ -11,7 +10,7 @@ use serde_derive::{Serialize, Deserialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
path_map::PathMap,
|
path_map::PathMap,
|
||||||
project::InstanceProjectNodeMetadata,
|
rbx_session::{MetadataPerPath, MetadataPerInstance},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
@@ -62,8 +61,7 @@ pub struct RbxSnapshotInstance<'a> {
|
|||||||
pub class_name: Cow<'a, str>,
|
pub class_name: Cow<'a, str>,
|
||||||
pub properties: HashMap<String, RbxValue>,
|
pub properties: HashMap<String, RbxValue>,
|
||||||
pub children: Vec<RbxSnapshotInstance<'a>>,
|
pub children: Vec<RbxSnapshotInstance<'a>>,
|
||||||
pub source_path: Option<PathBuf>,
|
pub metadata: MetadataPerInstance,
|
||||||
pub metadata: Option<InstanceProjectNodeMetadata>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snapshot_from_tree(tree: &RbxTree, id: RbxId) -> Option<RbxSnapshotInstance<'static>> {
|
pub fn snapshot_from_tree(tree: &RbxTree, id: RbxId) -> Option<RbxSnapshotInstance<'static>> {
|
||||||
@@ -79,33 +77,34 @@ pub fn snapshot_from_tree(tree: &RbxTree, id: RbxId) -> Option<RbxSnapshotInstan
|
|||||||
class_name: Cow::Owned(instance.class_name.to_owned()),
|
class_name: Cow::Owned(instance.class_name.to_owned()),
|
||||||
properties: instance.properties.clone(),
|
properties: instance.properties.clone(),
|
||||||
children,
|
children,
|
||||||
source_path: None,
|
metadata: MetadataPerInstance {
|
||||||
metadata: None,
|
source_path: None,
|
||||||
|
ignore_unknown_instances: false,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reify_root(
|
pub fn reify_root(
|
||||||
snapshot: &RbxSnapshotInstance,
|
snapshot: &RbxSnapshotInstance,
|
||||||
path_map: &mut PathMap<RbxId>,
|
metadata_per_path: &mut PathMap<MetadataPerPath>,
|
||||||
instance_metadata_map: &mut HashMap<RbxId, InstanceProjectNodeMetadata>,
|
instance_metadata_map: &mut HashMap<RbxId, MetadataPerInstance>,
|
||||||
changes: &mut InstanceChanges,
|
changes: &mut InstanceChanges,
|
||||||
) -> RbxTree {
|
) -> RbxTree {
|
||||||
let instance = reify_core(snapshot);
|
let instance = reify_core(snapshot);
|
||||||
let mut tree = RbxTree::new(instance);
|
let mut tree = RbxTree::new(instance);
|
||||||
let root_id = tree.get_root_id();
|
let root_id = tree.get_root_id();
|
||||||
|
|
||||||
if let Some(source_path) = &snapshot.source_path {
|
if let Some(source_path) = &snapshot.metadata.source_path {
|
||||||
path_map.insert(source_path.clone(), root_id);
|
let path_meta = metadata_per_path.entry(source_path.to_owned()).or_default();
|
||||||
|
path_meta.instance_id = Some(root_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(metadata) = &snapshot.metadata {
|
instance_metadata_map.insert(root_id, snapshot.metadata.clone());
|
||||||
instance_metadata_map.insert(root_id, metadata.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
changes.added.insert(root_id);
|
changes.added.insert(root_id);
|
||||||
|
|
||||||
for child in &snapshot.children {
|
for child in &snapshot.children {
|
||||||
reify_subtree(child, &mut tree, root_id, path_map, instance_metadata_map, changes);
|
reify_subtree(child, &mut tree, root_id, metadata_per_path, instance_metadata_map, changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree
|
tree
|
||||||
@@ -115,25 +114,24 @@ pub fn reify_subtree(
|
|||||||
snapshot: &RbxSnapshotInstance,
|
snapshot: &RbxSnapshotInstance,
|
||||||
tree: &mut RbxTree,
|
tree: &mut RbxTree,
|
||||||
parent_id: RbxId,
|
parent_id: RbxId,
|
||||||
path_map: &mut PathMap<RbxId>,
|
metadata_per_path: &mut PathMap<MetadataPerPath>,
|
||||||
instance_metadata_map: &mut HashMap<RbxId, InstanceProjectNodeMetadata>,
|
instance_metadata_map: &mut HashMap<RbxId, MetadataPerInstance>,
|
||||||
changes: &mut InstanceChanges,
|
changes: &mut InstanceChanges,
|
||||||
) {
|
) {
|
||||||
let instance = reify_core(snapshot);
|
let instance = reify_core(snapshot);
|
||||||
let id = tree.insert_instance(instance, parent_id);
|
let id = tree.insert_instance(instance, parent_id);
|
||||||
|
|
||||||
if let Some(source_path) = &snapshot.source_path {
|
if let Some(source_path) = &snapshot.metadata.source_path {
|
||||||
path_map.insert(source_path.clone(), id);
|
let path_meta = metadata_per_path.entry(source_path.clone()).or_default();
|
||||||
|
path_meta.instance_id = Some(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(metadata) = &snapshot.metadata {
|
instance_metadata_map.insert(id, snapshot.metadata.clone());
|
||||||
instance_metadata_map.insert(id, metadata.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
changes.added.insert(id);
|
changes.added.insert(id);
|
||||||
|
|
||||||
for child in &snapshot.children {
|
for child in &snapshot.children {
|
||||||
reify_subtree(child, tree, id, path_map, instance_metadata_map, changes);
|
reify_subtree(child, tree, id, metadata_per_path, instance_metadata_map, changes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,23 +139,22 @@ pub fn reconcile_subtree(
|
|||||||
tree: &mut RbxTree,
|
tree: &mut RbxTree,
|
||||||
id: RbxId,
|
id: RbxId,
|
||||||
snapshot: &RbxSnapshotInstance,
|
snapshot: &RbxSnapshotInstance,
|
||||||
path_map: &mut PathMap<RbxId>,
|
metadata_per_path: &mut PathMap<MetadataPerPath>,
|
||||||
instance_metadata_map: &mut HashMap<RbxId, InstanceProjectNodeMetadata>,
|
instance_metadata_map: &mut HashMap<RbxId, MetadataPerInstance>,
|
||||||
changes: &mut InstanceChanges,
|
changes: &mut InstanceChanges,
|
||||||
) {
|
) {
|
||||||
if let Some(source_path) = &snapshot.source_path {
|
if let Some(source_path) = &snapshot.metadata.source_path {
|
||||||
path_map.insert(source_path.clone(), id);
|
let path_meta = metadata_per_path.entry(source_path.to_owned()).or_default();
|
||||||
|
path_meta.instance_id = Some(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(metadata) = &snapshot.metadata {
|
instance_metadata_map.insert(id, snapshot.metadata.clone());
|
||||||
instance_metadata_map.insert(id, metadata.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
if reconcile_instance_properties(tree.get_instance_mut(id).unwrap(), snapshot) {
|
if reconcile_instance_properties(tree.get_instance_mut(id).unwrap(), snapshot) {
|
||||||
changes.updated.insert(id);
|
changes.updated.insert(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
reconcile_instance_children(tree, id, snapshot, path_map, instance_metadata_map, changes);
|
reconcile_instance_children(tree, id, snapshot, metadata_per_path, instance_metadata_map, changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reify_core(snapshot: &RbxSnapshotInstance) -> RbxInstanceProperties {
|
fn reify_core(snapshot: &RbxSnapshotInstance) -> RbxInstanceProperties {
|
||||||
@@ -237,8 +234,8 @@ fn reconcile_instance_children(
|
|||||||
tree: &mut RbxTree,
|
tree: &mut RbxTree,
|
||||||
id: RbxId,
|
id: RbxId,
|
||||||
snapshot: &RbxSnapshotInstance,
|
snapshot: &RbxSnapshotInstance,
|
||||||
path_map: &mut PathMap<RbxId>,
|
metadata_per_path: &mut PathMap<MetadataPerPath>,
|
||||||
instance_metadata_map: &mut HashMap<RbxId, InstanceProjectNodeMetadata>,
|
instance_metadata_map: &mut HashMap<RbxId, MetadataPerInstance>,
|
||||||
changes: &mut InstanceChanges,
|
changes: &mut InstanceChanges,
|
||||||
) {
|
) {
|
||||||
let mut visited_snapshot_indices = HashSet::new();
|
let mut visited_snapshot_indices = HashSet::new();
|
||||||
@@ -290,7 +287,7 @@ fn reconcile_instance_children(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for child_snapshot in &children_to_add {
|
for child_snapshot in &children_to_add {
|
||||||
reify_subtree(child_snapshot, tree, id, path_map, instance_metadata_map, changes);
|
reify_subtree(child_snapshot, tree, id, metadata_per_path, instance_metadata_map, changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
for child_id in &children_to_remove {
|
for child_id in &children_to_remove {
|
||||||
@@ -303,6 +300,6 @@ fn reconcile_instance_children(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (child_id, child_snapshot) in &children_to_update {
|
for (child_id, child_snapshot) in &children_to_update {
|
||||||
reconcile_subtree(tree, *child_id, child_snapshot, path_map, instance_metadata_map, changes);
|
reconcile_subtree(tree, *child_id, child_snapshot, metadata_per_path, instance_metadata_map, changes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,11 +17,25 @@ use rbx_tree::{RbxId, RbxInstance};
|
|||||||
use crate::{
|
use crate::{
|
||||||
session::Session,
|
session::Session,
|
||||||
session_id::SessionId,
|
session_id::SessionId,
|
||||||
project::InstanceProjectNodeMetadata,
|
|
||||||
snapshot_reconciler::InstanceChanges,
|
snapshot_reconciler::InstanceChanges,
|
||||||
visualize::{VisualizeRbxSession, VisualizeImfs, graphviz_to_svg},
|
visualize::{VisualizeRbxSession, VisualizeImfs, graphviz_to_svg},
|
||||||
|
rbx_session::{MetadataPerInstance},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Contains the instance metadata relevant to Rojo clients.
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct InstanceMetadata {
|
||||||
|
ignore_unknown_instances: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstanceMetadata {
|
||||||
|
fn from_session_metadata(meta: &MetadataPerInstance) -> InstanceMetadata {
|
||||||
|
InstanceMetadata {
|
||||||
|
ignore_unknown_instances: meta.ignore_unknown_instances,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Used to attach metadata specific to Rojo to instances, which come from the
|
/// Used to attach metadata specific to Rojo to instances, which come from the
|
||||||
/// rbx_tree crate.
|
/// rbx_tree crate.
|
||||||
///
|
///
|
||||||
@@ -33,7 +47,7 @@ pub struct InstanceWithMetadata<'a> {
|
|||||||
pub instance: Cow<'a, RbxInstance>,
|
pub instance: Cow<'a, RbxInstance>,
|
||||||
|
|
||||||
#[serde(rename = "Metadata")]
|
#[serde(rename = "Metadata")]
|
||||||
pub metadata: Option<Cow<'a, InstanceProjectNodeMetadata>>,
|
pub metadata: Option<InstanceMetadata>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@@ -163,7 +177,7 @@ impl Server {
|
|||||||
for &requested_id in &requested_ids {
|
for &requested_id in &requested_ids {
|
||||||
if let Some(instance) = tree.get_instance(requested_id) {
|
if let Some(instance) = tree.get_instance(requested_id) {
|
||||||
let metadata = rbx_session.get_instance_metadata(requested_id)
|
let metadata = rbx_session.get_instance_metadata(requested_id)
|
||||||
.map(Cow::Borrowed);
|
.map(InstanceMetadata::from_session_metadata);
|
||||||
|
|
||||||
instances.insert(instance.get_id(), InstanceWithMetadata {
|
instances.insert(instance.get_id(), InstanceWithMetadata {
|
||||||
instance: Cow::Borrowed(instance),
|
instance: Cow::Borrowed(instance),
|
||||||
@@ -172,7 +186,7 @@ impl Server {
|
|||||||
|
|
||||||
for descendant in tree.descendants(requested_id) {
|
for descendant in tree.descendants(requested_id) {
|
||||||
let descendant_meta = rbx_session.get_instance_metadata(descendant.get_id())
|
let descendant_meta = rbx_session.get_instance_metadata(descendant.get_id())
|
||||||
.map(Cow::Borrowed);
|
.map(InstanceMetadata::from_session_metadata);
|
||||||
|
|
||||||
instances.insert(descendant.get_id(), InstanceWithMetadata {
|
instances.insert(descendant.get_id(), InstanceWithMetadata {
|
||||||
instance: Cow::Borrowed(descendant),
|
instance: Cow::Borrowed(descendant),
|
||||||
@@ -205,10 +219,10 @@ impl Server {
|
|||||||
Response::svg(graphviz_to_svg(&dot_source))
|
Response::svg(graphviz_to_svg(&dot_source))
|
||||||
},
|
},
|
||||||
|
|
||||||
(GET) (/visualize/path_map) => {
|
(GET) (/visualize/path_metadata) => {
|
||||||
let rbx_session = self.session.rbx_session.lock().unwrap();
|
let rbx_session = self.session.rbx_session.lock().unwrap();
|
||||||
|
|
||||||
Response::json(&rbx_session.debug_get_path_map())
|
Response::json(&rbx_session.debug_get_metadata_per_path())
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => Response::empty_404()
|
_ => Response::empty_404()
|
||||||
|
|||||||
Reference in New Issue
Block a user