Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions src/cortex-cli/src/dag_cmd/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ use crate::styled_output::print_info;

use super::types::TaskExecutionResult;

fn shell_invocation() -> (&'static str, &'static str) {
if cfg!(windows) {
("cmd.exe", "/C")
} else {
("sh", "-c")
}
}

/// Task executor that runs the actual task commands.
pub struct TaskExecutor {
timeout: Duration,
Expand All @@ -33,6 +41,11 @@ impl TaskExecutor {
.get("command")
.and_then(|v| v.as_str())
.map(String::from);
let working_dir = task
.metadata
.get("working_dir")
.and_then(|v| v.as_str())
.map(String::from);

if self.verbose {
if let Some(ref cmd) = command {
Expand All @@ -47,7 +60,7 @@ impl TaskExecutor {

// If there's a command, execute it
let (status, output, error) = if let Some(cmd) = command {
match self.run_command(&cmd).await {
match self.run_command(&cmd, working_dir.as_deref()).await {
Ok(output) => (TaskStatus::Completed, Some(output), None),
Err(e) => (TaskStatus::Failed, None, Some(e.to_string())),
}
Expand All @@ -72,13 +85,19 @@ impl TaskExecutor {
}

/// Run a shell command with timeout.
async fn run_command(&self, cmd: &str) -> Result<String> {
async fn run_command(&self, cmd: &str, working_dir: Option<&str>) -> Result<String> {
let timeout_duration = self.timeout;

let result = tokio::time::timeout(timeout_duration, async {
let output = tokio::process::Command::new("sh")
.arg("-c")
.arg(cmd)
let (shell, shell_arg) = shell_invocation();
let mut command = tokio::process::Command::new(shell);
command.arg(shell_arg).arg(cmd);

if let Some(dir) = working_dir {
command.current_dir(dir);
}

let output = command
.output()
.await
.context("Failed to execute command")?;
Expand Down
4 changes: 4 additions & 0 deletions src/cortex-cli/src/dag_cmd/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ pub fn convert_specs(input: &DagSpecInput) -> Vec<TaskSpec> {
spec = spec.with_metadata("command", serde_json::json!(cmd));
}

if let Some(working_dir) = &t.working_dir {
spec = spec.with_metadata("working_dir", serde_json::json!(working_dir));
}

for (key, value) in &t.metadata {
spec = spec.with_metadata(key, value.clone());
}
Expand Down
2 changes: 2 additions & 0 deletions src/cortex-cli/src/dag_cmd/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fn test_convert_specs() {
name: "a".to_string(),
description: "Task A".to_string(),
command: Some("echo A".to_string()),
working_dir: None,
depends_on: vec![],
affected_files: vec![],
priority: 10,
Expand All @@ -51,6 +52,7 @@ fn test_convert_specs() {
name: "b".to_string(),
description: "Task B".to_string(),
command: None,
working_dir: None,
depends_on: vec!["a".to_string()],
affected_files: vec!["file.txt".to_string()],
priority: 5,
Expand Down
3 changes: 3 additions & 0 deletions src/cortex-cli/src/dag_cmd/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ pub struct TaskSpecInput {
/// Command to execute (optional).
#[serde(default)]
pub command: Option<String>,
/// Working directory for command execution.
#[serde(default)]
pub working_dir: Option<String>,
/// Task dependencies (names of tasks).
#[serde(default)]
pub depends_on: Vec<String>,
Expand Down