rusty_x/
git.rs

1use error;
2use project::{Project, SnippetLocation};
3use std::ffi::OsStr;
4use std::io::Error;
5use std::process::Output;
6use std::process::{Command, Stdio};
7
8/// Runt git command for this snippet location
9fn run_git_command_for<I, S>(location: &SnippetLocation, commands: I) -> Result<Output, Error>
10where
11    I: IntoIterator<Item = S>,
12    S: AsRef<OsStr>,
13{
14    Command::new("git")
15        .stdout(Stdio::piped())
16        .current_dir(&location.local)
17        .args(commands)
18        .spawn()?
19        .wait_with_output()
20}
21
22/// Determine the git support for a project, modifies the git status
23pub fn determine_git_status(project: &mut Project) -> bool {
24    for location in &mut project.locations {
25        if location.git == None {
26            let support = determine_git_support(location)
27                .expect("Cannot determine git support for project location");
28            if support {
29                location.git = Some(true);
30            } else {
31                location.git = Some(false);
32            }
33        }
34    }
35    false
36}
37
38/// Determine the git support for a given snippet location
39pub fn determine_git_support(location: &mut SnippetLocation) -> Result<bool, error::Error> {
40    let output = run_git_command_for(location, &["rev-parse", "--is-inside-work-tree"]);
41    let output_str_result = String::from_utf8(output?.stdout);
42    match output_str_result {
43        Ok(s) => {
44            if s.eq_ignore_ascii_case("true\n") {
45                return Ok(true);
46            } else {
47                return Ok(false);
48            }
49        }
50        Err(_) => Ok(false),
51    }
52}
53
54/// Struct that gives the git status of the project
55pub enum GitStatus {
56    Clean,
57    Modified,
58}
59
60/// Determine the git file status for the snippet location
61pub fn determine_git_modified_status(
62    location: &SnippetLocation,
63) -> Result<GitStatus, error::Error> {
64    let output = run_git_command_for(location, &["status", "--porcelain"]);
65    let output_str_result = String::from_utf8(output?.stdout);
66
67    output_str_result.map(|s| {
68        if s.eq_ignore_ascii_case("") {
69            Ok(GitStatus::Clean)
70        } else {
71            Ok(GitStatus::Modified)
72        }
73    })?
74}
75
76/// Sync/pull git location with upstream repo
77pub fn git_pull(location: &SnippetLocation) -> Result<(), error::Error> {
78    let output = run_git_command_for(location, &["pull"]);
79
80    // Return if success
81    if output?.status.success() {
82        Ok(())
83    } else {
84        Err(error::Error::InternalError(
85            "Failed to execute pull command".to_string(),
86        ))
87    }
88}
89
90/// Git push from snippet location
91pub fn git_push(location: &SnippetLocation) -> Result<(), error::Error> {
92    let output = run_git_command_for(location, &["push"]);
93
94    // Return if success
95    if output?.status.success() {
96        Ok(())
97    } else {
98        Err(error::Error::InternalError(
99            "Failed to execute push command".to_string(),
100        ))
101    }
102}
103
104/// Git add from snippet location
105pub fn git_add(location: &SnippetLocation) -> Result<(), error::Error> {
106    let output = run_git_command_for(location, &["add", "-A"]);
107
108    // Return if success
109    if output?.status.success() {
110        Ok(())
111    } else {
112        Err(error::Error::InternalError(
113            "Failed to execute `add -A` command".to_string(),
114        ))
115    }
116}
117
118/// Git commit from snippet location
119pub fn git_commit(location: &SnippetLocation, msg: String) -> Result<(), error::Error> {
120    let output = run_git_command_for(location, &["commit", "-am", &format!("\"{}\"", msg)]);
121
122    // Return if success
123    if output?.status.success() {
124        Ok(())
125    } else {
126        Err(error::Error::InternalError(
127            "Failed to execute `commit -a` command".to_string(),
128        ))
129    }
130}