Maintain/Run/
Process.rs

1//=============================================================================//
2// File Path: Element/Maintain/Source/Run/Process.rs
3//=============================================================================//
4// Module: Process
5//
6// Brief Description: Process management for run operations.
7//
8// RESPONSIBILITIES:
9// ================
10//
11// Primary:
12// - Start and manage the development run process
13// - Handle hot-reload and watch mode
14// - Manage process lifecycle
15//
16// Secondary:
17// - Provide process status reporting
18// - Handle graceful shutdown
19//
20// ARCHITECTURAL ROLE:
21// ===================
22//
23// Position:
24// - Infrastructure/Process management layer
25// - Process orchestration
26//
27// Dependencies (What this module requires):
28// - External crates: log, std
29// - Internal modules: Definition, Environment, Logger, Error
30// - Traits implemented: None
31//
32// Dependents (What depends on this module):
33// - Run entry point (Fn)
34//
35//=============================================================================//
36// IMPLEMENTATION
37//=============================================================================//
38
39use crate::Run::Definition::{Argument, RunConfig};
40use crate::Run::Environment;
41use crate::Run::Logger::{log_run_start, log_run_complete, log_hot_reload_status, log_watch_status};
42use crate::Run::Error::{Error, Result};
43
44use log::{debug, error, info};
45use std::process::{Command, Stdio};
46
47/// Executes the run process with the provided configuration.
48///
49/// This function orchestrates the development run, including:
50/// 1. Setting up the environment
51/// 2. Starting the development server
52/// 3. Managing hot-reload and watch mode
53/// 4. Handling process lifecycle
54///
55/// # Arguments
56///
57/// * `arg` - The parsed command-line arguments
58///
59/// # Returns
60///
61/// Result indicating success or failure
62pub fn Process(arg: &Argument) -> Result<()> {
63    // Resolve environment variables
64    let env_vars = crate::Run::Environment::resolve(
65        &crate::Run::Definition::Profile {
66            name: arg.Profile.clone(),
67            description: None,
68            workbench: arg.Workbench.clone(),
69            env: None,
70            run_config: None,
71        },
72        true, // merge_shell
73        &arg.env_override,
74    )?;
75
76    // Validate environment
77    let validation_errors = Environment::validate(&env_vars);
78    if !validation_errors.is_empty() {
79        for err in validation_errors {
80            error!("Environment validation: {}", err);
81        }
82        return Err(Error::InvalidConfig("Environment validation failed".to_string()));
83    }
84
85    // Create run configuration
86    let config = RunConfig::new(arg, env_vars.clone());
87
88    // Log run header
89    log_run_header(&config);
90
91    // Log hot-reload and watch status
92    log_hot_reload_status(config.hot_reload, config.live_reload_port);
93    log_watch_status(config.watch);
94
95    // Dry run mode
96    if arg.DryRun {
97        info!("Dry run mode - showing configuration without executing");
98        debug!("Configuration: {:?}", config);
99        return Ok(());
100    }
101
102    // Determine the run command
103    let command = determine_run_command(&config);
104
105    // Start the run process
106    execute_run(&command, &env_vars)
107}
108
109/// Logs the run header.
110///
111/// # Arguments
112///
113/// * `config` - The run configuration
114fn log_run_header(config: &RunConfig) {
115    info!("========================================");
116    info!("Land Run: {}", config.profile_name);
117    info!("========================================");
118
119    if let Some(workbench) = config.get_workbench() {
120        info!("Workbench: {}", workbench);
121    }
122
123    info!("Hot-reload: {}", if config.hot_reload { "enabled" } else { "disabled" });
124    info!("Watch mode: {}", if config.watch { "enabled" } else { "disabled" });
125}
126
127/// Determines the run command based on configuration.
128///
129/// # Arguments
130///
131/// * `config` - The run configuration
132///
133/// # Returns
134///
135/// A vector of command arguments
136fn determine_run_command(config: &RunConfig) -> Vec<String> {
137    // If custom command is provided, use it
138    if !config.command.is_empty() {
139        return config.command.clone();
140    }
141
142    // Default to pnpm tauri dev for debug profiles
143    if config.is_debug() {
144        vec!["pnpm".to_string(), "tauri".to_string(), "dev".to_string()]
145    } else {
146        vec!["pnpm".to_string(), "dev".to_string()]
147    }
148}
149
150/// Executes the run command.
151///
152/// # Arguments
153///
154/// * `command` - The command to execute
155/// * `env_vars` - Environment variables to set
156///
157/// # Returns
158///
159/// Result indicating success or failure
160fn execute_run(command: &[String], env_vars: &std::collections::HashMap<String, String>) -> Result<()> {
161    if command.is_empty() {
162        return Err(Error::ProcessStart("Empty command".to_string()));
163    }
164
165    let (program, args) = command.split_first().unwrap();
166
167    log_run_start(&command.join(" "));
168
169    debug!("Executing: {} {:?}", program, args);
170
171    let mut cmd = Command::new(program);
172    cmd.args(args);
173    cmd.stdin(Stdio::inherit());
174    cmd.stdout(Stdio::inherit());
175    cmd.stderr(Stdio::inherit());
176
177    // Set all environment variables
178    for (key, value) in env_vars {
179        cmd.env(key, value);
180    }
181
182    // Set run mode indicators
183    cmd.env("MAINTAIN_RUN_MODE", "true");
184
185    // Execute the command
186    let status = cmd.status()
187        .map_err(|e| Error::ProcessStart(format!("Failed to start {}: {}", program, e)))?;
188
189    if status.success() {
190        log_run_complete(true);
191        Ok(())
192    } else {
193        let code = status.code().unwrap_or(-1);
194        log_run_complete(false);
195        Err(Error::ProcessExit(code))
196    }
197}
198
199/// Starts a hot-reload watcher.
200///
201/// # Arguments
202///
203/// * `watch_dirs` - Directories to watch
204/// * `callback` - Function to call on file changes
205///
206/// # Returns
207///
208/// Result indicating success or failure
209#[allow(dead_code)]
210fn start_hot_reload_watcher(
211    watch_dirs: &[String],
212    _callback: impl Fn() + Send + 'static,
213) -> Result<()> {
214    // Placeholder for hot-reload watcher implementation
215    // In a full implementation, this would use the `notify` crate
216    // to watch for file changes and trigger reloads
217
218    info!("Hot-reload watcher would watch: {:?}", watch_dirs);
219    
220    Ok(())
221}
222
223/// Gracefully shuts down the run process.
224///
225/// This function handles cleanup and graceful termination
226/// of any child processes.
227pub fn shutdown() {
228    info!("Shutting down run process...");
229    // Cleanup logic would go here
230}