Compare commits

..

2 commits

Author SHA1 Message Date
b101089ebd feat(fs)!: remove legacy filesystem module
Some checks failed
Rust / build (map[name:nightly]) (push) Failing after 32s
Rust / build (map[name:stable]) (push) Failing after 35s
2024-11-01 08:56:30 +00:00
b756881a60 refactor: extract result module
All checks were successful
Rust / build (map[name:nightly]) (push) Successful in 1m55s
Rust / build (map[name:stable]) (push) Successful in 2m5s
Release Please / Release-plz (push) Successful in 1m33s
2024-11-01 08:33:02 +00:00
5 changed files with 26 additions and 203 deletions

View file

@ -1,167 +0,0 @@
#![allow(deprecated)]
use std::{
ops::Deref,
path::PathBuf,
sync::{Arc, Mutex},
};
use tempfile::{tempdir, TempDir};
use tracing::{debug, info};
pub fn real(cwd: Option<PathBuf>) -> FileSystem {
let cwd = cwd.unwrap_or_default();
FileSystem::Real(RealFileSystem::new(cwd))
}
pub fn temp() -> std::io::Result<FileSystem> {
TempFileSystem::new().map(FileSystem::Temp)
}
#[derive(Clone, Debug)]
#[deprecated(since = "1.1.0", note = "Use [kxio::fs::FileSystem] instead")]
pub enum FileSystem {
Real(RealFileSystem),
Temp(TempFileSystem),
}
impl FileSystem {
#[deprecated(since = "1.1.0", note = "Use [kxio::filesystem::real()] instead")]
pub fn new_real(cwd: Option<PathBuf>) -> Self {
real(cwd)
}
#[deprecated(since = "1.1.0", note = "Use [kxio::filesystem::temp()] instead")]
pub fn new_temp() -> std::io::Result<Self> {
temp()
}
}
impl Deref for FileSystem {
type Target = dyn FileSystemLike;
fn deref(&self) -> &Self::Target {
match self {
Self::Real(env) => env,
Self::Temp(env) => env,
}
}
}
pub trait FileSystemLike: Sync + Send + std::fmt::Debug {
fn cwd(&self) -> &PathBuf;
fn in_cwd(&self, name: &str) -> PathBuf {
self.cwd().join(name)
}
fn write_file(&self, file_name: &str, content: &str) -> std::io::Result<PathBuf> {
use std::fs::File;
use std::io::{LineWriter, Write};
let path = self.in_cwd(file_name);
debug!("writing to {:?}", path);
let file = File::create(path.clone())?;
let mut file = LineWriter::new(file);
file.write_all(content.as_bytes())?;
Ok(path)
}
fn file_exists(&self, name: &PathBuf) -> bool {
use std::fs::File;
File::open(name).is_ok()
}
fn read_file(&self, file_name: &str) -> std::io::Result<String> {
use std::fs::File;
use std::io::Read;
let path = self.in_cwd(file_name);
debug!("reading from {:?}", path);
let mut file = File::open(path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}
}
#[derive(Clone, Debug, Default)]
pub struct RealFileSystem {
cwd: PathBuf,
}
#[derive(Clone, Debug)]
pub struct TempFileSystem {
cwd: PathBuf,
// Handle to the temporary directory
// When this handle is dropped the directory is deleted
_temp_dir: Arc<Mutex<TempDir>>,
}
impl FileSystemLike for TempFileSystem {
fn cwd(&self) -> &PathBuf {
&self.cwd
}
}
impl FileSystemLike for RealFileSystem {
fn cwd(&self) -> &PathBuf {
&self.cwd
}
}
impl RealFileSystem {
const fn new(cwd: PathBuf) -> Self {
Self { cwd }
}
}
impl TempFileSystem {
fn new() -> std::io::Result<Self> {
let temp_dir = tempdir()?;
info!("temp dir: {:?}", temp_dir.path());
let cwd = temp_dir.path().to_path_buf();
let temp_dir = Arc::new(Mutex::new(temp_dir));
Ok(Self {
cwd,
_temp_dir: temp_dir,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test_log::test]
fn test_cwd() {
let cwd = PathBuf::from("/tmp");
let env = RealFileSystem::new(cwd.clone());
assert_eq!(env.cwd(), &cwd);
}
#[test_log::test]
fn test_create_on_temp_fs() -> std::io::Result<()> {
let env = TempFileSystem::new()?;
assert!(env.cwd().exists());
Ok(())
}
#[test_log::test]
fn test_create_on_real_fs() {
let cwd = PathBuf::from("/tmp");
let env = RealFileSystem::new(cwd.clone());
assert_eq!(env.cwd(), &cwd);
}
#[test_log::test]
fn test_write_and_read_file() -> std::io::Result<()> {
let env = TempFileSystem::new()?;
let file_name = "test.txt";
let content = "Hello, World!";
let path = env.write_file(file_name, content)?;
assert_eq!(env.read_file(file_name)?, content);
assert!(path.exists());
Ok(())
}
}

View file

@ -1,35 +1,16 @@
use std::path::PathBuf;
use derive_more::From;
mod real;
mod result;
mod temp;
mod dir_item;
pub use dir_item::DirItem;
pub use dir_item::DirItemIterator;
use real::FileSystem;
pub use result::*;
use temp::TempFileSystem;
#[derive(Debug, From, derive_more::Display)]
pub enum Error {
Io(std::io::Error),
#[display("Path access attempted outside of base ({base:?}): {path:?}")]
PathTraversal {
base: PathBuf,
path: PathBuf,
},
#[display("Path must be a directory: {path:?}")]
NotADirectory {
path: PathBuf,
},
}
impl std::error::Error for Error {}
pub type Result<T> = core::result::Result<T, Error>;
pub const fn new(base: PathBuf) -> FileSystem {
real::new(base)
}

23
src/fs/result.rs Normal file
View file

@ -0,0 +1,23 @@
//
use std::path::PathBuf;
use derive_more::From;
#[derive(Debug, From, derive_more::Display)]
pub enum Error {
Io(std::io::Error),
#[display("Path access attempted outside of base ({base:?}): {path:?}")]
PathTraversal {
base: PathBuf,
path: PathBuf,
},
#[display("Path must be a directory: {path:?}")]
NotADirectory {
path: PathBuf,
},
}
impl std::error::Error for Error {}
pub type Result<T> = core::result::Result<T, Error>;

View file

@ -1,6 +1,4 @@
#[cfg(feature = "fs")]
pub mod filesystem;
//
#[cfg(feature = "fs")]
pub mod fs;

View file

@ -1,12 +0,0 @@
type TestResult = Result<(), Box<dyn std::error::Error>>;
#[test]
fn write_read_file_exists() -> TestResult {
let fs = crate::filesystem::temp()?;
let pathbuf = fs.write_file("foo", "content")?;
let c = fs.read_file("foo")?;
assert_eq!(c, "content");
assert!(fs.file_exists(&pathbuf));
Ok(())
}