From 2b2d699b35d69375def80fe51c6a8c3bfbe53828 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Fri, 8 Jan 2021 01:08:46 +0800 Subject: [PATCH] Report progress for cargo metadata and output-dir --- crates/project_model/src/cargo_workspace.rs | 26 ++++++++++++---- crates/project_model/src/workspace.rs | 22 ++++++++----- crates/rust-analyzer/src/cli/load_cargo.rs | 1 + crates/rust-analyzer/src/main_loop.rs | 12 ++++++++ crates/rust-analyzer/src/reload.rs | 34 ++++++++++++++++++--- 5 files changed, 77 insertions(+), 18 deletions(-) diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index 0e667954244..2ee4e88b2e0 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs @@ -3,9 +3,10 @@ use std::{ convert::TryInto, ffi::OsStr, + io::BufReader, ops, path::{Path, PathBuf}, - process::Command, + process::{Command, Stdio}, }; use anyhow::{Context, Result}; @@ -15,6 +16,7 @@ use itertools::Itertools; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; +use stdx::JodChild; use crate::cfg_flag::CfgFlag; use crate::utf8_stdout; @@ -171,6 +173,7 @@ impl CargoWorkspace { pub fn from_cargo_metadata( cargo_toml: &AbsPath, config: &CargoConfig, + progress: &dyn Fn(String), ) -> Result { let mut meta = MetadataCommand::new(); meta.cargo_path(toolchain::cargo()); @@ -220,6 +223,9 @@ pub fn from_cargo_metadata( meta.other_options(vec![String::from("--filter-platform"), target]); } + // FIXME: Currently MetadataCommand is not based on parse_stream, + // So we just report it as a whole + progress("metadata".to_string()); let mut meta = meta.exec().with_context(|| { let cwd: Option = std::env::current_dir().ok().and_then(|p| p.try_into().ok()); @@ -243,7 +249,7 @@ pub fn from_cargo_metadata( let mut envs = FxHashMap::default(); let mut proc_macro_dylib_paths = FxHashMap::default(); if config.load_out_dirs_from_check { - let resources = load_extern_resources(cargo_toml, config)?; + let resources = load_extern_resources(cargo_toml, config, progress)?; out_dir_by_id = resources.out_dirs; cfgs = resources.cfgs; envs = resources.env; @@ -368,6 +374,7 @@ pub(crate) struct ExternResources { pub(crate) fn load_extern_resources( cargo_toml: &Path, cargo_features: &CargoConfig, + progress: &dyn Fn(String), ) -> Result { let mut cmd = Command::new(toolchain::cargo()); cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); @@ -395,11 +402,14 @@ pub(crate) fn load_extern_resources( } } - let output = cmd.output()?; + cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); + + let mut child = cmd.spawn().map(JodChild)?; + let child_stdout = child.stdout.take().unwrap(); + let stdout = BufReader::new(child_stdout); let mut res = ExternResources::default(); - - for message in cargo_metadata::Message::parse_stream(output.stdout.as_slice()) { + for message in cargo_metadata::Message::parse_stream(stdout) { if let Ok(message) = message { match message { Message::BuildScriptExecuted(BuildScript { @@ -432,6 +442,8 @@ pub(crate) fn load_extern_resources( res.env.insert(package_id, env); } Message::CompilerArtifact(message) => { + progress(format!("metadata {}", message.target.name)); + if message.target.kind.contains(&"proc-macro".to_string()) { let package_id = message.package_id; // Skip rmeta file @@ -442,7 +454,9 @@ pub(crate) fn load_extern_resources( } } } - Message::CompilerMessage(_) => (), + Message::CompilerMessage(message) => { + progress(message.target.name.clone()); + } Message::Unknown => (), Message::BuildFinished(_) => {} Message::TextLine(_) => {} diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index 68a235ce3c3..06a0be284a0 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs @@ -64,7 +64,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } impl ProjectWorkspace { - pub fn load(manifest: ProjectManifest, config: &CargoConfig) -> Result { + pub fn load( + manifest: ProjectManifest, + config: &CargoConfig, + progress: &dyn Fn(String), + ) -> Result { let res = match manifest { ProjectManifest::ProjectJson(project_json) => { let file = fs::read_to_string(&project_json).with_context(|| { @@ -84,15 +88,14 @@ pub fn load(manifest: ProjectManifest, config: &CargoConfig) -> Result Result)>), Workspaces(Vec>), PrimeCaches(PrimeCachesProgress), + FetchWorkspace(ProjectWorkspaceProgress), } impl fmt::Debug for Event { @@ -216,6 +218,16 @@ fn handle_event(&mut self, event: Event) -> Result<()> { } PrimeCachesProgress::Finished => prime_caches_progress.push(progress), }, + Task::FetchWorkspace(progress) => { + let (state, msg) = match progress { + ProjectWorkspaceProgress::Begin => (Progress::Begin, None), + ProjectWorkspaceProgress::Report(msg) => { + (Progress::Report, Some(msg)) + } + ProjectWorkspaceProgress::End => (Progress::End, None), + }; + self.report_progress("fetching", state, msg, None); + } } // Coalesce multiple task events into one loop turn task = match self.task_pool.receiver.try_recv() { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 76b50931ad6..f4e084741b6 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -15,6 +15,13 @@ }; use lsp_ext::StatusParams; +#[derive(Debug)] +pub(crate) enum ProjectWorkspaceProgress { + Begin, + Report(String), + End, +} + impl GlobalState { pub(crate) fn update_configuration(&mut self, config: Config) { let _p = profile::span("GlobalState::update_configuration"); @@ -93,23 +100,42 @@ pub(crate) fn transition(&mut self, new_status: Status) { } pub(crate) fn fetch_workspaces(&mut self) { log::info!("will fetch workspaces"); - self.task_pool.handle.spawn({ + + self.task_pool.handle.spawn_with_sender({ let linked_projects = self.config.linked_projects(); let cargo_config = self.config.cargo(); - move || { + + move |sender| { + let progress = { + let sender = sender.clone(); + move |msg| { + sender + .send(Task::FetchWorkspace(ProjectWorkspaceProgress::Report(msg))) + .unwrap() + } + }; + + sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::Begin)).unwrap(); + let workspaces = linked_projects .iter() .map(|project| match project { LinkedProject::ProjectManifest(manifest) => { - project_model::ProjectWorkspace::load(manifest.clone(), &cargo_config) + project_model::ProjectWorkspace::load( + manifest.clone(), + &cargo_config, + &progress, + ) } LinkedProject::InlineJsonProject(it) => { project_model::ProjectWorkspace::load_inline(it.clone()) } }) .collect::>(); + + sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::End)).unwrap(); log::info!("did fetch workspaces {:?}", workspaces); - Task::Workspaces(workspaces) + sender.send(Task::Workspaces(workspaces)).unwrap() } }); }