aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 3b9caea0eaf23a21d71cad15cac939594176bfa2 (plain)
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
mod git_tools;

use std::env;
use std::fs;
use std::io::{Result, Error, ErrorKind};
use std::path::Path;
use std::process::exit;

use git_tools::*;

fn main() -> Result<()> {
    if let Ok(cwd) = env::current_dir() {
        if let Err(e) = scan_directories_to_synchronize(&cwd) {
            eprintln!("Could not check directory for git repositories: {}", e);
            exit(1);
        }
    } else {
        eprintln!("Could not find current directory.");
        exit(1);
    }
    Ok(())
}

fn scan_directories_to_synchronize(path: &Path) -> Result<()> {
    let sync_ignore_file = path.join(".syncignore");
    if sync_ignore_file.exists() {
        return Ok(())
    }
    let git_directory = path.join(".git");
    if git_directory.exists() {
        if let Err(e) = synchronize_directory(&path) {
            let relative_path = get_relative_path(path).unwrap();
            eprintln!("Sync failed for {:?}. {}", relative_path, e);
        }
    } else {
        for entry in fs::read_dir(path)? {
            let path = entry?.path();
            if path.is_dir() {
                scan_directories_to_synchronize(&path)?;
            }
        }
    }
    Ok(())
}

fn synchronize_directory(path: &Path) -> Result<()> {
    let previous_branch = git_save_previous_branch(path)?;
    git_checkout(path, "main")?;
    let result = attempt_synchronization(path);
    git_checkout(path, &previous_branch)?;
    result
}

fn attempt_synchronization(path: &Path) -> Result<()> {
    let relative_path = get_relative_path(path).unwrap();
    eprint!("{:?}. ", relative_path);
    let previous_commit = get_commit(path, "HEAD")?;
    git_fetch(path)?;
    let remote_commit = get_commit(path, "origin/main")?;
    if previous_commit == remote_commit {
        eprintln!("Already up to date.");
        return Ok(());
    }
    match git_check_for_conflicts(path) {
        Ok(conflicts) => {
            if !conflicts {
                git_merge(path)?;
                let new_commit = get_commit(path, "HEAD")?;
                eprint!("Merged origin {:?}->{:?}. ", previous_commit, new_commit);
                git_push(path)?;
                eprintln!("Pushed.");
            } else {
                return Err(Error::new(ErrorKind::Other, "Conflicts detected"));
            }
        },
        Err(e) => {
            return Err(e);
        }
    }
    Ok(())
}

// Path Helpers

fn get_relative_path(path: &Path) -> Option<String> {
    let cwd = env::current_dir().unwrap();
    path.strip_prefix(cwd)
        .ok()
        .and_then(|p| p.to_str())
        .map(|s| s.to_string())
}