Skip to content

Commit 87e609a

Browse files
committed
Auto merge of rust-lang#15868 - wasd96040501:fix/symlink2, r=Veykril
fix: failed to infer OUT_DIR when workspace root contains symlink fix rust-lang#15867
2 parents 18abb12 + 22cda95 commit 87e609a

File tree

6 files changed

+114
-27
lines changed

6 files changed

+114
-27
lines changed

crates/project-model/src/build_scripts.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ impl WorkspaceBuildScripts {
6060
fn build_command(
6161
config: &CargoConfig,
6262
allowed_features: &FxHashSet<String>,
63+
workspace_root: &AbsPathBuf,
6364
) -> io::Result<Command> {
6465
let mut cmd = match config.run_build_script_command.as_deref() {
6566
Some([program, args @ ..]) => {
@@ -73,6 +74,9 @@ impl WorkspaceBuildScripts {
7374
cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]);
7475
cmd.args(&config.extra_args);
7576

77+
cmd.arg("--manifest-path");
78+
cmd.arg(workspace_root.join("Cargo.toml").as_os_str());
79+
7680
if let Some(target_dir) = &config.target_dir {
7781
cmd.arg("--target-dir").arg(target_dir);
7882
}
@@ -143,7 +147,11 @@ impl WorkspaceBuildScripts {
143147
let allowed_features = workspace.workspace_features();
144148

145149
match Self::run_per_ws(
146-
Self::build_command(config, &allowed_features)?,
150+
Self::build_command(
151+
config,
152+
&allowed_features,
153+
&workspace.workspace_root().to_path_buf(),
154+
)?,
147155
workspace,
148156
current_dir,
149157
progress,
@@ -153,7 +161,11 @@ impl WorkspaceBuildScripts {
153161
{
154162
// building build scripts failed, attempt to build with --keep-going so
155163
// that we potentially get more build data
156-
let mut cmd = Self::build_command(config, &allowed_features)?;
164+
let mut cmd = Self::build_command(
165+
config,
166+
&allowed_features,
167+
&workspace.workspace_root().to_path_buf(),
168+
)?;
157169
cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
158170
let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
159171
res.error = Some(error);
@@ -169,6 +181,7 @@ impl WorkspaceBuildScripts {
169181
config: &CargoConfig,
170182
workspaces: &[&CargoWorkspace],
171183
progress: &dyn Fn(String),
184+
workspace_root: &AbsPathBuf,
172185
) -> io::Result<Vec<WorkspaceBuildScripts>> {
173186
assert_eq!(config.invocation_strategy, InvocationStrategy::Once);
174187

@@ -181,7 +194,7 @@ impl WorkspaceBuildScripts {
181194
))
182195
}
183196
};
184-
let cmd = Self::build_command(config, &Default::default())?;
197+
let cmd = Self::build_command(config, &Default::default(), workspace_root)?;
185198
// NB: Cargo.toml could have been modified between `cargo metadata` and
186199
// `cargo check`. We shouldn't assume that package ids we see here are
187200
// exactly those from `config`.

crates/project-model/src/workspace.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ impl ProjectWorkspace {
413413
workspaces: &[ProjectWorkspace],
414414
config: &CargoConfig,
415415
progress: &dyn Fn(String),
416+
workspace_root: &AbsPathBuf,
416417
) -> Vec<anyhow::Result<WorkspaceBuildScripts>> {
417418
if matches!(config.invocation_strategy, InvocationStrategy::PerWorkspace)
418419
|| config.run_build_script_command.is_none()
@@ -427,11 +428,13 @@ impl ProjectWorkspace {
427428
_ => None,
428429
})
429430
.collect();
430-
let outputs = &mut match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) {
431-
Ok(it) => Ok(it.into_iter()),
432-
// io::Error is not Clone?
433-
Err(e) => Err(sync::Arc::new(e)),
434-
};
431+
let outputs =
432+
&mut match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress, workspace_root)
433+
{
434+
Ok(it) => Ok(it.into_iter()),
435+
// io::Error is not Clone?
436+
Err(e) => Err(sync::Arc::new(e)),
437+
};
435438

436439
workspaces
437440
.iter()

crates/rust-analyzer/src/reload.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ impl GlobalState {
275275
tracing::info!(%cause, "will fetch build data");
276276
let workspaces = Arc::clone(&self.workspaces);
277277
let config = self.config.cargo();
278+
let root_path = self.config.root_path().clone();
279+
278280
self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
279281
sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
280282

@@ -284,7 +286,12 @@ impl GlobalState {
284286
sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap()
285287
}
286288
};
287-
let res = ProjectWorkspace::run_all_build_scripts(&workspaces, &config, &progress);
289+
let res = ProjectWorkspace::run_all_build_scripts(
290+
&workspaces,
291+
&config,
292+
&progress,
293+
&root_path,
294+
);
288295

289296
sender.send(Task::FetchBuildData(BuildDataProgress::End((workspaces, res)))).unwrap();
290297
});

crates/rust-analyzer/tests/slow-tests/main.rs

+31-16
Original file line numberDiff line numberDiff line change
@@ -682,13 +682,12 @@ version = \"0.0.0\"
682682
);
683683
}
684684

685-
#[test]
686-
fn out_dirs_check() {
685+
fn out_dirs_check_impl(root_contains_symlink: bool) {
687686
if skip_slow_tests() {
688687
return;
689688
}
690689

691-
let server = Project::with_fixture(
690+
let mut server = Project::with_fixture(
692691
r###"
693692
//- /Cargo.toml
694693
[package]
@@ -745,20 +744,26 @@ fn main() {
745744
let another_str = include_str!("main.rs");
746745
}
747746
"###,
748-
)
749-
.with_config(serde_json::json!({
750-
"cargo": {
751-
"buildScripts": {
752-
"enable": true
753-
},
754-
"sysroot": null,
755-
"extraEnv": {
756-
"RUSTC_BOOTSTRAP": "1"
747+
);
748+
749+
if root_contains_symlink {
750+
server = server.with_root_dir_contains_symlink();
751+
}
752+
753+
let server = server
754+
.with_config(serde_json::json!({
755+
"cargo": {
756+
"buildScripts": {
757+
"enable": true
758+
},
759+
"sysroot": null,
760+
"extraEnv": {
761+
"RUSTC_BOOTSTRAP": "1"
762+
}
757763
}
758-
}
759-
}))
760-
.server()
761-
.wait_until_workspace_is_loaded();
764+
}))
765+
.server()
766+
.wait_until_workspace_is_loaded();
762767

763768
let res = server.send_request::<HoverRequest>(HoverParams {
764769
text_document_position_params: TextDocumentPositionParams::new(
@@ -831,6 +836,16 @@ fn main() {
831836
);
832837
}
833838

839+
#[test]
840+
fn out_dirs_check() {
841+
out_dirs_check_impl(false);
842+
}
843+
844+
#[test]
845+
fn root_contains_symlink_out_dirs_check() {
846+
out_dirs_check_impl(true);
847+
}
848+
834849
#[test]
835850
#[cfg(any(feature = "sysroot-abi", rust_analyzer))]
836851
fn resolve_proc_macro() {

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

+15-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub(crate) struct Project<'a> {
2323
tmp_dir: Option<TestDir>,
2424
roots: Vec<PathBuf>,
2525
config: serde_json::Value,
26+
root_dir_contains_symlink: bool,
2627
}
2728

2829
impl Project<'_> {
@@ -45,6 +46,7 @@ impl Project<'_> {
4546
"enable": false,
4647
}
4748
}),
49+
root_dir_contains_symlink: false,
4850
}
4951
}
5052

@@ -58,6 +60,11 @@ impl Project<'_> {
5860
self
5961
}
6062

63+
pub(crate) fn with_root_dir_contains_symlink(mut self) -> Self {
64+
self.root_dir_contains_symlink = true;
65+
self
66+
}
67+
6168
pub(crate) fn with_config(mut self, config: serde_json::Value) -> Self {
6269
fn merge(dst: &mut serde_json::Value, src: serde_json::Value) {
6370
match (dst, src) {
@@ -74,7 +81,14 @@ impl Project<'_> {
7481
}
7582

7683
pub(crate) fn server(self) -> Server {
77-
let tmp_dir = self.tmp_dir.unwrap_or_else(TestDir::new);
84+
let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
85+
if self.root_dir_contains_symlink {
86+
TestDir::new_symlink()
87+
} else {
88+
TestDir::new()
89+
}
90+
});
91+
7892
static INIT: Once = Once::new();
7993
INIT.call_once(|| {
8094
let filter: tracing_subscriber::filter::Targets =

crates/rust-analyzer/tests/slow-tests/testdir.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ pub(crate) struct TestDir {
1111

1212
impl TestDir {
1313
pub(crate) fn new() -> TestDir {
14+
return TestDir::new_dir(false);
15+
}
16+
17+
pub(crate) fn new_symlink() -> TestDir {
18+
return TestDir::new_dir(true);
19+
}
20+
21+
fn new_dir(symlink: bool) -> TestDir {
1422
let temp_dir = std::env::temp_dir();
1523
// On MacOS builders on GitHub actions, the temp dir is a symlink, and
1624
// that causes problems down the line. Specifically:
@@ -33,10 +41,24 @@ impl TestDir {
3341
continue;
3442
}
3543
fs::create_dir_all(&path).unwrap();
44+
45+
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
46+
if symlink {
47+
let symlink_path = base.join(format!("{pid}_{cnt}_symlink"));
48+
#[cfg(any(target_os = "macos", target_os = "linux"))]
49+
std::os::unix::fs::symlink(path, &symlink_path).unwrap();
50+
51+
#[cfg(target_os = "windows")]
52+
std::os::windows::fs::symlink_dir(path, &symlink_path).unwrap();
53+
54+
return TestDir { path: symlink_path, keep: false };
55+
}
56+
3657
return TestDir { path, keep: false };
3758
}
3859
panic!("Failed to create a temporary directory")
3960
}
61+
4062
#[allow(unused)]
4163
pub(crate) fn keep(mut self) -> TestDir {
4264
self.keep = true;
@@ -52,9 +74,22 @@ impl Drop for TestDir {
5274
if self.keep {
5375
return;
5476
}
77+
78+
let filetype = fs::symlink_metadata(&self.path).unwrap().file_type();
79+
let actual_path = filetype.is_symlink().then(|| fs::read_link(&self.path).unwrap());
80+
81+
if let Some(actual_path) = actual_path {
82+
remove_dir_all(&actual_path).unwrap_or_else(|err| {
83+
panic!(
84+
"failed to remove temporary link to directory {}: {err}",
85+
actual_path.display()
86+
)
87+
})
88+
}
89+
5590
remove_dir_all(&self.path).unwrap_or_else(|err| {
5691
panic!("failed to remove temporary directory {}: {err}", self.path.display())
57-
})
92+
});
5893
}
5994
}
6095

0 commit comments

Comments
 (0)