From ba0069e6aecbc85e184beb84c7f692736feaa84d Mon Sep 17 00:00:00 2001 From: Nikita Galaiko Date: Wed, 1 Nov 2023 13:27:12 +0100 Subject: [PATCH] fix hunk locking --- .../tauri/src/virtual_branches/virtual.rs | 34 ++++++++-- packages/tauri/tests/virtual_branches/mod.rs | 66 +++++++++++++++++++ 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/packages/tauri/src/virtual_branches/virtual.rs b/packages/tauri/src/virtual_branches/virtual.rs index fb0d85a89..e5643cf1b 100644 --- a/packages/tauri/src/virtual_branches/virtual.rs +++ b/packages/tauri/src/virtual_branches/virtual.rs @@ -1,4 +1,8 @@ -use std::{collections::HashMap, os::unix::fs::PermissionsExt, path, time, vec}; +use std::{ + collections::{HashMap, HashSet}, + os::unix::fs::PermissionsExt, + path, time, vec, +}; use anyhow::{anyhow, bail, Context, Result}; use diffy::{apply_bytes, Patch}; @@ -640,10 +644,20 @@ pub fn list_virtual_branches( let statuses = get_status_by_branch(gb_repository, project_repository)?; for (branch, files) in &statuses { + let file_diffs = files + .iter() + .map(|(filepath, hunks)| { + ( + filepath, + hunks.iter().map(|hunk| &hunk.diff).collect::>(), + ) + }) + .collect::>(); + // check if head tree does not match target tree // if so, we diff the head tree and the new write_tree output to see what is new and filter the hunks to just those let files = - calculate_non_commited_files(project_repository, branch, &default_target, files)?; + calculate_non_commited_diffs(project_repository, branch, &default_target, files)?; let repo = &project_repository.git_repository; @@ -732,6 +746,18 @@ pub fn list_virtual_branches( ) }); + // mark locked hunks + for file in &mut files { + file.hunks.iter_mut().for_each(|hunk| { + // we consider a hunk to be locked if it's not seen verbatim + // non-commited. reason beging - we can't partialy move hunks between + // branches just yet. + hunk.locked = file_diffs + .get(&file.path) + .map_or(false, |h| !h.contains(&hunk.diff)); + }); + } + let requires_force = is_requires_force(project_repository, branch)?; let branch = VirtualBranch { id: branch.id, @@ -786,7 +812,7 @@ fn is_requires_force( // given a virtual branch and it's files that are calculated off of a default target, // return files adjusted to the branch's head commit -fn calculate_non_commited_files( +fn calculate_non_commited_diffs( project_repository: &project_repository::Repository, branch: &branch::Branch, default_target: &target::Target, @@ -1876,7 +1902,7 @@ pub fn commit( .find(|(branch, _)| branch.id == *branch_id) .ok_or_else(|| anyhow!("branch {} not found", branch_id))?; - let files = calculate_non_commited_files(project_repository, branch, &default_target, files)?; + let files = calculate_non_commited_diffs(project_repository, branch, &default_target, files)?; if conflicts::is_conflicting(project_repository, None)? { return Err(CommitError::Conflicted); } diff --git a/packages/tauri/tests/virtual_branches/mod.rs b/packages/tauri/tests/virtual_branches/mod.rs index 9b80ad2fc..25e2f3edf 100644 --- a/packages/tauri/tests/virtual_branches/mod.rs +++ b/packages/tauri/tests/virtual_branches/mod.rs @@ -41,6 +41,72 @@ impl Default for Test { } } +mod create_commit { + use super::*; + + #[tokio::test] + async fn should_lock_updated_hunks() { + let Test { + project_id, + controller, + repository, + .. + } = Test::default(); + + controller + .set_base_branch( + &project_id, + &git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(), + ) + .unwrap(); + + let branch_id = controller + .create_virtual_branch(&project_id, &branch::BranchCreateRequest::default()) + .await + .unwrap(); + + { + // by default, hunks are not locked + + fs::write(repository.path().join("file.txt"), "content").unwrap(); + + let branch = controller + .list_virtual_branches(&project_id) + .await + .unwrap() + .into_iter() + .find(|b| b.id == branch_id) + .unwrap(); + assert_eq!(branch.files.len(), 1); + assert_eq!(branch.files[0].path.display().to_string(), "file.txt"); + assert_eq!(branch.files[0].hunks.len(), 1); + assert!(!branch.files[0].hunks[0].locked); + } + + controller + .create_commit(&project_id, &branch_id, "test", None) + .await + .unwrap(); + + { + // change in the comitted hunks leads to hunk locking + fs::write(repository.path().join("file.txt"), "updated content").unwrap(); + + let branch = controller + .list_virtual_branches(&project_id) + .await + .unwrap() + .into_iter() + .find(|b| b.id == branch_id) + .unwrap(); + assert_eq!(branch.files.len(), 1); + assert_eq!(branch.files[0].path.display().to_string(), "file.txt"); + assert_eq!(branch.files[0].hunks.len(), 1); + assert!(branch.files[0].hunks[0].locked); + } + } +} + mod references { use super::*;