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
use std::{process::{Command, Output}, error::Error, time::{SystemTime, SystemTimeError}, path::Path};
use config::Config;
pub mod config;
mod file_watcher;
pub fn earthquake_procedure(config: Config) -> Result<(), Box<dyn Error>> {
let current_branch = current_branch()?;
let user_email = user_email()?;
let elapsed = current_unix_epoch()?;
let branch_name = format!("earthquake/{current_branch}-{user_email}-{elapsed}");
checkout(&branch_name)?;
if any_uncommited_changes()? {
add()?;
commit(&config.commit_message)?;
}
push(&branch_name)?;
Ok(())
}
fn any_uncommited_changes() -> Result<bool, Box<dyn Error>> {
let output = Command::new("git").args(&["status", "--porcelain"]).output()?;
let output = String::from_utf8(output.stdout)?;
Ok(!output.is_empty())
}
fn current_branch() -> Result<String, Box<dyn Error>> {
let output = Command::new("git").args(&["branch", "--show-current"]).output()?;
read_git_info(output)
}
fn user_email() -> Result<String, Box<dyn Error>> {
let output = Command::new("git").args(&["config", "--get", "user.email"]).output()?;
read_git_info(output)
}
fn current_unix_epoch() -> Result<u64, SystemTimeError> {
let current_unix_epoch = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
Ok(current_unix_epoch.as_secs())
}
fn checkout(branch_name: &str) -> Result<(), Box<dyn Error>> {
execute_git_command(&["checkout", "-b", branch_name])
}
fn add() -> Result<(), Box<dyn Error>> {
execute_git_command(&["add", "--all"])
}
fn commit(message: &str) -> Result<(), Box<dyn Error>> {
execute_git_command(&["commit", "-m", message])
}
fn push(branch_name: &str) -> Result<(), Box<dyn Error>> {
execute_git_command(&["push", "-u", "origin", branch_name])
}
fn execute_git_command(args: &[&str]) -> Result<(), Box<dyn Error>> {
wait_git_lock_released()?;
let mut child = Command::new("git").args(args).spawn()?;
child.wait()?;
Ok(())
}
fn wait_git_lock_released() -> Result<(), Box<dyn Error>> {
let output = Command::new("git").args(&["rev-parse", "--show-toplevel"]).output()?;
let git_root_directory = read_git_info(output)?;
let lock_path = Path::new(&git_root_directory).join(".git/index.lock");
if lock_path.exists() {
file_watcher::wait_until_deleted(&lock_path);
}
Ok(())
}
fn read_git_info(output: Output) -> Result<String, Box<dyn Error>> {
let mut info = String::from_utf8(output.stdout)?;
trim_newline(&mut info);
Ok(info)
}
fn trim_newline(s: &mut String) {
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
}