mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-21 05:06:29 +00:00
Clean up VFS code to make it much more robust
This commit is contained in:
@@ -37,8 +37,12 @@ impl RbxSession {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_created_or_updated(&mut self, path: &Path) {
|
||||
info!("Path changed: {}", path.display());
|
||||
pub fn path_created(&mut self, path: &Path) {
|
||||
info!("Path created: {}", path.display());
|
||||
}
|
||||
|
||||
pub fn path_updated(&mut self, path: &Path) {
|
||||
info!("Path updated: {}", path.display());
|
||||
}
|
||||
|
||||
pub fn path_removed(&mut self, path: &Path) {
|
||||
@@ -121,7 +125,7 @@ fn construct_sync_point_node(
|
||||
) {
|
||||
match vfs.get(&file_path) {
|
||||
Some(VfsItem::File(file)) => {
|
||||
let contents = str::from_utf8(vfs.get_contents(&file.path).unwrap()).unwrap();
|
||||
let contents = str::from_utf8(&file.contents).unwrap();
|
||||
|
||||
let mut properties = HashMap::new();
|
||||
properties.insert("Source".to_string(), RbxValue::String { value: contents.to_string() });
|
||||
|
||||
@@ -90,21 +90,32 @@ impl Session {
|
||||
match watch_rx.recv() {
|
||||
Ok(event) => {
|
||||
match event {
|
||||
DebouncedEvent::Create(path) | DebouncedEvent::Write(path) => {
|
||||
DebouncedEvent::Create(path) => {
|
||||
{
|
||||
let mut vfs = vfs.lock().unwrap();
|
||||
vfs.add_or_update(&path).unwrap();
|
||||
vfs.path_created(&path).unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
let mut rbx_session = rbx_session.lock().unwrap();
|
||||
rbx_session.path_created_or_updated(&path);
|
||||
rbx_session.path_created(&path);
|
||||
}
|
||||
},
|
||||
DebouncedEvent::Write(path) => {
|
||||
{
|
||||
let mut vfs = vfs.lock().unwrap();
|
||||
vfs.path_updated(&path).unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
let mut rbx_session = rbx_session.lock().unwrap();
|
||||
rbx_session.path_updated(&path);
|
||||
}
|
||||
},
|
||||
DebouncedEvent::Remove(path) => {
|
||||
{
|
||||
let mut vfs = vfs.lock().unwrap();
|
||||
vfs.remove(&path);
|
||||
vfs.path_removed(&path).unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
@@ -115,8 +126,7 @@ impl Session {
|
||||
DebouncedEvent::Rename(from_path, to_path) => {
|
||||
{
|
||||
let mut vfs = vfs.lock().unwrap();
|
||||
vfs.remove(&from_path);
|
||||
vfs.add_or_update(&to_path).unwrap();
|
||||
vfs.path_moved(&from_path, &to_path).unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@ use std::{
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Vfs {
|
||||
contents: HashMap<PathBuf, Vec<u8>>,
|
||||
items: HashMap<PathBuf, VfsItem>,
|
||||
roots: HashSet<PathBuf>,
|
||||
}
|
||||
@@ -15,81 +14,110 @@ pub struct Vfs {
|
||||
impl Vfs {
|
||||
pub fn new() -> Vfs {
|
||||
Vfs {
|
||||
contents: HashMap::new(),
|
||||
items: HashMap::new(),
|
||||
roots: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_root<'a, 'b>(&'a mut self, root_path: &'b Path) -> io::Result<&'a VfsItem> {
|
||||
debug_assert!(root_path.is_absolute());
|
||||
|
||||
self.roots.insert(root_path.to_path_buf());
|
||||
|
||||
VfsItem::get(self, root_path)
|
||||
}
|
||||
|
||||
pub fn get_roots(&self) -> &HashSet<PathBuf> {
|
||||
&self.roots
|
||||
}
|
||||
|
||||
pub fn get(&self, path: &Path) -> Option<&VfsItem> {
|
||||
debug_assert!(path.is_absolute());
|
||||
debug_assert!(self.is_valid_path(path));
|
||||
debug_assert!(self.is_within_roots(path));
|
||||
|
||||
self.items.get(path)
|
||||
}
|
||||
|
||||
pub fn get_contents(&self, path: &Path) -> Option<&[u8]> {
|
||||
pub fn add_root(&mut self, path: &Path) -> io::Result<()> {
|
||||
debug_assert!(path.is_absolute());
|
||||
debug_assert!(self.is_valid_path(path));
|
||||
debug_assert!(!self.is_within_roots(path));
|
||||
|
||||
self.contents.get(path).map(Vec::as_slice)
|
||||
self.roots.insert(path.to_path_buf());
|
||||
|
||||
VfsItem::read_from_disk(self, path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, path: &Path) {
|
||||
pub fn path_created(&mut self, path: &Path) -> io::Result<()> {
|
||||
debug_assert!(path.is_absolute());
|
||||
debug_assert!(self.is_valid_path(path));
|
||||
debug_assert!(self.is_within_roots(path));
|
||||
|
||||
match self.items.remove(path) {
|
||||
Some(item) => match item {
|
||||
VfsItem::File(_) => {
|
||||
self.contents.remove(path);
|
||||
},
|
||||
VfsItem::Directory(VfsDirectory { children, .. }) => {
|
||||
for child_path in &children {
|
||||
self.remove(child_path);
|
||||
}
|
||||
},
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_or_update<'a, 'b>(&'a mut self, path: &'b Path) -> io::Result<&'a VfsItem> {
|
||||
debug_assert!(path.is_absolute());
|
||||
debug_assert!(self.is_valid_path(path));
|
||||
|
||||
VfsItem::get(self, path)
|
||||
}
|
||||
|
||||
fn is_valid_path(&self, path: &Path) -> bool {
|
||||
let mut is_valid_path = false;
|
||||
|
||||
for root_path in &self.roots {
|
||||
if path.starts_with(root_path) {
|
||||
is_valid_path = true;
|
||||
break;
|
||||
if let Some(parent_path) = path.parent() {
|
||||
if self.is_within_roots(parent_path) && self.get(parent_path).is_none() {
|
||||
self.path_created(parent_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
is_valid_path
|
||||
VfsItem::read_from_disk(self, path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn path_updated(&mut self, path: &Path) -> io::Result<()> {
|
||||
debug_assert!(path.is_absolute());
|
||||
debug_assert!(self.is_within_roots(path));
|
||||
|
||||
if let Some(parent_path) = path.parent() {
|
||||
if self.is_within_roots(parent_path) && self.get(parent_path).is_none() {
|
||||
self.path_created(parent_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
VfsItem::read_from_disk(self, path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn path_removed(&mut self, path: &Path) -> io::Result<()> {
|
||||
debug_assert!(path.is_absolute());
|
||||
debug_assert!(self.is_within_roots(path));
|
||||
|
||||
if let Some(parent_path) = path.parent() {
|
||||
if self.is_within_roots(parent_path) {
|
||||
if let Some(VfsItem::Directory(parent)) = self.items.get_mut(parent_path) {
|
||||
parent.children.remove(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match self.items.remove(path) {
|
||||
Some(VfsItem::Directory(directory)) => {
|
||||
for child_path in &directory.children {
|
||||
self.path_removed(child_path)?;
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn path_moved(&mut self, from_path: &Path, to_path: &Path) -> io::Result<()> {
|
||||
debug_assert!(from_path.is_absolute());
|
||||
debug_assert!(self.is_within_roots(from_path));
|
||||
debug_assert!(to_path.is_absolute());
|
||||
debug_assert!(self.is_within_roots(to_path));
|
||||
|
||||
self.path_removed(from_path)?;
|
||||
self.path_created(to_path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_within_roots(&self, path: &Path) -> bool {
|
||||
for root_path in &self.roots {
|
||||
if path.starts_with(root_path) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VfsFile {
|
||||
pub path: PathBuf,
|
||||
pub contents: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -105,42 +133,41 @@ pub enum VfsItem {
|
||||
}
|
||||
|
||||
impl VfsItem {
|
||||
fn get<'a, 'b>(vfs: &'a mut Vfs, root_path: &'b Path) -> io::Result<&'a VfsItem> {
|
||||
let metadata = fs::metadata(root_path)?;
|
||||
fn read_from_disk<'a, 'b>(vfs: &'a mut Vfs, path: &'b Path) -> io::Result<&'a VfsItem> {
|
||||
let metadata = fs::metadata(path)?;
|
||||
|
||||
if metadata.is_file() {
|
||||
let contents = fs::read(path)?;
|
||||
let item = VfsItem::File(VfsFile {
|
||||
path: root_path.to_path_buf(),
|
||||
path: path.to_path_buf(),
|
||||
contents,
|
||||
});
|
||||
|
||||
vfs.items.insert(root_path.to_path_buf(), item);
|
||||
vfs.items.insert(path.to_path_buf(), item);
|
||||
|
||||
let contents = fs::read(root_path)?;
|
||||
vfs.contents.insert(root_path.to_path_buf(), contents);
|
||||
|
||||
Ok(vfs.items.get(root_path).unwrap())
|
||||
Ok(vfs.items.get(path).unwrap())
|
||||
} else if metadata.is_dir() {
|
||||
let mut children = HashSet::new();
|
||||
|
||||
for entry in fs::read_dir(root_path)? {
|
||||
for entry in fs::read_dir(path)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
let child_path = entry.path();
|
||||
|
||||
VfsItem::get(vfs, &path)?;
|
||||
VfsItem::read_from_disk(vfs, &child_path)?;
|
||||
|
||||
children.insert(path);
|
||||
children.insert(child_path);
|
||||
}
|
||||
|
||||
let item = VfsItem::Directory(VfsDirectory {
|
||||
path: root_path.to_path_buf(),
|
||||
path: path.to_path_buf(),
|
||||
children,
|
||||
});
|
||||
|
||||
vfs.items.insert(root_path.to_path_buf(), item);
|
||||
vfs.items.insert(path.to_path_buf(), item);
|
||||
|
||||
Ok(vfs.items.get(root_path).unwrap())
|
||||
Ok(vfs.items.get(path).unwrap())
|
||||
} else {
|
||||
unimplemented!();
|
||||
panic!("Unexpected non-file, non-directory item");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user