summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/utils/string_proc/src/format_path.rs9
-rw-r--r--crates/vcs_actions/src/actions/sheet_actions.rs162
-rw-r--r--crates/vcs_actions/src/registry/client_registry.rs5
-rw-r--r--crates/vcs_actions/src/registry/server_registry.rs5
-rw-r--r--crates/vcs_data/src/data/local/align.rs3
-rw-r--r--crates/vcs_data/src/data/local/file_status.rs22
-rw-r--r--crates/vcs_data/src/data/sheet.rs3
7 files changed, 188 insertions, 21 deletions
diff --git a/crates/utils/string_proc/src/format_path.rs b/crates/utils/string_proc/src/format_path.rs
index 152b791..35689b8 100644
--- a/crates/utils/string_proc/src/format_path.rs
+++ b/crates/utils/string_proc/src/format_path.rs
@@ -38,6 +38,11 @@ pub fn format_path_str(path: impl Into<String>) -> Result<String, std::io::Error
result.push('/');
}
+ // Special case: when result is only "./", return ""
+ if result == "./" {
+ return Ok(String::new());
+ }
+
Ok(result)
}
@@ -97,6 +102,10 @@ mod tests {
"/home/my_user/DOCS/JVCS_TEST/Vault/"
);
+ assert_eq!(format_path_str("./home/file.txt")?, "home/file.txt");
+ assert_eq!(format_path_str("./home/path/")?, "home/path/");
+ assert_eq!(format_path_str("./")?, "");
+
Ok(())
}
}
diff --git a/crates/vcs_actions/src/actions/sheet_actions.rs b/crates/vcs_actions/src/actions/sheet_actions.rs
index ff467d9..e8d9c94 100644
--- a/crates/vcs_actions/src/actions/sheet_actions.rs
+++ b/crates/vcs_actions/src/actions/sheet_actions.rs
@@ -1,12 +1,21 @@
-use std::io::ErrorKind;
+use std::{collections::HashMap, io::ErrorKind};
use action_system::{action::ActionContext, macros::action_gen};
use serde::{Deserialize, Serialize};
use tcp_connection::error::TcpTargetError;
-use vcs_data::data::{local::vault_modified::sign_vault_modified, sheet::SheetName};
+use vcs_data::data::{
+ local::{
+ file_status::{FromRelativePathBuf, ToRelativePathBuf},
+ vault_modified::sign_vault_modified,
+ },
+ sheet::SheetName,
+};
use crate::{
- actions::{auth_member, check_connection_instance, try_get_local_workspace, try_get_vault},
+ actions::{
+ auth_member, check_connection_instance, get_current_sheet_name, try_get_local_workspace,
+ try_get_vault,
+ },
write_and_return,
};
@@ -200,19 +209,134 @@ pub async fn drop_sheet_action(
Err(TcpTargetError::NoResult("No result.".to_string()))
}
-// #[derive(Serialize, Deserialize)]
-// pub enum AlignSheetActionResult {
-// Success,
-// }
-
-// #[derive(Serialize, Deserialize)]
-// pub struct AlignSheetActionArguments {
-// pub
-// }
-
-// #[action_gen]
-// pub async fn align_sheet_action(
-// ctx: ActionContext,
-// args: AlignSheetActionArgument,
-// ) -> Result<DropSheetActionResult, TcpTargetError> {
-// }
+pub type OperationArgument = (EditMappingOperations, Option<ToRelativePathBuf>);
+
+#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)]
+pub enum EditMappingOperations {
+ Move,
+ Erase,
+}
+
+#[derive(Serialize, Deserialize, Default)]
+pub enum EditMappingActionResult {
+ Success,
+
+ // Fail
+ AuthorizeFailed(String),
+ MappingNotFound(FromRelativePathBuf),
+ InvalidMove(InvalidMoveReason),
+
+ #[default]
+ Unknown,
+}
+
+#[derive(Serialize, Deserialize)]
+pub enum InvalidMoveReason {
+ MoveOperationButNoTarget(FromRelativePathBuf),
+ ContainsDuplicateMapping(ToRelativePathBuf),
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct EditMappingActionArguments {
+ pub operations: HashMap<FromRelativePathBuf, OperationArgument>,
+}
+
+/// This Action only modifies Sheet Mapping and
+/// does not interfere with the actual location of local files or Local Mapping
+#[action_gen]
+pub async fn edit_mapping_action(
+ ctx: ActionContext,
+ args: EditMappingActionArguments,
+) -> Result<EditMappingActionResult, TcpTargetError> {
+ let instance = check_connection_instance(&ctx)?;
+
+ // Auth Member
+ let member_id = match auth_member(&ctx, instance).await {
+ Ok(id) => id,
+ Err(e) => {
+ return Ok(EditMappingActionResult::AuthorizeFailed(e.to_string()));
+ }
+ };
+
+ // Check sheet
+ let sheet_name = get_current_sheet_name(&ctx, instance, &member_id).await?;
+
+ if ctx.is_proc_on_remote() {
+ let vault = try_get_vault(&ctx)?;
+ let mut sheet = vault.sheet(&sheet_name).await?;
+
+ // Precheck
+ for (from_path, (operation, to_path)) in args.operations.iter() {
+ // Check mapping exists
+ if !sheet.mapping().contains_key(from_path) {
+ write_and_return!(
+ instance,
+ EditMappingActionResult::MappingNotFound(from_path.clone())
+ );
+ }
+
+ // Move check
+ if operation == &EditMappingOperations::Move {
+ // Check if target exists
+ if let Some(to_path) = to_path {
+ // Check if target is duplicate
+ if sheet.mapping().contains_key(to_path) {
+ write_and_return!(
+ instance,
+ EditMappingActionResult::InvalidMove(
+ InvalidMoveReason::ContainsDuplicateMapping(to_path.clone())
+ )
+ );
+ }
+ } else {
+ write_and_return!(
+ instance,
+ EditMappingActionResult::InvalidMove(
+ InvalidMoveReason::MoveOperationButNoTarget(from_path.clone())
+ )
+ );
+ }
+ }
+ }
+
+ // Process
+ for (from_path, (operation, to_path)) in args.operations {
+ match operation {
+ // During the Precheck phase, it has been ensured that:
+ // 1. The mapping to be edited for the From path indeed exists
+ // 2. The location of the To path is indeed empty
+ // 3. In Move mode, To path can be safely unwrapped
+ // Therefore, the following unwrap() calls are safe to execute
+ EditMappingOperations::Move => {
+ let mapping = sheet.mapping_mut().remove(&from_path).unwrap();
+ let to_path = to_path.unwrap();
+ sheet
+ .add_mapping(to_path, mapping.id, mapping.version)
+ .await?;
+ }
+ EditMappingOperations::Erase => {
+ sheet.mapping_mut().remove(&from_path).unwrap();
+ }
+ }
+ }
+
+ // Write
+ sheet.persist().await?;
+
+ write_and_return!(instance, EditMappingActionResult::Success);
+ }
+
+ if ctx.is_proc_on_local() {
+ let result = instance
+ .lock()
+ .await
+ .read::<EditMappingActionResult>()
+ .await?;
+ if matches!(result, EditMappingActionResult::Success) {
+ sign_vault_modified(true).await;
+ }
+ return Ok(result);
+ }
+
+ Ok(EditMappingActionResult::Success)
+}
diff --git a/crates/vcs_actions/src/registry/client_registry.rs b/crates/vcs_actions/src/registry/client_registry.rs
index 6e2814f..6667a74 100644
--- a/crates/vcs_actions/src/registry/client_registry.rs
+++ b/crates/vcs_actions/src/registry/client_registry.rs
@@ -13,7 +13,9 @@ use crate::{
local_actions::{
register_set_upstream_vault_action, register_update_to_latest_info_action,
},
- sheet_actions::{register_drop_sheet_action, register_make_sheet_action},
+ sheet_actions::{
+ register_drop_sheet_action, register_edit_mapping_action, register_make_sheet_action,
+ },
track_action::register_track_file_action,
user_actions::register_change_virtual_file_edit_right_action,
},
@@ -30,6 +32,7 @@ fn register_actions(pool: &mut ActionPool) {
// Sheet Actions
register_make_sheet_action(pool);
register_drop_sheet_action(pool);
+ register_edit_mapping_action(pool);
// Track Action
register_track_file_action(pool);
diff --git a/crates/vcs_actions/src/registry/server_registry.rs b/crates/vcs_actions/src/registry/server_registry.rs
index 9c12d24..404625c 100644
--- a/crates/vcs_actions/src/registry/server_registry.rs
+++ b/crates/vcs_actions/src/registry/server_registry.rs
@@ -2,7 +2,9 @@ use action_system::action_pool::ActionPool;
use crate::actions::{
local_actions::{register_set_upstream_vault_action, register_update_to_latest_info_action},
- sheet_actions::{register_drop_sheet_action, register_make_sheet_action},
+ sheet_actions::{
+ register_drop_sheet_action, register_edit_mapping_action, register_make_sheet_action,
+ },
track_action::register_track_file_action,
user_actions::register_change_virtual_file_edit_right_action,
};
@@ -17,6 +19,7 @@ pub fn server_action_pool() -> ActionPool {
// Sheet Actions
register_make_sheet_action(&mut pool);
register_drop_sheet_action(&mut pool);
+ register_edit_mapping_action(&mut pool);
// Track Action
register_track_file_action(&mut pool);
diff --git a/crates/vcs_data/src/data/local/align.rs b/crates/vcs_data/src/data/local/align.rs
index 1b8c3c9..715c785 100644
--- a/crates/vcs_data/src/data/local/align.rs
+++ b/crates/vcs_data/src/data/local/align.rs
@@ -16,6 +16,7 @@ pub struct AlignTasks {
pub created: Vec<(AlignTasksName, AlignPathBuf)>,
pub lost: Vec<(AlignTasksName, AlignPathBuf)>,
pub moved: Vec<(AlignTasksName, (AlignLostPathBuf, AlignCreatedPathBuf))>,
+ pub erased: Vec<(AlignTasksName, AlignPathBuf)>,
}
impl AlignTasks {
@@ -24,6 +25,7 @@ impl AlignTasks {
created: path_hash_set_sort_helper(result.created.clone(), "created"),
lost: path_hash_set_sort_helper(result.lost.clone(), "lost"),
moved: path_hash_map_sort_helper(result.moved.clone(), "moved"),
+ erased: path_hash_set_sort_helper(result.erased.clone(), "erased"),
}
}
@@ -32,6 +34,7 @@ impl AlignTasks {
created: path_hash_set_sort_helper(result.created, "created"),
lost: path_hash_set_sort_helper(result.lost, "lost"),
moved: path_hash_map_sort_helper(result.moved, "moved"),
+ erased: path_hash_set_sort_helper(result.erased, "erased"),
}
}
}
diff --git a/crates/vcs_data/src/data/local/file_status.rs b/crates/vcs_data/src/data/local/file_status.rs
index 7841237..599e4a3 100644
--- a/crates/vcs_data/src/data/local/file_status.rs
+++ b/crates/vcs_data/src/data/local/file_status.rs
@@ -33,6 +33,9 @@ pub struct AnalyzeResult<'a> {
/// Lost local files
pub lost: HashSet<LostRelativePathBuf>,
+ /// Erased local files
+ pub erased: HashSet<LostRelativePathBuf>,
+
/// Modified local files (excluding moved files)
/// For files that were both moved and modified, changes can only be detected after LocalSheet mapping is aligned with actual files
pub modified: HashSet<ModifiedRelativePathBuf>,
@@ -154,6 +157,23 @@ impl<'a> AnalyzeResult<'a> {
.cloned()
.collect();
+ // Files that exist locally but not in remote
+ let mut erased_files: HashSet<PathBuf> = HashSet::new();
+
+ if let Some(cached_data) = &analyze_ctx.cached_sheet_data {
+ if let Some(local_sheet) = &analyze_ctx.local_sheet {
+ let cached_sheet_mapping = cached_data.mapping();
+ let local_sheet_mapping = &local_sheet.data.mapping;
+
+ // Find paths that exist in local sheet but not in cached sheet
+ for local_path in local_sheet_mapping.keys() {
+ if !cached_sheet_mapping.contains_key(local_path) {
+ erased_files.insert(local_path.clone());
+ }
+ }
+ }
+ }
+
// Calculate hashes for new files
let new_files_for_hash: Vec<PathBuf> = new_files
.iter()
@@ -231,6 +251,7 @@ impl<'a> AnalyzeResult<'a> {
vfid.map(|vfid| (vfid, (from.clone(), to.clone())))
})
.collect();
+ result.erased = erased_files;
Ok(())
}
@@ -299,6 +320,7 @@ impl<'a> AnalyzeResult<'a> {
created: HashSet::new(),
lost: HashSet::new(),
modified: HashSet::new(),
+ erased: HashSet::new(),
}
}
}
diff --git a/crates/vcs_data/src/data/sheet.rs b/crates/vcs_data/src/data/sheet.rs
index 891888a..900331d 100644
--- a/crates/vcs_data/src/data/sheet.rs
+++ b/crates/vcs_data/src/data/sheet.rs
@@ -69,6 +69,9 @@ pub struct SheetData {
pub(crate) id_mapping: Option<HashMap<VirtualFileId, SheetPathBuf>>,
}
+#[derive(Default, Serialize, Deserialize, ConfigFile, Clone)]
+pub struct SheetInputs {}
+
#[derive(Debug, Default, Serialize, Deserialize, ConfigFile, Clone, Eq, PartialEq)]
pub struct SheetMappingMetadata {
pub id: VirtualFileId,