summaryrefslogtreecommitdiff
path: root/rola-vcs/src/workdraft.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rola-vcs/src/workdraft.rs')
-rw-r--r--rola-vcs/src/workdraft.rs150
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(())
+ }
+ }
+}