From 46eb84bd34f8ff67f749eec8a287d5a3e7a0919a Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Wed, 16 Dec 2020 23:17:45 +0000 Subject: Exit with diff's exit code (#449) Fixes #448 --- src/config.rs | 5 ++- src/main.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 92 insertions(+), 18 deletions(-) diff --git a/src/config.rs b/src/config.rs index b2cd2eab..28e571d6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,6 +23,7 @@ pub struct Config { pub commit_style: Style, pub color_only: bool, pub decorations_width: cli::Width, + pub error_exit_code: i32, pub file_added_label: String, pub file_copied_label: String, pub file_modified_label: String, @@ -153,6 +154,7 @@ impl From for Config { commit_style, color_only: opt.color_only, decorations_width: opt.computed.decorations_width, + error_exit_code: 2, // Use 2 for error because diff uses 0 and 1 for non-error. file_added_label: opt.file_added_label, file_copied_label: opt.file_copied_label, file_modified_label: opt.file_modified_label, @@ -411,10 +413,11 @@ pub fn user_supplied_option(option: &str, arg_matches: &clap::ArgMatches) -> boo } pub fn delta_unreachable(message: &str) -> ! { + let error_exit_code = 2; // This is also stored in Config. eprintln!( "{} This should not be possible. \ Please report the bug at https://github.com/dandavison/delta/issues.", message ); - process::exit(1); + process::exit(error_exit_code); } diff --git a/src/main.rs b/src/main.rs index 51a0b702..36239b67 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,7 @@ use structopt::StructOpt; use crate::bat_utils::assets::{list_languages, HighlightingAssets}; use crate::bat_utils::output::{OutputType, PagingMode}; +use crate::config::delta_unreachable; use crate::delta::delta; use crate::options::theme::is_light_syntax_theme; @@ -73,17 +74,20 @@ fn main() -> std::io::Result<()> { let mut stdout = stdout.lock(); show_config(&config, &mut stdout)?; process::exit(0); - } else if atty::is(atty::Stream::Stdin) { - return diff( - config.minus_file.as_ref(), - config.plus_file.as_ref(), - &config, - ); } let mut output_type = OutputType::from_mode(config.paging_mode, None, &config).unwrap(); let mut writer = output_type.handle().unwrap(); + if atty::is(atty::Stream::Stdin) { + process::exit(diff( + config.minus_file.as_ref(), + config.plus_file.as_ref(), + &config, + &mut writer, + )); + } + if let Err(error) = delta(io::stdin().lock().byte_lines(), &mut writer, &config) { match error.kind() { ErrorKind::BrokenPipe => process::exit(0), @@ -98,14 +102,15 @@ fn diff( minus_file: Option<&PathBuf>, plus_file: Option<&PathBuf>, config: &config::Config, -) -> std::io::Result<()> { + writer: &mut dyn Write, +) -> i32 { use std::io::BufReader; let die = || { eprintln!("Usage: delta minus_file plus_file"); - process::exit(1); + process::exit(config.error_exit_code); }; - let command = "diff"; - let diff_process = process::Command::new(PathBuf::from(command)) + let diff_command = "diff"; + let mut diff_process = process::Command::new(PathBuf::from(diff_command)) .arg("-u") .args(&[ minus_file.unwrap_or_else(die), @@ -114,23 +119,34 @@ fn diff( .stdout(process::Stdio::piped()) .spawn() .unwrap_or_else(|err| { - eprintln!("Failed to execute the command '{}': {}", command, err); - process::exit(1); + eprintln!("Failed to execute the command '{}': {}", diff_command, err); + process::exit(config.error_exit_code); + }); + let exit_code = diff_process + .wait() + .unwrap_or_else(|_| { + delta_unreachable(&format!("'{}' process not running.", diff_command)); + }) + .code() + .unwrap_or_else(|| { + eprintln!("'{}' process terminated without exit status.", diff_command); + process::exit(config.error_exit_code); }); - let mut output_type = OutputType::from_mode(config.paging_mode, None, &config).unwrap(); - let mut writer = output_type.handle().unwrap(); if let Err(error) = delta( BufReader::new(diff_process.stdout.unwrap()).byte_lines(), - &mut writer, + writer, &config, ) { match error.kind() { ErrorKind::BrokenPipe => process::exit(0), - _ => eprintln!("{}", error), + _ => { + eprintln!("{}", error); + process::exit(config.error_exit_code); + } } }; - Ok(()) + exit_code } fn show_config(config: &config::Config, writer: &mut dyn Write) -> std::io::Result<()> { @@ -467,4 +483,59 @@ mod main_tests { assert!(s.contains("light GitHub\n")); assert!(s.contains("dark Dracula\n")); } + + #[test] + #[cfg_attr(target_os = "windows", ignore)] + fn test_diff_same_empty_file() { + let config = integration_test_utils::make_config_from_args(&[]); + let mut writer = Cursor::new(vec![]); + let exit_code = diff( + Some(&PathBuf::from("/dev/null")), + Some(&PathBuf::from("/dev/null")), + &config, + &mut writer, + ); + assert_eq!(exit_code, 0); + let mut s = String::new(); + writer.seek(SeekFrom::Start(0)).unwrap(); + writer.read_to_string(&mut s).unwrap(); + assert!(s.is_empty()); + } + + #[test] + #[cfg_attr(target_os = "windows", ignore)] + fn test_diff_same_non_empty_file() { + let config = integration_test_utils::make_config_from_args(&[]); + let mut writer = Cursor::new(vec![]); + let exit_code = diff( + Some(&PathBuf::from("/etc/passwd")), + Some(&PathBuf::from("/etc/passwd")), + &config, + &mut writer, + ); + assert_eq!(exit_code, 0); + let mut s = String::new(); + writer.seek(SeekFrom::Start(0)).unwrap(); + writer.read_to_string(&mut s).unwrap(); + assert!(s.is_empty()); + } + + #[test] + #[cfg_attr(target_os = "windows", ignore)] + fn test_diff_differing_files() { + let config = integration_test_utils::make_config_from_args(&[]); + let mut writer = Cursor::new(vec![]); + let exit_code = diff( + Some(&PathBuf::from("/dev/null")), + Some(&PathBuf::from("/etc/passwd")), + &config, + &mut writer, + ); + assert_eq!(exit_code, 1); + let mut s = String::new(); + writer.seek(SeekFrom::Start(0)).unwrap(); + writer.read_to_string(&mut s).unwrap(); + let s = ansi::strip_ansi_codes(&s); + assert!(s.contains("comparing: /dev/null ⟶ /etc/passwd\n")); + } } -- cgit v1.2.3