perf: short circuit remapping detection on recursive symlink (#1225)

This commit is contained in:
Matthias Seitz 2022-05-05 16:21:51 +02:00 committed by GitHub
parent a656830790
commit bc958792af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 31 additions and 3 deletions

View File

@ -1,3 +1,4 @@
use crate::utils;
use serde::{Deserialize, Serialize};
use std::{
collections::{hash_map::Entry, HashMap},
@ -172,13 +173,15 @@ impl Remapping {
let dir = dir.as_ref();
let is_inside_node_modules = dir.ends_with("node_modules");
// iterate over all dirs that are children of the root
for dir in walkdir::WalkDir::new(dir)
.follow_links(true)
.min_depth(1)
.max_depth(1)
.into_iter()
.filter_map(std::result::Result::ok)
.filter_entry(|e| !is_hidden(e))
.filter_map(Result::ok)
.filter(|e| e.file_type().is_dir())
{
let depth1_dir = dir.path();
@ -487,6 +490,11 @@ fn is_lib_dir(dir: &Path) -> bool {
.unwrap_or_default()
}
/// Returns true if the file is _hidden_
fn is_hidden(entry: &walkdir::DirEntry) -> bool {
entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false)
}
/// Finds all remappings in the directory recursively
fn find_remapping_candidates(
current_dir: &Path,
@ -506,8 +514,8 @@ fn find_remapping_candidates(
.min_depth(1)
.max_depth(1)
.into_iter()
.filter_map(std::result::Result::ok)
.filter(|entry| !entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false))
.filter_entry(|e| !is_hidden(e))
.filter_map(Result::ok)
{
let entry: walkdir::DirEntry = entry;
@ -518,6 +526,26 @@ fn find_remapping_candidates(
{
is_candidate = true;
} else if entry.file_type().is_dir() {
// if the dir is a symlink to a parent dir we short circuit here
// `walkdir` will catch symlink loops, but this check prevents that we end up scanning a
// workspace like
// ```text
// my-package/node_modules
// ├── dep/node_modules
// ├── symlink to `my-package`
// ```
if entry.path_is_symlink() {
if let Ok(target) = utils::canonicalize(entry.path()) {
// the symlink points to a parent dir of the current window
if open.components().count() > target.components().count() &&
utils::common_ancestor(open, &target).is_some()
{
// short-circuiting
return Vec::new()
}
}
}
let subdir = entry.path();
// we skip commonly used subdirs that should not be searched for recursively
if !(subdir.ends_with("tests") || subdir.ends_with("test") || subdir.ends_with("demo"))