Skip to content

Commit

Permalink
Watch VERSIONS changes
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser committed Aug 14, 2024
1 parent 10aaa1b commit f2385fa
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 16 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

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

42 changes: 42 additions & 0 deletions crates/red_knot/tests/file_watching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,48 @@ fn remove_search_path() -> anyhow::Result<()> {
Ok(())
}

#[test]
fn changed_versions_file() -> anyhow::Result<()> {
let mut case = setup_with_search_paths(
|root_path: &SystemPath, workspace_path: &SystemPath| {
std::fs::write(workspace_path.join("bar.py").as_std_path(), "import sub.a")?;
std::fs::create_dir_all(root_path.join("typeshed/stdlib").as_std_path())?;
std::fs::write(root_path.join("typeshed/stdlib/VERSIONS").as_std_path(), "")?;
std::fs::write(
root_path.join("typeshed/stdlib/os.pyi").as_std_path(),
"# not important",
)?;

Ok(())
},
|root_path, _workspace_path| SearchPathConfiguration {
custom_typeshed: Some(root_path.join("typeshed")),
..SearchPathConfiguration::default()
},
)?;

// Remove site packages from the search path settings.
assert_eq!(
resolve_module(case.db(), ModuleName::new("os").unwrap()),
None
);

std::fs::write(
case.root_path()
.join("typeshed/stdlib/VERSIONS")
.as_std_path(),
"os: 3.0-",
)?;

let changes = case.stop_watch();

case.apply_changes(changes);

assert!(resolve_module(case.db(), ModuleName::new("os").unwrap()).is_some());

Ok(())
}

/// Watch a workspace that contains two files where one file is a hardlink to another.
///
/// Setup:
Expand Down
10 changes: 10 additions & 0 deletions crates/red_knot_python_semantic/src/module_resolver/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,16 @@ impl SearchPaths {
}
}

pub(crate) fn custom_stdlib(&self) -> Option<&SystemPath> {
self.static_paths.iter().find_map(|search_path| {
if search_path.is_standard_library() {
search_path.as_system_path()
} else {
None
}
})
}

pub(super) fn typeshed_versions(&self) -> &TypeshedVersions {
&self.typeshed_versions
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl TypeshedVersions {
}
}

/// Possible answers [`LazyTypeshedVersions::query_module()`] could give to the question:
/// Possible answers [`TypeshedVersions::query_module()`] could give to the question:
/// "Does this module exist in the stdlib at runtime on a certain target version?"
#[derive(Debug, Copy, PartialEq, Eq, Clone, Hash)]
pub(crate) enum TypeshedVersionsQueryResult {
Expand Down
6 changes: 5 additions & 1 deletion crates/red_knot_python_semantic/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use anyhow::Context;
use salsa::Durability;
use salsa::Setter;

use ruff_db::system::SystemPathBuf;
use ruff_db::system::{SystemPath, SystemPathBuf};

use crate::module_resolver::SearchPaths;
use crate::Db;
Expand Down Expand Up @@ -47,6 +47,10 @@ impl Program {

Ok(())
}

pub fn custom_stdlib_search_path(self, db: &dyn Db) -> Option<&SystemPath> {
self.search_paths(db).custom_stdlib()
}
}

#[derive(Debug, Eq, PartialEq)]
Expand Down
1 change: 0 additions & 1 deletion crates/red_knot_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ repository = { workspace = true }
license = { workspace = true }

[dependencies]
red_knot_python_semantic = { workspace = true }
red_knot_workspace = { workspace = true }
ruff_db = { workspace = true }
ruff_linter = { workspace = true }
Expand Down
35 changes: 32 additions & 3 deletions crates/red_knot_workspace/src/db/changes.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use rustc_hash::FxHashSet;

use red_knot_python_semantic::Program;
use ruff_db::files::{system_path_to_file, File, Files};
use ruff_db::system::walk_directory::WalkState;
use ruff_db::system::SystemPath;
use ruff_db::Db;
use rustc_hash::FxHashSet;

use crate::db::RootDatabase;
use crate::watch;
Expand All @@ -20,8 +20,14 @@ impl RootDatabase {
) {
let workspace = self.workspace();
let workspace_path = workspace.root(self).to_path_buf();
let program = Program::get(self);
let custom_stdlib_versions_path = program
.custom_stdlib_search_path(self)
.map(|path| path.join("VERSIONS"));

let mut workspace_change = false;
// Changes to a custom stdlib path's VERSION
let mut custom_stdlib_change = false;
// Packages that need reloading
let mut changed_packages = FxHashSet::default();
// Paths that were added
Expand Down Expand Up @@ -59,6 +65,10 @@ impl RootDatabase {

continue;
}

if Some(path) == custom_stdlib_versions_path.as_deref() {
custom_stdlib_change = true;
}
}

match change {
Expand Down Expand Up @@ -105,7 +115,13 @@ impl RootDatabase {
} else {
sync_recursively(self, &path);

// TODO: Remove after converting `package.files()` to a salsa query.
if custom_stdlib_versions_path
.as_ref()
.is_some_and(|versions_path| versions_path.starts_with(&path))
{
custom_stdlib_change = true;
}

if let Some(package) = workspace.package(self, &path) {
changed_packages.insert(package);
} else {
Expand Down Expand Up @@ -135,6 +151,19 @@ impl RootDatabase {
}

return;
} else if custom_stdlib_change {
let search_path_configuration = workspace.search_path_configuration(self);

match search_path_configuration.to_settings(&workspace_path, self.system()) {
Ok(search_path_settings) => {
if let Err(error) = program.update_search_paths(self, search_path_settings) {
tracing::error!("Failed to apply to set the new search paths: {error}");
}
}
Err(error) => {
tracing::error!("Failed to resolve the search path settings: {error}.");
}
}
}

let mut added_paths = added_paths.into_iter().filter(|path| {
Expand Down
12 changes: 11 additions & 1 deletion crates/red_knot_workspace/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use ruff_db::{
use ruff_python_ast::{name::Name, PySourceType};

use crate::workspace::files::{Index, IndexedFiles, PackageFiles};
use crate::workspace::settings::SearchPathConfiguration;
use crate::{
db::Db,
lint::{lint_semantic, lint_syntax, Diagnostics},
Expand Down Expand Up @@ -80,6 +81,10 @@ pub struct Workspace {
/// The (first-party) packages in this workspace.
#[return_ref]
package_tree: BTreeMap<SystemPathBuf, Package>,

/// The unresolved search path configuration.
#[return_ref]
pub search_path_configuration: SearchPathConfiguration,
}

/// A first-party package in a workspace.
Expand Down Expand Up @@ -108,7 +113,7 @@ impl Workspace {
packages.insert(package.root.clone(), Package::from_metadata(db, package));
}

Workspace::builder(metadata.root, packages)
Workspace::builder(metadata.root, packages, metadata.configuration.search_paths)
.durability(Durability::MEDIUM)
.open_fileset_durability(Durability::LOW)
.new(db)
Expand Down Expand Up @@ -142,6 +147,11 @@ impl Workspace {
new_packages.insert(path, package);
}

if &metadata.configuration.search_paths != self.search_path_configuration(db) {
self.set_search_path_configuration(db)
.to(metadata.configuration.search_paths);
}

self.set_package_tree(db)
.with_durability(Durability::MEDIUM)
.to(new_packages);
Expand Down
6 changes: 3 additions & 3 deletions crates/red_knot_workspace/src/workspace/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub struct WorkspaceConfiguration {
pub search_paths: SearchPathConfiguration,
}

#[derive(Debug, Default, Clone)]
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct SearchPathConfiguration {
/// List of user-provided paths that should take first priority in the module resolution.
/// Examples in other type checkers are mypy's MYPYPATH environment variable,
Expand All @@ -28,7 +28,7 @@ pub struct SearchPathConfiguration {
pub site_packages: Option<SitePackages>,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum SitePackages {
Derived {
venv_path: SystemPathBuf,
Expand Down Expand Up @@ -75,7 +75,7 @@ impl SearchPathConfiguration {
.src_root
.clone()
.unwrap_or_else(|| workspace_root.to_path_buf()),
custom_typeshed: None,
custom_typeshed: self.custom_typeshed.clone(),
site_packages,
})
}
Expand Down
10 changes: 5 additions & 5 deletions crates/red_knot_workspace/tests/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ use red_knot_workspace::db::RootDatabase;
use red_knot_workspace::lint::lint_semantic;
use red_knot_workspace::workspace::WorkspaceMetadata;
use ruff_db::files::system_path_to_file;
use ruff_db::system::{OsSystem, SystemPathBuf};
use ruff_db::system::{OsSystem, SystemPath, SystemPathBuf};
use std::fs;
use std::path::PathBuf;

fn setup_db(workspace_root: SystemPathBuf) -> anyhow::Result<RootDatabase> {
let system = OsSystem::new(&workspace_root);
let workspace = WorkspaceMetadata::from_path(&workspace_root, &system, &())?;
fn setup_db(workspace_root: &SystemPath) -> anyhow::Result<RootDatabase> {
let system = OsSystem::new(workspace_root);
let workspace = WorkspaceMetadata::from_path(workspace_root, &system, &())?;
RootDatabase::new(workspace, system)
}

Expand All @@ -19,7 +19,7 @@ fn corpus_no_panic() -> anyhow::Result<()> {
let corpus = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("resources/test/corpus");
let system_corpus =
SystemPathBuf::from_path_buf(corpus.clone()).expect("corpus path to be UTF8");
let db = setup_db(system_corpus.clone())?;
let db = setup_db(&system_corpus)?;

for path in fs::read_dir(&corpus).expect("corpus to be a directory") {
let path = path.expect("path to not be an error").path();
Expand Down

0 comments on commit f2385fa

Please sign in to comment.