diff --git a/src/git.rs b/src/git.rs index 62bf318..f369646 100644 --- a/src/git.rs +++ b/src/git.rs @@ -1,10 +1,11 @@ use chrono::{DateTime, FixedOffset}; use git2::{AttrCheckFlags, AttrValue, Delta, DiffOptions, Repository}; +use lazy_static::lazy_static; use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::process::Command; use std::process::Output as ProcessOutput; - +use std::sync::Mutex; #[derive(Debug, Clone)] pub struct Hunk { pub path: PathBuf, @@ -52,17 +53,34 @@ impl Output { } } } +lazy_static! { + static ref LFS_CACHE: Mutex> = Mutex::new(HashMap::new()); +} fn is_lfs(repo: &Repository, path: &Path) -> bool { + let path_str = path.to_string_lossy().to_string(); + + // Check the cache first + if let Some(&cached_result) = LFS_CACHE.lock().unwrap().get(&path_str) { + return cached_result; + } + // "filter" is the primary LFS attribute, see gitattributes(5) // FILE_THEN_INDEX checks working tree then index; mimics git itself // https://github.com/libgit2/libgit2/blob/v1.5.0/include/git2/attr.h#L104-L116 - if let Ok(filter_bytes) = repo.get_attr_bytes(path, "filter", AttrCheckFlags::FILE_THEN_INDEX) { + let result = if let Ok(filter_bytes) = + repo.get_attr_bytes(path, "filter", AttrCheckFlags::FILE_THEN_INDEX) + { let filter = AttrValue::from_bytes(filter_bytes); filter.eq(&AttrValue::from_string(Some("lfs"))) } else { false - } + }; + + // Store the result in the cache + LFS_CACHE.lock().unwrap().insert(path_str, result); + + result } pub fn modified_since(upstream: &str, repo_path: Option<&Path>) -> anyhow::Result { @@ -106,7 +124,7 @@ pub fn modified_since(upstream: &str, repo_path: Option<&Path>) -> anyhow::Resul let mut ret = FileChanges::default(); let mut maybe_current_hunk: Option = None; diff.foreach( - &mut |delta, _| { + &mut |delta: git2::DiffDelta<'_>, _| { if let Some(path) = delta.new_file().path() { if !is_lfs(&repo, path) { match delta.status() { @@ -132,13 +150,13 @@ pub fn modified_since(upstream: &str, repo_path: Option<&Path>) -> anyhow::Resul None, Some(&mut |delta, _, line| { if let Some(path) = delta.new_file().path() { - if !is_lfs(&repo, path) { - match delta.status() { - Delta::Added - | Delta::Copied - | Delta::Untracked - | Delta::Modified - | Delta::Renamed => { + match delta.status() { + Delta::Added + | Delta::Copied + | Delta::Untracked + | Delta::Modified + | Delta::Renamed => { + if !is_lfs(&repo, path) { if let Some(new_lineno) = line.new_lineno() { if line.old_lineno().is_none() { maybe_current_hunk = maybe_current_hunk @@ -161,13 +179,13 @@ pub fn modified_since(upstream: &str, repo_path: Option<&Path>) -> anyhow::Resul } } } - Delta::Unmodified - | Delta::Deleted - | Delta::Ignored - | Delta::Typechange - | Delta::Unreadable - | Delta::Conflicted => (), } + Delta::Unmodified + | Delta::Deleted + | Delta::Ignored + | Delta::Typechange + | Delta::Unreadable + | Delta::Conflicted => (), } } true diff --git a/src/rules/if_change_then_change.rs b/src/rules/if_change_then_change.rs index 607cb93..08ddd4f 100644 --- a/src/rules/if_change_then_change.rs +++ b/src/rules/if_change_then_change.rs @@ -1,15 +1,14 @@ use crate::run::Run; use anyhow::Context; -use log::{debug, trace}; +use log::{debug, trace, warn}; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; +use regex::Regex; use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::{BufRead, BufReader}; use std::path::Path; use std::path::PathBuf; -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; -use regex::Regex; - use crate::diagnostic; use crate::git; @@ -54,7 +53,12 @@ pub fn find_ictc_blocks(path: &PathBuf) -> anyhow::Result> { trace!("scanning contents of {}", path.display()); - let in_file = File::open(path).with_context(|| format!("failed to open: {:#?}", path))?; + let in_file = File::open(path).with_context(|| { + let error_message = format!("failed to open: {:#?}", path); + warn!("{}", error_message); + error_message + })?; + let in_buf = BufReader::new(in_file); let mut block: Option = None;