summaryrefslogtreecommitdiff
path: root/systems/workspace
diff options
context:
space:
mode:
Diffstat (limited to 'systems/workspace')
-rw-r--r--systems/workspace/Cargo.toml14
-rw-r--r--systems/workspace/src/func.rs45
-rw-r--r--systems/workspace/src/lib.rs2
-rw-r--r--systems/workspace/src/workspace.rs38
-rw-r--r--systems/workspace/src/workspace/config.rs121
-rw-r--r--systems/workspace/src/workspace/error.rs40
-rw-r--r--systems/workspace/src/workspace/manager.rs38
7 files changed, 298 insertions, 0 deletions
diff --git a/systems/workspace/Cargo.toml b/systems/workspace/Cargo.toml
new file mode 100644
index 0000000..c394bb3
--- /dev/null
+++ b/systems/workspace/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "workspace_system"
+edition = "2024"
+version.workspace = true
+
+[dependencies]
+asset_system = { path = "../_asset" }
+config_system = { path = "../_config" }
+constants = { path = "../_constants" }
+framework = { path = "../_framework" }
+
+serde.workspace = true
+thiserror.workspace = true
+tokio.workspace = true
diff --git a/systems/workspace/src/func.rs b/systems/workspace/src/func.rs
new file mode 100644
index 0000000..4a1e57d
--- /dev/null
+++ b/systems/workspace/src/func.rs
@@ -0,0 +1,45 @@
+use std::{env::current_dir, path::PathBuf};
+
+use asset_system::asset::Handle;
+use framework::space::Space;
+
+use crate::workspace::{
+ Workspace, config::WorkspaceConfig, error::WorkspaceOperationError, manager::WorkspaceManager,
+};
+
+/// Create a workspace at the current location
+pub async fn create_workspace_here() -> Result<(), WorkspaceOperationError> {
+ create_workspace(current_dir()?).await
+}
+
+/// Create a workspace at the specified location
+pub async fn create_workspace(path: impl Into<PathBuf>) -> Result<(), WorkspaceOperationError> {
+ let path = path.into();
+ let mut space = Space::new(Workspace);
+ space.set_current_dir(path)?;
+ space.init_here().await?;
+
+ Ok(())
+}
+
+#[allow(unused)]
+/// Get a handle to the workspace configuration file and edit its content
+pub async fn operate_workspace_config<F>(
+ workspace_path: impl Into<PathBuf>,
+ operate: F,
+) -> Result<(), WorkspaceOperationError>
+where
+ F: AsyncFn(Handle<WorkspaceConfig>),
+{
+ // Get the workspace manager and set the context to the given workspace path
+ let mut mgr = WorkspaceManager::new();
+ mgr.get_space_mut().set_current_dir(workspace_path.into())?;
+
+ // Obtain the read-only asset of the workspace configuration file,
+ // lock it to get a writable handle, and pass it to the function for execution
+ let config = mgr.workspace_config()?;
+ let handle = config.get_handle().await?;
+ operate(handle).await;
+
+ Ok(())
+}
diff --git a/systems/workspace/src/lib.rs b/systems/workspace/src/lib.rs
new file mode 100644
index 0000000..9fd4ec8
--- /dev/null
+++ b/systems/workspace/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod func;
+pub mod workspace;
diff --git a/systems/workspace/src/workspace.rs b/systems/workspace/src/workspace.rs
new file mode 100644
index 0000000..6310146
--- /dev/null
+++ b/systems/workspace/src/workspace.rs
@@ -0,0 +1,38 @@
+use asset_system::rw::RWData;
+use constants::workspace::{dirs::workspace_dir_workspace, files::workspace_file_config};
+use framework::{SpaceRootTest, space::SpaceRoot};
+use tokio::fs::create_dir_all;
+
+use crate::workspace::config::WorkspaceConfig;
+
+pub mod config;
+pub mod error;
+pub mod manager;
+
+#[derive(Default, SpaceRootTest)]
+pub struct Workspace;
+
+impl SpaceRoot for Workspace {
+ fn get_pattern() -> framework::space::SpaceRootFindPattern {
+ framework::space::SpaceRootFindPattern::IncludeDotDir(workspace_dir_workspace().into())
+ }
+
+ async fn create_space(
+ path: &std::path::Path,
+ ) -> Result<(), framework::space::error::SpaceError> {
+ let workspace_root = path.join(workspace_dir_workspace());
+ let workspace_toml = path.join(workspace_file_config());
+
+ // Create workspace directory
+ create_dir_all(workspace_root)
+ .await
+ .map_err(framework::space::error::SpaceError::from)?;
+
+ // Create configuration file
+ WorkspaceConfig::write(WorkspaceConfig::default(), &workspace_toml)
+ .await
+ .map_err(|e| framework::space::error::SpaceError::Other(e.to_string()))?;
+
+ Ok(())
+ }
+}
diff --git a/systems/workspace/src/workspace/config.rs b/systems/workspace/src/workspace/config.rs
new file mode 100644
index 0000000..278ec08
--- /dev/null
+++ b/systems/workspace/src/workspace/config.rs
@@ -0,0 +1,121 @@
+use std::{io::Error, path::PathBuf};
+
+use asset_system::{
+ RWDataTest,
+ error::{DataReadError, DataWriteError},
+ rw::RWData,
+};
+use config_system::rw::{read_config, write_config};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, RWDataTest)]
+pub struct WorkspaceConfig {
+ /// Upstream address, pointing to the upstream Vault
+ #[serde(rename = "upstream")]
+ upstream: String,
+
+ /// Vault Uuid, used to ensure consistency between upstream and local
+ #[serde(rename = "uuid")]
+ uuid: Option<String>,
+
+ /// Account name used by self,
+ /// upstream Vault uses this parameter for identity verification
+ #[serde(rename = "account")]
+ use_accout: Option<String>,
+}
+
+impl WorkspaceConfig {
+ /// Returns a reference to the upstream address.
+ pub fn upstream(&self) -> &String {
+ &self.upstream
+ }
+
+ /// Sets the upstream address.
+ pub fn set_upstream(&mut self, upstream: String) {
+ self.upstream = upstream
+ }
+
+ /// Returns a new instance with the given upstream address.
+ pub fn with_upstream(mut self, upstream: String) -> Self {
+ self.upstream = upstream;
+ self
+ }
+
+ /// Returns a reference to the vault UUID, if any.
+ pub fn uuid(&self) -> Option<&String> {
+ self.uuid.as_ref()
+ }
+
+ /// Sets the vault UUID.
+ pub fn set_uuid(&mut self, uuid: String) {
+ self.uuid = Some(uuid)
+ }
+
+ /// Returns a new instance with the given vault UUID.
+ pub fn with_uuid(mut self, uuid: String) -> Self {
+ self.uuid = Some(uuid);
+ self
+ }
+
+ /// Clears the vault UUID.
+ pub fn erase_uuid(&mut self) {
+ self.uuid = None;
+ }
+
+ /// Returns a reference to the account name, if any.
+ pub fn account(&self) -> Option<&String> {
+ self.use_accout.as_ref()
+ }
+
+ /// Sets the account name.
+ pub fn set_account(&mut self, account: String) {
+ self.use_accout = Some(account)
+ }
+
+ /// Returns a new instance with the given account name.
+ pub fn with_account(mut self, account: String) -> Self {
+ self.use_accout = Some(account);
+ self
+ }
+
+ /// Clears the account name.
+ pub fn erase_account(&mut self) {
+ self.use_accout = None;
+ }
+}
+
+impl RWData<WorkspaceConfig> for WorkspaceConfig {
+ type DataType = WorkspaceConfig;
+
+ async fn read(path: &PathBuf) -> Result<Self::DataType, DataReadError> {
+ let read_config = read_config(path).await;
+ match read_config {
+ Ok(config) => Ok(config),
+ Err(e) => Err(DataReadError::IoError(Error::new(
+ std::io::ErrorKind::Other,
+ e,
+ ))),
+ }
+ }
+
+ async fn write(data: Self::DataType, path: &PathBuf) -> Result<(), DataWriteError> {
+ let write_config = write_config(path, &data).await;
+ match write_config {
+ Ok(_) => Ok(()),
+ Err(e) => {
+ return Err(DataWriteError::IoError(Error::new(
+ std::io::ErrorKind::Other,
+ e,
+ )));
+ }
+ }
+ }
+
+ fn test_data() -> Self::DataType {
+ WorkspaceConfig::default()
+ }
+
+ fn verify_data(data_a: Self::DataType, data_b: Self::DataType) -> bool {
+ &data_a == &data_b
+ }
+}
diff --git a/systems/workspace/src/workspace/error.rs b/systems/workspace/src/workspace/error.rs
new file mode 100644
index 0000000..495558b
--- /dev/null
+++ b/systems/workspace/src/workspace/error.rs
@@ -0,0 +1,40 @@
+use asset_system::error::{DataApplyError, DataReadError, DataWriteError, HandleLockError};
+use framework::space::error::SpaceError;
+
+#[derive(thiserror::Error, Debug)]
+pub enum WorkspaceOperationError {
+ #[error("IO error: {0}")]
+ Io(#[from] std::io::Error),
+
+ #[error("{0}")]
+ Other(String),
+
+ #[error("Configuration not found")]
+ ConfigNotFound,
+
+ #[error("Workspace not found")]
+ WorkspaceNotFound,
+
+ #[error("Handle lock error: {0}")]
+ HandleLock(#[from] HandleLockError),
+
+ #[error("Data read error: {0}")]
+ DataRead(#[from] DataReadError),
+
+ #[error("Data write error: {0}")]
+ DataWrite(#[from] DataWriteError),
+
+ #[error("Data apply error: {0}")]
+ DataApply(#[from] DataApplyError),
+}
+
+impl From<SpaceError> for WorkspaceOperationError {
+ fn from(value: SpaceError) -> Self {
+ match value {
+ SpaceError::SpaceNotFound => WorkspaceOperationError::WorkspaceNotFound,
+ SpaceError::Io(error) => WorkspaceOperationError::Io(error),
+ SpaceError::Other(e) => Self::Other(e),
+ _ => Self::Other(value.to_string()),
+ }
+ }
+}
diff --git a/systems/workspace/src/workspace/manager.rs b/systems/workspace/src/workspace/manager.rs
new file mode 100644
index 0000000..9e319a1
--- /dev/null
+++ b/systems/workspace/src/workspace/manager.rs
@@ -0,0 +1,38 @@
+use crate::workspace::{Workspace, config::WorkspaceConfig, error::WorkspaceOperationError};
+use asset_system::asset::ReadOnlyAsset;
+use constants::workspace::files::workspace_file_config;
+use framework::space::Space;
+
+pub struct WorkspaceManager {
+ space: Space<Workspace>,
+}
+
+impl WorkspaceManager {
+ pub fn new() -> Self {
+ WorkspaceManager {
+ space: Space::new(Workspace),
+ }
+ }
+
+ /// Get an immutable reference to the internal Space
+ pub fn get_space(&self) -> &Space<Workspace> {
+ &self.space
+ }
+
+ /// Get a mutable reference to the internal Space
+ pub fn get_space_mut(&mut self) -> &mut Space<Workspace> {
+ &mut self.space
+ }
+
+ /// Get a read-only instance of the workspace configuration file
+ pub fn workspace_config(
+ &self,
+ ) -> Result<ReadOnlyAsset<WorkspaceConfig>, WorkspaceOperationError> {
+ let config_path = self.space.local_path(workspace_file_config())?;
+ if !config_path.exists() {
+ return Err(WorkspaceOperationError::ConfigNotFound);
+ }
+ let asset = ReadOnlyAsset::from(config_path);
+ Ok(asset)
+ }
+}