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