crates_io_changes/
lib.rs

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(); // Skip the first commit
50
51        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}