diff options
Diffstat (limited to 'rola-vcs/src/workdraft.rs')
| -rw-r--r-- | rola-vcs/src/workdraft.rs | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/rola-vcs/src/workdraft.rs b/rola-vcs/src/workdraft.rs new file mode 100644 index 0000000..45bb418 --- /dev/null +++ b/rola-vcs/src/workdraft.rs @@ -0,0 +1,150 @@ +//! Work Draft +//! +//! Work Draft is the local workspace of `Rorolala`, used to store files being modified + +use std::path::PathBuf; + +use crate::{ + DirPtrData, DirSearchPattern, RolaError, RolaModule, dir_search_prev, + workdraft::constants::ROLA_DRAFT_DIR, +}; + +#[rorolala_internal_macros::constants] +pub mod constants { + /// The name of the workdraft directory + pub const ROLA_DRAFT_DIR: &str = ".rola"; + + /// The name of the directory containing bucket bindings + pub const ROLA_BINDED_BUCKETS_DIR: &str = ".rola/BIND/"; + + /// The name of the bind file + pub const ROLA_BINDED_BUCKET_FILE: &str = ".rola/BIND/{bucket}"; +} + +/// Work Draft Pointer +/// +/// This struct is used to point to an operable local work draft directory on disk +#[derive(Debug, Default, Clone)] +pub struct WorkDraft; + +impl DirPtrData for WorkDraft { + fn fix(raw_path: PathBuf) -> Option<PathBuf> { + let draft_dir = ROLA_DRAFT_DIR(); + dir_search_prev(raw_path, DirSearchPattern::Dir(&draft_dir)) + } +} + +impl WorkDraft { + /// Creates a new work draft directory at the given path + pub fn create(path: PathBuf) -> Result<(), RolaError> { + let dir = path.join(ROLA_DRAFT_DIR()); + std::fs::create_dir_all(dir).map_err(|e| RolaError::from((RolaModule::Workdraft, e)))?; + Ok(()) + } +} + +/// Module for managing workdraft bucket bindings +pub mod bucket_bind_mgr { + use std::path::PathBuf; + + use crate::{ + DirPtr, RolaError, RolaModule, WorkDraft, constants::ROLA_BINDED_BUCKETS_DIR, + workdraft::constants::ROLA_BINDED_BUCKET_FILE, + }; + + impl DirPtr<WorkDraft> { + /// Returns the path to the bind file for this work draft + pub fn bind_bucket_path(&self, bucket: impl AsRef<str>) -> PathBuf { + self.path().join(ROLA_BINDED_BUCKET_FILE(bucket)) + } + + /// Returns the path to the bind file for this work draft + pub fn bind_bucket(&self, bucket: impl AsRef<str>) -> Result<String, RolaError> { + let bucket_path = self.bind_bucket_path(bucket); + let parent = bucket_path.parent().ok_or_else(|| -> RolaError { + RolaError::from(( + RolaModule::Workdraft, + std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!("Invalid bucket path: {}", bucket_path.to_string_lossy()), + ), + )) + })?; + + if !parent.exists() { + std::fs::create_dir_all(parent) + .map_err(|e| RolaError::from((RolaModule::Workdraft, e)))?; + } + + match std::fs::read_to_string(bucket_path) { + Ok(str) => Ok(str), + Err(err) => Err(RolaError::from((RolaModule::Workdraft, err))), + } + } + + /// Binds the work draft to the specified bucket + pub fn bind_bucket_to(&self, bucket: &str) -> Result<(), RolaError> { + let bucket_path = self.bind_bucket_path(bucket); + let parent = bucket_path.parent().ok_or_else(|| -> RolaError { + RolaError::from(( + RolaModule::Workdraft, + std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid bucket path"), + )) + })?; + if !parent.exists() { + std::fs::create_dir_all(parent) + .map_err(|e| RolaError::from((RolaModule::Workdraft, e)))?; + } + std::fs::write(&bucket_path, bucket) + .map_err(|e| RolaError::from((RolaModule::Workdraft, e)))?; + Ok(()) + } + + /// Returns all bound bucket names for this work draft + pub fn binded_buckets(&self) -> Result<Vec<String>, RolaError> { + let bind_dir = self.path().join(ROLA_BINDED_BUCKETS_DIR()); + if !bind_dir.exists() { + return Ok(Vec::new()); + } + + let mut buckets = Vec::new(); + let entries = std::fs::read_dir(&bind_dir) + .map_err(|e| RolaError::from((RolaModule::Workdraft, e)))?; + + for entry in entries { + let entry = entry.map_err(|e| RolaError::from((RolaModule::Workdraft, e)))?; + let path = entry.path(); + + if path.is_file() { + // Read the file content which contains the bucket name + if let Ok(content) = std::fs::read_to_string(&path) { + let bucket = content.trim().to_string(); + if !bucket.is_empty() { + buckets.push(bucket); + } + } + } + } + + Ok(buckets) + } + + /// Removes the binding for the specified bucket + pub fn unbind_bucket(&self, bucket: impl AsRef<str>) -> Result<(), RolaError> { + let bucket_path = self.bind_bucket_path(bucket); + if bucket_path.exists() { + std::fs::remove_file(&bucket_path) + .map_err(|e| RolaError::from((RolaModule::Workdraft, e)))?; + } + Ok(()) + } + + /// Removes bindings for all specified buckets + pub fn unbind_buckets(&self, buckets: &[impl AsRef<str>]) -> Result<(), RolaError> { + for bucket in buckets { + self.unbind_bucket(bucket)?; + } + Ok(()) + } + } +} |
