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
use {
git2::{self, Repository, Status},
std::{
collections::HashMap,
path::{Path, PathBuf},
},
};
const INTERESTING: Status = Status::from_bits_truncate(
Status::WT_NEW.bits() | Status::CONFLICTED.bits() | Status::WT_MODIFIED.bits(),
);
#[derive(Debug, Clone, Copy)]
pub struct LineGitStatus {
pub status: Status,
}
impl LineGitStatus {
pub fn from(repo: &Repository, relative_path: &Path) -> Option<LineGitStatus> {
repo.status_file(&relative_path)
.ok()
.map(|status| LineGitStatus { status })
}
pub fn is_interesting(self) -> bool {
self.status.intersects(INTERESTING)
}
}
pub struct LineStatusComputer {
interesting_statuses: HashMap<PathBuf, Status>,
}
impl LineStatusComputer {
pub fn from(repo: Repository) -> Self {
let repo_path = repo.path().parent().unwrap().to_path_buf();
let mut interesting_statuses = HashMap::new();
if let Ok(statuses) = &repo.statuses(None) {
for entry in statuses.iter() {
let status = entry.status();
if status.intersects(INTERESTING) {
if let Some(path) = entry.path() {
let path = repo_path.join(path);
interesting_statuses.insert(path, status);
}
}
}
} else {
debug!("get statuses failed");
}
Self {
interesting_statuses,
}
}
pub fn line_status(&self, path: &Path) -> Option<LineGitStatus> {
self.interesting_statuses
.get(path)
.map(|&status| LineGitStatus { status })
}
pub fn is_interesting(&self, path: &Path) -> bool {
self.interesting_statuses.contains_key(path)
}
}
#[derive(Debug, Clone)]
pub struct TreeGitStatus {
pub current_branch_name: Option<String>,
pub insertions: usize,
pub deletions: usize,
}
impl TreeGitStatus {
pub fn from(repo: &Repository) -> Option<Self> {
let current_branch_name = repo
.head()
.ok()
.and_then(|head| head.shorthand().map(String::from));
let stats = match repo.diff_index_to_workdir(None, None) {
Ok(diff) => {
match diff.stats() {
Ok(stats) => stats,
Err(e) => {
debug!("get stats failed : {:?}", e);
return None;
}
}
}
Err(e) => {
debug!("get diff failed : {:?}", e);
return None;
}
};
Some(Self {
current_branch_name,
insertions: stats.insertions(),
deletions: stats.deletions(),
})
}
}