mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 11:20:54 +00:00
Watch for user config ratoml
This commit is contained in:
parent
4a418837f2
commit
4fcecbb55e
@ -123,7 +123,7 @@ pub fn load_workspace(
|
|||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[]);
|
let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[], None);
|
||||||
loader.set_config(vfs::loader::Config {
|
loader.set_config(vfs::loader::Config {
|
||||||
load: project_folders.load,
|
load: project_folders.load,
|
||||||
watch: vec![],
|
watch: vec![],
|
||||||
@ -153,7 +153,11 @@ pub struct ProjectFolders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectFolders {
|
impl ProjectFolders {
|
||||||
pub fn new(workspaces: &[ProjectWorkspace], global_excludes: &[AbsPathBuf]) -> ProjectFolders {
|
pub fn new(
|
||||||
|
workspaces: &[ProjectWorkspace],
|
||||||
|
global_excludes: &[AbsPathBuf],
|
||||||
|
user_config_dir_path: Option<&'static AbsPath>,
|
||||||
|
) -> ProjectFolders {
|
||||||
let mut res = ProjectFolders::default();
|
let mut res = ProjectFolders::default();
|
||||||
let mut fsc = FileSetConfig::builder();
|
let mut fsc = FileSetConfig::builder();
|
||||||
let mut local_filesets = vec![];
|
let mut local_filesets = vec![];
|
||||||
@ -291,6 +295,22 @@ impl ProjectFolders {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(user_config_path) = user_config_dir_path {
|
||||||
|
let ratoml_path = {
|
||||||
|
let mut p = user_config_path.to_path_buf();
|
||||||
|
p.push("rust-analyzer.toml");
|
||||||
|
p
|
||||||
|
};
|
||||||
|
|
||||||
|
let file_set_roots: Vec<VfsPath> = vec![VfsPath::from(ratoml_path.to_owned())];
|
||||||
|
let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]);
|
||||||
|
|
||||||
|
res.watch.push(res.load.len());
|
||||||
|
res.load.push(entry);
|
||||||
|
local_filesets.push(fsc.len() as u64);
|
||||||
|
fsc.add_file_set(file_set_roots)
|
||||||
|
}
|
||||||
|
|
||||||
let fsc = fsc.build();
|
let fsc = fsc.build();
|
||||||
res.source_root_config = SourceRootConfig { fsc, local_filesets };
|
res.source_root_config = SourceRootConfig { fsc, local_filesets };
|
||||||
|
|
||||||
|
@ -804,22 +804,14 @@ impl std::ops::Deref for Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Path to the root configuration file. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer/rust-analyzer.toml` in Linux.
|
/// Path to the user configuration dir. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer` in Linux.
|
||||||
/// This path is equal to:
|
pub fn user_config_dir_path() -> Option<&'static AbsPath> {
|
||||||
///
|
|
||||||
/// |Platform | Value | Example |
|
|
||||||
/// | ------- | ------------------------------------- | ---------------------------------------- |
|
|
||||||
/// | Linux | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config |
|
|
||||||
/// | macOS | `$HOME`/Library/Application Support | /Users/Alice/Library/Application Support |
|
|
||||||
/// | Windows | `{FOLDERID_RoamingAppData}` | C:\Users\Alice\AppData\Roaming |
|
|
||||||
pub fn user_config_path() -> Option<&'static AbsPath> {
|
|
||||||
static USER_CONFIG_PATH: LazyLock<Option<AbsPathBuf>> = LazyLock::new(|| {
|
static USER_CONFIG_PATH: LazyLock<Option<AbsPathBuf>> = LazyLock::new(|| {
|
||||||
let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
|
let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
|
||||||
std::path::PathBuf::from(path)
|
std::path::PathBuf::from(path)
|
||||||
} else {
|
} else {
|
||||||
dirs::config_dir()?.join("rust-analyzer")
|
dirs::config_dir()?.join("rust-analyzer")
|
||||||
}
|
};
|
||||||
.join("rust-analyzer.toml");
|
|
||||||
Some(AbsPathBuf::assert_utf8(user_config_path))
|
Some(AbsPathBuf::assert_utf8(user_config_path))
|
||||||
});
|
});
|
||||||
USER_CONFIG_PATH.as_deref()
|
USER_CONFIG_PATH.as_deref()
|
||||||
|
@ -392,7 +392,14 @@ impl GlobalState {
|
|||||||
|| !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
|
|| !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
|
||||||
{
|
{
|
||||||
let config_change = {
|
let config_change = {
|
||||||
let user_config_path = Config::user_config_path();
|
let user_config_path = {
|
||||||
|
let mut p = Config::user_config_dir_path().unwrap().to_path_buf();
|
||||||
|
p.push("rust-analyzer.toml");
|
||||||
|
p
|
||||||
|
};
|
||||||
|
|
||||||
|
let user_config_abs_path = Some(user_config_path.as_path());
|
||||||
|
|
||||||
let mut change = ConfigChange::default();
|
let mut change = ConfigChange::default();
|
||||||
let db = self.analysis_host.raw_database();
|
let db = self.analysis_host.raw_database();
|
||||||
|
|
||||||
@ -411,7 +418,7 @@ impl GlobalState {
|
|||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
for (file_id, (_change_kind, vfs_path)) in modified_ratoml_files {
|
for (file_id, (_change_kind, vfs_path)) in modified_ratoml_files {
|
||||||
if vfs_path.as_path() == user_config_path {
|
if vfs_path.as_path() == user_config_abs_path {
|
||||||
change.change_user_config(Some(db.file_text(file_id)));
|
change.change_user_config(Some(db.file_text(file_id)));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -590,7 +590,7 @@ impl GlobalState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
watchers.extend(
|
watchers.extend(
|
||||||
iter::once(Config::user_config_path())
|
iter::once(Config::user_config_dir_path())
|
||||||
.chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
|
.chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
|
||||||
.flatten()
|
.flatten()
|
||||||
.map(|glob_pattern| lsp_types::FileSystemWatcher {
|
.map(|glob_pattern| lsp_types::FileSystemWatcher {
|
||||||
@ -613,7 +613,11 @@ impl GlobalState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let files_config = self.config.files();
|
let files_config = self.config.files();
|
||||||
let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
|
let project_folders = ProjectFolders::new(
|
||||||
|
&self.workspaces,
|
||||||
|
&files_config.exclude,
|
||||||
|
Config::user_config_dir_path().to_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
if (self.proc_macro_clients.is_empty() || !same_workspaces)
|
if (self.proc_macro_clients.is_empty() || !same_workspaces)
|
||||||
&& self.config.expand_proc_macros()
|
&& self.config.expand_proc_macros()
|
||||||
|
@ -30,6 +30,23 @@ impl RatomlTest {
|
|||||||
fixtures: Vec<&str>,
|
fixtures: Vec<&str>,
|
||||||
roots: Vec<&str>,
|
roots: Vec<&str>,
|
||||||
client_config: Option<serde_json::Value>,
|
client_config: Option<serde_json::Value>,
|
||||||
|
) -> Self {
|
||||||
|
RatomlTest::new_with_lock(fixtures, roots, client_config, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_locked(
|
||||||
|
fixtures: Vec<&str>,
|
||||||
|
roots: Vec<&str>,
|
||||||
|
client_config: Option<serde_json::Value>,
|
||||||
|
) -> Self {
|
||||||
|
RatomlTest::new_with_lock(fixtures, roots, client_config, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_lock(
|
||||||
|
fixtures: Vec<&str>,
|
||||||
|
roots: Vec<&str>,
|
||||||
|
client_config: Option<serde_json::Value>,
|
||||||
|
prelock: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let tmp_dir = TestDir::new();
|
let tmp_dir = TestDir::new();
|
||||||
let tmp_path = tmp_dir.path().to_owned();
|
let tmp_path = tmp_dir.path().to_owned();
|
||||||
@ -46,7 +63,7 @@ impl RatomlTest {
|
|||||||
project = project.with_config(client_config);
|
project = project.with_config(client_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
let server = project.server().wait_until_workspace_is_loaded();
|
let server = project.server_with_lock(prelock).wait_until_workspace_is_loaded();
|
||||||
|
|
||||||
let mut case = Self { urls: vec![], server, tmp_path };
|
let mut case = Self { urls: vec![], server, tmp_path };
|
||||||
let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::<Vec<_>>();
|
let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::<Vec<_>>();
|
||||||
@ -72,7 +89,7 @@ impl RatomlTest {
|
|||||||
let mut spl = spl.into_iter();
|
let mut spl = spl.into_iter();
|
||||||
if let Some(first) = spl.next() {
|
if let Some(first) = spl.next() {
|
||||||
if first == "$$CONFIG_DIR$$" {
|
if first == "$$CONFIG_DIR$$" {
|
||||||
path = Config::user_config_path().unwrap().to_path_buf().into();
|
path = Config::user_config_dir_path().unwrap().to_path_buf().into();
|
||||||
} else {
|
} else {
|
||||||
path = path.join(first);
|
path = path.join(first);
|
||||||
}
|
}
|
||||||
@ -285,16 +302,15 @@ enum Value {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "the user config is currently not being watched on startup, fix this"]
|
|
||||||
fn ratoml_user_config_detected() {
|
fn ratoml_user_config_detected() {
|
||||||
if skip_slow_tests() {
|
if skip_slow_tests() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let server = RatomlTest::new(
|
let server = RatomlTest::new_locked(
|
||||||
vec![
|
vec![
|
||||||
r#"
|
r#"
|
||||||
//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
|
//- /$$CONFIG_DIR$$/rust-analyzer.toml
|
||||||
assist.emitMustUse = true
|
assist.emitMustUse = true
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
@ -322,13 +338,12 @@ enum Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "the user config is currently not being watched on startup, fix this"]
|
|
||||||
fn ratoml_create_user_config() {
|
fn ratoml_create_user_config() {
|
||||||
if skip_slow_tests() {
|
if skip_slow_tests() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut server = RatomlTest::new(
|
let mut server = RatomlTest::new_locked(
|
||||||
vec![
|
vec![
|
||||||
r#"
|
r#"
|
||||||
//- /p1/Cargo.toml
|
//- /p1/Cargo.toml
|
||||||
@ -353,10 +368,7 @@ enum Value {
|
|||||||
1,
|
1,
|
||||||
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
|
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
|
||||||
);
|
);
|
||||||
server.create(
|
server.create("//- /$$CONFIG_DIR$$/rust-analyzer.toml", RatomlTest::EMIT_MUST_USE.to_owned());
|
||||||
"//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml",
|
|
||||||
RatomlTest::EMIT_MUST_USE.to_owned(),
|
|
||||||
);
|
|
||||||
server.query(
|
server.query(
|
||||||
InternalTestingFetchConfigOption::AssistEmitMustUse,
|
InternalTestingFetchConfigOption::AssistEmitMustUse,
|
||||||
1,
|
1,
|
||||||
@ -365,13 +377,12 @@ enum Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "the user config is currently not being watched on startup, fix this"]
|
|
||||||
fn ratoml_modify_user_config() {
|
fn ratoml_modify_user_config() {
|
||||||
if skip_slow_tests() {
|
if skip_slow_tests() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut server = RatomlTest::new(
|
let mut server = RatomlTest::new_locked(
|
||||||
vec![
|
vec![
|
||||||
r#"
|
r#"
|
||||||
//- /p1/Cargo.toml
|
//- /p1/Cargo.toml
|
||||||
@ -386,7 +397,7 @@ enum Value {
|
|||||||
Text(String),
|
Text(String),
|
||||||
}"#,
|
}"#,
|
||||||
r#"
|
r#"
|
||||||
//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
|
//- /$$CONFIG_DIR$$/rust-analyzer.toml
|
||||||
assist.emitMustUse = true"#,
|
assist.emitMustUse = true"#,
|
||||||
],
|
],
|
||||||
vec!["p1"],
|
vec!["p1"],
|
||||||
@ -407,13 +418,12 @@ assist.emitMustUse = true"#,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "the user config is currently not being watched on startup, fix this"]
|
|
||||||
fn ratoml_delete_user_config() {
|
fn ratoml_delete_user_config() {
|
||||||
if skip_slow_tests() {
|
if skip_slow_tests() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut server = RatomlTest::new(
|
let mut server = RatomlTest::new_locked(
|
||||||
vec![
|
vec![
|
||||||
r#"
|
r#"
|
||||||
//- /p1/Cargo.toml
|
//- /p1/Cargo.toml
|
||||||
@ -428,7 +438,7 @@ enum Value {
|
|||||||
Text(String),
|
Text(String),
|
||||||
}"#,
|
}"#,
|
||||||
r#"
|
r#"
|
||||||
//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
|
//- /$$CONFIG_DIR$$/rust-analyzer.toml
|
||||||
assist.emitMustUse = true"#,
|
assist.emitMustUse = true"#,
|
||||||
],
|
],
|
||||||
vec!["p1"],
|
vec!["p1"],
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fs,
|
env, fs,
|
||||||
sync::Once,
|
sync::Once,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
@ -127,7 +127,30 @@ impl Project<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn server(self) -> Server {
|
pub(crate) fn server(self) -> Server {
|
||||||
|
Project::server_with_lock(self, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `prelock` : Forcefully acquire a lock that will maintain the path to the config dir throughout the whole test.
|
||||||
|
///
|
||||||
|
/// When testing we set the user config dir by setting an envvar `__TEST_RA_USER_CONFIG_DIR`.
|
||||||
|
/// This value must be maintained until the end of a test case. When tests run in parallel
|
||||||
|
/// this value may change thus making the tests flaky. As such, we use a `MutexGuard` that locks
|
||||||
|
/// the process until `Server` is dropped. To optimize parallelization we use a lock only when it is
|
||||||
|
/// needed, that is when a test uses config directory to do stuff. Our naive approach is to use a lock
|
||||||
|
/// if there is a path to config dir in the test fixture. However, in certain cases we create a
|
||||||
|
/// file in the config dir after server is run, something where our naive approach comes short.
|
||||||
|
/// Using a `prelock` allows us to force a lock when we know we need it.
|
||||||
|
pub(crate) fn server_with_lock(self, prelock: bool) -> Server {
|
||||||
static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
|
static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
|
||||||
|
|
||||||
|
let mut config_dir_guard = if prelock {
|
||||||
|
let v = Some(CONFIG_DIR_LOCK.lock());
|
||||||
|
env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
|
||||||
|
v
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
|
let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
|
||||||
if self.root_dir_contains_symlink {
|
if self.root_dir_contains_symlink {
|
||||||
TestDir::new_symlink()
|
TestDir::new_symlink()
|
||||||
@ -160,13 +183,14 @@ impl Project<'_> {
|
|||||||
assert!(mini_core.is_none());
|
assert!(mini_core.is_none());
|
||||||
assert!(toolchain.is_none());
|
assert!(toolchain.is_none());
|
||||||
|
|
||||||
let mut config_dir_guard = None;
|
|
||||||
for entry in fixture {
|
for entry in fixture {
|
||||||
if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") {
|
if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") {
|
||||||
if config_dir_guard.is_none() {
|
if config_dir_guard.is_none() {
|
||||||
config_dir_guard = Some(CONFIG_DIR_LOCK.lock());
|
config_dir_guard = Some(CONFIG_DIR_LOCK.lock());
|
||||||
|
env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
|
||||||
}
|
}
|
||||||
let path = Config::user_config_path().unwrap().join(&pth['/'.len_utf8()..]);
|
|
||||||
|
let path = Config::user_config_dir_path().unwrap().join(&pth['/'.len_utf8()..]);
|
||||||
fs::create_dir_all(path.parent().unwrap()).unwrap();
|
fs::create_dir_all(path.parent().unwrap()).unwrap();
|
||||||
fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
|
fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user