1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
extern crate git2;
use git2::Repository;
use git2::*;
use std::path::Path;
pub struct CratesIndex {
repo: Repository
}
pub struct IndexIter<'a> {
repo: &'a Repository,
revwalk: Revwalk<'a>
}
#[derive(Debug)]
pub enum ChangeType {
Modified,
Deleted
}
#[derive(Debug)]
pub struct Change {
delta: Delta,
payload: String
}
impl Default for Change {
fn default() -> Change {
Change { delta: Delta::Modified, payload: String::new() }
}
}
impl CratesIndex {
pub fn new<P: AsRef<Path>>(p: P) -> Result<CratesIndex, Error> {
let path = p.as_ref();
Repository::open(path)
.and_then(|repo| {
Ok(CratesIndex { repo: repo })
})
}
pub fn iter<'a>(&'a self) -> Result<IndexIter<'a>, Error> {
let mut revwalk = self.repo.revwalk()?;
revwalk.set_sorting(git2::SORT_REVERSE);
revwalk.push_head()?;
revwalk.next();
Ok(IndexIter { repo: &self.repo, revwalk })
}
}
impl<'a> IndexIter<'a> {
fn get_last_diff(&self, rev: Oid) -> Result<Diff, Error> {
let commit = self.repo.find_commit(rev)?;
let tree = self.repo.find_tree(commit.tree_id())?;
let parent = commit.parent(0)?;
let parent_tree = self.repo.find_tree(parent.tree_id())?;
self.repo.diff_tree_to_tree(Some(&tree), Some(&parent_tree), None)
}
}
impl<'a> Iterator for IndexIter<'a> {
type Item = Result<Change, Error>;
fn next(&mut self) -> Option<Result<Change, Error>> {
let rev = match self.revwalk.next() {
Some(Ok(r)) => r,
Some(Err(e)) => return Some(Err(e)),
None => return None
};
let diff = self.get_last_diff(rev).unwrap();
fn file_cb(_: DiffDelta, _: f32) -> bool {
true
}
let mut change = Change::default();
let res = diff.foreach(
&mut file_cb,
None,
None,
Some(&mut |delta, _, line| -> bool {
change.delta = delta.status();
change.payload.push_str(std::str::from_utf8(line.content()).unwrap());
true
})
);
match res {
Err(e) => Some(Err(e)),
_ => Some(Ok(change))
}
}
}
#[test]
fn test() {
let index = CratesIndex::new("crates.io-index").unwrap();
let iter = index.iter().unwrap();
for i in iter.take(5) {
println!("{:?}", i);
}
}