diff options
author | tummychow <tummychow@users.noreply.github.com> | 2018-02-26 21:18:09 -0800 |
---|---|---|
committer | tummychow <tummychow@users.noreply.github.com> | 2018-02-26 21:18:09 -0800 |
commit | 9843d7fbb3c8fb14099df599bbf2000e8db1d931 (patch) | |
tree | c2a3e051eaf49a5d08f03fdef879d14600476e7d | |
parent | d18a973d57ee770444e7ed183a544e6cd2e70c7c (diff) |
index paths in diff structure
-rw-r--r-- | src/lib.rs | 4 | ||||
-rw-r--r-- | src/owned.rs | 53 |
2 files changed, 49 insertions, 8 deletions
@@ -37,7 +37,7 @@ pub fn run(config: &Config) -> Result<(), failure::Error> { let stack = stack::working_stack(&repo, base.as_ref(), config.logger)?; let mut diffs = Vec::with_capacity(stack.len()); for commit in &stack { - let diff = owned::parse_diff(&repo.diff_tree_to_tree( + let diff = owned::Diff::new(&repo.diff_tree_to_tree( if commit.parents().len() == 0 { None } else { @@ -56,7 +56,7 @@ pub fn run(config: &Config) -> Result<(), failure::Error> { stack.into_iter().zip(diffs.into_iter()).collect() }; - let index = owned::parse_diff(&repo.diff_tree_to_index( + let index = owned::Diff::new(&repo.diff_tree_to_index( Some(&repo.head()?.peel_to_tree()?), None, diff_options.as_mut(), diff --git a/src/owned.rs b/src/owned.rs index 578846a..dd06182 100644 --- a/src/owned.rs +++ b/src/owned.rs @@ -2,14 +2,55 @@ extern crate failure; extern crate git2; use std::rc::Rc; +use std::collections::hash_map::HashMap; -pub fn parse_diff(diff: &git2::Diff) -> Result<Vec<Patch>, failure::Error> { - let mut ret = Vec::new(); - for (delta_idx, _delta) in diff.deltas().enumerate() { - ret.push(Patch::new(&mut git2::Patch::from_diff(diff, delta_idx)? - .ok_or_else(|| failure::err_msg("got empty delta"))?)?); +#[derive(Debug)] +pub struct Diff { + patches: Vec<Patch>, + by_new: HashMap<Vec<u8>, usize>, + by_old: HashMap<Vec<u8>, usize>, +} +impl ::std::ops::Deref for Diff { + type Target = [Patch]; + fn deref(&self) -> &[Patch] { + self.patches.as_slice() + } +} +impl Diff { + pub fn new(diff: &git2::Diff) -> Result<Diff, failure::Error> { + let mut ret = Diff { + patches: Vec::new(), + by_old: HashMap::new(), + by_new: HashMap::new(), + }; + + for (delta_idx, _delta) in diff.deltas().enumerate() { + let patch = Patch::new(&mut git2::Patch::from_diff(diff, delta_idx)? + .ok_or_else(|| failure::err_msg("got empty delta"))?)?; + if let Some(path) = patch.old_path.as_ref() { + if ret.by_old.contains_key(path) { + // TODO: would this case be hit if the diff was put through copy detection? + return Err(failure::err_msg("old path already occupied")); + } + ret.by_old.insert(path.to_vec(), ret.patches.len()); + } + if let Some(path) = patch.new_path.as_ref() { + if ret.by_new.contains_key(path) { + return Err(failure::err_msg("new path already occupied")); + } + ret.by_new.insert(path.to_vec(), ret.patches.len()); + } + ret.patches.push(patch); + } + + Ok(ret) + } + pub fn by_old(&self, path: &[u8]) -> Option<&Patch> { + self.by_old.get(path).map(|&idx| &self.patches[idx]) + } + pub fn by_new(&self, path: &[u8]) -> Option<&Patch> { + self.by_new.get(path).map(|&idx| &self.patches[idx]) } - Ok(ret) } #[derive(Debug, Clone)] |