gitui/asyncgit/src/sync/hunks.rs
2020-05-07 17:00:17 +02:00

108 lines
2.3 KiB
Rust

use super::{
diff::{get_diff_raw, HunkHeader},
utils::repo,
};
use crate::hash;
use git2::{ApplyLocation, ApplyOptions, Diff};
use log::error;
use scopetime::scope_time;
///
pub fn stage_hunk(
repo_path: &str,
file_path: String,
hunk_hash: u64,
) -> bool {
scope_time!("stage_hunk");
let repo = repo(repo_path);
let diff = get_diff_raw(&repo, &file_path, false, false).unwrap();
let mut opt = ApplyOptions::new();
opt.hunk_callback(|hunk| {
let header = HunkHeader::from(hunk.unwrap());
hash(&header) == hunk_hash
});
repo.apply(&diff, ApplyLocation::Index, Some(&mut opt))
.is_ok()
}
fn find_hunk_index(diff: &Diff, hunk_hash: u64) -> Option<usize> {
let mut result = None;
let mut hunk_count = 0;
let foreach_result = diff.foreach(
&mut |_, _| true,
None,
Some(&mut |_, hunk| {
let header = HunkHeader::from(hunk);
if hash(&header) == hunk_hash {
result = Some(hunk_count);
}
hunk_count += 1;
true
}),
None,
);
if foreach_result.is_ok() {
result
} else {
None
}
}
///
pub fn unstage_hunk(
repo_path: &str,
file_path: String,
hunk_hash: u64,
) -> bool {
scope_time!("revert_hunk");
let repo = repo(repo_path);
let diff = get_diff_raw(&repo, &file_path, true, false).unwrap();
let diff_count_positive = diff.deltas().len();
let hunk_index = find_hunk_index(&diff, hunk_hash);
if hunk_index.is_none() {
error!("hunk not found");
return false;
}
let diff = get_diff_raw(&repo, &file_path, true, true).unwrap();
assert_eq!(diff.deltas().len(), diff_count_positive);
let mut count = 0;
{
let mut hunk_idx = 0;
let mut opt = ApplyOptions::new();
opt.hunk_callback(|_hunk| {
let res = if hunk_idx == hunk_index.unwrap() {
count += 1;
true
} else {
false
};
hunk_idx += 1;
res
});
if repo
.apply(&diff, ApplyLocation::Index, Some(&mut opt))
.is_err()
{
error!("apply failed");
return false;
}
}
count == 1
}