mirror of https://github.com/astral-sh/ruff
[ty] Speedup project file discovery (#19913)
This commit is contained in:
parent
7f8f1ab2c1
commit
ce938fe205
|
|
@ -87,11 +87,12 @@ impl Files {
|
||||||
.system_by_path
|
.system_by_path
|
||||||
.entry(absolute.clone())
|
.entry(absolute.clone())
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
tracing::trace!("Adding file '{path}'");
|
|
||||||
|
|
||||||
let metadata = db.system().path_metadata(path);
|
let metadata = db.system().path_metadata(path);
|
||||||
|
|
||||||
|
tracing::trace!("Adding file '{absolute}'");
|
||||||
|
|
||||||
let durability = self
|
let durability = self
|
||||||
.root(db, path)
|
.root(db, &absolute)
|
||||||
.map_or(Durability::default(), |root| root.durability(db));
|
.map_or(Durability::default(), |root| root.durability(db));
|
||||||
|
|
||||||
let builder = File::builder(FilePath::System(absolute))
|
let builder = File::builder(FilePath::System(absolute))
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ mod changes;
|
||||||
#[salsa::db]
|
#[salsa::db]
|
||||||
pub trait Db: SemanticDb {
|
pub trait Db: SemanticDb {
|
||||||
fn project(&self) -> Project;
|
fn project(&self) -> Project;
|
||||||
|
|
||||||
|
fn dyn_clone(&self) -> Box<dyn Db>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[salsa::db]
|
#[salsa::db]
|
||||||
|
|
@ -484,6 +486,10 @@ impl Db for ProjectDatabase {
|
||||||
fn project(&self) -> Project {
|
fn project(&self) -> Project {
|
||||||
self.project.unwrap()
|
self.project.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dyn_clone(&self) -> Box<dyn Db> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "format")]
|
#[cfg(feature = "format")]
|
||||||
|
|
@ -611,6 +617,10 @@ pub(crate) mod tests {
|
||||||
fn project(&self) -> Project {
|
fn project(&self) -> Project {
|
||||||
self.project.unwrap()
|
self.project.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dyn_clone(&self) -> Box<dyn Db> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[salsa::db]
|
#[salsa::db]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use ruff_db::files::{File, system_path_to_file};
|
||||||
use ruff_db::system::walk_directory::{ErrorKind, WalkDirectoryBuilder, WalkState};
|
use ruff_db::system::walk_directory::{ErrorKind, WalkDirectoryBuilder, WalkState};
|
||||||
use ruff_db::system::{SystemPath, SystemPathBuf};
|
use ruff_db::system::{SystemPath, SystemPathBuf};
|
||||||
use ruff_python_ast::PySourceType;
|
use ruff_python_ast::PySourceType;
|
||||||
use rustc_hash::{FxBuildHasher, FxHashSet};
|
use rustc_hash::FxHashSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
|
@ -163,20 +163,24 @@ impl<'a> ProjectFilesWalker<'a> {
|
||||||
|
|
||||||
/// Walks the project paths and collects the paths of all files that
|
/// Walks the project paths and collects the paths of all files that
|
||||||
/// are included in the project.
|
/// are included in the project.
|
||||||
pub(crate) fn walk_paths(self) -> (Vec<SystemPathBuf>, Vec<IOErrorDiagnostic>) {
|
pub(crate) fn collect_vec(self, db: &dyn Db) -> (Vec<File>, Vec<IOErrorDiagnostic>) {
|
||||||
let paths = std::sync::Mutex::new(Vec::new());
|
let files = std::sync::Mutex::new(Vec::new());
|
||||||
let diagnostics = std::sync::Mutex::new(Vec::new());
|
let diagnostics = std::sync::Mutex::new(Vec::new());
|
||||||
|
|
||||||
self.walker.run(|| {
|
self.walker.run(|| {
|
||||||
Box::new(|entry| {
|
let db = db.dyn_clone();
|
||||||
|
let filter = &self.filter;
|
||||||
|
let files = &files;
|
||||||
|
let diagnostics = &diagnostics;
|
||||||
|
|
||||||
|
Box::new(move |entry| {
|
||||||
match entry {
|
match entry {
|
||||||
Ok(entry) => {
|
Ok(entry) => {
|
||||||
// Skip excluded directories unless they were explicitly passed to the walker
|
// Skip excluded directories unless they were explicitly passed to the walker
|
||||||
// (which is the case passed to `ty check <paths>`).
|
// (which is the case passed to `ty check <paths>`).
|
||||||
if entry.file_type().is_directory() {
|
if entry.file_type().is_directory() {
|
||||||
if entry.depth() > 0 {
|
if entry.depth() > 0 {
|
||||||
let directory_included = self
|
let directory_included = filter
|
||||||
.filter
|
|
||||||
.is_directory_included(entry.path(), GlobFilterCheckMode::TopDown);
|
.is_directory_included(entry.path(), GlobFilterCheckMode::TopDown);
|
||||||
return match directory_included {
|
return match directory_included {
|
||||||
IncludeResult::Included => WalkState::Continue,
|
IncludeResult::Included => WalkState::Continue,
|
||||||
|
|
@ -210,8 +214,7 @@ impl<'a> ProjectFilesWalker<'a> {
|
||||||
// For all files, except the ones that were explicitly passed to the walker (CLI),
|
// For all files, except the ones that were explicitly passed to the walker (CLI),
|
||||||
// check if they're included in the project.
|
// check if they're included in the project.
|
||||||
if entry.depth() > 0 {
|
if entry.depth() > 0 {
|
||||||
match self
|
match filter
|
||||||
.filter
|
|
||||||
.is_file_included(entry.path(), GlobFilterCheckMode::TopDown)
|
.is_file_included(entry.path(), GlobFilterCheckMode::TopDown)
|
||||||
{
|
{
|
||||||
IncludeResult::Included => {},
|
IncludeResult::Included => {},
|
||||||
|
|
@ -232,8 +235,11 @@ impl<'a> ProjectFilesWalker<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut paths = paths.lock().unwrap();
|
// If this returns `Err`, then the file was deleted between now and when the walk callback was called.
|
||||||
paths.push(entry.into_path());
|
// We can ignore this.
|
||||||
|
if let Ok(file) = system_path_to_file(&*db, entry.path()) {
|
||||||
|
files.lock().unwrap().push(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(error) => match error.kind() {
|
Err(error) => match error.kind() {
|
||||||
|
|
@ -274,39 +280,14 @@ impl<'a> ProjectFilesWalker<'a> {
|
||||||
});
|
});
|
||||||
|
|
||||||
(
|
(
|
||||||
paths.into_inner().unwrap(),
|
files.into_inner().unwrap(),
|
||||||
diagnostics.into_inner().unwrap(),
|
diagnostics.into_inner().unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn collect_vec(self, db: &dyn Db) -> (Vec<File>, Vec<IOErrorDiagnostic>) {
|
|
||||||
let (paths, diagnostics) = self.walk_paths();
|
|
||||||
|
|
||||||
(
|
|
||||||
paths
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(move |path| {
|
|
||||||
// If this returns `None`, then the file was deleted between the `walk_directory` call and now.
|
|
||||||
// We can ignore this.
|
|
||||||
system_path_to_file(db, &path).ok()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
diagnostics,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn collect_set(self, db: &dyn Db) -> (FxHashSet<File>, Vec<IOErrorDiagnostic>) {
|
pub(crate) fn collect_set(self, db: &dyn Db) -> (FxHashSet<File>, Vec<IOErrorDiagnostic>) {
|
||||||
let (paths, diagnostics) = self.walk_paths();
|
let (files, diagnostics) = self.collect_vec(db);
|
||||||
|
(files.into_iter().collect(), diagnostics)
|
||||||
let mut files = FxHashSet::with_capacity_and_hasher(paths.len(), FxBuildHasher);
|
|
||||||
|
|
||||||
for path in paths {
|
|
||||||
if let Ok(file) = system_path_to_file(db, &path) {
|
|
||||||
files.insert(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(files, diagnostics)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue