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 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 let Config = RunConfig::new(Arg, EnvVars.clone());
90
91 LogRunHeader(&Config);
93
94 LogHotReloadStatus(Config.hot_reload, Config.live_reload_port);
96 LogWatchStatus(Config.watch);
97
98 if Arg.DryRun {
100 info!("Dry run mode - showing configuration without executing");
101 debug!("Configuration: {:?}", Config);
102 return Ok(());
103 }
104
105 let Command = DetermineRunCommand(&Config);
107
108 ExecuteRun(&Command, &EnvVars)
110}
111
112fn 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
130fn DetermineRunCommand(config:&RunConfig) -> Vec<String> {
140 if !config.command.is_empty() {
142 return config.command.clone();
143 }
144
145 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
153fn 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 for (Key, Value) in EnvVars {
182 Cmd.env(Key, Value);
183 }
184
185 Cmd.env("MAINTAIN_RUN_MODE", "true");
187
188 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#[allow(dead_code)]
214fn start_hot_reload_watcher(watch_dirs:&[String], _callback:impl Fn() + Send + 'static) -> Result<()> {
215 info!("Hot-reload watcher would watch: {:?}", watch_dirs);
220
221 Ok(())
222}
223
224pub fn shutdown() {
229 info!("Shutting down run process...");
230 }