Merge pull request #21164 from Wilfred/multiple_discover_requests

fix: Allow multiple discover operations
This commit is contained in:
Lukas Wirth 2025-12-03 08:51:11 +00:00 committed by GitHub
commit 95cee9cccf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 69 additions and 30 deletions

View file

@ -197,4 +197,22 @@ impl<T: Sized + Send + 'static> CommandHandle<T> {
)))
}
}
pub(crate) fn has_exited(&mut self) -> bool {
match self.child.0.try_wait() {
Ok(Some(_exit_code)) => {
// We have an exit code.
true
}
Ok(None) => {
// Hasn't exited yet.
false
}
Err(_) => {
// Couldn't get an exit code. Assume that we've
// exited.
true
}
}
}
}

View file

@ -67,7 +67,7 @@ impl DiscoverCommand {
cmd.args(args);
Ok(DiscoverHandle {
_handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?,
handle: CommandHandle::spawn(cmd, DiscoverProjectParser, self.sender.clone(), None)?,
span: info_span!("discover_command").entered(),
})
}
@ -76,7 +76,7 @@ impl DiscoverCommand {
/// A handle to a spawned [Discover].
#[derive(Debug)]
pub(crate) struct DiscoverHandle {
_handle: CommandHandle<DiscoverProjectMessage>,
pub(crate) handle: CommandHandle<DiscoverProjectMessage>,
#[allow(dead_code)] // not accessed, but used to log on drop.
span: EnteredSpan,
}

View file

@ -121,9 +121,10 @@ pub(crate) struct GlobalState {
pub(crate) test_run_remaining_jobs: usize,
// Project loading
pub(crate) discover_handle: Option<discover::DiscoverHandle>,
pub(crate) discover_handles: Vec<discover::DiscoverHandle>,
pub(crate) discover_sender: Sender<discover::DiscoverProjectMessage>,
pub(crate) discover_receiver: Receiver<discover::DiscoverProjectMessage>,
pub(crate) discover_jobs_active: u32,
// Debouncing channel for fetching the workspace
// we want to delay it until the VFS looks stable-ish (and thus is not currently in the middle
@ -175,7 +176,6 @@ pub(crate) struct GlobalState {
pub(crate) fetch_build_data_queue: OpQueue<(), FetchBuildDataResponse>,
pub(crate) fetch_proc_macros_queue: OpQueue<(ChangeWithProcMacros, Vec<ProcMacroPaths>), bool>,
pub(crate) prime_caches_queue: OpQueue,
pub(crate) discover_workspace_queue: OpQueue,
/// A deferred task queue.
///
@ -292,9 +292,10 @@ impl GlobalState {
test_run_receiver,
test_run_remaining_jobs: 0,
discover_handle: None,
discover_handles: vec![],
discover_sender,
discover_receiver,
discover_jobs_active: 0,
fetch_ws_receiver: None,
@ -313,7 +314,6 @@ impl GlobalState {
fetch_proc_macros_queue: OpQueue::default(),
prime_caches_queue: OpQueue::default(),
discover_workspace_queue: OpQueue::default(),
deferred_task_queue,
incomplete_crate_graph: false,

View file

@ -531,6 +531,8 @@ impl GlobalState {
}
}
self.cleanup_discover_handles();
if let Some(diagnostic_changes) = self.diagnostics.take_changes() {
for file_id in diagnostic_changes {
let uri = file_id_to_url(&self.vfs.read().0, file_id);
@ -806,33 +808,34 @@ impl GlobalState {
self.report_progress("Fetching", state, msg, None, None);
}
Task::DiscoverLinkedProjects(arg) => {
if let Some(cfg) = self.config.discover_workspace_config()
&& !self.discover_workspace_queue.op_in_progress()
{
if let Some(cfg) = self.config.discover_workspace_config() {
// the clone is unfortunately necessary to avoid a borrowck error when
// `self.report_progress` is called later
let title = &cfg.progress_label.clone();
let command = cfg.command.clone();
let discover = DiscoverCommand::new(self.discover_sender.clone(), command);
self.report_progress(title, Progress::Begin, None, None, None);
self.discover_workspace_queue
.request_op("Discovering workspace".to_owned(), ());
let _ = self.discover_workspace_queue.should_start_op();
if self.discover_jobs_active == 0 {
self.report_progress(title, Progress::Begin, None, None, None);
}
self.discover_jobs_active += 1;
let arg = match arg {
DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it),
DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
};
let handle = discover.spawn(
arg,
&std::env::current_dir()
.expect("Failed to get cwd during project discovery"),
);
self.discover_handle = Some(handle.unwrap_or_else(|e| {
panic!("Failed to spawn project discovery command: {e}")
}));
let handle = discover
.spawn(
arg,
&std::env::current_dir()
.expect("Failed to get cwd during project discovery"),
)
.unwrap_or_else(|e| {
panic!("Failed to spawn project discovery command: {e}")
});
self.discover_handles.push(handle);
}
}
Task::FetchBuildData(progress) => {
@ -1036,27 +1039,45 @@ impl GlobalState {
.expect("No title could be found; this is a bug");
match message {
DiscoverProjectMessage::Finished { project, buildfile } => {
self.discover_handle = None;
self.report_progress(&title, Progress::End, None, None, None);
self.discover_workspace_queue.op_completed(());
self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1);
if self.discover_jobs_active == 0 {
self.report_progress(&title, Progress::End, None, None, None);
}
let mut config = Config::clone(&*self.config);
config.add_discovered_project_from_command(project, buildfile);
self.update_configuration(config);
}
DiscoverProjectMessage::Progress { message } => {
self.report_progress(&title, Progress::Report, Some(message), None, None)
if self.discover_jobs_active > 0 {
self.report_progress(&title, Progress::Report, Some(message), None, None)
}
}
DiscoverProjectMessage::Error { error, source } => {
self.discover_handle = None;
let message = format!("Project discovery failed: {error}");
self.discover_workspace_queue.op_completed(());
self.show_and_log_error(message.clone(), source);
self.report_progress(&title, Progress::End, Some(message), None, None)
self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1);
if self.discover_jobs_active == 0 {
self.report_progress(&title, Progress::End, Some(message), None, None)
}
}
}
}
/// Drop any discover command processes that have exited, due to
/// finishing or erroring.
fn cleanup_discover_handles(&mut self) {
let mut active_handles = vec![];
for mut discover_handle in self.discover_handles.drain(..) {
if !discover_handle.handle.has_exited() {
active_handles.push(discover_handle);
}
}
self.discover_handles = active_handles;
}
fn handle_cargo_test_msg(&mut self, message: CargoTestMessage) {
match message.output {
CargoTestOutput::Test { name, state } => {

View file

@ -74,7 +74,7 @@ impl GlobalState {
&& !self.fetch_workspaces_queue.op_in_progress()
&& !self.fetch_build_data_queue.op_in_progress()
&& !self.fetch_proc_macros_queue.op_in_progress()
&& !self.discover_workspace_queue.op_in_progress()
&& self.discover_jobs_active == 0
&& self.vfs_progress_config_version >= self.vfs_config_version
}
@ -297,7 +297,7 @@ impl GlobalState {
.collect();
let cargo_config = self.config.cargo(None);
let discover_command = self.config.discover_workspace_config().cloned();
let is_quiescent = !(self.discover_workspace_queue.op_in_progress()
let is_quiescent = !(self.discover_jobs_active > 0
|| self.vfs_progress_config_version < self.vfs_config_version
|| !self.vfs_done);