diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index 89b8631cd2..52f59679b5 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -42,7 +42,7 @@ pub fn load_workspace_at( root: &Path, cargo_config: &CargoConfig, load_config: &LoadCargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option)> { let root = AbsPathBuf::assert_utf8(std::env::current_dir()?.join(root)); let root = ProjectManifest::discover_single(&root)?; diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 1fade7b332..392650e150 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -12,6 +12,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use serde_derive::Deserialize; use serde_json::from_value; use span::Edition; +use stdx::process::spawn_with_streaming_output; use toolchain::Tool; use crate::{CfgOverrides, InvocationStrategy}; @@ -399,11 +400,21 @@ impl CargoWorkspace { // FIXME: Fetching metadata is a slow process, as it might require // calling crates.io. We should be reporting progress here, but it's // unclear whether cargo itself supports it. - progress("metadata".to_owned()); + progress("cargo metadata: started".to_owned()); - (|| -> anyhow::Result<(_, _)> { - let output = meta.cargo_command().output()?; + let res = (|| -> anyhow::Result<(_, _)> { + let mut errored = false; + let output = + spawn_with_streaming_output(meta.cargo_command(), &mut |_| (), &mut |line| { + errored = errored || line.starts_with("error") || line.starts_with("warning"); + if errored { + progress("cargo metadata: ?".to_owned()); + return; + } + progress(format!("cargo metadata: {line}")); + })?; if !output.status.success() { + progress(format!("cargo metadata: failed {}", output.status)); let error = cargo_metadata::Error::CargoMetadata { stderr: String::from_utf8(output.stderr)?, } @@ -431,7 +442,9 @@ impl CargoWorkspace { .ok_or(cargo_metadata::Error::NoJson)?; Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None)) })() - .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command())) + .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command())); + progress("cargo metadata: finished".to_owned()); + res } pub fn new( diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index ebd86e3dc4..29818acd32 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -195,6 +195,7 @@ impl Sysroot { pub fn load_workspace( &self, sysroot_source_config: &RustSourceWorkspaceConfig, + progress: &dyn Fn(String), ) -> Option { assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded"); let Self { root: _, rust_lib_src_root: Some(src_root), workspace: _, error: _ } = self @@ -205,7 +206,7 @@ impl Sysroot { let library_manifest = ManifestPath::try_from(src_root.join("Cargo.toml")).unwrap(); if fs::metadata(&library_manifest).is_ok() { if let Some(loaded) = - self.load_library_via_cargo(library_manifest, src_root, cargo_config) + self.load_library_via_cargo(library_manifest, src_root, cargo_config, progress) { return Some(loaded); } @@ -296,6 +297,7 @@ impl Sysroot { library_manifest: ManifestPath, rust_lib_src_dir: &AbsPathBuf, cargo_config: &CargoMetadataConfig, + progress: &dyn Fn(String), ) -> Option { tracing::debug!("Loading library metadata: {library_manifest}"); let mut cargo_config = cargo_config.clone(); @@ -313,7 +315,7 @@ impl Sysroot { false, // Make sure we never attempt to write to the sysroot true, - &|_| (), + progress, ) { Ok(it) => it, Err(e) => { diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index c69891b746..426aa58137 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -235,7 +235,8 @@ fn smoke_test_real_sysroot_cargo() { AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))), &Default::default(), ); - let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo()); + let loaded_sysroot = + sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &|_| ()); if let Some(loaded_sysroot) = loaded_sysroot { sysroot.set_workspace(loaded_sysroot); } diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index eec0077ea6..9366c0a8b4 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -170,7 +170,7 @@ impl ProjectWorkspace { pub fn load( manifest: ProjectManifest, config: &CargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> anyhow::Result { ProjectWorkspace::load_inner(&manifest, config, progress) .with_context(|| format!("Failed to load the project at {manifest}")) @@ -179,7 +179,7 @@ impl ProjectWorkspace { fn load_inner( manifest: &ProjectManifest, config: &CargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> anyhow::Result { let res = match manifest { ProjectManifest::ProjectJson(project_json) => { @@ -206,7 +206,7 @@ impl ProjectWorkspace { fn load_cargo( cargo_toml: &ManifestPath, config: &CargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> Result { progress("Discovering sysroot".to_owned()); let CargoConfig { @@ -304,7 +304,7 @@ impl ProjectWorkspace { &sysroot, *no_deps, false, - &|_| (), + progress, ) { Ok((meta, _error)) => { let workspace = CargoWorkspace::new( @@ -347,13 +347,16 @@ impl ProjectWorkspace { &sysroot, *no_deps, false, - &|_| (), + progress, ) }); let loaded_sysroot = s.spawn(|| { - sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata( - sysroot_metadata_config(extra_env, &targets), - )) + sysroot.load_workspace( + &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( + extra_env, &targets, + )), + progress, + ) }); let cargo_config_extra_env = s.spawn(|| cargo_config_env(cargo_toml, extra_env, &sysroot)); @@ -411,7 +414,7 @@ impl ProjectWorkspace { pub fn load_inline( mut project_json: ProjectJson, config: &CargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> ProjectWorkspace { progress("Discovering sysroot".to_owned()); let mut sysroot = @@ -443,11 +446,18 @@ impl ProjectWorkspace { }); let loaded_sysroot = s.spawn(|| { if let Some(sysroot_project) = sysroot_project { - sysroot.load_workspace(&RustSourceWorkspaceConfig::Json(*sysroot_project)) + sysroot.load_workspace( + &RustSourceWorkspaceConfig::Json(*sysroot_project), + progress, + ) } else { - sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata( - sysroot_metadata_config(&config.extra_env, &targets), - )) + sysroot.load_workspace( + &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( + &config.extra_env, + &targets, + )), + progress, + ) } }); @@ -497,9 +507,13 @@ impl ProjectWorkspace { .unwrap_or_default(); let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env); let data_layout = target_data_layout::get(query_config, None, &config.extra_env); - let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata( - sysroot_metadata_config(&config.extra_env, &targets), - )); + let loaded_sysroot = sysroot.load_workspace( + &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( + &config.extra_env, + &targets, + )), + &|_| (), + ); if let Some(loaded_sysroot) = loaded_sysroot { sysroot.set_workspace(loaded_sysroot); } diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs index e3b372c914..0e8b9185f6 100644 --- a/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -76,7 +76,8 @@ impl Tester { }; let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env); - let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo()); + let loaded_sysroot = + sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &|_| ()); if let Some(loaded_sysroot) = loaded_sysroot { sysroot.set_workspace(loaded_sysroot); }