internal: do not drop errors from cargo metadata/check

Work towards #3155
This commit is contained in:
Aleksey Kladov 2021-04-05 22:30:19 +03:00
parent 047b531301
commit aaa8c208b1
4 changed files with 60 additions and 51 deletions

View file

@ -52,7 +52,7 @@ pub struct BuildDataCollector {
configs: FxHashMap<AbsPathBuf, BuildDataConfig>, configs: FxHashMap<AbsPathBuf, BuildDataConfig>,
} }
#[derive(Debug, Default, PartialEq, Eq)] #[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct BuildDataResult { pub struct BuildDataResult {
data: FxHashMap<AbsPathBuf, BuildDataMap>, data: FxHashMap<AbsPathBuf, BuildDataMap>,
} }

View file

@ -82,11 +82,16 @@ pub(crate) struct GlobalState {
pub(crate) source_root_config: SourceRootConfig, pub(crate) source_root_config: SourceRootConfig,
pub(crate) proc_macro_client: Option<ProcMacroClient>, pub(crate) proc_macro_client: Option<ProcMacroClient>,
/// For both `workspaces` and `workspace_build_data`, the field stores the
/// data we actually use, while the `OpQueue` stores the result of the last
/// fetch.
///
/// If the fetch (partially) fails, we do not update the values.
pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
pub(crate) fetch_workspaces_queue: OpQueue<(), ()>, pub(crate) fetch_workspaces_queue: OpQueue<(), Vec<anyhow::Result<ProjectWorkspace>>>,
pub(crate) workspace_build_data: Option<BuildDataResult>, pub(crate) workspace_build_data: Option<BuildDataResult>,
pub(crate) fetch_build_data_queue: OpQueue<BuildDataCollector, ()>, pub(crate) fetch_build_data_queue:
OpQueue<BuildDataCollector, Option<anyhow::Result<BuildDataResult>>>,
latest_requests: Arc<RwLock<LatestRequests>>, latest_requests: Arc<RwLock<LatestRequests>>,
} }
@ -140,10 +145,12 @@ impl GlobalState {
status: Status::default(), status: Status::default(),
source_root_config: SourceRootConfig::default(), source_root_config: SourceRootConfig::default(),
proc_macro_client: None, proc_macro_client: None,
workspaces: Arc::new(Vec::new()), workspaces: Arc::new(Vec::new()),
fetch_workspaces_queue: OpQueue::default(), fetch_workspaces_queue: OpQueue::default(),
workspace_build_data: None, workspace_build_data: None,
fetch_build_data_queue: OpQueue::default(), fetch_build_data_queue: OpQueue::default(),
latest_requests: Default::default(), latest_requests: Default::default(),
} }
} }

View file

@ -12,6 +12,7 @@ use ide::{Canceled, FileId};
use ide_db::base_db::VfsPath; use ide_db::base_db::VfsPath;
use lsp_server::{Connection, Notification, Request, Response}; use lsp_server::{Connection, Notification, Request, Response};
use lsp_types::notification::Notification as _; use lsp_types::notification::Notification as _;
use project_model::BuildDataCollector;
use vfs::ChangeKind; use vfs::ChangeKind;
use crate::{ use crate::{
@ -227,8 +228,15 @@ impl GlobalState {
(Progress::Report, Some(msg)) (Progress::Report, Some(msg))
} }
ProjectWorkspaceProgress::End(workspaces) => { ProjectWorkspaceProgress::End(workspaces) => {
self.fetch_workspaces_completed(); self.fetch_workspaces_completed(workspaces);
self.switch_workspaces(workspaces, None); self.switch_workspaces();
if self.config.run_build_scripts() {
let mut collector = BuildDataCollector::default();
for ws in self.workspaces.iter() {
ws.collect_build_data_configs(&mut collector);
}
self.fetch_build_data_request(collector)
}
(Progress::End, None) (Progress::End, None)
} }
}; };
@ -240,11 +248,9 @@ impl GlobalState {
BuildDataProgress::Report(msg) => { BuildDataProgress::Report(msg) => {
(Some(Progress::Report), Some(msg)) (Some(Progress::Report), Some(msg))
} }
BuildDataProgress::End(collector) => { BuildDataProgress::End(build_data_result) => {
self.fetch_build_data_completed(); self.fetch_build_data_completed(build_data_result);
let workspaces = self.switch_workspaces();
(*self.workspaces).clone().into_iter().map(Ok).collect();
self.switch_workspaces(workspaces, Some(collector));
(Some(Progress::End), None) (Some(Progress::End), None)
} }
}; };

View file

@ -139,8 +139,11 @@ impl GlobalState {
sender.send(Task::FetchBuildData(BuildDataProgress::End(res))).unwrap(); sender.send(Task::FetchBuildData(BuildDataProgress::End(res))).unwrap();
}); });
} }
pub(crate) fn fetch_build_data_completed(&mut self) { pub(crate) fn fetch_build_data_completed(
self.fetch_build_data_queue.op_completed(()) &mut self,
build_data: anyhow::Result<BuildDataResult>,
) {
self.fetch_build_data_queue.op_completed(Some(build_data))
} }
pub(crate) fn fetch_workspaces_request(&mut self) { pub(crate) fn fetch_workspaces_request(&mut self) {
@ -194,54 +197,55 @@ impl GlobalState {
} }
}); });
} }
pub(crate) fn fetch_workspaces_completed(&mut self) { pub(crate) fn fetch_workspaces_completed(
self.fetch_workspaces_queue.op_completed(())
}
pub(crate) fn switch_workspaces(
&mut self, &mut self,
workspaces: Vec<anyhow::Result<ProjectWorkspace>>, workspaces: Vec<anyhow::Result<ProjectWorkspace>>,
workspace_build_data: Option<anyhow::Result<BuildDataResult>>,
) { ) {
self.fetch_workspaces_queue.op_completed(workspaces)
}
pub(crate) fn switch_workspaces(&mut self) {
let _p = profile::span("GlobalState::switch_workspaces"); let _p = profile::span("GlobalState::switch_workspaces");
let workspaces = self.fetch_workspaces_queue.last_op_result();
log::info!("will switch workspaces: {:?}", workspaces); log::info!("will switch workspaces: {:?}", workspaces);
let mut has_errors = false; let mut error_message = None;
let workspaces = workspaces let workspaces = workspaces
.into_iter() .iter()
.filter_map(|res| { .filter_map(|res| match res {
res.map_err(|err| { Ok(it) => Some(it.clone()),
has_errors = true; Err(err) => {
log::error!("failed to load workspace: {:#}", err); log::error!("failed to load workspace: {:#}", err);
if self.workspaces.is_empty() { let message = error_message.get_or_insert_with(String::new);
self.show_message( stdx::format_to!(
lsp_types::MessageType::Error, message,
format!("rust-analyzer failed to load workspace: {:#}", err), "rust-analyzer failed to load workspace: {:#}\n",
err
); );
None
} }
}) })
.ok()
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let workspace_build_data = match workspace_build_data { let workspace_build_data = match self.fetch_build_data_queue.last_op_result() {
Some(Ok(it)) => Some(it), Some(Ok(it)) => Some(it.clone()),
None => None,
Some(Err(err)) => { Some(Err(err)) => {
log::error!("failed to fetch build data: {:#}", err); log::error!("failed to fetch build data: {:#}", err);
self.show_message( let message = error_message.get_or_insert_with(String::new);
lsp_types::MessageType::Error, stdx::format_to!(message, "rust-analyzer failed to fetch build data: {:#}\n", err);
format!("rust-analyzer failed to fetch build data: {:#}", err), None
);
return;
} }
None => None,
}; };
if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data { if let Some(error_message) = error_message {
self.show_message(lsp_types::MessageType::Error, error_message);
if !self.workspaces.is_empty() {
return; return;
} }
}
if !self.workspaces.is_empty() && has_errors { if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data {
return; return;
} }
@ -337,14 +341,6 @@ impl GlobalState {
}; };
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);
if self.config.run_build_scripts() && workspace_build_data.is_none() {
let mut collector = BuildDataCollector::default();
for ws in &workspaces {
ws.collect_build_data_configs(&mut collector);
}
self.fetch_build_data_request(collector)
}
self.source_root_config = project_folders.source_root_config; self.source_root_config = project_folders.source_root_config;
self.workspaces = Arc::new(workspaces); self.workspaces = Arc::new(workspaces);
self.workspace_build_data = workspace_build_data; self.workspace_build_data = workspace_build_data;