feat: Show what cargo metadata is doing in status

This commit is contained in:
Lukas Wirth 2025-06-16 18:05:44 +02:00
parent e2c3647c6a
commit 9dfbd56bb8
6 changed files with 56 additions and 25 deletions

View file

@ -42,7 +42,7 @@ pub fn load_workspace_at(
root: &Path, root: &Path,
cargo_config: &CargoConfig, cargo_config: &CargoConfig,
load_config: &LoadCargoConfig, load_config: &LoadCargoConfig,
progress: &dyn Fn(String), progress: &(dyn Fn(String) + Sync),
) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option<ProcMacroClient>)> { ) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option<ProcMacroClient>)> {
let root = AbsPathBuf::assert_utf8(std::env::current_dir()?.join(root)); let root = AbsPathBuf::assert_utf8(std::env::current_dir()?.join(root));
let root = ProjectManifest::discover_single(&root)?; let root = ProjectManifest::discover_single(&root)?;

View file

@ -12,6 +12,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::from_value; use serde_json::from_value;
use span::Edition; use span::Edition;
use stdx::process::spawn_with_streaming_output;
use toolchain::Tool; use toolchain::Tool;
use crate::{CfgOverrides, InvocationStrategy}; use crate::{CfgOverrides, InvocationStrategy};
@ -399,11 +400,21 @@ impl CargoWorkspace {
// FIXME: Fetching metadata is a slow process, as it might require // FIXME: Fetching metadata is a slow process, as it might require
// calling crates.io. We should be reporting progress here, but it's // calling crates.io. We should be reporting progress here, but it's
// unclear whether cargo itself supports it. // unclear whether cargo itself supports it.
progress("metadata".to_owned()); progress("cargo metadata: started".to_owned());
(|| -> anyhow::Result<(_, _)> { let res = (|| -> anyhow::Result<(_, _)> {
let output = meta.cargo_command().output()?; 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() { if !output.status.success() {
progress(format!("cargo metadata: failed {}", output.status));
let error = cargo_metadata::Error::CargoMetadata { let error = cargo_metadata::Error::CargoMetadata {
stderr: String::from_utf8(output.stderr)?, stderr: String::from_utf8(output.stderr)?,
} }
@ -431,7 +442,9 @@ impl CargoWorkspace {
.ok_or(cargo_metadata::Error::NoJson)?; .ok_or(cargo_metadata::Error::NoJson)?;
Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None)) 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( pub fn new(

View file

@ -195,6 +195,7 @@ impl Sysroot {
pub fn load_workspace( pub fn load_workspace(
&self, &self,
sysroot_source_config: &RustSourceWorkspaceConfig, sysroot_source_config: &RustSourceWorkspaceConfig,
progress: &dyn Fn(String),
) -> Option<RustLibSrcWorkspace> { ) -> Option<RustLibSrcWorkspace> {
assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded"); assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded");
let Self { root: _, rust_lib_src_root: Some(src_root), workspace: _, error: _ } = self 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(); let library_manifest = ManifestPath::try_from(src_root.join("Cargo.toml")).unwrap();
if fs::metadata(&library_manifest).is_ok() { if fs::metadata(&library_manifest).is_ok() {
if let Some(loaded) = 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); return Some(loaded);
} }
@ -296,6 +297,7 @@ impl Sysroot {
library_manifest: ManifestPath, library_manifest: ManifestPath,
rust_lib_src_dir: &AbsPathBuf, rust_lib_src_dir: &AbsPathBuf,
cargo_config: &CargoMetadataConfig, cargo_config: &CargoMetadataConfig,
progress: &dyn Fn(String),
) -> Option<RustLibSrcWorkspace> { ) -> Option<RustLibSrcWorkspace> {
tracing::debug!("Loading library metadata: {library_manifest}"); tracing::debug!("Loading library metadata: {library_manifest}");
let mut cargo_config = cargo_config.clone(); let mut cargo_config = cargo_config.clone();
@ -313,7 +315,7 @@ impl Sysroot {
false, false,
// Make sure we never attempt to write to the sysroot // Make sure we never attempt to write to the sysroot
true, true,
&|_| (), progress,
) { ) {
Ok(it) => it, Ok(it) => it,
Err(e) => { Err(e) => {

View file

@ -235,7 +235,8 @@ fn smoke_test_real_sysroot_cargo() {
AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))), AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
&Default::default(), &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 { if let Some(loaded_sysroot) = loaded_sysroot {
sysroot.set_workspace(loaded_sysroot); sysroot.set_workspace(loaded_sysroot);
} }

View file

@ -170,7 +170,7 @@ impl ProjectWorkspace {
pub fn load( pub fn load(
manifest: ProjectManifest, manifest: ProjectManifest,
config: &CargoConfig, config: &CargoConfig,
progress: &dyn Fn(String), progress: &(dyn Fn(String) + Sync),
) -> anyhow::Result<ProjectWorkspace> { ) -> anyhow::Result<ProjectWorkspace> {
ProjectWorkspace::load_inner(&manifest, config, progress) ProjectWorkspace::load_inner(&manifest, config, progress)
.with_context(|| format!("Failed to load the project at {manifest}")) .with_context(|| format!("Failed to load the project at {manifest}"))
@ -179,7 +179,7 @@ impl ProjectWorkspace {
fn load_inner( fn load_inner(
manifest: &ProjectManifest, manifest: &ProjectManifest,
config: &CargoConfig, config: &CargoConfig,
progress: &dyn Fn(String), progress: &(dyn Fn(String) + Sync),
) -> anyhow::Result<ProjectWorkspace> { ) -> anyhow::Result<ProjectWorkspace> {
let res = match manifest { let res = match manifest {
ProjectManifest::ProjectJson(project_json) => { ProjectManifest::ProjectJson(project_json) => {
@ -206,7 +206,7 @@ impl ProjectWorkspace {
fn load_cargo( fn load_cargo(
cargo_toml: &ManifestPath, cargo_toml: &ManifestPath,
config: &CargoConfig, config: &CargoConfig,
progress: &dyn Fn(String), progress: &(dyn Fn(String) + Sync),
) -> Result<ProjectWorkspace, anyhow::Error> { ) -> Result<ProjectWorkspace, anyhow::Error> {
progress("Discovering sysroot".to_owned()); progress("Discovering sysroot".to_owned());
let CargoConfig { let CargoConfig {
@ -304,7 +304,7 @@ impl ProjectWorkspace {
&sysroot, &sysroot,
*no_deps, *no_deps,
false, false,
&|_| (), progress,
) { ) {
Ok((meta, _error)) => { Ok((meta, _error)) => {
let workspace = CargoWorkspace::new( let workspace = CargoWorkspace::new(
@ -347,13 +347,16 @@ impl ProjectWorkspace {
&sysroot, &sysroot,
*no_deps, *no_deps,
false, false,
&|_| (), progress,
) )
}); });
let loaded_sysroot = s.spawn(|| { let loaded_sysroot = s.spawn(|| {
sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata( sysroot.load_workspace(
sysroot_metadata_config(extra_env, &targets), &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
)) extra_env, &targets,
)),
progress,
)
}); });
let cargo_config_extra_env = let cargo_config_extra_env =
s.spawn(|| cargo_config_env(cargo_toml, extra_env, &sysroot)); s.spawn(|| cargo_config_env(cargo_toml, extra_env, &sysroot));
@ -411,7 +414,7 @@ impl ProjectWorkspace {
pub fn load_inline( pub fn load_inline(
mut project_json: ProjectJson, mut project_json: ProjectJson,
config: &CargoConfig, config: &CargoConfig,
progress: &dyn Fn(String), progress: &(dyn Fn(String) + Sync),
) -> ProjectWorkspace { ) -> ProjectWorkspace {
progress("Discovering sysroot".to_owned()); progress("Discovering sysroot".to_owned());
let mut sysroot = let mut sysroot =
@ -443,11 +446,18 @@ impl ProjectWorkspace {
}); });
let loaded_sysroot = s.spawn(|| { let loaded_sysroot = s.spawn(|| {
if let Some(sysroot_project) = sysroot_project { if let Some(sysroot_project) = sysroot_project {
sysroot.load_workspace(&RustSourceWorkspaceConfig::Json(*sysroot_project)) sysroot.load_workspace(
&RustSourceWorkspaceConfig::Json(*sysroot_project),
progress,
)
} else { } else {
sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata( sysroot.load_workspace(
sysroot_metadata_config(&config.extra_env, &targets), &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
)) &config.extra_env,
&targets,
)),
progress,
)
} }
}); });
@ -497,9 +507,13 @@ impl ProjectWorkspace {
.unwrap_or_default(); .unwrap_or_default();
let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env); 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 data_layout = target_data_layout::get(query_config, None, &config.extra_env);
let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata( let loaded_sysroot = sysroot.load_workspace(
sysroot_metadata_config(&config.extra_env, &targets), &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
)); &config.extra_env,
&targets,
)),
&|_| (),
);
if let Some(loaded_sysroot) = loaded_sysroot { if let Some(loaded_sysroot) = loaded_sysroot {
sysroot.set_workspace(loaded_sysroot); sysroot.set_workspace(loaded_sysroot);
} }

View file

@ -76,7 +76,8 @@ impl Tester {
}; };
let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env); 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 { if let Some(loaded_sysroot) = loaded_sysroot {
sysroot.set_workspace(loaded_sysroot); sysroot.set_workspace(loaded_sysroot);
} }