summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortummychow <tummychow@users.noreply.github.com>2018-02-26 21:18:09 -0800
committertummychow <tummychow@users.noreply.github.com>2018-02-26 21:18:09 -0800
commit9843d7fbb3c8fb14099df599bbf2000e8db1d931 (patch)
treec2a3e051eaf49a5d08f03fdef879d14600476e7d
parentd18a973d57ee770444e7ed183a544e6cd2e70c7c (diff)
index paths in diff structure
-rw-r--r--src/lib.rs4
-rw-r--r--src/owned.rs53
2 files changed, 49 insertions, 8 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 2ccde2e..304a28e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)]