1#![forbid(unsafe_code)]
21
22#![deny(
23 non_camel_case_types,
24 non_snake_case,
25 path_statements,
26 trivial_numeric_casts,
27 unstable_features,
28 unused_allocation,
29 unused_import_braces,
30 unused_imports,
31 unused_must_use,
32 unused_mut,
33 unused_qualifications,
34 while_true,
35)]
36
37extern crate clap;
38#[macro_use] extern crate log;
39extern crate toml;
40extern crate toml_query;
41#[macro_use] extern crate failure;
42
43extern crate libimagrt;
44extern crate libimagerror;
45
46use std::io::ErrorKind;
47use std::process::Command;
48
49use toml::Value;
50use toml_query::read::TomlValueReadExt;
51use clap::App;
52use failure::Fallible as Result;
53use failure::ResultExt;
54use failure::err_msg;
55
56use libimagrt::runtime::Runtime;
57use libimagrt::application::ImagApplication;
58
59mod ui;
60
61pub enum ImagGit {}
66impl ImagApplication for ImagGit {
67 fn run(rt: Runtime) -> Result<()> {
68 let execute_in_store = rt
69 .config()
70 .ok_or_else(|| err_msg("No configuration. Please use git yourself, not via imag-git"))
71 .context("Won't continue without configuration.")
72 ?
73 .read("git.execute_in_store")
74 .context("Failed to read config setting 'git.execute_in_store'")
75 ?
76 .ok_or_else(|| err_msg("Missing config setting 'git.execute_in_store'"))
77 ?;
78
79 let execute_in_store = match *execute_in_store {
80 Value::Boolean(b) => Ok(b),
81 _ => Err(err_msg("Type error: 'git.execute_in_store' is not a boolean!")),
82 }?;
83
84 let execpath = if execute_in_store {
85 rt.store().path().to_str()
86 } else {
87 rt.rtp().to_str()
88 }
89 .map(String::from)
90 .ok_or_else(|| format_err!("Cannot parse to string: {:?}", rt.store().path()))?;
91
92 let mut command = Command::new("git");
93 command
94 .stdin(::std::process::Stdio::inherit())
95 .stdout(::std::process::Stdio::inherit())
96 .stderr(::std::process::Stdio::inherit())
97 .arg("-C").arg(&execpath);
98
99 let args = rt
100 .cli()
101 .values_of("")
102 .map(|vs| vs.map(String::from).collect())
103 .unwrap_or_else(|| vec![]);
104
105 debug!("Adding args = {:?}", args);
106 command.args(&args);
107
108 if let (external, Some(ext_m)) = rt.cli().subcommand() {
109 command.arg(external);
110 let args = ext_m
111 .values_of("")
112 .map(|vs| vs.map(String::from).collect())
113 .unwrap_or_else(|| vec![]);
114
115 debug!("Adding subcommand '{}' and args = {:?}", external, args);
116 command.args(&args);
117 }
118
119 debug!("Calling: {:?}", command);
120
121 match command.spawn().and_then(|mut c| c.wait()) {
122 Ok(exit_status) => {
123 if !exit_status.success() {
124 debug!("git exited with non-zero exit code: {:?}", exit_status);
125 Err(format_err!("git exited with non-zero exit code: {:?}", exit_status))
126 } else {
127 debug!("Successful exit!");
128 Ok(())
129 }
130 },
131
132 Err(e) => {
133 debug!("Error calling git");
134 Err(match e.kind() {
135 ErrorKind::NotFound => err_msg("Cannot find 'git' executable"),
136 ErrorKind::PermissionDenied => err_msg("No permission to execute: 'git'"),
137 _ => format_err!("Error spawning: {:?}", e),
138 })
139 }
140 }
141 }
142
143 fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
144 ui::build_ui(app)
145 }
146
147 fn name() -> &'static str {
148 env!("CARGO_PKG_NAME")
149 }
150
151 fn description() -> &'static str {
152 "Helper to call git in the store"
153 }
154
155 fn version() -> &'static str {
156 env!("CARGO_PKG_VERSION")
157 }
158}