summaryrefslogtreecommitdiff
path: root/rola-utils/space-system/src/space.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rola-utils/space-system/src/space.rs')
-rw-r--r--rola-utils/space-system/src/space.rs369
1 files changed, 300 insertions, 69 deletions
diff --git a/rola-utils/space-system/src/space.rs b/rola-utils/space-system/src/space.rs
index 3fe3507..55c3add 100644
--- a/rola-utils/space-system/src/space.rs
+++ b/rola-utils/space-system/src/space.rs
@@ -10,7 +10,7 @@ use std::{
mod error;
pub use error::*;
-pub struct Space<T: SpaceRoot> {
+pub struct Space<T: SpaceRoot + Default> {
path_format_cfg: PathFormatConfig,
content: T,
@@ -20,7 +20,19 @@ pub struct Space<T: SpaceRoot> {
pub(crate) override_pattern: Option<SpaceRootFindPattern>,
}
-impl<T: SpaceRoot> Space<T> {
+impl<T: SpaceRoot + Default> Clone for Space<T> {
+ fn clone(&self) -> Self {
+ Self {
+ path_format_cfg: self.path_format_cfg,
+ content: T::default(),
+ space_dir: RwLock::new(None),
+ current_dir: self.current_dir.clone(),
+ override_pattern: None,
+ }
+ }
+}
+
+impl<T: SpaceRoot + Default> Space<T> {
/// Create a new `Space` instance with the given content.
pub fn new(content: T) -> Self {
Space {
@@ -35,11 +47,11 @@ impl<T: SpaceRoot> Space<T> {
}
}
- /// Initialize a space at the given path.
+ /// Initialize a space at the given path (sync version).
///
/// Checks if a space exists at the given path. If not, creates a new space
/// by calling `T::create_space()` at that path.
- pub async fn init(&self, path: impl AsRef<Path>) -> Result<(), SpaceError> {
+ pub fn init(&self, path: impl AsRef<Path>) -> Result<(), SpaceError> {
let path = path.as_ref();
let pattern = match &self.override_pattern {
Some(pattern) => pattern,
@@ -53,38 +65,90 @@ impl<T: SpaceRoot> Space<T> {
};
if find_space_root_with(&path, pattern).is_err() {
- T::create_space(&path).await?;
+ T::create_space(&path)?
}
Ok(())
}
- /// Create a new space at the given path with the specified name.
+ /// Initialize a space at the given path (async version).
+ ///
+ /// Checks if a space exists at the given path. If not, creates a new space
+ /// by calling `T::create_space()` at that path.
+ pub async fn init_async(&self, path: impl AsRef<Path>) -> Result<(), SpaceError> {
+ let path = path.as_ref();
+ let pattern = match &self.override_pattern {
+ Some(pattern) => pattern,
+ None => &T::get_pattern(),
+ };
+
+ // If using Absolute, directly read the internal path
+ let path = match &pattern {
+ SpaceRootFindPattern::AbsolutePath(path_buf) => path_buf.clone(),
+ _ => path.to_path_buf(),
+ };
+
+ if find_space_root_with(&path, pattern).is_err() {
+ T::create_space(&path)?;
+ }
+ Ok(())
+ }
+
+ /// Create a new space at the given path with the specified name (sync version).
+ ///
+ /// The full path is constructed as `path/name`. Checks if a space already
+ /// exists at that location. If not, creates a new space by calling
+ /// `T::create_space()` at that path.
+ pub fn create(&self, path: impl AsRef<Path>, name: &str) -> Result<(), SpaceError> {
+ let full_path = path.as_ref().join(name);
+ self.init(full_path)
+ }
+
+ /// Create a new space at the given path with the specified name (async version).
///
/// The full path is constructed as `path/name`. Checks if a space already
/// exists at that location. If not, creates a new space by calling
/// `T::create_space()` at that path.
- pub async fn create(&self, path: impl AsRef<Path>, name: &str) -> Result<(), SpaceError> {
+ pub async fn create_async(&self, path: impl AsRef<Path>, name: &str) -> Result<(), SpaceError> {
let full_path = path.as_ref().join(name);
- self.init(full_path).await
+ self.init_async(full_path).await
+ }
+
+ /// Initialize a space in the current directory (sync version).
+ ///
+ /// Checks if a space exists in the current directory. If not, creates a new space
+ /// by calling `T::create_space()` at the current directory.
+ pub fn init_here(&self) -> Result<(), SpaceError> {
+ let current_dir = self.current_dir()?;
+ self.init(current_dir)
}
- /// Initialize a space in the current directory.
+ /// Initialize a space in the current directory (async version).
///
/// Checks if a space exists in the current directory. If not, creates a new space
/// by calling `T::create_space()` at the current directory.
- pub async fn init_here(&self) -> Result<(), SpaceError> {
+ pub async fn init_here_async(&self) -> Result<(), SpaceError> {
let current_dir = self.current_dir()?;
- self.init(current_dir).await
+ self.init_async(current_dir).await
}
- /// Create a new space in the current directory with the specified name.
+ /// Create a new space in the current directory with the specified name (sync version).
///
/// The full path is constructed as `current_dir/name`. Checks if a space already
/// exists at that location. If not, creates a new space by calling
/// `T::create_space()` at that path.
- pub async fn create_here(&self, name: &str) -> Result<(), SpaceError> {
+ pub fn create_here(&self, name: &str) -> Result<(), SpaceError> {
let current_dir = self.current_dir()?;
- self.create(current_dir, name).await
+ self.create(current_dir, name)
+ }
+
+ /// Create a new space in the current directory with the specified name (async version).
+ ///
+ /// The full path is constructed as `current_dir/name`. Checks if a space already
+ /// exists at that location. If not, creates a new space by calling
+ /// `T::create_space()` at that path.
+ pub async fn create_here_async(&self, name: &str) -> Result<(), SpaceError> {
+ let current_dir = self.current_dir()?;
+ self.create_async(current_dir, name).await
}
/// Consume the `Space`, returning the inner content.
@@ -131,9 +195,9 @@ impl<T: SpaceRoot> Space<T> {
/// Set the current directory explicitly.
///
/// This clears any cached space directory.
- pub fn set_current_dir(&mut self, path: PathBuf) -> Result<(), SpaceError> {
+ pub fn set_current_dir(&mut self, path: impl AsRef<Path>) -> Result<(), SpaceError> {
self.update_space_dir(None);
- self.current_dir = Some(fmt_path(path)?);
+ self.current_dir = Some(fmt_path(path.as_ref())?);
Ok(())
}
@@ -177,7 +241,7 @@ impl<T: SpaceRoot> Space<T> {
}
}
-impl<T: SpaceRoot> Space<T> {
+impl<T: SpaceRoot + Default> Space<T> {
/// Convert a relative path to an absolute path within the space.
///
/// The path is formatted according to the space's path format configuration.
@@ -203,65 +267,122 @@ impl<T: SpaceRoot> Space<T> {
}
/// Canonicalize a relative path within the space.
- pub async fn canonicalize(
+ pub fn canonicalize(&self, relative_path: impl AsRef<Path>) -> Result<PathBuf, SpaceError> {
+ let path = self.local_path(relative_path)?;
+ Ok(std::fs::canonicalize(path)?)
+ }
+
+ /// Canonicalize a relative path within the space (async version).
+ pub async fn canonicalize_async(
&self,
relative_path: impl AsRef<Path>,
) -> Result<PathBuf, SpaceError> {
- let path = self.local_path(relative_path)?;
- Ok(tokio::fs::canonicalize(path).await?)
+ self.canonicalize(relative_path)
}
/// Copy a file from one relative path to another within the space.
- pub async fn copy(
+ pub fn copy(&self, from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<u64, SpaceError> {
+ let from_path = self.local_path(from)?;
+ let to_path = self.local_path(to)?;
+ Ok(std::fs::copy(from_path, to_path)?)
+ }
+
+ /// Copy a file from one relative path to another within the space (async version).
+ pub async fn copy_async(
&self,
from: impl AsRef<Path>,
to: impl AsRef<Path>,
) -> Result<u64, SpaceError> {
- let from_path = self.local_path(from)?;
- let to_path = self.local_path(to)?;
- Ok(tokio::fs::copy(from_path, to_path).await?)
+ self.copy(from, to)
}
/// Create a directory at the given relative path within the space.
- pub async fn create_dir(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
+ pub fn create_dir(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::create_dir(path).await?)
+ Ok(std::fs::create_dir(path)?)
+ }
+
+ /// Create a directory at the given relative path within the space (async version).
+ pub async fn create_dir_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<(), SpaceError> {
+ self.create_dir(relative_path)
}
/// Recursively create a directory and all its parents at the given relative path within the space.
- pub async fn create_dir_all(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
+ pub fn create_dir_all(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::create_dir_all(path).await?)
+ Ok(std::fs::create_dir_all(path)?)
+ }
+
+ /// Recursively create a directory and all its parents at the given relative path within the space (async version).
+ pub async fn create_dir_all_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<(), SpaceError> {
+ self.create_dir_all(relative_path)
}
/// Create a hard link from `src` to `dst` within the space.
- pub async fn hard_link(
+ pub fn hard_link(
&self,
src: impl AsRef<Path>,
dst: impl AsRef<Path>,
) -> Result<(), SpaceError> {
let src_path = self.local_path(src)?;
let dst_path = self.local_path(dst)?;
- Ok(tokio::fs::hard_link(src_path, dst_path).await?)
+ Ok(std::fs::hard_link(src_path, dst_path)?)
+ }
+
+ /// Create a hard link from `src` to `dst` within the space (async version).
+ pub async fn hard_link_async(
+ &self,
+ src: impl AsRef<Path>,
+ dst: impl AsRef<Path>,
+ ) -> Result<(), SpaceError> {
+ self.hard_link(src, dst)
}
/// Get metadata for a file or directory at the given relative path within the space.
- pub async fn metadata(
+ pub fn metadata(
&self,
relative_path: impl AsRef<Path>,
) -> Result<std::fs::Metadata, SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::metadata(path).await?)
+ Ok(std::fs::metadata(path)?)
+ }
+
+ /// Get metadata for a file or directory at the given relative path within the space (async version).
+ pub async fn metadata_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<std::fs::Metadata, SpaceError> {
+ self.metadata(relative_path)
}
/// Read the entire contents of a file at the given relative path within the space.
- pub async fn read(&self, relative_path: impl AsRef<Path>) -> Result<Vec<u8>, SpaceError> {
+ pub fn read(&self, relative_path: impl AsRef<Path>) -> Result<Vec<u8>, SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::read(path).await?)
+ Ok(std::fs::read(path)?)
+ }
+
+ /// Read the entire contents of a file at the given relative path within the space (async version).
+ pub async fn read_async(&self, relative_path: impl AsRef<Path>) -> Result<Vec<u8>, SpaceError> {
+ self.read(relative_path)
}
/// Read the directory entries at the given relative path within the space.
- pub async fn read_dir(
+ pub fn read_dir(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<std::fs::ReadDir, SpaceError> {
+ let path = self.local_path(relative_path)?;
+ Ok(std::fs::read_dir(path)?)
+ }
+
+ /// Read the directory entries at the given relative path within the space (async version).
+ pub async fn read_dir_async(
&self,
relative_path: impl AsRef<Path>,
) -> Result<tokio::fs::ReadDir, SpaceError> {
@@ -270,112 +391,216 @@ impl<T: SpaceRoot> Space<T> {
}
/// Read the target of a symbolic link at the given relative path within the space.
- pub async fn read_link(&self, relative_path: impl AsRef<Path>) -> Result<PathBuf, SpaceError> {
+ pub fn read_link(&self, relative_path: impl AsRef<Path>) -> Result<PathBuf, SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::read_link(path).await?)
+ Ok(std::fs::read_link(path)?)
+ }
+
+ /// Read the target of a symbolic link at the given relative path within the space (async version).
+ pub async fn read_link_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<PathBuf, SpaceError> {
+ self.read_link(relative_path)
}
/// Read the entire contents of a file as a string at the given relative path within the space.
- pub async fn read_to_string(
+ pub fn read_to_string(&self, relative_path: impl AsRef<Path>) -> Result<String, SpaceError> {
+ let path = self.local_path(relative_path)?;
+ Ok(std::fs::read_to_string(path)?)
+ }
+
+ /// Read the entire contents of a file as a string at the given relative path within the space (async version).
+ pub async fn read_to_string_async(
&self,
relative_path: impl AsRef<Path>,
) -> Result<String, SpaceError> {
- let path = self.local_path(relative_path)?;
- Ok(tokio::fs::read_to_string(path).await?)
+ self.read_to_string(relative_path)
}
/// Remove an empty directory at the given relative path within the space.
- pub async fn remove_dir(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
+ pub fn remove_dir(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::remove_dir(path).await?)
+ Ok(std::fs::remove_dir(path)?)
+ }
+
+ /// Remove an empty directory at the given relative path within the space (async version).
+ pub async fn remove_dir_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<(), SpaceError> {
+ self.remove_dir(relative_path)
}
/// Remove a directory and all its contents at the given relative path within the space.
- pub async fn remove_dir_all(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
+ pub fn remove_dir_all(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::remove_dir_all(path).await?)
+ Ok(std::fs::remove_dir_all(path)?)
+ }
+
+ /// Remove a directory and all its contents at the given relative path within the space (async version).
+ pub async fn remove_dir_all_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<(), SpaceError> {
+ self.remove_dir_all(relative_path)
}
/// Remove a file at the given relative path within the space.
- pub async fn remove_file(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
+ pub fn remove_file(&self, relative_path: impl AsRef<Path>) -> Result<(), SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::remove_file(path).await?)
+ Ok(std::fs::remove_file(path)?)
+ }
+
+ /// Remove a file at the given relative path within the space (async version).
+ pub async fn remove_file_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<(), SpaceError> {
+ self.remove_file(relative_path)
}
/// Rename a file or directory from one relative path to another within the space.
- pub async fn rename(
+ pub fn rename(&self, from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<(), SpaceError> {
+ let from_path = self.local_path(from)?;
+ let to_path = self.local_path(to)?;
+ Ok(std::fs::rename(from_path, to_path)?)
+ }
+
+ /// Rename a file or directory from one relative path to another within the space (async version).
+ pub async fn rename_async(
&self,
from: impl AsRef<Path>,
to: impl AsRef<Path>,
) -> Result<(), SpaceError> {
- let from_path = self.local_path(from)?;
- let to_path = self.local_path(to)?;
- Ok(tokio::fs::rename(from_path, to_path).await?)
+ self.rename(from, to)
}
/// Set permissions for a file or directory at the given relative path within the space.
- pub async fn set_permissions(
+ pub fn set_permissions(
&self,
relative_path: impl AsRef<Path>,
perm: std::fs::Permissions,
) -> Result<(), SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::set_permissions(path, perm).await?)
+ Ok(std::fs::set_permissions(path, perm)?)
+ }
+
+ /// Set permissions for a file or directory at the given relative path within the space (async version).
+ pub async fn set_permissions_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ perm: std::fs::Permissions,
+ ) -> Result<(), SpaceError> {
+ self.set_permissions(relative_path, perm)
}
/// Create a symbolic link from `src` to `dst` within the space (Unix only).
#[cfg(unix)]
- pub async fn symlink(
+ pub fn symlink(&self, src: impl AsRef<Path>, dst: impl AsRef<Path>) -> Result<(), SpaceError> {
+ let src_path = self.local_path(src)?;
+ let dst_path = self.local_path(dst)?;
+ Ok(std::os::unix::fs::symlink(src_path, dst_path)?)
+ }
+
+ /// Create a symbolic link from `src` to `dst` within the space (Unix only, async version).
+ #[cfg(unix)]
+ pub async fn symlink_async(
&self,
src: impl AsRef<Path>,
dst: impl AsRef<Path>,
) -> Result<(), SpaceError> {
- let src_path = self.local_path(src)?;
- let dst_path = self.local_path(dst)?;
- Ok(tokio::fs::symlink(src_path, dst_path).await?)
+ self.symlink(src, dst)
}
/// Create a directory symbolic link from `src` to `dst` within the space (Windows only).
#[cfg(windows)]
- pub async fn symlink_dir(
+ pub fn symlink_dir(
&self,
src: impl AsRef<Path>,
dst: impl AsRef<Path>,
) -> Result<(), SpaceError> {
let src_path = self.local_path(src)?;
let dst_path = self.local_path(dst)?;
- Ok(tokio::fs::symlink_dir(src_path, dst_path).await?)
+ Ok(std::os::windows::fs::symlink_dir(src_path, dst_path)?)
+ }
+
+ /// Create a directory symbolic link from `src` to `dst` within the space (Windows only, async version).
+ #[cfg(windows)]
+ pub async fn symlink_dir_async(
+ &self,
+ src: impl AsRef<Path>,
+ dst: impl AsRef<Path>,
+ ) -> Result<(), SpaceError> {
+ self.symlink_dir(src, dst)
}
/// Create a file symbolic link from `src` to `dst` within the space (Windows only).
#[cfg(windows)]
- pub async fn symlink_file(
+ pub fn symlink_file(
&self,
src: impl AsRef<Path>,
dst: impl AsRef<Path>,
) -> Result<(), SpaceError> {
let src_path = self.local_path(src)?;
let dst_path = self.local_path(dst)?;
- Ok(tokio::fs::symlink_file(src_path, dst_path).await?)
+ Ok(std::os::windows::fs::symlink_file(src_path, dst_path)?)
+ }
+
+ /// Create a file symbolic link from `src` to `dst` within the space (Windows only, async version).
+ #[cfg(windows)]
+ pub async fn symlink_file_async(
+ &self,
+ src: impl AsRef<Path>,
+ dst: impl AsRef<Path>,
+ ) -> Result<(), SpaceError> {
+ self.symlink_file(src, dst)
}
/// Get metadata for a file or directory without following symbolic links.
- pub async fn symlink_metadata(
+ pub fn symlink_metadata(
&self,
relative_path: impl AsRef<Path>,
) -> Result<std::fs::Metadata, SpaceError> {
let path = self.local_path(relative_path)?;
- Ok(tokio::fs::symlink_metadata(path).await?)
+ Ok(std::fs::symlink_metadata(path)?)
+ }
+
+ /// Get metadata for a file or directory without following symbolic links (async version).
+ pub async fn symlink_metadata_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<std::fs::Metadata, SpaceError> {
+ self.symlink_metadata(relative_path)
}
/// Check if a file or directory exists at the given relative path within the space.
- pub async fn try_exists(&self, relative_path: impl AsRef<Path>) -> Result<bool, SpaceError> {
+ pub fn try_exists(&self, relative_path: impl AsRef<Path>) -> Result<bool, SpaceError> {
+ let path = self.local_path(relative_path)?;
+ Ok(path.try_exists()?)
+ }
+
+ /// Check if a file or directory exists at the given relative path within the space (async version).
+ pub async fn try_exists_async(
+ &self,
+ relative_path: impl AsRef<Path>,
+ ) -> Result<bool, SpaceError> {
let path = self.local_path(relative_path)?;
Ok(tokio::fs::try_exists(path).await?)
}
/// Write data to a file at the given relative path within the space.
- pub async fn write(
+ pub fn write(
+ &self,
+ relative_path: impl AsRef<Path>,
+ contents: impl AsRef<[u8]>,
+ ) -> Result<(), SpaceError> {
+ let path = self.local_path(relative_path)?;
+ Ok(std::fs::write(path, contents)?)
+ }
+
+ /// Write data to a file at the given relative path within the space (async version).
+ pub async fn write_async(
&self,
relative_path: impl AsRef<Path>,
contents: impl AsRef<[u8]>,
@@ -385,25 +610,31 @@ impl<T: SpaceRoot> Space<T> {
}
/// Check if a file or directory exists at the given relative path within the space.
- pub async fn exists(&self, relative_path: impl AsRef<Path>) -> Result<bool, SpaceError> {
+ pub fn exists(&self, relative_path: impl AsRef<Path>) -> Result<bool, SpaceError> {
+ let path = self.local_path(relative_path)?;
+ Ok(path.try_exists()?)
+ }
+
+ /// Check if a file or directory exists at the given relative path within the space (async version).
+ pub async fn exists_async(&self, relative_path: impl AsRef<Path>) -> Result<bool, SpaceError> {
let path = self.local_path(relative_path)?;
Ok(tokio::fs::try_exists(path).await?)
}
}
-impl<T: SpaceRoot> From<T> for Space<T> {
+impl<T: SpaceRoot + Default> From<T> for Space<T> {
fn from(content: T) -> Self {
Space::<T>::new(content)
}
}
-impl<T: SpaceRoot> AsRef<T> for Space<T> {
+impl<T: SpaceRoot + Default> AsRef<T> for Space<T> {
fn as_ref(&self) -> &T {
&self.content
}
}
-impl<T: SpaceRoot> Deref for Space<T> {
+impl<T: SpaceRoot + Default> Deref for Space<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.as_ref()
@@ -415,7 +646,7 @@ pub trait SpaceRoot: Sized {
fn get_pattern() -> SpaceRootFindPattern;
/// Given a non-space directory, implement logic to make it a space-recognizable directory
- fn create_space(path: &Path) -> impl Future<Output = Result<(), SpaceError>> + Send;
+ fn create_space(path: &Path) -> Result<(), SpaceError>;
}
pub enum SpaceRootFindPattern {