Skip to main content

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 std::process::{Command, Stdio};
40
41use log::{debug, error, info};
42
43use crate::Run::{
44	Definition::{Argument, RunConfig},
45	Environment,
46	Error::{Error, Result},
47	Logger::{LogHotReloadStatus, LogRunComplete, LogRunStart, LogWatchStatus},
48};
49
50/// Executes the run process with the provided configuration.
51///
52/// This function orchestrates the development run, including:
53/// 1. Setting up the environment
54/// 2. Starting the development server
55/// 3. Managing hot-reload and watch mode
56/// 4. Handling process lifecycle
57///
58/// # Arguments
59///
60/// * `arg` - The parsed command-line arguments
61///
62/// # Returns
63///
64/// Result indicating success or failure
65pub fn Process(Arg:&Argument) -> Result<()> {
66	// Resolve environment variables
67	let EnvVars = crate::Run::Environment::Resolve(
68		&crate::Run::Definition::Profile {
69			name:Arg.Profile.clone(),
70			description:None,
71			workbench:Arg.Workbench.clone(),
72			env:None,
73			run_config:None,
74		},
75		true, // merge_shell
76		&Arg.env_override,
77	)?;
78
79	// Validate environment
80	let ValidationErrors = Environment::Validate(&EnvVars);
81
82	if !ValidationErrors.is_empty() {
83		for Error in ValidationErrors {
84			error!("Environment validation: {}", Error);
85		}
86
87		return Err(Error::InvalidConfig("Environment validation failed".to_string()));
88	}
89
90	// Create run configuration
91	let Config = RunConfig::new(Arg, EnvVars.clone());
92
93	// Log run header
94	LogRunHeader(&Config);
95
96	// Log hot-reload and watch status
97	LogHotReloadStatus(Config.hot_reload, Config.live_reload_port);
98
99	LogWatchStatus(Config.watch);
100
101	// Dry run mode
102	if Arg.DryRun {
103		info!("Dry run mode - showing configuration without executing");
104
105		debug!("Configuration: {:?}", Config);
106
107		return Ok(());
108	}
109
110	// Determine the run command
111	let Command = DetermineRunCommand(&Config);
112
113	// Start the run process
114	ExecuteRun(&Command, &EnvVars)
115}
116
117/// Logs the run header.
118///
119/// # Arguments
120///
121/// * `config` - The run configuration
122fn LogRunHeader(config:&RunConfig) {
123	info!("========================================");
124
125	info!("Land Run: {}", config.profile_name);
126
127	info!("========================================");
128
129	if let Some(Workbench) = config.get_workbench() {
130		info!("Workbench: {}", Workbench);
131	}
132
133	info!("Hot-reload: {}", if config.hot_reload { "enabled" } else { "disabled" });
134
135	info!("Watch mode: {}", if config.watch { "enabled" } else { "disabled" });
136}
137
138/// Determines the run command based on configuration.
139///
140/// # Arguments
141///
142/// * `config` - The run configuration
143///
144/// # Returns
145///
146/// A vector of command arguments
147fn DetermineRunCommand(config:&RunConfig) -> Vec<String> {
148	// If custom command is provided, use it
149	if !config.command.is_empty() {
150		return config.command.clone();
151	}
152
153	// Default to pnpm tauri dev for debug profiles
154	if config.is_debug() {
155		vec!["pnpm".to_string(), "tauri".to_string(), "dev".to_string()]
156	} else {
157		vec!["pnpm".to_string(), "dev".to_string()]
158	}
159}
160
161/// Executes the run command.
162///
163/// # Arguments
164///
165/// * `command` - The command to execute
166/// * `env_vars` - Environment variables to set
167///
168/// # Returns
169///
170/// Result indicating success or failure
171fn ExecuteRun(Command:&[String], EnvVars:&std::collections::HashMap<String, String>) -> Result<()> {
172	if Command.is_empty() {
173		return Err(Error::ProcessStart("Empty command".to_string()));
174	}
175
176	let (Program, Args) = Command.split_first().unwrap();
177
178	LogRunStart(&Command.join(" "));
179
180	debug!("Executing: {} {:?}", Program, Args);
181
182	let mut Cmd = Command::new(Program);
183
184	Cmd.args(Args);
185
186	Cmd.stdin(Stdio::inherit());
187
188	Cmd.stdout(Stdio::inherit());
189
190	Cmd.stderr(Stdio::inherit());
191
192	// Set all environment variables
193	for (Key, Value) in EnvVars {
194		Cmd.env(Key, Value);
195	}
196
197	// Set run mode indicators
198	Cmd.env("MAINTAIN_RUN_MODE", "true");
199
200	// Execute the command
201	let Status = Cmd
202		.status()
203		.map_err(|Error| Error::ProcessStart(format!("Failed to start {}: {}", Program, Error)))?;
204
205	if Status.success() {
206		LogRunComplete(true);
207
208		Ok(())
209	} else {
210		let Code = Status.code().unwrap_or(-1);
211
212		LogRunComplete(false);
213
214		Err(Error::ProcessExit(Code))
215	}
216}
217
218/// Starts a hot-reload watcher.
219///
220/// # Arguments
221///
222/// * `watch_dirs` - Directories to watch
223/// * `callback` - Function to call on file changes
224///
225/// # Returns
226///
227/// Result indicating success or failure
228#[allow(dead_code)]
229fn start_hot_reload_watcher(watch_dirs:&[String], _callback:impl Fn() + Send + 'static) -> Result<()> {
230	// Placeholder for hot-reload watcher implementation
231	// In a full implementation, this would use the `notify` crate
232	// to watch for file changes and trigger reloads
233
234	info!("Hot-reload watcher would watch: {:?}", watch_dirs);
235
236	Ok(())
237}
238
239/// Gracefully shuts down the run process.
240///
241/// This function handles cleanup and graceful termination
242/// of any child processes.
243pub fn shutdown() {
244	info!("Shutting down run process...");
245
246	// Cleanup logic would go here
247}