mincd/
lib.rs

1use std::fmt::Display;
2use std::process::Command;
3use std::thread::sleep;
4use std::time::Duration;
5
6pub fn wait_for_change(
7    url: String,
8    branch: String,
9    interval: Duration,
10    local_path: Option<String>,
11) -> Result<(), GitWatcherError> {
12    let last_commit_hash = match local_path {
13        Some(path) => match get_last_local_commit_hash(&path, &branch) {
14            Some(commit) => commit,
15            None => {
16                return Err(GitWatcherError::LocalHashCheckError);
17            }
18        },
19        None => match get_last_remote_commit_hash(&url, &branch) {
20            Some(commit) => commit,
21            None => {
22                return Err(GitWatcherError::RemoteHashCheckError);
23            }
24        },
25    };
26    loop {
27        let current_commit_hash = match get_last_remote_commit_hash(&url, &branch) {
28            Some(commit) => commit,
29            None => {
30                return Err(GitWatcherError::LoopError);
31            }
32        };
33        if current_commit_hash != last_commit_hash {
34            return Ok(());
35        }
36        sleep(interval);
37    }
38}
39
40#[derive(Debug)]
41pub enum GitWatcherError {
42    LocalHashCheckError,
43    RemoteHashCheckError,
44    LoopError,
45}
46
47impl Display for GitWatcherError {
48    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
49        match self {
50            GitWatcherError::LocalHashCheckError => write!(f, "Local hash check error"),
51            GitWatcherError::RemoteHashCheckError => write!(f, "Remote hash check error"),
52            GitWatcherError::LoopError => write!(f, "Loop error"),
53        }
54    }
55}
56
57pub fn get_last_remote_commit_hash(url: &String, branch: &String) -> Option<String> {
58    let output = Command::new("git")
59        .arg("ls-remote")
60        .arg(url)
61        .arg(branch)
62        .output();
63    match output {
64        Ok(output) => get_head_hash(output),
65        Err(_) => {
66            println!("There was an error while running git ls-remote.");
67            println!("This might happen if the internet connection is down or the URL is invalid.");
68            None
69        }
70    }
71}
72
73pub fn get_last_local_commit_hash(path: &String, branch: &String) -> Option<String> {
74    let output = Command::new("git")
75        .arg("rev-parse")
76        .arg(branch)
77        .current_dir(path)
78        .output();
79    match output {
80        Ok(output) => get_head_hash(output),
81        Err(_) => {
82            println!("There was an error while running git rev-parse on the local repository.");
83            None
84        }
85    }
86}
87
88fn get_head_hash(output: std::process::Output) -> Option<String> {
89    let output = String::from_utf8(output.stdout).expect("utf8");
90    if output.is_empty() {
91        println!("There was an error while parsing the git output.");
92        None
93    } else {
94        let mut lines = output.lines();
95        let line = lines.next()?;
96        let hash = line.split('\t').next()?;
97        return Some(hash.to_string());
98    }
99}