Skip to content

Commit b23b276

Browse files
committed
internal: Show more project building errors to the user
1 parent cf9c825 commit b23b276

File tree

8 files changed

+82
-51
lines changed

8 files changed

+82
-51
lines changed

crates/flycheck/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ impl CargoActor {
329329
Ok(output) if output.status.success() => Ok(()),
330330
Ok(output) => {
331331
Err(io::Error::new(io::ErrorKind::Other, format!(
332-
"Cargo watcher failed, the command produced no valid metadata (exit code: {:?})\nCargo's stderr output:\n{}",
332+
"Cargo watcher failed, the command produced no valid metadata (exit code: {:?}):\n{}",
333333
output.status, error
334334
)))
335335
}

crates/project_model/src/build_scripts.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
//! here, but it covers procedural macros as well.
88
99
use std::{
10+
io,
1011
path::PathBuf,
1112
process::{Command, Stdio},
1213
};
1314

14-
use anyhow::Result;
1515
use cargo_metadata::{camino::Utf8Path, Message};
1616
use la_arena::ArenaMap;
1717
use paths::AbsPathBuf;
@@ -80,7 +80,7 @@ impl WorkspaceBuildScripts {
8080
config: &CargoConfig,
8181
workspace: &CargoWorkspace,
8282
progress: &dyn Fn(String),
83-
) -> Result<WorkspaceBuildScripts> {
83+
) -> io::Result<WorkspaceBuildScripts> {
8484
let mut cmd = Self::build_command(config);
8585

8686
if config.wrap_rustc_in_build_scripts {
@@ -107,12 +107,12 @@ impl WorkspaceBuildScripts {
107107
by_id.insert(workspace[package].id.clone(), package);
108108
}
109109

110-
let mut callback_err = None;
110+
let mut cfg_err = None;
111111
let mut stderr = String::new();
112112
let output = stdx::process::streaming_output(
113113
cmd,
114114
&mut |line| {
115-
if callback_err.is_some() {
115+
if cfg_err.is_some() {
116116
return;
117117
}
118118

@@ -126,7 +126,7 @@ impl WorkspaceBuildScripts {
126126
match message {
127127
Message::BuildScriptExecuted(message) => {
128128
let package = match by_id.get(&message.package_id.repr) {
129-
Some(it) => *it,
129+
Some(&it) => it,
130130
None => return,
131131
};
132132
let cfgs = {
@@ -135,7 +135,7 @@ impl WorkspaceBuildScripts {
135135
match cfg.parse::<CfgFlag>() {
136136
Ok(it) => acc.push(it),
137137
Err(err) => {
138-
callback_err = Some(anyhow::format_err!(
138+
cfg_err = Some(format!(
139139
"invalid cfg from cargo-metadata: {}",
140140
err
141141
));
@@ -191,6 +191,11 @@ impl WorkspaceBuildScripts {
191191

192192
for package in workspace.packages() {
193193
let package_build_data = &mut res.outputs[package];
194+
tracing::info!(
195+
"{} BuildScriptOutput: {:?}",
196+
workspace[package].manifest.parent().display(),
197+
package_build_data,
198+
);
194199
// inject_cargo_env(package, package_build_data);
195200
if let Some(out_dir) = &package_build_data.out_dir {
196201
// NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
@@ -200,6 +205,11 @@ impl WorkspaceBuildScripts {
200205
}
201206
}
202207

208+
if let Some(cfg_err) = cfg_err {
209+
stderr.push_str(&cfg_err);
210+
stderr.push('\n');
211+
}
212+
203213
if !output.status.success() {
204214
if stderr.is_empty() {
205215
stderr = "cargo check failed".to_string();

crates/project_model/src/workspace.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,9 @@ impl ProjectWorkspace {
256256
) -> Result<WorkspaceBuildScripts> {
257257
match self {
258258
ProjectWorkspace::Cargo { cargo, .. } => {
259-
WorkspaceBuildScripts::run(config, cargo, progress)
259+
WorkspaceBuildScripts::run(config, cargo, progress).with_context(|| {
260+
format!("Failed to run build scripts for {}", &cargo.workspace_root().display())
261+
})
260262
}
261263
ProjectWorkspace::Json { .. } | ProjectWorkspace::DetachedFiles { .. } => {
262264
Ok(WorkspaceBuildScripts::default())

crates/rust-analyzer/src/bin/main.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ fn setup_logging(log_file: Option<&Path>) -> Result<()> {
119119
None => None,
120120
};
121121
let filter = env::var("RA_LOG").ok();
122-
logger::Logger::new(log_file, filter.as_deref()).install()?;
122+
// deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually useful
123+
// information in there for debugging
124+
logger::Logger::new(log_file, filter.as_deref().or(Some("error"))).install()?;
123125

124126
profile::init();
125127

crates/rust-analyzer/src/global_state.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ impl GlobalState {
190190

191191
for file in changed_files {
192192
if !file.is_created_or_deleted() {
193+
// FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/11357
193194
let crates = self.analysis_host.raw_database().relevant_crates(file.file_id);
194195
let crate_graph = self.analysis_host.raw_database().crate_graph();
195196

@@ -255,6 +256,7 @@ impl GlobalState {
255256
let request = self.req_queue.outgoing.register(R::METHOD.to_string(), params, handler);
256257
self.send(request.into());
257258
}
259+
258260
pub(crate) fn complete_request(&mut self, response: lsp_server::Response) {
259261
let handler = self
260262
.req_queue
@@ -281,6 +283,7 @@ impl GlobalState {
281283
.incoming
282284
.register(request.id.clone(), (request.method.clone(), request_received));
283285
}
286+
284287
pub(crate) fn respond(&mut self, response: lsp_server::Response) {
285288
if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) {
286289
if let Some(err) = &response.error {
@@ -294,6 +297,7 @@ impl GlobalState {
294297
self.send(response.into());
295298
}
296299
}
300+
297301
pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) {
298302
if let Some(response) = self.req_queue.incoming.cancel(request_id) {
299303
self.send(response.into());
@@ -307,7 +311,7 @@ impl GlobalState {
307311

308312
impl Drop for GlobalState {
309313
fn drop(&mut self) {
310-
self.analysis_host.request_cancellation()
314+
self.analysis_host.request_cancellation();
311315
}
312316
}
313317

crates/rust-analyzer/src/lsp_utils.rs

+20
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@ impl GlobalState {
4747
)
4848
}
4949

50+
/// Sends a notification to the client containing the error `message`.
51+
/// If `additional_info` is [`Some`], appends a note to the notification telling to check the logs.
52+
/// This will always log `message` + `additional_info` to the server's error log.
53+
pub(crate) fn show_and_log_error(&mut self, message: String, additional_info: Option<String>) {
54+
let mut message = message;
55+
match additional_info {
56+
Some(additional_info) => {
57+
tracing::error!("{}\n\n{}", &message, &additional_info);
58+
if tracing::enabled!(tracing::Level::ERROR) {
59+
message.push_str("\n\nCheck the server logs for additional info.");
60+
}
61+
}
62+
None => tracing::error!("{}", &message),
63+
}
64+
65+
self.send_notification::<lsp_types::notification::ShowMessage>(
66+
lsp_types::ShowMessageParams { typ: lsp_types::MessageType::ERROR, message },
67+
)
68+
}
69+
5070
/// rust-analyzer is resilient -- if it fails, this doesn't usually affect
5171
/// the user experience. Part of that is that we deliberately hide panics
5272
/// from the user.

crates/rust-analyzer/src/main_loop.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,7 @@ impl GlobalState {
111111
&& self.config.detached_files().is_empty()
112112
&& self.config.notifications().cargo_toml_not_found
113113
{
114-
self.show_message(
115-
lsp_types::MessageType::ERROR,
116-
"rust-analyzer failed to discover workspace".to_string(),
117-
);
114+
self.show_and_log_error("rust-analyzer failed to discover workspace".to_string(), None);
118115
};
119116

120117
if self.config.did_save_text_document_dynamic_registration() {
@@ -406,9 +403,9 @@ impl GlobalState {
406403
flycheck::Progress::DidCancel => (Progress::End, None),
407404
flycheck::Progress::DidFinish(result) => {
408405
if let Err(err) = result {
409-
self.show_message(
410-
lsp_types::MessageType::ERROR,
411-
format!("cargo check failed: {}", err),
406+
self.show_and_log_error(
407+
"cargo check failed".to_string(),
408+
Some(err.to_string()),
412409
);
413410
}
414411
(Progress::End, None)
@@ -564,7 +561,6 @@ impl GlobalState {
564561
if self.workspaces.is_empty() && !self.is_quiescent() {
565562
self.respond(lsp_server::Response::new_err(
566563
req.id,
567-
// FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion)
568564
lsp_server::ErrorCode::ContentModified as i32,
569565
"waiting for cargo metadata or cargo check".to_owned(),
570566
));

crates/rust-analyzer/src/reload.rs

+30-33
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,10 @@ impl GlobalState {
7272
status.message =
7373
Some("Reload required due to source changes of a procedural macro.".into())
7474
}
75-
if let Some(error) = self.fetch_build_data_error() {
75+
if let Err(_) = self.fetch_build_data_error() {
7676
status.health = lsp_ext::Health::Warning;
77-
status.message = Some(error)
77+
status.message =
78+
Some("Failed to run build scripts of some packages, check the logs.".to_string());
7879
}
7980
if !self.config.cargo_autoreload()
8081
&& self.is_quiescent()
@@ -84,7 +85,7 @@ impl GlobalState {
8485
status.message = Some("Workspace reload required".to_string())
8586
}
8687

87-
if let Some(error) = self.fetch_workspace_error() {
88+
if let Err(error) = self.fetch_workspace_error() {
8889
status.health = lsp_ext::Health::Error;
8990
status.message = Some(error)
9091
}
@@ -167,17 +168,20 @@ impl GlobalState {
167168
let _p = profile::span("GlobalState::switch_workspaces");
168169
tracing::info!("will switch workspaces");
169170

170-
if let Some(error_message) = self.fetch_workspace_error() {
171-
tracing::error!("failed to switch workspaces: {}", error_message);
171+
if let Err(error_message) = self.fetch_workspace_error() {
172+
self.show_and_log_error(error_message, None);
172173
if !self.workspaces.is_empty() {
173174
// It only makes sense to switch to a partially broken workspace
174175
// if we don't have any workspace at all yet.
175176
return;
176177
}
177178
}
178179

179-
if let Some(error_message) = self.fetch_build_data_error() {
180-
tracing::error!("failed to switch build data: {}", error_message);
180+
if let Err(error) = self.fetch_build_data_error() {
181+
self.show_and_log_error(
182+
"rust-analyzer failed to run build scripts".to_string(),
183+
Some(error),
184+
);
181185
}
182186

183187
let workspaces = self
@@ -277,20 +281,18 @@ impl GlobalState {
277281
let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
278282

279283
if self.proc_macro_client.is_none() {
280-
self.proc_macro_client = match self.config.proc_macro_srv() {
281-
None => None,
282-
Some((path, args)) => match ProcMacroServer::spawn(path.clone(), args) {
283-
Ok(it) => Some(it),
284+
if let Some((path, args)) = self.config.proc_macro_srv() {
285+
match ProcMacroServer::spawn(path.clone(), args) {
286+
Ok(it) => self.proc_macro_client = Some(it),
284287
Err(err) => {
285288
tracing::error!(
286289
"Failed to run proc_macro_srv from path {}, error: {:?}",
287290
path.display(),
288291
err
289292
);
290-
None
291293
}
292-
},
293-
};
294+
}
295+
}
294296
}
295297

296298
let watch = match files_config.watcher {
@@ -348,7 +350,7 @@ impl GlobalState {
348350
tracing::info!("did switch workspaces");
349351
}
350352

351-
fn fetch_workspace_error(&self) -> Option<String> {
353+
fn fetch_workspace_error(&self) -> Result<(), String> {
352354
let mut buf = String::new();
353355

354356
for ws in self.fetch_workspaces_queue.last_op_result() {
@@ -358,35 +360,30 @@ impl GlobalState {
358360
}
359361

360362
if buf.is_empty() {
361-
return None;
363+
return Ok(());
362364
}
363365

364-
Some(buf)
366+
Err(buf)
365367
}
366368

367-
fn fetch_build_data_error(&self) -> Option<String> {
368-
let mut buf = "rust-analyzer failed to run build scripts:\n".to_string();
369-
let mut has_errors = false;
369+
fn fetch_build_data_error(&self) -> Result<(), String> {
370+
let mut buf = String::new();
370371

371372
for ws in &self.fetch_build_data_queue.last_op_result().1 {
372373
match ws {
373-
Ok(data) => {
374-
if let Some(err) = data.error() {
375-
has_errors = true;
376-
stdx::format_to!(buf, "{:#}\n", err);
377-
}
378-
}
379-
Err(err) => {
380-
has_errors = true;
381-
stdx::format_to!(buf, "{:#}\n", err);
382-
}
374+
Ok(data) => match data.error() {
375+
Some(stderr) => stdx::format_to!(buf, "{:#}\n", stderr),
376+
_ => (),
377+
},
378+
// io errors
379+
Err(err) => stdx::format_to!(buf, "{:#}\n", err),
383380
}
384381
}
385382

386-
if has_errors {
387-
Some(buf)
383+
if buf.is_empty() {
384+
Ok(())
388385
} else {
389-
None
386+
Err(buf)
390387
}
391388
}
392389

0 commit comments

Comments
 (0)