Skip to content

Commit afdf4c8

Browse files
alibektasVeykril
authored andcommitted
Watch for user config ratoml
1 parent 8358c13 commit afdf4c8

File tree

6 files changed

+94
-37
lines changed

6 files changed

+94
-37
lines changed

src/tools/rust-analyzer/crates/load-cargo/src/lib.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pub fn load_workspace(
123123
.collect()
124124
};
125125

126-
let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[]);
126+
let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[], None);
127127
loader.set_config(vfs::loader::Config {
128128
load: project_folders.load,
129129
watch: vec![],
@@ -153,7 +153,11 @@ pub struct ProjectFolders {
153153
}
154154

155155
impl ProjectFolders {
156-
pub fn new(workspaces: &[ProjectWorkspace], global_excludes: &[AbsPathBuf]) -> ProjectFolders {
156+
pub fn new(
157+
workspaces: &[ProjectWorkspace],
158+
global_excludes: &[AbsPathBuf],
159+
user_config_dir_path: Option<&'static AbsPath>,
160+
) -> ProjectFolders {
157161
let mut res = ProjectFolders::default();
158162
let mut fsc = FileSetConfig::builder();
159163
let mut local_filesets = vec![];
@@ -291,6 +295,22 @@ impl ProjectFolders {
291295
}
292296
}
293297

298+
if let Some(user_config_path) = user_config_dir_path {
299+
let ratoml_path = {
300+
let mut p = user_config_path.to_path_buf();
301+
p.push("rust-analyzer.toml");
302+
p
303+
};
304+
305+
let file_set_roots: Vec<VfsPath> = vec![VfsPath::from(ratoml_path.to_owned())];
306+
let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]);
307+
308+
res.watch.push(res.load.len());
309+
res.load.push(entry);
310+
local_filesets.push(fsc.len() as u64);
311+
fsc.add_file_set(file_set_roots)
312+
}
313+
294314
let fsc = fsc.build();
295315
res.source_root_config = SourceRootConfig { fsc, local_filesets };
296316

src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -804,22 +804,14 @@ impl std::ops::Deref for Config {
804804
}
805805

806806
impl Config {
807-
/// 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.
808-
/// This path is equal to:
809-
///
810-
/// |Platform | Value | Example |
811-
/// | ------- | ------------------------------------- | ---------------------------------------- |
812-
/// | Linux | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config |
813-
/// | macOS | `$HOME`/Library/Application Support | /Users/Alice/Library/Application Support |
814-
/// | Windows | `{FOLDERID_RoamingAppData}` | C:\Users\Alice\AppData\Roaming |
815-
pub fn user_config_path() -> Option<&'static AbsPath> {
807+
/// 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.
808+
pub fn user_config_dir_path() -> Option<&'static AbsPath> {
816809
static USER_CONFIG_PATH: LazyLock<Option<AbsPathBuf>> = LazyLock::new(|| {
817810
let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
818811
std::path::PathBuf::from(path)
819812
} else {
820813
dirs::config_dir()?.join("rust-analyzer")
821-
}
822-
.join("rust-analyzer.toml");
814+
};
823815
Some(AbsPathBuf::assert_utf8(user_config_path))
824816
});
825817
USER_CONFIG_PATH.as_deref()

src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,14 @@ impl GlobalState {
392392
|| !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
393393
{
394394
let config_change = {
395-
let user_config_path = Config::user_config_path();
395+
let user_config_path = {
396+
let mut p = Config::user_config_dir_path().unwrap().to_path_buf();
397+
p.push("rust-analyzer.toml");
398+
p
399+
};
400+
401+
let user_config_abs_path = Some(user_config_path.as_path());
402+
396403
let mut change = ConfigChange::default();
397404
let db = self.analysis_host.raw_database();
398405

@@ -411,7 +418,7 @@ impl GlobalState {
411418
.collect_vec();
412419

413420
for (file_id, (_change_kind, vfs_path)) in modified_ratoml_files {
414-
if vfs_path.as_path() == user_config_path {
421+
if vfs_path.as_path() == user_config_abs_path {
415422
change.change_user_config(Some(db.file_text(file_id)));
416423
continue;
417424
}

src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ impl GlobalState {
590590
}
591591

592592
watchers.extend(
593-
iter::once(Config::user_config_path())
593+
iter::once(Config::user_config_dir_path())
594594
.chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
595595
.flatten()
596596
.map(|glob_pattern| lsp_types::FileSystemWatcher {
@@ -613,7 +613,11 @@ impl GlobalState {
613613
}
614614

615615
let files_config = self.config.files();
616-
let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
616+
let project_folders = ProjectFolders::new(
617+
&self.workspaces,
618+
&files_config.exclude,
619+
Config::user_config_dir_path().to_owned(),
620+
);
617621

618622
if (self.proc_macro_clients.is_empty() || !same_workspaces)
619623
&& self.config.expand_proc_macros()

src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ impl RatomlTest {
3030
fixtures: Vec<&str>,
3131
roots: Vec<&str>,
3232
client_config: Option<serde_json::Value>,
33+
) -> Self {
34+
RatomlTest::new_with_lock(fixtures, roots, client_config, false)
35+
}
36+
37+
fn new_locked(
38+
fixtures: Vec<&str>,
39+
roots: Vec<&str>,
40+
client_config: Option<serde_json::Value>,
41+
) -> Self {
42+
RatomlTest::new_with_lock(fixtures, roots, client_config, true)
43+
}
44+
45+
fn new_with_lock(
46+
fixtures: Vec<&str>,
47+
roots: Vec<&str>,
48+
client_config: Option<serde_json::Value>,
49+
prelock: bool,
3350
) -> Self {
3451
let tmp_dir = TestDir::new();
3552
let tmp_path = tmp_dir.path().to_owned();
@@ -46,7 +63,7 @@ impl RatomlTest {
4663
project = project.with_config(client_config);
4764
}
4865

49-
let server = project.server().wait_until_workspace_is_loaded();
66+
let server = project.server_with_lock(prelock).wait_until_workspace_is_loaded();
5067

5168
let mut case = Self { urls: vec![], server, tmp_path };
5269
let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::<Vec<_>>();
@@ -72,7 +89,7 @@ impl RatomlTest {
7289
let mut spl = spl.into_iter();
7390
if let Some(first) = spl.next() {
7491
if first == "$$CONFIG_DIR$$" {
75-
path = Config::user_config_path().unwrap().to_path_buf().into();
92+
path = Config::user_config_dir_path().unwrap().to_path_buf().into();
7693
} else {
7794
path = path.join(first);
7895
}
@@ -285,16 +302,15 @@ enum Value {
285302
// }
286303

287304
#[test]
288-
#[ignore = "the user config is currently not being watched on startup, fix this"]
289305
fn ratoml_user_config_detected() {
290306
if skip_slow_tests() {
291307
return;
292308
}
293309

294-
let server = RatomlTest::new(
310+
let server = RatomlTest::new_locked(
295311
vec![
296312
r#"
297-
//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
313+
//- /$$CONFIG_DIR$$/rust-analyzer.toml
298314
assist.emitMustUse = true
299315
"#,
300316
r#"
@@ -322,13 +338,12 @@ enum Value {
322338
}
323339

324340
#[test]
325-
#[ignore = "the user config is currently not being watched on startup, fix this"]
326341
fn ratoml_create_user_config() {
327342
if skip_slow_tests() {
328343
return;
329344
}
330345

331-
let mut server = RatomlTest::new(
346+
let mut server = RatomlTest::new_locked(
332347
vec![
333348
r#"
334349
//- /p1/Cargo.toml
@@ -353,10 +368,7 @@ enum Value {
353368
1,
354369
InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
355370
);
356-
server.create(
357-
"//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml",
358-
RatomlTest::EMIT_MUST_USE.to_owned(),
359-
);
371+
server.create("//- /$$CONFIG_DIR$$/rust-analyzer.toml", RatomlTest::EMIT_MUST_USE.to_owned());
360372
server.query(
361373
InternalTestingFetchConfigOption::AssistEmitMustUse,
362374
1,
@@ -365,13 +377,12 @@ enum Value {
365377
}
366378

367379
#[test]
368-
#[ignore = "the user config is currently not being watched on startup, fix this"]
369380
fn ratoml_modify_user_config() {
370381
if skip_slow_tests() {
371382
return;
372383
}
373384

374-
let mut server = RatomlTest::new(
385+
let mut server = RatomlTest::new_locked(
375386
vec![
376387
r#"
377388
//- /p1/Cargo.toml
@@ -386,7 +397,7 @@ enum Value {
386397
Text(String),
387398
}"#,
388399
r#"
389-
//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
400+
//- /$$CONFIG_DIR$$/rust-analyzer.toml
390401
assist.emitMustUse = true"#,
391402
],
392403
vec!["p1"],
@@ -407,13 +418,12 @@ assist.emitMustUse = true"#,
407418
}
408419

409420
#[test]
410-
#[ignore = "the user config is currently not being watched on startup, fix this"]
411421
fn ratoml_delete_user_config() {
412422
if skip_slow_tests() {
413423
return;
414424
}
415425

416-
let mut server = RatomlTest::new(
426+
let mut server = RatomlTest::new_locked(
417427
vec![
418428
r#"
419429
//- /p1/Cargo.toml
@@ -428,7 +438,7 @@ enum Value {
428438
Text(String),
429439
}"#,
430440
r#"
431-
//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
441+
//- /$$CONFIG_DIR$$/rust-analyzer.toml
432442
assist.emitMustUse = true"#,
433443
],
434444
vec!["p1"],

src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{
22
cell::{Cell, RefCell},
3-
fs,
3+
env, fs,
44
sync::Once,
55
time::Duration,
66
};
@@ -127,7 +127,30 @@ impl Project<'_> {
127127
}
128128

129129
pub(crate) fn server(self) -> Server {
130+
Project::server_with_lock(self, false)
131+
}
132+
133+
/// `prelock` : Forcefully acquire a lock that will maintain the path to the config dir throughout the whole test.
134+
///
135+
/// When testing we set the user config dir by setting an envvar `__TEST_RA_USER_CONFIG_DIR`.
136+
/// This value must be maintained until the end of a test case. When tests run in parallel
137+
/// this value may change thus making the tests flaky. As such, we use a `MutexGuard` that locks
138+
/// the process until `Server` is dropped. To optimize parallelization we use a lock only when it is
139+
/// needed, that is when a test uses config directory to do stuff. Our naive approach is to use a lock
140+
/// if there is a path to config dir in the test fixture. However, in certain cases we create a
141+
/// file in the config dir after server is run, something where our naive approach comes short.
142+
/// Using a `prelock` allows us to force a lock when we know we need it.
143+
pub(crate) fn server_with_lock(self, prelock: bool) -> Server {
130144
static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
145+
146+
let mut config_dir_guard = if prelock {
147+
let v = Some(CONFIG_DIR_LOCK.lock());
148+
env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
149+
v
150+
} else {
151+
None
152+
};
153+
131154
let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
132155
if self.root_dir_contains_symlink {
133156
TestDir::new_symlink()
@@ -160,13 +183,14 @@ impl Project<'_> {
160183
assert!(mini_core.is_none());
161184
assert!(toolchain.is_none());
162185

163-
let mut config_dir_guard = None;
164186
for entry in fixture {
165187
if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") {
166188
if config_dir_guard.is_none() {
167189
config_dir_guard = Some(CONFIG_DIR_LOCK.lock());
190+
env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
168191
}
169-
let path = Config::user_config_path().unwrap().join(&pth['/'.len_utf8()..]);
192+
193+
let path = Config::user_config_dir_path().unwrap().join(&pth['/'.len_utf8()..]);
170194
fs::create_dir_all(path.parent().unwrap()).unwrap();
171195
fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
172196
} else {

0 commit comments

Comments
 (0)