1use 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
50pub fn Process(Arg:&Argument) -> Result<()> {
66 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, &Arg.env_override,
77 )?;
78
79 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 let Config = RunConfig::new(Arg, EnvVars.clone());
92
93 LogRunHeader(&Config);
95
96 LogHotReloadStatus(Config.hot_reload, Config.live_reload_port);
98
99 LogWatchStatus(Config.watch);
100
101 if Arg.DryRun {
103 info!("Dry run mode - showing configuration without executing");
104
105 debug!("Configuration: {:?}", Config);
106
107 return Ok(());
108 }
109
110 let Command = DetermineRunCommand(&Config);
112
113 ExecuteRun(&Command, &EnvVars)
115}
116
117fn 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
138fn DetermineRunCommand(config:&RunConfig) -> Vec<String> {
148 if !config.command.is_empty() {
150 return config.command.clone();
151 }
152
153 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
161fn 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 for (Key, Value) in EnvVars {
194 Cmd.env(Key, Value);
195 }
196
197 Cmd.env("MAINTAIN_RUN_MODE", "true");
199
200 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#[allow(dead_code)]
229fn start_hot_reload_watcher(watch_dirs:&[String], _callback:impl Fn() + Send + 'static) -> Result<()> {
230 info!("Hot-reload watcher would watch: {:?}", watch_dirs);
235
236 Ok(())
237}
238
239pub fn shutdown() {
244 info!("Shutting down run process...");
245
246 }