Skip to main content

actr_cli/commands/
run.rs

1//! Run command implementation
2
3use crate::commands::Command;
4use crate::error::{ActrCliError, Result};
5use crate::utils::{execute_command_streaming, is_actr_project, warn_if_not_actr_project};
6use actr_config::ConfigParser;
7use async_trait::async_trait;
8use clap::Args;
9use tracing::info;
10
11#[derive(Args)]
12pub struct RunCommand {
13    /// Script name to run (defaults to "run")
14    pub script_name: Option<String>,
15}
16
17#[async_trait]
18impl Command for RunCommand {
19    async fn execute(&self) -> Result<()> {
20        info!("🚀 Running Actor-RTC project");
21
22        // Check that we're in an Actor-RTC project
23        warn_if_not_actr_project();
24
25        let _project_root = std::env::current_dir()?;
26
27        // Load configuration if available
28        let config = if is_actr_project() {
29            Some(ConfigParser::from_file("Actr.toml")?)
30        } else {
31            None
32        };
33
34        // Get script command from configuration
35        let script_name = self.script_name.as_deref().unwrap_or("run");
36
37        let Some(ref config) = config else {
38            return Err(ActrCliError::command_error(
39                "No Actr.toml found. Run 'actr init' to create a project.".to_string(),
40            ));
41        };
42
43        let available_scripts = config.list_scripts();
44
45        let Some(command) = config.get_script(script_name) else {
46            if available_scripts.is_empty() {
47                return Err(ActrCliError::command_error(
48                    "No scripts defined in Actr.toml. Add a [scripts] section.".to_string(),
49                ));
50            }
51            return Err(ActrCliError::command_error(format!(
52                "Script '{}' not found. Available scripts: {}",
53                script_name,
54                available_scripts.join(", ")
55            )));
56        };
57
58        info!("📜 Executing script '{}': {}", script_name, command);
59
60        // Execute the script command
61        self.run_script_command(command).await?;
62
63        Ok(())
64    }
65}
66
67impl RunCommand {
68    async fn run_script_command(&self, command: &str) -> Result<()> {
69        // Parse command into program and args
70        let parts: Vec<&str> = command.split_whitespace().collect();
71        if parts.is_empty() {
72            return Err(ActrCliError::command_error("Empty command".to_string()));
73        }
74
75        let program = parts[0];
76        let args = parts[1..].to_vec();
77
78        info!("▶️  Executing: {} {}", program, args.join(" "));
79
80        // Execute the command
81        execute_command_streaming(program, &args, None).await
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88
89    #[test]
90    fn test_script_name_default() {
91        let cmd = RunCommand { script_name: None };
92
93        let script_name = cmd.script_name.as_deref().unwrap_or("run");
94        assert_eq!(script_name, "run");
95    }
96
97    #[test]
98    fn test_script_name_custom() {
99        let cmd = RunCommand {
100            script_name: Some("test".to_string()),
101        };
102
103        let script_name = cmd.script_name.as_deref().unwrap_or("run");
104        assert_eq!(script_name, "test");
105    }
106}