From 2b2d699b35d69375def80fe51c6a8c3bfbe53828 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Fri, 8 Jan 2021 01:08:46 +0800 Subject: 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 0e6679542..2ee4e88b2 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 cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId} 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 @@ impl CargoWorkspace { 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 @@ impl CargoWorkspace { 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 res = ExternResources::default(); + let mut child = cmd.spawn().map(JodChild)?; + let child_stdout = child.stdout.take().unwrap(); + let stdout = BufReader::new(child_stdout); - for message in cargo_metadata::Message::parse_stream(output.stdout.as_slice()) { + let mut res = ExternResources::default(); + 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 68a235ce3..06a0be284 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs @@ -64,7 +64,11 @@ impl fmt::Debug for ProjectWorkspace { } 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 @@ impl ProjectWorkspace { cmd })?; - let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config).with_context( - || { + let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config, progress) + .with_context(|| { format!( "Failed to read Cargo metadata from Cargo.toml file {}, {}", cargo_toml.display(), cargo_version ) - }, - )?; + })?; let sysroot = if config.no_sysroot { Sysroot::default() } else { @@ -105,9 +108,12 @@ impl ProjectWorkspace { }; let rustc = if let Some(rustc_dir) = &config.rustc_source { - Some(CargoWorkspace::from_cargo_metadata(&rustc_dir, config).with_context( - || format!("Failed to read Cargo metadata for Rust sources"), - )?) + Some( + CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress) + .with_context(|| { + format!("Failed to read Cargo metadata for Rust sources") + })?, + ) } else { None }; diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index e5ab6c73b..31a16ca46 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -21,6 +21,7 @@ pub fn load_cargo( let ws = ProjectWorkspace::load( root, &CargoConfig { load_out_dirs_from_check, ..Default::default() }, + &|_| {}, )?; let (sender, receiver) = unbounded(); diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 7ac6acf70..22ee96775 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -22,6 +22,7 @@ use crate::{ global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, handlers, lsp_ext, lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, + reload::ProjectWorkspaceProgress, Result, }; @@ -63,6 +64,7 @@ pub(crate) enum Task { Diagnostics(Vec<(FileId, Vec)>), Workspaces(Vec>), PrimeCaches(PrimeCachesProgress), + FetchWorkspace(ProjectWorkspaceProgress), } impl fmt::Debug for Event { @@ -216,6 +218,16 @@ impl GlobalState { } 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 76b50931a..f4e084741 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -15,6 +15,13 @@ use crate::{ }; 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 @@ impl GlobalState { } 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() } }); } -- cgit v1.2.3