From e0fcf2b84b825c278de525b7b5636d2ae35ff57a Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Sun, 18 Dec 2022 23:55:22 -0800 Subject: [PATCH] Add a --check-only flag Fixes #386 --- CHANGELOG.md | 4 ++++ src/main.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++- src/options.rs | 9 +++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bb607107..966684d29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ interleaved output from different files. ### Command Line Interface +Added a `--check-only` flag that reports if there are any syntactic +differences, but doesn't calculate or print them. This is much faster +than normal syntactic diffing. + Difftastic now sets the exit code if it finds changes and `--exit-code` is set. See [usage in the manual](https://difftastic.wilfred.me.uk/usage.html) for the full list diff --git a/src/main.rs b/src/main.rs index 770c79cd4..f957caa65 100644 --- a/src/main.rs +++ b/src/main.rs @@ -162,6 +162,7 @@ fn main() { display_options, missing_as_empty, set_exit_code, + check_only, language_override, lhs_path, rhs_path, @@ -211,6 +212,7 @@ fn main() { &display_options, graph_limit, byte_limit, + check_only, language_override, ) .try_for_each_with(send, |s, diff_result| s.send(diff_result)) @@ -230,6 +232,7 @@ fn main() { missing_as_empty, graph_limit, byte_limit, + check_only, language_override, ); print_diff_result(&display_options, &diff_result); @@ -270,6 +273,7 @@ fn diff_file( missing_as_empty: bool, graph_limit: usize, byte_limit: usize, + check_only: bool, language_override: Option, ) -> DiffResult { let (lhs_bytes, rhs_bytes) = read_files_or_die(lhs_path, rhs_path, missing_as_empty); @@ -283,6 +287,7 @@ fn diff_file( display_options, graph_limit, byte_limit, + check_only, language_override, ) } @@ -297,6 +302,7 @@ fn diff_file_content( display_options: &DisplayOptions, graph_limit: usize, byte_limit: usize, + check_only: bool, language_override: Option, ) -> DiffResult { let (mut lhs_src, mut rhs_src) = match (guess_content(lhs_bytes), guess_content(rhs_bytes)) { @@ -376,6 +382,25 @@ fn diff_file_content( init_all_info(&lhs, &rhs); + if check_only { + let lang_name = language.map(|l| language_name(l).into()); + let has_syntactic_changes = lhs != rhs; + + return DiffResult { + lhs_display_path: lhs_display_path.into(), + rhs_display_path: rhs_display_path.into(), + language: lang_name, + detected_language: language, + lhs_src: FileContent::Text(lhs_src), + rhs_src: FileContent::Text(rhs_src), + lhs_positions: vec![], + rhs_positions: vec![], + hunks: vec![], + has_byte_changes: true, + has_syntactic_changes, + }; + } + let mut change_map = ChangeMap::default(); let possibly_changed = if env::var("DFT_DBG_KEEP_UNCHANGED").is_ok() { vec![(lhs.clone(), rhs.clone())] @@ -475,6 +500,7 @@ fn diff_directories<'a>( display_options: &DisplayOptions, graph_limit: usize, byte_limit: usize, + check_only: bool, language_override: Option, ) -> impl ParallelIterator + 'a { let display_options = display_options.clone(); @@ -499,6 +525,7 @@ fn diff_directories<'a>( true, graph_limit, byte_limit, + check_only, language_override, ) }) @@ -510,7 +537,7 @@ fn print_diff_result(display_options: &DisplayOptions, summary: &DiffResult) { let hunks = &summary.hunks; let lang_name = summary.language.clone().unwrap_or_else(|| "Text".into()); - if hunks.is_empty() { + if !summary.has_syntactic_changes { if display_options.print_unchanged { println!( "{}", @@ -534,6 +561,29 @@ fn print_diff_result(display_options: &DisplayOptions, summary: &DiffResult) { return; } + if summary.has_syntactic_changes && hunks.is_empty() { + println!( + "{}", + display::style::header( + &summary.lhs_display_path, + &summary.rhs_display_path, + 1, + 1, + &lang_name, + display_options + ) + ); + if lang_name == "Text" { + // TODO: there are other Text names now, so + // they will hit the second case incorrectly. + println!("Has changes.\n"); + } else { + println!("Has syntactic changes.\n"); + } + + return; + } + match display_options.display_mode { DisplayMode::Inline => { display::inline::print( @@ -624,6 +674,7 @@ mod tests { &DisplayOptions::default(), DEFAULT_GRAPH_LIMIT, DEFAULT_BYTE_LIMIT, + false, None, ); diff --git a/src/options.rs b/src/options.rs index bd768de3b..403129ceb 100644 --- a/src/options.rs +++ b/src/options.rs @@ -157,6 +157,11 @@ fn app() -> clap::Command<'static> { .env("DFT_EXIT_CODE") .help("Set the exit code to 1 if there are syntactic changes in any text files, or byte changes in any binary files.") ) + .arg( + Arg::new("check-only").long("check-only") + .env("DFT_CHECK_ONLY") + .help("Report whether there are any syntactic changes, but don't calculate them. Much faster.") + ) .arg( Arg::new("skip-unchanged").long("skip-unchanged") .help("Don't display anything if a file is unchanged.") @@ -265,6 +270,7 @@ pub enum Mode { display_options: DisplayOptions, missing_as_empty: bool, set_exit_code: bool, + check_only: bool, language_override: Option, /// The path where we can read the LHS file. This is often a /// temporary file generated by source control. @@ -459,6 +465,8 @@ pub fn parse_args() -> Mode { let set_exit_code = matches.is_present("exit-code"); + let check_only = matches.is_present("check-only"); + let display_options = DisplayOptions { background_color, use_color, @@ -477,6 +485,7 @@ pub fn parse_args() -> Mode { display_options, missing_as_empty, set_exit_code, + check_only, language_override, lhs_path, rhs_path,