-
Notifications
You must be signed in to change notification settings - Fork 68
/
snapshots.rs
124 lines (106 loc) · 3.34 KB
/
snapshots.rs
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
113
114
115
116
117
118
119
120
121
122
123
124
use git2::{BranchType, DiffOptions, Error, IndexAddOption, Repository, Signature};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::path::Path;
use crate::config::Config;
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct CaptureStatus {
pub dura_branch: String,
pub commit_hash: String,
pub base_hash: String,
}
impl fmt::Display for CaptureStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"dura: {}, commit_hash: {}, base: {}",
self.dura_branch, self.commit_hash, self.base_hash
)
}
}
pub fn is_repo(path: &Path) -> bool {
Repository::open(path).is_ok()
}
pub fn capture(path: &Path) -> Result<Option<CaptureStatus>, Error> {
let repo = Repository::open(path)?;
let head = repo.head()?.peel_to_commit()?;
let message = "dura auto-backup";
// status check
if repo.statuses(None)?.is_empty() {
return Ok(None);
}
let branch_name = format!("dura/{}", head.id());
let branch_commit = match repo.find_branch(&branch_name, BranchType::Local) {
Ok(mut branch) => {
match branch.get().peel_to_commit() {
Ok(commit) if commit.id() != head.id() => Some(commit),
_ => {
// Dura branch exist but no commit is made by dura
// So we clean this branch
branch.delete()?;
None
}
}
}
Err(_) => None,
};
let parent_commit = branch_commit.as_ref().unwrap_or(&head);
// tree
let mut index = repo.index()?;
index.add_all(["*"].iter(), IndexAddOption::DEFAULT, None)?;
let dirty_diff = repo.diff_tree_to_index(
Some(&parent_commit.tree()?),
Some(&index),
Some(DiffOptions::new().include_untracked(true)),
)?;
if dirty_diff.deltas().len() == 0 {
return Ok(None);
}
let tree_oid = index.write_tree()?;
let tree = repo.find_tree(tree_oid)?;
if repo.find_branch(&branch_name, BranchType::Local).is_err() {
repo.branch(branch_name.as_str(), &head, false)?;
}
let committer = Signature::now(&get_git_author(&repo), &get_git_email(&repo))?;
let oid = repo.commit(
Some(&format!("refs/heads/{}", &branch_name)),
&committer,
&committer,
message,
&tree,
&[parent_commit],
)?;
Ok(Some(CaptureStatus {
dura_branch: branch_name,
commit_hash: oid.to_string(),
base_hash: head.id().to_string(),
}))
}
fn get_git_author(repo: &Repository) -> String {
let dura_cfg = Config::load();
if let Some(value) = dura_cfg.commit_author {
return value;
}
if !dura_cfg.commit_exclude_git_config {
if let Ok(git_cfg) = repo.config() {
if let Ok(value) = git_cfg.get_string("user.name") {
return value;
}
}
}
"dura".to_string()
}
fn get_git_email(repo: &Repository) -> String {
let dura_cfg = Config::load();
if let Some(value) = dura_cfg.commit_email {
return value;
}
if !dura_cfg.commit_exclude_git_config {
if let Ok(git_cfg) = repo.config() {
if let Ok(value) = git_cfg.get_string("user.email") {
return value;
}
}
}
"dura@github.io".to_string()
}