Skip to content

Commit

Permalink
Fix rubocop#8646 for faster find of all files by getting all director…
Browse files Browse the repository at this point in the history
…ies first and then apply Rubocop Exclude on directories before finding files
  • Loading branch information
tleish committed Sep 29, 2020
1 parent cb06e4a commit 7c8a679
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,10 @@

* [#8796](https://github.com/rubocop-hq/rubocop/pull/8796): Add new `Lint/HashCompareByIdentity` cop. ([@fatkodima][])

### Changes

* [#8646](https://github.com/rubocop-hq/rubocop/issues/8646): Faster find of all files in `TargetFinder` class which improves rubocop initial startup speed. ([@tleish][])

## 0.92.0 (2020-09-25)

### New features
Expand Down
37 changes: 25 additions & 12 deletions lib/rubocop/target_finder.rb
Expand Up @@ -81,20 +81,33 @@ def to_inspect?(file, hidden_files, base_dir_config)
# the top level directories that are excluded in configuration in the
# normal way (dir/**/*).
def find_files(base_dir, flags)
# get all wanted directories first to improve speed of finding all files
patterns = wanted_dir_patterns(base_dir, flags)
# We need this special case to avoid creating the pattern
# /**/* which searches the entire file system.
patterns = ["#{base_dir}/**/*"] if patterns.empty?

Dir.glob(patterns, flags).select { |path| FileTest.file?(path) }
end

def wanted_dir_patterns(base_dir, flags)
exclude_pattern = combined_exclude_glob_patterns(base_dir)
flags = flags | File::FNM_PATHNAME | File::FNM_EXTGLOB | File::FNM_DOTMATCH
wanted_toplevel_dirs = toplevel_dirs(base_dir, flags) -
excluded_dirs(base_dir)
wanted_toplevel_dirs.map! { |dir| dir << '/**/*' }

pattern = if wanted_toplevel_dirs.empty?
# We need this special case to avoid creating the pattern
# /**/* which searches the entire file system.
["#{base_dir}/**/*"]
else
# Search the non-excluded top directories, but also add files
# on the top level, which would otherwise not be found.
wanted_toplevel_dirs.unshift("#{base_dir}/*")
end
Dir.glob(pattern, flags).select { |path| FileTest.file?(path) }
wanted_toplevel_dirs.map! { |dir| dir << '/**/' }

Dir.glob(wanted_toplevel_dirs, flags)
.map { |dir| dir << '*' } # add file glob pattern to end of each dir
.reject { |dir| File.fnmatch?(exclude_pattern, dir, flags) }
.unshift("#{base_dir}/*")
end

def combined_exclude_glob_patterns(base_dir)
all_cops_config = @config_store.for(base_dir).for_all_cops
patterns = all_cops_config['Exclude'].select { |pattern| pattern.is_a? String }
.map { |pattern| pattern.sub("#{base_dir}/", '') }
"#{base_dir}/{#{patterns.join(',')}}"
end

def toplevel_dirs(base_dir, flags)
Expand Down

0 comments on commit 7c8a679

Please sign in to comment.