Cargo.lock 🔗
@@ -15732,6 +15732,7 @@ dependencies = [
"serde_json_lenient",
"sha2",
"shellexpand 2.1.2",
+ "smol",
"util",
"workspace-hack",
"zed_actions",
Cole Miller created
Closes #32688
Release Notes:
- Fixed tasks (including build tasks for debug configurations) silently
using `/` as a working directory when the specified `cwd` didn't exist.
Cargo.lock | 1 +
crates/debugger_ui/src/session/running.rs | 11 ++++++++++-
crates/task/Cargo.toml | 1 +
crates/task/src/task_template.rs | 24 +++++++++++++++++++++++-
crates/terminal_view/src/terminal_panel.rs | 19 ++++++++++++++++++-
crates/workspace/src/workspace.rs | 2 +-
6 files changed, 54 insertions(+), 4 deletions(-)
@@ -15732,6 +15732,7 @@ dependencies = [
"serde_json_lenient",
"sha2",
"shellexpand 2.1.2",
+ "smol",
"util",
"workspace-hack",
"zed_actions",
@@ -850,9 +850,18 @@ impl RunningState {
(task, None)
}
};
- let Some(task) = task_template.resolve_task("debug-build-task", &task_context) else {
+ let Some(task) = task_template.resolve_task_and_check_cwd("debug-build-task", &task_context, cx.background_executor().clone()) else {
anyhow::bail!("Could not resolve task variables within a debug scenario");
};
+ let task = match task.await {
+ Ok(task) => task,
+ Err(e) => {
+ workspace.update(cx, |workspace, cx| {
+ workspace.show_error(&e, cx);
+ }).ok();
+ return Err(e)
+ }
+ };
let locator_name = if let Some(locator_name) = locator_name {
debug_assert!(!config_is_valid);
@@ -29,6 +29,7 @@ serde_json.workspace = true
serde_json_lenient.workspace = true
sha2.workspace = true
shellexpand.workspace = true
+smol.workspace = true
util.workspace = true
workspace-hack.workspace = true
zed_actions.workspace = true
@@ -1,5 +1,6 @@
-use anyhow::{Context as _, bail};
+use anyhow::{Context as _, Result, anyhow, bail};
use collections::{HashMap, HashSet};
+use gpui::{BackgroundExecutor, Task};
use schemars::{JsonSchema, r#gen::SchemaSettings};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
@@ -270,6 +271,27 @@ impl TaskTemplate {
},
})
}
+
+ pub fn resolve_task_and_check_cwd(
+ &self,
+ id_base: &str,
+ task_context: &TaskContext,
+ executor: BackgroundExecutor,
+ ) -> Option<Task<Result<ResolvedTask>>> {
+ let resolved_task = self.resolve_task(id_base, task_context)?;
+ let task = executor.spawn(async move {
+ if let Some(cwd) = resolved_task.resolved.cwd.as_deref() {
+ match smol::fs::metadata(cwd).await {
+ Ok(metadata) if metadata.is_dir() => Ok(resolved_task),
+ Ok(_) => Err(anyhow!("cwd for resolved task is not a directory: {cwd:?}")),
+ Err(e) => Err(e).context(format!("reading cwd of resolved task: {cwd:?}")),
+ }
+ } else {
+ Ok(resolved_task)
+ }
+ });
+ Some(task)
+ }
}
const MAX_DISPLAY_VARIABLE_LENGTH: usize = 15;
@@ -1461,10 +1461,27 @@ impl workspace::TerminalProvider for TerminalProvider {
&self,
task: SpawnInTerminal,
window: &mut Window,
- cx: &mut App,
+ cx: &mut Context<Workspace>,
) -> Task<Option<Result<ExitStatus>>> {
let terminal_panel = self.0.clone();
+ let workspace = cx.weak_entity();
window.spawn(cx, async move |cx| {
+ if let Some(cwd) = task.cwd.as_deref() {
+ let result = match smol::fs::metadata(cwd).await {
+ Ok(metadata) if metadata.is_dir() => Ok(()),
+ Ok(_) => Err(anyhow!("cwd for resolved task is not a directory: {cwd:?}")),
+ Err(e) => Err(e).context(format!("reading cwd of resolved task: {cwd:?}")),
+ };
+ if let Err(e) = result {
+ workspace
+ .update(cx, |workspace, cx| {
+ workspace.show_error(&e, cx);
+ })
+ .ok();
+ return None;
+ }
+ }
+
let terminal = terminal_panel
.update_in(cx, |terminal_panel, window, cx| {
terminal_panel.spawn_task(&task, window, cx)
@@ -135,7 +135,7 @@ pub trait TerminalProvider {
&self,
task: SpawnInTerminal,
window: &mut Window,
- cx: &mut App,
+ cx: &mut Context<Workspace>,
) -> Task<Option<Result<ExitStatus>>>;
}