Skip to content

Commit

Permalink
Build settings index in parallel for the native server (#12299)
Browse files Browse the repository at this point in the history
## 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 #11366 but
ideally we would want to build it lazily.

## Test Plan

`cargo insta test`
  • Loading branch information
dhruvmanila committed Jul 15, 2024
1 parent b9a8cd3 commit ecd4b4d
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 65 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/ruff_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ ruff_workspace = { workspace = true }

anyhow = { workspace = true }
crossbeam = { workspace = true }
ignore = { workspace = true }
jod-thread = { workspace = true }
lsp-server = { workspace = true }
lsp-types = { workspace = true }
Expand All @@ -38,7 +39,6 @@ serde_json = { workspace = true }
shellexpand = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
walkdir = { workspace = true }

[dev-dependencies]
insta = { workspace = true }
Expand Down
146 changes: 83 additions & 63 deletions crates/ruff_server/src/session/index/ruff_settings.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;

use ignore::{WalkBuilder, WalkState};

use ruff_linter::{
display_settings, fs::normalize_path_to, settings::types::FilePattern,
settings::types::PreviewMode,
Expand All @@ -8,12 +14,6 @@ use ruff_workspace::{
pyproject::{find_user_settings_toml, settings_toml},
resolver::{ConfigurationTransformer, Relativity},
};
use std::{
collections::BTreeMap,
path::{Path, PathBuf},
sync::Arc,
};
use walkdir::WalkDir;

use crate::session::settings::{ConfigurationPreference, ResolvedEditorSettings};

Expand All @@ -30,7 +30,7 @@ pub struct RuffSettings {
}

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>>,
fallback: Arc<RuffSettings>,
}
Expand Down Expand Up @@ -100,6 +100,7 @@ impl RuffSettings {
impl RuffSettingsIndex {
pub(super) fn new(root: &Path, editor_settings: &ResolvedEditorSettings) -> Self {
let mut index = BTreeMap::default();
let mut respect_gitignore = true;

// Add any settings from above the workspace root.
for directory in root.ancestors() {
Expand All @@ -112,6 +113,7 @@ impl RuffSettingsIndex {
continue;
};

respect_gitignore = settings.file_resolver.respect_gitignore;
index.insert(
directory.to_path_buf(),
Arc::new(RuffSettings {
Expand All @@ -126,70 +128,88 @@ impl RuffSettingsIndex {
}

// Add any settings within the workspace itself
let mut walker = WalkDir::new(root).into_iter();

while let Some(entry) = walker.next() {
let Ok(entry) = entry else {
continue;
};

// Skip non-directories.
if !entry.file_type().is_dir() {
continue;
}

let directory = entry.into_path();
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();

let index = std::sync::RwLock::new(index);
walker.run(|| {
Box::new(|result| {
let Ok(entry) = result else {
return WalkState::Continue;
};

// 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))
// Skip non-directories.
if !entry
.file_type()
.is_some_and(|file_type| file_type.is_dir())
{
if match_exclusion(&directory, file_name, &settings.file_resolver.exclude) {
tracing::debug!("Ignored path via `exclude`: {}", directory.display());

walker.skip_current_dir();
continue;
} 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();
continue;
return WalkState::Continue;
}

let directory = entry.into_path();
tracing::debug!("Visiting: {}", directory.display());

// If the directory is excluded from the workspace, skip it.
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() {
let Ok(settings) = ruff_workspace::resolver::resolve_root_settings(
&pyproject,
Relativity::Parent,
&EditorConfigurationTransformer(editor_settings, root),
) else {
continue;
};
index.insert(
directory,
Arc::new(RuffSettings {
path: Some(pyproject),
file_resolver: settings.file_resolver,
linter: settings.linter,
formatter: settings.formatter,
}),
);
}
}
if let Some(pyproject) = settings_toml(&directory).ok().flatten() {
let Ok(settings) = ruff_workspace::resolver::resolve_root_settings(
&pyproject,
Relativity::Parent,
&EditorConfigurationTransformer(editor_settings, root),
) else {
return WalkState::Continue;
};
index.write().unwrap().insert(
directory,
Arc::new(RuffSettings {
path: Some(pyproject),
file_resolver: settings.file_resolver,
linter: settings.linter,
formatter: settings.formatter,
}),
);
}

WalkState::Continue
})
});

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> {
Expand Down

0 comments on commit ecd4b4d

Please sign in to comment.