diff --git a/src/daemon/requests/run.rs b/src/daemon/requests/run.rs index 2643268..6a31d67 100644 --- a/src/daemon/requests/run.rs +++ b/src/daemon/requests/run.rs @@ -6,8 +6,10 @@ use crate::{ #[cfg(feature = "daemon")] use { - crate::constants::DAEMON_STATE, crate::types::SimDevice, crate::xcode::append_build_root, - crate::Error, xcodebuild::runner::build_settings, + crate::{constants::DAEMON_STATE, types::SimDevice, xcode::append_build_root, Error}, + std::str::FromStr, + tokio_stream::StreamExt, + xcodebuild::runner, }; #[derive(Debug, Serialize, Deserialize)] @@ -48,25 +50,18 @@ impl Handler for Run { let args = { let mut args = config.as_args(); - if let Some(platform) = platform { + if let Some(ref platform) = platform { args.extend(platform.sdk_simulator_args()) } append_build_root(&root, args)? }; - let build_settings = build_settings(&root, &args).await?; - let ref app_id = build_settings.product_bundle_identifier; + tracing::debug!("args: {:?}", args); - // FIX(run): When running with release path_to_app is incorrect - // - // Err: application bundle was not found at the provided path.\nProvide a valid path to the - // desired application bundle. - // - // Path doesn't point to local directory build - let ref path_to_app = build_settings.metal_library_output_dir; + let settings = runner::build_settings(&root, &args).await?; + let platform = platform.unwrap_or(Platform::from_str(&settings.platform_display_name)?); - tracing::warn!("{app_id}: {:?}", path_to_app); let (success, ref win) = nvim .new_logger("Build", &config.target, &direction) .log_build_stream(&root, &args, true, true) @@ -78,27 +73,78 @@ impl Handler for Run { return Err(Error::Build(msg)); } - let ref mut logger = nvim.new_logger("Run", &config.target, &direction); + let mut logger = nvim.new_logger("Run", &config.target, &direction); - logger.set_running().await?; + if platform.is_mac_os() { + let program = settings.path_to_output_binary()?; + tracing::debug!("Running binary {program:?}"); - if let Some(mut device) = get_device(&state, device) { - device.try_boot(logger, win).await?; - device.try_install(path_to_app, app_id, logger, win).await?; - device.try_launch(app_id, logger, win).await?; + logger.log_title().await?; + tokio::spawn(async move { + let mut stream = runner::run(program).await?; + + use xcodebuild::runner::ProcessUpdate::*; + // NOTE: This is required so when neovim exist this should also exit + while let Some(update) = stream.next().await { + let state = DAEMON_STATE.clone(); + let state = state.lock().await; + + let nvim = state.clients.get(&pid)?; + let mut logger = nvim.new_logger("Run", &config.target, &direction); + let ref win = Some(logger.open_win().await?); + + // NOTE: NSLog get directed to error by default which is odd + match update { + Stdout(msg) => { + logger.log(format!("[Output] {msg}"), win).await?; + } + Error(msg) | Stderr(msg) => { + logger.log(format!("[Error] {msg}"), win).await?; + } + Exit(ref code) => { + logger.log(format!("[Exit] {code}"), win).await?; + logger.set_status_end(code == "0", win.is_none()).await?; + } + } + } + anyhow::Ok(()) + }); + return Ok(()); + } else if let Some(mut device) = get_device(&state, device) { + let path_to_app = settings.metal_library_output_dir; + let app_id = settings.product_bundle_identifier; - logger.set_status_end(true, true).await?; + tracing::debug!("{app_id}: {:?}", path_to_app); + logger.log_title().await?; tokio::spawn(async move { + // NOTE: This is required so when neovim exist this should also exit + let state = DAEMON_STATE.clone().lock_owned().await; + let nvim = state.clients.get(&pid)?; + let ref mut logger = nvim.new_logger("Run", &config.target, &direction); + let ref win = Some(logger.open_win().await?); + + logger.set_running().await?; + + device.try_boot(logger, win).await?; + device + .try_install(&path_to_app, &app_id, logger, win) + .await?; + device.try_launch(&app_id, logger, win).await?; + + // TODO: Remove and repalce with app logs + logger.set_status_end(true, win.is_none()).await?; + let mut state = DAEMON_STATE.clone().lock_owned().await; state.devices.insert(device); state.sync_client_state().await }); - } else { - // TODO: check if macOS is the platform and run it + return Ok(()); } - Ok(()) + let msg = format!("Unable to run `{}` under `{platform}`", config.target); + logger.log(msg.clone(), win).await?; + Err(Error::Run(msg)) } } diff --git a/src/nvim/logger.rs b/src/nvim/logger.rs index 99bbc24..d9a63e6 100644 --- a/src/nvim/logger.rs +++ b/src/nvim/logger.rs @@ -108,6 +108,7 @@ impl<'a> Logger<'a> { let mut success = false; self.set_running().await?; + self.log_title().await?; while let Some(line) = stream.next().await { line.contains("Succeed").then(|| success = true); @@ -120,7 +121,7 @@ impl<'a> Logger<'a> { Ok((success, win)) } - async fn log_title(&mut self) -> Result<()> { + pub async fn log_title(&mut self) -> Result<()> { self.log(self.title.clone(), &None).await?; Ok(()) } @@ -146,7 +147,6 @@ impl<'a> Logger<'a> { } pub async fn set_running(&mut self) -> Result<()> { - self.log_title().await?; self.nvim .exec("let g:xbase_watch_build_status='running'", false) .await?; diff --git a/src/types/project/platform.rs b/src/types/project/platform.rs index 0767486..d7c009e 100644 --- a/src/types/project/platform.rs +++ b/src/types/project/platform.rs @@ -1,15 +1,23 @@ use super::*; -#[derive(Clone, Debug, Default, Deserialize, Serialize, Hash, PartialEq, Eq)] +use strum::{Display, EnumString}; +#[derive( + Clone, Debug, Default, Deserialize, Serialize, Hash, PartialEq, Eq, Display, EnumString, +)] pub enum Platform { #[serde(rename = "iOS")] + #[strum(serialize = "iOS")] IOS, #[serde(rename = "watchOS")] + #[strum(serialize = "watchOS")] WatchOS, #[serde(rename = "tvOS")] + #[strum(serialize = "tvOS")] TvOS, + #[strum(serialize = "macOS")] #[serde(rename = "macOS")] MacOS, #[default] + #[strum(serialize = "")] None, } @@ -43,19 +51,6 @@ impl Platform { } } -impl ToString for Platform { - fn to_string(&self) -> String { - match self { - Platform::IOS => "iOS", - Platform::WatchOS => "watchOS", - Platform::TvOS => "tvOS", - Platform::MacOS => "macOS", - Platform::None => "", - } - .into() - } -} - #[cfg(feature = "lua")] use mlua::prelude::*; diff --git a/src/util/mod.rs b/src/util/mod.rs index e69b05d..ba58b28 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -31,8 +31,11 @@ pub async fn proc_kill(pid_str: &String) -> anyhow::Result { pub fn string_as_section(mut content: String) -> String { let len = content.len(); - let sep = "-".repeat(73 - len); - content.push_str(" "); - content.push_str(&sep); + let rep = 73 - len; + if rep > 0 { + let sep = "-".repeat(73 - len); + content.push_str(" "); + content.push_str(&sep); + } content } diff --git a/syntax/xcodebuildlog.vim b/syntax/xcodebuildlog.vim index 8be2fb9..ef10838 100644 --- a/syntax/xcodebuildlog.vim +++ b/syntax/xcodebuildlog.vim @@ -13,7 +13,10 @@ syn region Scope display oneline start='^\[' end='\]' syn match LogError "^\(\[Error\]\)" syn match LogWarn "^\(\[Warning\]\)" syn match LogSuccess "^\(\[Succeed\]\)" -syn match LogLaunched "^\(\[Launched\]\)" +syn match LogDone "^\(\[Done\]\)" +syn match LogLaunched "^\(\[Launched\]\)" +syn match LogOutput "^\(\[Output\]\)" +syn match LogOutput "^\(\[Exit\]\)" syn match Target "`\(\w.*\)`" syn match FilePath "`\(\/.*\)`" syn region Sep display oneline start='-' end='-$' @@ -23,6 +26,7 @@ hi def link LogSuccess healthSuccess hi def link Operations Function hi def link Entitlement Comment hi def link Package Comment +hi def link LogOutput Comment hi def link Sep Comment hi def link FilePath String hi def link Target Label