From 75a673eb7df059d4e126b62e38506ef72fcf948c Mon Sep 17 00:00:00 2001 From: Arpita-Jaiswal Date: Fri, 5 Aug 2022 15:23:37 +0530 Subject: [PATCH 1/2] Remove debug logs --- src/apis/sync2.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/apis/sync2.rs b/src/apis/sync2.rs index 0290d92a..fd8fc542 100644 --- a/src/apis/sync2.rs +++ b/src/apis/sync2.rs @@ -116,7 +116,6 @@ pub(crate) async fn sync_worker(request: SyncRequest) -> fpm::Result { // TODO: We need to check if, file is already available on server @@ -250,30 +249,25 @@ pub(crate) async fn sync_worker(request: SyncRequest) -> fpm::Result Date: Fri, 5 Aug 2022 16:28:04 +0530 Subject: [PATCH 2/2] Working: fpm revert --- src/commands/resolve_conflict.rs | 2 +- src/commands/revert.rs | 45 +++- src/commands/sync2.rs | 5 +- src/commands/sync_status.rs | 2 +- src/snapshot.rs | 4 - src/sync_utils.rs | 382 ++++++++++++++++--------------- 6 files changed, 250 insertions(+), 190 deletions(-) diff --git a/src/commands/resolve_conflict.rs b/src/commands/resolve_conflict.rs index bf42b506..effb7215 100644 --- a/src/commands/resolve_conflict.rs +++ b/src/commands/resolve_conflict.rs @@ -15,7 +15,7 @@ pub async fn resolve_conflict( if number_of_times_flag_used > 1 { return fpm::usage_error("AmbiguousOptionError: Use only one flag".to_string()); } - let get_files_status = fpm::sync_utils::get_files_status(config).await?; + let get_files_status = config.get_files_status().await?; let file_status = if let Some(file_status) = get_files_status.iter().find(|v| v.get_file_path().eq(path)) { file_status diff --git a/src/commands/revert.rs b/src/commands/revert.rs index 8dd9d59b..11a99720 100644 --- a/src/commands/revert.rs +++ b/src/commands/revert.rs @@ -1,4 +1,47 @@ +use itertools::Itertools; + pub async fn revert(config: &fpm::Config, path: &str) -> fpm::Result<()> { + let mut workspace: std::collections::BTreeMap = config + .read_workspace() + .await? + .iter() + .map(|v| (v.filename.to_string(), v.clone())) + .collect(); + let get_files_status = config + .get_files_status_with_workspace(&mut workspace) + .await?; + let file_status = + if let Some(file_status) = get_files_status.iter().find(|v| v.get_file_path().eq(path)) { + file_status + } else { + config + .write_workspace(workspace.into_values().collect_vec().as_slice()) + .await?; + return Err(fpm::Error::UsageError { + message: format!("{} not found", path), + }); + }; + + if let Some(server_version) = file_status.get_latest_version() { + let server_path = config.history_path(path, server_version); + let content = tokio::fs::read(&server_path).await?; + fpm::utils::update(&config.root.join(path), content.as_slice()).await?; + if let Some(workspace_entry) = workspace.get_mut(path) { + workspace_entry.version = Some(server_version); + workspace_entry.deleted = None; + } + } else { + // in case of new file added + tokio::fs::remove_file(path).await?; + workspace.remove(path); + } + config + .write_workspace(workspace.into_values().collect_vec().as_slice()) + .await?; + Ok(()) +} + +/*pub async fn revert_(config: &fpm::Config, path: &str) -> fpm::Result<()> { use itertools::Itertools; let mut workspaces = fpm::snapshot::get_workspace(config).await?; @@ -36,4 +79,4 @@ pub async fn revert(config: &fpm::Config, path: &str) -> fpm::Result<()> { } Ok(()) -} +}*/ diff --git a/src/commands/sync2.rs b/src/commands/sync2.rs index 642a4393..436e4c5f 100644 --- a/src/commands/sync2.rs +++ b/src/commands/sync2.rs @@ -8,8 +8,9 @@ pub async fn sync2(config: &fpm::Config, files: Option>) -> fpm::Res .map(|v| (v.filename.to_string(), v.clone())) .collect(); let changed_files = { - let mut changed_files = - fpm::sync_utils::get_files_status_with_workspace(config, &mut workspace).await?; + let mut changed_files = config + .get_files_status_with_workspace(&mut workspace) + .await?; if let Some(ref files) = files { changed_files = changed_files .into_iter() diff --git a/src/commands/sync_status.rs b/src/commands/sync_status.rs index 8eca8f03..748bbcf1 100644 --- a/src/commands/sync_status.rs +++ b/src/commands/sync_status.rs @@ -1,7 +1,7 @@ use itertools::Itertools; pub async fn sync_status(config: &fpm::Config, source: Option<&str>) -> fpm::Result<()> { - let get_files_status = fpm::sync_utils::get_files_status(config).await?; + let get_files_status = config.get_files_status().await?; if let Some(source) = source { if let Some(file_status) = get_files_status .iter() diff --git a/src/snapshot.rs b/src/snapshot.rs index 19b4a40c..ebbf40a7 100644 --- a/src/snapshot.rs +++ b/src/snapshot.rs @@ -100,10 +100,6 @@ impl Workspace { pub(crate) fn set_abort(&mut self) { self.workspace = WorkspaceType::AbortMerge; } - - pub(crate) fn set_revert(&mut self) { - self.workspace = WorkspaceType::Revert; - } } pub(crate) async fn resolve_workspace( diff --git a/src/sync_utils.rs b/src/sync_utils.rs index e6f11bdb..e2d61643 100644 --- a/src/sync_utils.rs +++ b/src/sync_utils.rs @@ -61,6 +61,21 @@ impl FileStatus { status.is_conflicted() } + pub(crate) fn get_latest_version(&self) -> Option { + // Either file must be in conflict with latest version, so conflicted version would be + // latest, or it's version would be latest + match self { + FileStatus::Add { .. } => None, + FileStatus::Update { + status, version, .. + } + | FileStatus::Delete { + status, version, .. + } => Some(status.conflicted_version().unwrap_or(*version)), + FileStatus::Untracked { version, .. } => Some(*version), + } + } + pub(crate) fn status(&self) -> Option<&Status> { match self { FileStatus::Add { status, .. } @@ -104,210 +119,215 @@ impl FileStatus { }) } } -pub(crate) async fn get_files_status(config: &fpm::Config) -> fpm::Result> { - let file_list = config.read_workspace().await?; - let mut workspace: std::collections::BTreeMap = - file_list - .iter() - .map(|v| (v.filename.to_string(), v.clone())) - .collect(); - let changed_files = get_files_status_with_workspace(config, &mut workspace).await?; - config - .write_workspace(workspace.into_values().collect_vec().as_slice()) - .await?; - Ok(changed_files) -} -pub(crate) async fn get_files_status_with_workspace( - config: &fpm::Config, - workspace: &mut std::collections::BTreeMap, -) -> fpm::Result> { - let mut changed_files = get_files_status_wrt_workspace(config, workspace).await?; - get_files_status_wrt_server_latest(config, &mut changed_files, workspace).await?; - Ok(changed_files) -} +impl fpm::Config { + pub(crate) async fn get_files_status(&self) -> fpm::Result> { + let file_list = self.read_workspace().await?; + let mut workspace: std::collections::BTreeMap = + file_list + .iter() + .map(|v| (v.filename.to_string(), v.clone())) + .collect(); + let changed_files = self.get_files_status_with_workspace(&mut workspace).await?; + self.write_workspace(workspace.into_values().collect_vec().as_slice()) + .await?; + Ok(changed_files) + } + + pub(crate) async fn get_files_status_with_workspace( + &self, + workspace: &mut std::collections::BTreeMap, + ) -> fpm::Result> { + let mut changed_files = self.get_files_status_wrt_workspace(workspace).await?; + self.get_files_status_wrt_server_latest(&mut changed_files, workspace) + .await?; + Ok(changed_files) + } + + async fn get_files_status_wrt_workspace( + &self, + workspace: &std::collections::BTreeMap, + ) -> fpm::Result> { + let files = workspace.values().collect_vec(); + let mut changed_files = vec![]; + for workspace_entry in files { + let version = if let Some(version) = workspace_entry.version { + version + } else { + let content = + tokio::fs::read(self.root.join(workspace_entry.filename.as_str())).await?; + changed_files.push(FileStatus::Add { + path: workspace_entry.filename.to_string(), + content, + status: Status::NoConflict, + }); + continue; + }; + if workspace_entry.deleted.unwrap_or(false) { + changed_files.push(FileStatus::Delete { + path: workspace_entry.filename.to_string(), + version: workspace_entry.version.ok_or(fpm::Error::UsageError { + message: format!( + "{}, which is to be deleted, doesn't define version in workspace", + workspace_entry.filename + ), + })?, + status: Status::NoConflict, + }); + continue; + } -async fn get_files_status_wrt_workspace( - config: &fpm::Config, - workspace: &std::collections::BTreeMap, -) -> fpm::Result> { - let files = workspace.values().collect_vec(); - let mut changed_files = vec![]; - for workspace_entry in files { - let version = if let Some(version) = workspace_entry.version { - version - } else { let content = - tokio::fs::read(config.root.join(workspace_entry.filename.as_str())).await?; - changed_files.push(FileStatus::Add { + tokio::fs::read(self.root.join(workspace_entry.filename.as_str())).await?; + let history_path = self.history_path(workspace_entry.filename.as_str(), version); + let history_content = tokio::fs::read(history_path).await?; + if sha2::Sha256::digest(&content).eq(&sha2::Sha256::digest(&history_content)) { + changed_files.push(FileStatus::Untracked { + path: workspace_entry.filename.to_string(), + version, + }); + continue; + } + changed_files.push(FileStatus::Update { path: workspace_entry.filename.to_string(), content, - status: Status::NoConflict, - }); - continue; - }; - if workspace_entry.deleted.unwrap_or(false) { - changed_files.push(FileStatus::Delete { - path: workspace_entry.filename.to_string(), - version: workspace_entry.version.ok_or(fpm::Error::UsageError { - message: format!( - "{}, which is to be deleted, doesn't define version in workspace", - workspace_entry.filename - ), - })?, - status: Status::NoConflict, - }); - continue; - } - - let content = tokio::fs::read(config.root.join(workspace_entry.filename.as_str())).await?; - let history_path = config.history_path(workspace_entry.filename.as_str(), version); - let history_content = tokio::fs::read(history_path).await?; - if sha2::Sha256::digest(&content).eq(&sha2::Sha256::digest(&history_content)) { - changed_files.push(FileStatus::Untracked { - path: workspace_entry.filename.to_string(), version, + status: Status::NoConflict, }); - continue; } - changed_files.push(FileStatus::Update { - path: workspace_entry.filename.to_string(), - content, - version, - status: Status::NoConflict, - }); + Ok(changed_files) } - Ok(changed_files) -} -async fn get_files_status_wrt_server_latest( - config: &fpm::Config, - files: &mut Vec, - workspace: &mut std::collections::BTreeMap, -) -> fpm::Result<()> { - let mut remove_files = vec![]; - let server_latest = config.get_latest_file_edits().await?; - for (index, file) in files.iter_mut().enumerate() { - match file { - FileStatus::Untracked { .. } => { - continue; - } - FileStatus::Add { - path, - content, - status, - } => { - let server_version = if let Some(file_edit) = server_latest.get(path) { - if file_edit.is_deleted() { + async fn get_files_status_wrt_server_latest( + &self, + files: &mut Vec, + workspace: &mut std::collections::BTreeMap, + ) -> fpm::Result<()> { + let mut remove_files = vec![]; + let server_latest = self.get_latest_file_edits().await?; + for (index, file) in files.iter_mut().enumerate() { + match file { + FileStatus::Untracked { .. } => { + continue; + } + FileStatus::Add { + path, + content, + status, + } => { + let server_version = if let Some(file_edit) = server_latest.get(path) { + if file_edit.is_deleted() { + continue; + } + file_edit.version + } else { continue; + }; + let history_path = self.history_path(path, server_version); + let history_content = tokio::fs::read(history_path).await?; + if sha2::Sha256::digest(content).eq(&sha2::Sha256::digest(history_content)) { + workspace.insert( + path.to_string(), + fpm::workspace::WorkspaceEntry { + filename: path.to_string(), + deleted: None, + version: Some(server_version), + }, + ); + remove_files.push(index); + } else { + *status = Status::Conflict(server_version); } - file_edit.version - } else { - continue; - }; - let history_path = config.history_path(path, server_version); - let history_content = tokio::fs::read(history_path).await?; - if sha2::Sha256::digest(content).eq(&sha2::Sha256::digest(history_content)) { - workspace.insert( - path.to_string(), - fpm::workspace::WorkspaceEntry { - filename: path.to_string(), - deleted: None, - version: Some(server_version), - }, - ); - remove_files.push(index); - } else { - *status = Status::Conflict(server_version); } - } - FileStatus::Update { - path, - content, - version, - status, - } => { - let server_file_edit = if let Some(file_edit) = server_latest.get(path) { - file_edit - } else { - continue; - }; + FileStatus::Update { + path, + content, + version, + status, + } => { + let server_file_edit = if let Some(file_edit) = server_latest.get(path) { + file_edit + } else { + continue; + }; - if server_file_edit.is_deleted() { - // Conflict: ClientEditedServerDeleted - *status = Status::ClientEditedServerDeleted(server_file_edit.version); - continue; - } + if server_file_edit.is_deleted() { + // Conflict: ClientEditedServerDeleted + *status = Status::ClientEditedServerDeleted(server_file_edit.version); + continue; + } - if server_file_edit.version.eq(version) { - continue; - } + if server_file_edit.version.eq(version) { + continue; + } - let ancestor_content = if let Ok(content) = - tokio::fs::read_to_string(config.history_path(path, *version)).await - { - content - } else { - // binary file like images, can't resolve conflict - *status = Status::Conflict(server_file_edit.version); - continue; - }; + let ancestor_content = if let Ok(content) = + tokio::fs::read_to_string(self.history_path(path, *version)).await + { + content + } else { + // binary file like images, can't resolve conflict + *status = Status::Conflict(server_file_edit.version); + continue; + }; - // attempt resolving conflict - let theirs_content = - tokio::fs::read_to_string(config.history_path(path, server_file_edit.version)) - .await?; - let ours_content = String::from_utf8(content.clone())?; + // attempt resolving conflict + let theirs_content = tokio::fs::read_to_string( + self.history_path(path, server_file_edit.version), + ) + .await?; + let ours_content = String::from_utf8(content.clone())?; - match diffy::MergeOptions::new() - .set_conflict_style(diffy::ConflictStyle::Merge) - .merge(&ancestor_content, &ours_content, &theirs_content) - { - Ok(data) => { - tokio::fs::write(path, &data).await?; - *content = data.as_bytes().to_vec(); - *version = server_file_edit.version; + match diffy::MergeOptions::new() + .set_conflict_style(diffy::ConflictStyle::Merge) + .merge(&ancestor_content, &ours_content, &theirs_content) + { + Ok(data) => { + tokio::fs::write(path, &data).await?; + *content = data.as_bytes().to_vec(); + *version = server_file_edit.version; + } + Err(_) => { + // can't resolve conflict, so cannot sync + *status = Status::Conflict(server_file_edit.version); + } } - Err(_) => { - // can't resolve conflict, so cannot sync - *status = Status::Conflict(server_file_edit.version); + } + FileStatus::Delete { + path, + version, + status, + } => { + let server_file_edit = if let Some(server_file_edit) = server_latest.get(path) { + server_file_edit + } else { + remove_files.push(index); + workspace.remove(path); + continue; + }; + if server_file_edit.is_deleted() { + remove_files.push(index); + workspace.remove(path); + continue; + } + if !server_file_edit.version.eq(version) { + // Conflict modified by server and deleted by client + *status = Status::ClientDeletedServerEdited(server_file_edit.version); } } } - FileStatus::Delete { - path, - version, - status, - } => { - let server_file_edit = if let Some(server_file_edit) = server_latest.get(path) { - server_file_edit + } + *files = files + .iter_mut() + .enumerate() + .filter_map(|(k, v)| { + if !remove_files.contains(&k) { + Some(v.to_owned()) } else { - remove_files.push(index); - workspace.remove(path); - continue; - }; - if server_file_edit.is_deleted() { - remove_files.push(index); - workspace.remove(path); - continue; + None } - if !server_file_edit.version.eq(version) { - // Conflict modified by server and deleted by client - *status = Status::ClientDeletedServerEdited(server_file_edit.version); - } - } - } + }) + .collect_vec(); + Ok(()) } - *files = files - .iter_mut() - .enumerate() - .filter_map(|(k, v)| { - if !remove_files.contains(&k) { - Some(v.to_owned()) - } else { - None - } - }) - .collect_vec(); - Ok(()) }