mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 02:12:22 +00:00
Build settings index in parallel for the native server (#12299)
## Summary This PR updates the server to build the settings index in parallel using similar logic as `python_files_in_path`. This should help with https://github.com/astral-sh/ruff/issues/11366 but ideally we would want to build it lazily. ## Test Plan `cargo insta test`
This commit is contained in:
parent
b9a8cd390f
commit
ecd4b4d943
3 changed files with 82 additions and 62 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2439,6 +2439,7 @@ version = "0.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
|
"ignore",
|
||||||
"insta",
|
"insta",
|
||||||
"jod-thread",
|
"jod-thread",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -2463,7 +2464,6 @@ dependencies = [
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"walkdir",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -28,6 +28,7 @@ ruff_workspace = { workspace = true }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
crossbeam = { workspace = true }
|
crossbeam = { workspace = true }
|
||||||
|
ignore = { workspace = true }
|
||||||
jod-thread = { workspace = true }
|
jod-thread = { workspace = true }
|
||||||
lsp-server = { workspace = true }
|
lsp-server = { workspace = true }
|
||||||
lsp-types = { workspace = true }
|
lsp-types = { workspace = true }
|
||||||
|
@ -38,7 +39,6 @@ serde_json = { workspace = true }
|
||||||
shellexpand = { workspace = true }
|
shellexpand = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true }
|
tracing-subscriber = { workspace = true }
|
||||||
walkdir = { workspace = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
insta = { workspace = true }
|
insta = { workspace = true }
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ignore::{WalkBuilder, WalkState};
|
||||||
|
|
||||||
use ruff_linter::{
|
use ruff_linter::{
|
||||||
display_settings, fs::normalize_path_to, settings::types::FilePattern,
|
display_settings, fs::normalize_path_to, settings::types::FilePattern,
|
||||||
settings::types::PreviewMode,
|
settings::types::PreviewMode,
|
||||||
|
@ -8,12 +14,6 @@ use ruff_workspace::{
|
||||||
pyproject::{find_user_settings_toml, settings_toml},
|
pyproject::{find_user_settings_toml, settings_toml},
|
||||||
resolver::{ConfigurationTransformer, Relativity},
|
resolver::{ConfigurationTransformer, Relativity},
|
||||||
};
|
};
|
||||||
use std::{
|
|
||||||
collections::BTreeMap,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
use walkdir::WalkDir;
|
|
||||||
|
|
||||||
use crate::session::settings::{ConfigurationPreference, ResolvedEditorSettings};
|
use crate::session::settings::{ConfigurationPreference, ResolvedEditorSettings};
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ pub struct RuffSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct RuffSettingsIndex {
|
pub(super) struct RuffSettingsIndex {
|
||||||
/// Index from folder to the resoled ruff settings.
|
/// Index from folder to the resolved ruff settings.
|
||||||
index: BTreeMap<PathBuf, Arc<RuffSettings>>,
|
index: BTreeMap<PathBuf, Arc<RuffSettings>>,
|
||||||
fallback: Arc<RuffSettings>,
|
fallback: Arc<RuffSettings>,
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,7 @@ impl RuffSettings {
|
||||||
impl RuffSettingsIndex {
|
impl RuffSettingsIndex {
|
||||||
pub(super) fn new(root: &Path, editor_settings: &ResolvedEditorSettings) -> Self {
|
pub(super) fn new(root: &Path, editor_settings: &ResolvedEditorSettings) -> Self {
|
||||||
let mut index = BTreeMap::default();
|
let mut index = BTreeMap::default();
|
||||||
|
let mut respect_gitignore = true;
|
||||||
|
|
||||||
// Add any settings from above the workspace root.
|
// Add any settings from above the workspace root.
|
||||||
for directory in root.ancestors() {
|
for directory in root.ancestors() {
|
||||||
|
@ -112,6 +113,7 @@ impl RuffSettingsIndex {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
respect_gitignore = settings.file_resolver.respect_gitignore;
|
||||||
index.insert(
|
index.insert(
|
||||||
directory.to_path_buf(),
|
directory.to_path_buf(),
|
||||||
Arc::new(RuffSettings {
|
Arc::new(RuffSettings {
|
||||||
|
@ -126,70 +128,88 @@ impl RuffSettingsIndex {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add any settings within the workspace itself
|
// Add any settings within the workspace itself
|
||||||
let mut walker = WalkDir::new(root).into_iter();
|
let mut builder = WalkBuilder::new(root);
|
||||||
|
builder.standard_filters(respect_gitignore);
|
||||||
|
builder.hidden(false);
|
||||||
|
builder.threads(
|
||||||
|
std::thread::available_parallelism()
|
||||||
|
.map_or(1, std::num::NonZeroUsize::get)
|
||||||
|
.min(12),
|
||||||
|
);
|
||||||
|
let walker = builder.build_parallel();
|
||||||
|
|
||||||
while let Some(entry) = walker.next() {
|
let index = std::sync::RwLock::new(index);
|
||||||
let Ok(entry) = entry else {
|
walker.run(|| {
|
||||||
continue;
|
Box::new(|result| {
|
||||||
};
|
let Ok(entry) = result else {
|
||||||
|
return WalkState::Continue;
|
||||||
|
};
|
||||||
|
|
||||||
// Skip non-directories.
|
// Skip non-directories.
|
||||||
if !entry.file_type().is_dir() {
|
if !entry
|
||||||
continue;
|
.file_type()
|
||||||
}
|
.is_some_and(|file_type| file_type.is_dir())
|
||||||
|
|
||||||
let directory = entry.into_path();
|
|
||||||
|
|
||||||
// If the directory is excluded from the workspace, skip it.
|
|
||||||
if let Some(file_name) = directory.file_name() {
|
|
||||||
if let Some((_, settings)) = index
|
|
||||||
.range(..directory.clone())
|
|
||||||
.rfind(|(path, _)| directory.starts_with(path))
|
|
||||||
{
|
{
|
||||||
if match_exclusion(&directory, file_name, &settings.file_resolver.exclude) {
|
return WalkState::Continue;
|
||||||
tracing::debug!("Ignored path via `exclude`: {}", directory.display());
|
}
|
||||||
|
|
||||||
walker.skip_current_dir();
|
let directory = entry.into_path();
|
||||||
continue;
|
tracing::debug!("Visiting: {}", directory.display());
|
||||||
} else if match_exclusion(
|
|
||||||
&directory,
|
|
||||||
file_name,
|
|
||||||
&settings.file_resolver.extend_exclude,
|
|
||||||
) {
|
|
||||||
tracing::debug!(
|
|
||||||
"Ignored path via `extend-exclude`: {}",
|
|
||||||
directory.display()
|
|
||||||
);
|
|
||||||
|
|
||||||
walker.skip_current_dir();
|
// If the directory is excluded from the workspace, skip it.
|
||||||
continue;
|
if let Some(file_name) = directory.file_name() {
|
||||||
|
if let Some((_, settings)) = index
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.range(..directory.clone())
|
||||||
|
.rfind(|(path, _)| directory.starts_with(path))
|
||||||
|
{
|
||||||
|
if match_exclusion(&directory, file_name, &settings.file_resolver.exclude) {
|
||||||
|
tracing::debug!("Ignored path via `exclude`: {}", directory.display());
|
||||||
|
return WalkState::Continue;
|
||||||
|
} else if match_exclusion(
|
||||||
|
&directory,
|
||||||
|
file_name,
|
||||||
|
&settings.file_resolver.extend_exclude,
|
||||||
|
) {
|
||||||
|
tracing::debug!(
|
||||||
|
"Ignored path via `extend-exclude`: {}",
|
||||||
|
directory.display()
|
||||||
|
);
|
||||||
|
return WalkState::Continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(pyproject) = settings_toml(&directory).ok().flatten() {
|
if let Some(pyproject) = settings_toml(&directory).ok().flatten() {
|
||||||
let Ok(settings) = ruff_workspace::resolver::resolve_root_settings(
|
let Ok(settings) = ruff_workspace::resolver::resolve_root_settings(
|
||||||
&pyproject,
|
&pyproject,
|
||||||
Relativity::Parent,
|
Relativity::Parent,
|
||||||
&EditorConfigurationTransformer(editor_settings, root),
|
&EditorConfigurationTransformer(editor_settings, root),
|
||||||
) else {
|
) else {
|
||||||
continue;
|
return WalkState::Continue;
|
||||||
};
|
};
|
||||||
index.insert(
|
index.write().unwrap().insert(
|
||||||
directory,
|
directory,
|
||||||
Arc::new(RuffSettings {
|
Arc::new(RuffSettings {
|
||||||
path: Some(pyproject),
|
path: Some(pyproject),
|
||||||
file_resolver: settings.file_resolver,
|
file_resolver: settings.file_resolver,
|
||||||
linter: settings.linter,
|
linter: settings.linter,
|
||||||
formatter: settings.formatter,
|
formatter: settings.formatter,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
WalkState::Continue
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
let fallback = Arc::new(RuffSettings::fallback(editor_settings, root));
|
let fallback = Arc::new(RuffSettings::fallback(editor_settings, root));
|
||||||
|
|
||||||
Self { index, fallback }
|
Self {
|
||||||
|
index: index.into_inner().unwrap(),
|
||||||
|
fallback,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get(&self, document_path: &Path) -> Arc<RuffSettings> {
|
pub(super) fn get(&self, document_path: &Path) -> Arc<RuffSettings> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue