From da05078ff3b5b616eb07957ed26c4d5539e28270 Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Wed, 17 Jun 2020 23:13:29 -0700 Subject: [PATCH] Load project file from VFS instead of through fs. Fixes #320. Previously, the root project file was loaded via methods on Project (which do not know about the VFS) instead of through the VFS like all other disk access. This meant that Rojo was unable to build its own plugin because there is no project file on the real disk, only in the VFS. --- src/project.rs | 9 +++++++-- src/serve_session.rs | 31 ++++++++++++++++++++++++++----- src/snapshot_middleware/error.rs | 9 ++++----- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/project.rs b/src/project.rs index 4d29c72a..16c3a7cf 100644 --- a/src/project.rs +++ b/src/project.rs @@ -111,8 +111,13 @@ impl Project { pub fn load_from_slice( contents: &[u8], project_file_location: &Path, - ) -> Result { - let mut project: Self = serde_json::from_slice(&contents)?; + ) -> Result { + let mut project: Self = + serde_json::from_slice(&contents).map_err(|source| Error::Json { + source, + path: project_file_location.to_owned(), + })?; + project.file_location = project_file_location.to_path_buf(); project.check_compatibility(); Ok(project) diff --git a/src/serve_session.rs b/src/serve_session.rs index 1164dc5a..d43d4981 100644 --- a/src/serve_session.rs +++ b/src/serve_session.rs @@ -1,11 +1,14 @@ use std::{ + borrow::Cow, collections::HashSet, + io, path::{Path, PathBuf}, sync::{Arc, Mutex, MutexGuard}, time::Instant, }; use crossbeam_channel::Sender; +use memofs::IoResultExt; use memofs::Vfs; use rbx_dom_weak::RbxInstanceProperties; use thiserror::Error; @@ -97,11 +100,23 @@ impl ServeSession { log::trace!("Starting new ServeSession at path {}", start_path.display()); - log::debug!("Loading project file from {}", start_path.display()); - let root_project = - Project::load_fuzzy(start_path)?.ok_or_else(|| ServeSessionError::NoProjectFound { - path: start_path.to_owned(), - })?; + let project_path; + if Project::is_project_file(start_path) { + project_path = Cow::Borrowed(start_path); + } else { + project_path = Cow::Owned(start_path.join("default.project.json")); + } + + log::debug!("Loading project file from {}", project_path.display()); + + let root_project = match vfs.read(&project_path).with_not_found()? { + Some(contents) => Project::load_from_slice(&contents, &project_path)?, + None => { + return Err(ServeSessionError::NoProjectFound { + path: project_path.to_path_buf(), + }); + } + }; let mut tree = RojoTree::new(InstancePropertiesWithMeta { properties: RbxInstanceProperties { @@ -206,6 +221,12 @@ pub enum ServeSessionError { )] NoProjectFound { path: PathBuf }, + #[error(transparent)] + Io { + #[from] + source: io::Error, + }, + #[error(transparent)] Project { #[from] diff --git a/src/snapshot_middleware/error.rs b/src/snapshot_middleware/error.rs index a1c1665d..7e0e3847 100644 --- a/src/snapshot_middleware/error.rs +++ b/src/snapshot_middleware/error.rs @@ -2,6 +2,8 @@ use std::{io, path::PathBuf}; use thiserror::Error; +use crate::project::ProjectError; + #[derive(Debug, Error)] pub enum SnapshotError { #[error("file name had malformed Unicode")] @@ -14,10 +16,7 @@ pub enum SnapshotError { }, #[error("malformed project file at path {}", .path.display())] - MalformedProject { - source: serde_json::Error, - path: PathBuf, - }, + MalformedProject { source: ProjectError, path: PathBuf }, #[error("malformed .model.json file at path {}", .path.display())] MalformedModelJson { @@ -62,7 +61,7 @@ impl SnapshotError { } } - pub(crate) fn malformed_project(source: serde_json::Error, path: impl Into) -> Self { + pub(crate) fn malformed_project(source: ProjectError, path: impl Into) -> Self { Self::MalformedProject { source, path: path.into(),