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