From ba0a7f913b4b2a83d0c8862d657bdc867730a962 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 14 Jun 2026 14:06:06 +0900 Subject: fix(archiver): resolve infinite recursion in exclude filter dispatch The Phase B port invented an ArchivableFilesFilter trait whose filter impls called self.filter, recursing forever; the name also collided with the real ArchivableFilesFilter FilterIterator class. Composer has no such interface: the finder holds GitExcludeFilter/ComposerExcludeFilter (both extending BaseExcludeFilter) and calls $filter->filter(). Drop the invented trait, type the filters as Box, and implement BaseExcludeFilter on the concrete filters (accessors delegating to inner). Remove the unused generic default methods from the trait so it is dyn-compatible; they remain as inherent methods on BaseExcludeFilterBase, which is where every caller already reaches them. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../package/archiver/archivable_files_finder.rs | 19 +------- .../src/package/archiver/base_exclude_filter.rs | 56 ---------------------- .../package/archiver/composer_exclude_filter.rs | 15 ++++++ .../src/package/archiver/git_exclude_filter.rs | 15 ++++++ 4 files changed, 32 insertions(+), 73 deletions(-) (limited to 'crates/shirabe') diff --git a/crates/shirabe/src/package/archiver/archivable_files_finder.rs b/crates/shirabe/src/package/archiver/archivable_files_finder.rs index c6a2d39..cb1c3e5 100644 --- a/crates/shirabe/src/package/archiver/archivable_files_finder.rs +++ b/crates/shirabe/src/package/archiver/archivable_files_finder.rs @@ -1,5 +1,6 @@ //! ref: composer/src/Composer/Package/Archiver/ArchivableFilesFinder.php +use crate::package::archiver::BaseExcludeFilter; use crate::package::archiver::ComposerExcludeFilter; use crate::package::archiver::GitExcludeFilter; use crate::util::Filesystem; @@ -35,7 +36,7 @@ impl ArchivableFilesFinder { } let sources = fs.normalize_path(&sources_real_path.unwrap()); - let filters: Vec> = if ignore_filters { + let filters: Vec> = if ignore_filters { vec![] } else { vec![ @@ -97,22 +98,6 @@ impl ArchivableFilesFinder { } } -trait ArchivableFilesFilter { - fn filter(&self, relative_path: &str, exclude: bool) -> bool; -} - -impl ArchivableFilesFilter for GitExcludeFilter { - fn filter(&self, relative_path: &str, exclude: bool) -> bool { - self.filter(relative_path, exclude) - } -} - -impl ArchivableFilesFilter for ComposerExcludeFilter { - fn filter(&self, relative_path: &str, exclude: bool) -> bool { - self.filter(relative_path, exclude) - } -} - impl Iterator for ArchivableFilesFinder { type Item = PathBuf; diff --git a/crates/shirabe/src/package/archiver/base_exclude_filter.rs b/crates/shirabe/src/package/archiver/base_exclude_filter.rs index 1bd5b85..fa2007f 100644 --- a/crates/shirabe/src/package/archiver/base_exclude_filter.rs +++ b/crates/shirabe/src/package/archiver/base_exclude_filter.rs @@ -93,60 +93,4 @@ pub trait BaseExcludeFilter { exclude } - - /// Processes a file containing exclude rules of different formats per line - fn parse_lines(&self, lines: Vec, line_parser: F) -> Vec<(String, bool, bool)> - where - F: Fn(&str) -> Option<(String, bool, bool)>, - { - lines - .into_iter() - .filter_map(|line| { - let line = line.trim().to_string(); - if line.is_empty() || line.starts_with('#') { - return None; - } - line_parser(&line) - }) - .collect() - } - - /// Generates a set of exclude patterns for filter() from gitignore rules - fn generate_patterns(&self, rules: Vec) -> Vec<(String, bool, bool)> { - rules - .into_iter() - .map(|rule| self.generate_pattern(&rule)) - .collect() - } - - /// Generates an exclude pattern for filter() from a gitignore rule - fn generate_pattern(&self, rule: &str) -> (String, bool, bool) { - let mut negate = false; - let mut pattern = String::new(); - - let mut rule = rule.to_string(); - if !rule.is_empty() && rule.starts_with('!') { - negate = true; - rule = rule.trim_start_matches('!').to_string(); - } - - let first_slash_position = rule.find('/'); - if first_slash_position == Some(0) { - pattern = "^/".to_string(); - } else if first_slash_position.is_none() || first_slash_position == Some(rule.len() - 1) { - pattern = "/".to_string(); - } - - let rule = rule.trim_matches('/'); - - // remove delimiters as well as caret (^) and dollar sign ($) from the regex - let glob_regex = Glob::to_regex(rule, true, true); - let rule_regex = &glob_regex[2..glob_regex.len() - 2]; - - ( - format!("{{{}{}(?=$|/)}}", pattern, rule_regex), - negate, - false, - ) - } } diff --git a/crates/shirabe/src/package/archiver/composer_exclude_filter.rs b/crates/shirabe/src/package/archiver/composer_exclude_filter.rs index e685a4a..953984d 100644 --- a/crates/shirabe/src/package/archiver/composer_exclude_filter.rs +++ b/crates/shirabe/src/package/archiver/composer_exclude_filter.rs @@ -1,5 +1,6 @@ //! ref: composer/src/Composer/Package/Archiver/ComposerExcludeFilter.php +use super::BaseExcludeFilter; use super::BaseExcludeFilterBase; #[derive(Debug)] @@ -14,3 +15,17 @@ impl ComposerExcludeFilter { Self { inner } } } + +impl BaseExcludeFilter for ComposerExcludeFilter { + fn source_path(&self) -> &str { + &self.inner.source_path + } + + fn exclude_patterns(&self) -> &[(String, bool, bool)] { + &self.inner.exclude_patterns + } + + fn exclude_patterns_mut(&mut self) -> &mut Vec<(String, bool, bool)> { + &mut self.inner.exclude_patterns + } +} diff --git a/crates/shirabe/src/package/archiver/git_exclude_filter.rs b/crates/shirabe/src/package/archiver/git_exclude_filter.rs index aeaed0a..e8765db 100644 --- a/crates/shirabe/src/package/archiver/git_exclude_filter.rs +++ b/crates/shirabe/src/package/archiver/git_exclude_filter.rs @@ -1,5 +1,6 @@ //! ref: composer/src/Composer/Package/Archiver/GitExcludeFilter.php +use crate::package::archiver::BaseExcludeFilter; use crate::package::archiver::BaseExcludeFilterBase; use shirabe_external_packages::composer::pcre::Preg; use std::path::Path; @@ -50,3 +51,17 @@ impl GitExcludeFilter { None } } + +impl BaseExcludeFilter for GitExcludeFilter { + fn source_path(&self) -> &str { + &self.inner.source_path + } + + fn exclude_patterns(&self) -> &[(String, bool, bool)] { + &self.inner.exclude_patterns + } + + fn exclude_patterns_mut(&mut self) -> &mut Vec<(String, bool, bool)> { + &mut self.inner.exclude_patterns + } +} -- cgit v1.3.1