Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
feat(rome_fs): implement a read-only mode for MemoryFileSystem (#3897)
Browse files Browse the repository at this point in the history
  • Loading branch information
leops authored Nov 29, 2022
1 parent d9d8211 commit f71a2b2
Showing 1 changed file with 63 additions and 1 deletion.
64 changes: 63 additions & 1 deletion crates/rome_fs/src/fs/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,20 @@ use crate::{FileSystem, RomePath, TraversalContext, TraversalScope};
use super::{BoxedTraversal, ErrorKind, File, FileSystemDiagnostic};

/// Fully in-memory file system, stores the content of all known files in a hashmap
#[derive(Default)]
pub struct MemoryFileSystem {
files: AssertUnwindSafe<RwLock<HashMap<PathBuf, FileEntry>>>,
errors: HashMap<PathBuf, ErrorEntry>,
allow_write: bool,
}

impl Default for MemoryFileSystem {
fn default() -> Self {
Self {
files: Default::default(),
errors: Default::default(),
allow_write: true,
}
}
}

/// This is what's actually being stored for each file in the filesystem
Expand Down Expand Up @@ -48,6 +58,18 @@ pub enum ErrorEntry {
}

impl MemoryFileSystem {
/// Create a read-only instance of [MemoryFileSystem]
///
/// This instance will disallow any modification through the [FileSystem]
/// trait, but the content of the filesystem may still be modified using
/// the methods on [MemoryFileSystem] itself.
pub fn new_read_only() -> Self {
Self {
allow_write: false,
..Self::default()
}
}

/// Create or update a file in the filesystem
pub fn insert(&mut self, path: PathBuf, content: impl Into<Vec<u8>>) {
let files = self.files.0.get_mut();
Expand All @@ -72,6 +94,15 @@ impl MemoryFileSystem {

impl FileSystem for MemoryFileSystem {
fn open_with_options(&self, path: &Path, options: OpenOptions) -> io::Result<Box<dyn File>> {
if !self.allow_write
&& (options.create || options.create_new || options.truncate || options.write)
{
return Err(io::Error::new(
io::ErrorKind::PermissionDenied,
"cannot acquire write access to file in read-only filesystem",
));
}

let mut inner = if options.create || options.create_new {
// Acquire write access to the files map if the file may need to be created
let mut files = self.files.0.write();
Expand Down Expand Up @@ -231,6 +262,37 @@ mod tests {
use crate::{FileSystem, MemoryFileSystem, PathInterner, RomePath, TraversalContext};
use rome_diagnostics::location::FileId;

#[test]
fn fs_read_only() {
let mut fs = MemoryFileSystem::new_read_only();

let path = Path::new("file.js");
fs.insert(path.into(), *b"content");

assert!(fs.open(path).is_ok());

match fs.create(path) {
Ok(_) => panic!("fs.create() for a read-only filesystem should return an error"),
Err(error) => {
assert_eq!(error.kind(), io::ErrorKind::PermissionDenied);
}
}

match fs.create_new(path) {
Ok(_) => panic!("fs.create() for a read-only filesystem should return an error"),
Err(error) => {
assert_eq!(error.kind(), io::ErrorKind::PermissionDenied);
}
}

match fs.open_with_options(path, OpenOptions::default().read(true).write(true)) {
Ok(_) => panic!("fs.open_with_options(read + write) for a read-only filesystem should return an error"),
Err(error) => {
assert_eq!(error.kind(), io::ErrorKind::PermissionDenied);
}
}
}

#[test]
fn file_read_write() {
let mut fs = MemoryFileSystem::default();
Expand Down

0 comments on commit f71a2b2

Please sign in to comment.