1use error;
2use project::{Project, SnippetLocation};
3use std::ffi::OsStr;
4use std::io::Error;
5use std::process::Output;
6use std::process::{Command, Stdio};
7
8fn 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
22pub 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
38pub 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
54pub enum GitStatus {
56 Clean,
57 Modified,
58}
59
60pub 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
76pub fn git_pull(location: &SnippetLocation) -> Result<(), error::Error> {
78 let output = run_git_command_for(location, &["pull"]);
79
80 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
90pub fn git_push(location: &SnippetLocation) -> Result<(), error::Error> {
92 let output = run_git_command_for(location, &["push"]);
93
94 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
104pub fn git_add(location: &SnippetLocation) -> Result<(), error::Error> {
106 let output = run_git_command_for(location, &["add", "-A"]);
107
108 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
118pub fn git_commit(location: &SnippetLocation, msg: String) -> Result<(), error::Error> {
120 let output = run_git_command_for(location, &["commit", "-am", &format!("\"{}\"", msg)]);
121
122 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}