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}