// // imag - the personal information management suite for the commandline // Copyright (C) 2015-2019 Matthias Beyer and contributors // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; version // 2.1 of the License. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #![forbid(unsafe_code)] #![deny( non_camel_case_types, non_snake_case, path_statements, trivial_numeric_casts, unstable_features, unused_allocation, unused_import_braces, unused_imports, unused_must_use, unused_mut, unused_qualifications, while_true, )] extern crate clap; #[macro_use] extern crate log; extern crate toml; extern crate toml_query; extern crate failure; extern crate libimagrt; extern crate libimagerror; use std::io::Write; use std::io::ErrorKind; use std::process::Command; use toml::Value; use toml_query::read::TomlValueReadExt; use clap::App; use failure::Fallible as Result; use libimagerror::exit::ExitUnwrap; use libimagerror::io::ToExitCode; use libimagrt::runtime::Runtime; use libimagrt::application::ImagApplication; mod ui; /// Marker enum for implementing ImagApplication on /// /// This is used by binaries crates to execute business logic /// or to build a CLI completion. pub enum ImagGit {} impl ImagApplication for ImagGit { fn run(rt: Runtime) -> Result<()> { let execute_in_store = rt .config() .unwrap_or_else(|| { error!("No configuration. Please use git yourself, not via imag-git"); error!("Won't continue without configuration."); ::std::process::exit(1); }) .read("git.execute_in_store") .unwrap_or_else(|e| { error!("Failed to read config setting 'git.execute_in_store'"); error!("-> {:?}", e); ::std::process::exit(1) }) .unwrap_or_else(|| { error!("Missing config setting 'git.execute_in_store'"); ::std::process::exit(1) }); let execute_in_store = match *execute_in_store { Value::Boolean(b) => b, _ => { error!("Type error: 'git.execute_in_store' is not a boolean!"); ::std::process::exit(1) } }; let execpath = if execute_in_store { rt.store().path().to_str() } else { rt.rtp().to_str() } .map(String::from) .unwrap_or_else(|| { error!("Cannot parse to string: {:?}", rt.store().path()); ::std::process::exit(1) }); let mut command = Command::new("git"); command .stdin(::std::process::Stdio::inherit()) .stdout(::std::process::Stdio::inherit()) .stderr(::std::process::Stdio::inherit()) .arg("-C").arg(&execpath); let args = rt .cli() .values_of("") .map(|vs| vs.map(String::from).collect()) .unwrap_or_else(|| vec![]); debug!("Adding args = {:?}", args); command.args(&args); match rt.cli().subcommand() { (external, Some(ext_m)) => { command.arg(external); let args = ext_m .values_of("") .map(|vs| vs.map(String::from).collect()) .unwrap_or_else(|| vec![]); debug!("Adding subcommand '{}' and args = {:?}", external, args); command.args(&args); }, _ => {}, } let mut out = rt.stdout(); debug!("Calling: {:?}", command); match command.spawn().and_then(|mut c| c.wait()) { Ok(exit_status) => { if !exit_status.success() { debug!("git exited with non-zero exit code: {:?}", exit_status); let mut err = rt.stderr(); writeln!(err, "git exited with non-zero exit code") .to_exit_code() .unwrap_or_exit(); ::std::process::exit(exit_status.code().unwrap_or(1)); } debug!("Successful exit!"); }, Err(e) => { debug!("Error calling git"); match e.kind() { ErrorKind::NotFound => { let _ = writeln!(out, "Cannot find 'git' executable") .to_exit_code() .unwrap_or_exit(); ::std::process::exit(1); }, ErrorKind::PermissionDenied => { let _ = writeln!(out, "No permission to execute: 'git'") .to_exit_code() .unwrap_or_exit(); ::std::process::exit(1); }, _ => { let _ = writeln!(out, "Error spawning: {:?}", e) .to_exit_code() .unwrap_or_exit(); ::std::process::exit(1); } } } } Ok(()) } fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> { ui::build_ui(app) } fn name() -> &'static str { env!("CARGO_PKG_NAME") } fn description() -> &'static str { "Helper to call git in the store" } fn version() -> &'static str { env!("CARGO_PKG_VERSION") } }