Skip to content

Commit

Permalink
ref(runner): better architecture
Browse files Browse the repository at this point in the history
  • Loading branch information
kkharji committed May 23, 2022
1 parent 6ee4138 commit 7245899
Show file tree
Hide file tree
Showing 20 changed files with 564 additions and 518 deletions.
280 changes: 139 additions & 141 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ tokio = { version = "1.17.0", features = ["full"], optional = tr
tokio-util = { version = "0.7.1", features = ["codec"], optional = true }
async-trait = { version = "0.1.52", optional = true }
async-stream = { version = "0.3.3", optional = true }
process-stream = { version = "0.1.3", optional = true }
process-stream = { path = "../../rust/process-stream/", optional = true }
# Logging Feature
tracing = { version = "0.1.32", optional = true }
tracing-subscriber = { version = "0.3.9", features = ["env-filter"], optional = true}
Expand Down
3 changes: 2 additions & 1 deletion lua/xbase/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn libxbase(l: &Lua) -> LuaResult<LuaTable> {
("register", fun!(Register, l)),
("drop", fun!(Drop, l)),
("build", fun!(Build, l)),
("run", fun!(Run, l)),
("run", fun!(RunRequest, l)),
("watch_target", fun!(WatchTarget, l)),
])
}
Expand All @@ -34,6 +34,7 @@ pub fn is_running(_: &Lua, _: ()) -> LuaResult<bool> {

/// Ensure that daemon is currently running in background
pub fn ensure(lua: &Lua, _: ()) -> LuaResult<bool> {
// FIXME(dameon): resulting in connection refused
if is_running(lua, ()).unwrap() {
Ok(false)
} else if Command::new(DAEMON_BINARY).spawn().is_ok() {
Expand Down
4 changes: 2 additions & 2 deletions src/daemon/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Request {
#[derive(Debug, Serialize, Deserialize)]
pub enum Message {
Build(Build),
Run(Run),
RunRequest(RunRequest),
Register(Register),
Drop(Drop),
RenameFile(RenameFile),
Expand All @@ -33,7 +33,7 @@ impl Message {
pub async fn handle(self) -> crate::Result<()> {
match self {
Self::Build(c) => Handler::handle(c).await,
Self::Run(c) => Handler::handle(c).await,
Self::RunRequest(c) => Handler::handle(c).await,
Self::RenameFile(c) => Handler::handle(c).await,
Self::Register(c) => Handler::handle(c).await,
Self::Drop(c) => Handler::handle(c).await,
Expand Down
2 changes: 1 addition & 1 deletion src/daemon/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ macro_rules! convertable {
};
}
convertable!(Build);
convertable!(Run);
convertable!(RunRequest);
convertable!(Register);
convertable!(RenameFile);
convertable!(Drop);
Expand Down
10 changes: 4 additions & 6 deletions src/daemon/requests/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ use std::fmt::Debug;

#[cfg(feature = "daemon")]
use {
crate::constants::DAEMON_STATE,
crate::util::serde::value_or_default,
crate::xcode::{append_build_root, build_with_loggger},
crate::constants::DAEMON_STATE, crate::util::serde::value_or_default,
crate::xcode::build_with_logger,
};

/// Build a project.
Expand All @@ -32,15 +31,14 @@ impl Handler for Build {

let nvim = client.nvim(state)?;
let direction = self.direction.clone();

let args = append_build_root(&root, config.as_args())?;
let args = config.args(&root, &None)?;

let ref mut logger = nvim.logger();

logger.set_title(format!("Build:{}", config.target));
logger.set_direction(&direction);

let success = build_with_loggger(logger, &root, &args, true, true).await?;
let success = build_with_logger(logger, root, &args, true, true).await?;

if !success {
let ref msg = format!("Failed: {} ", config.to_string());
Expand Down
73 changes: 12 additions & 61 deletions src/daemon/requests/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,12 @@ use {

#[cfg(feature = "daemon")]
use {
crate::constants::DAEMON_STATE,
crate::runner::Runner,
crate::types::Platform,
crate::util::serde::value_or_default,
crate::xcode::{append_build_root, build_with_loggger},
crate::Error,
xcodebuild::runner::build_settings,
crate::constants::DAEMON_STATE, crate::run::RunService, crate::util::serde::value_or_default,
};

/// Run a project.
#[derive(Debug, Serialize, Deserialize)]
pub struct Run {
pub struct RunRequest {
pub client: Client,
pub config: BuildConfiguration,
#[cfg_attr(feature = "daemon", serde(deserialize_with = "value_or_default"))]
Expand All @@ -27,72 +21,29 @@ pub struct Run {

#[cfg(feature = "daemon")]
#[async_trait::async_trait]
impl Handler for Run {
impl Handler for RunRequest {
async fn handle(self) -> Result<()> {
let Client { root, .. } = &self.client;

tracing::info!("⚙️ Running command: {}", self.config.to_string());
tracing::info!("⚙️ Running: {}", self.config.to_string());

let state = DAEMON_STATE.clone();
let ref state = state.lock().await;
let device = state.devices.from_lookup(self.device);

let nvim = self.client.nvim(state)?;
let args = {
let mut args = self.config.as_args();
if let Some(ref device) = device {
args.extend(device.special_build_args())
}
append_build_root(&root, args)?
};

let ref mut logger = nvim.logger();
let ref mut state = state.lock().await;

logger.set_title(format!("Run:{}", self.config.target));
logger.set_direction(&self.direction);
// TODO: Insert runner into state.runners
RunService::new(state, self).await?;

let settings = build_settings(&root, &args).await?;
let platform = device
.as_ref()
.map(|d| d.platform.clone())
.unwrap_or_else(|| Platform::from_display(&settings.platform_display_name).unwrap());

let success = build_with_loggger(logger, &root, &args, true, true).await?;
if !success {
let msg = format!("Failed: {} ", self.config.to_string());
nvim.echo_err(&msg).await?;
return Err(Error::Build(msg));
}

// TODO(daemon): insert handler to state.runners
// TODO(nvim): provide mapping to close runners.
//
// If there is more then one runner then pick, else close from current buffer.
// C-c in normal/insert mode should close that process
Runner {
target: self.config.target,
platform,
client: self.client,
args,
udid: device.map(|d| d.udid.clone()),
direction: self.direction,
}
.run(state, settings)
.await?;

Ok(())
todo!();
}
}

#[cfg(feature = "lua")]
impl<'a> Requester<'a, Run> for Run {
fn pre(lua: &Lua, msg: &Run) -> LuaResult<()> {
impl<'a> Requester<'a, RunRequest> for RunRequest {
fn pre(lua: &Lua, msg: &RunRequest) -> LuaResult<()> {
lua.print(&msg.to_string());
Ok(())
}
}

impl ToString for Run {
impl ToString for RunRequest {
fn to_string(&self) -> String {
if let Some(ref name) = self.device.name {
format!("run [{}] with {}", name, self.config.to_string())
Expand All @@ -103,7 +54,7 @@ impl ToString for Run {
}

#[cfg(feature = "lua")]
impl<'a> FromLua<'a> for Run {
impl<'a> FromLua<'a> for RunRequest {
fn from_lua(lua_value: LuaValue<'a>, _lua: &'a Lua) -> LuaResult<Self> {
let table = match lua_value {
LuaValue::Table(t) => Ok(t),
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub mod store;
mod error;

#[cfg(feature = "daemon")]
mod runner;
mod run;

#[cfg(any(feature = "daemon", feature = "server"))]
pub use error::{CompileError, Error, LoopError, WatchError};
Expand Down
1 change: 1 addition & 0 deletions src/nvim/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ impl<'a> Logger<'a> {
})
}

// TODO(logger): append title
pub async fn log(&mut self, msg: String) -> Result<()> {
tracing::debug!("{msg}");

Expand Down
55 changes: 55 additions & 0 deletions src/run.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
mod bin;
mod handler;
mod meduim;
mod simulator;

use crate::{
client::Client, daemon::RunRequest, state::State, types::Device, xcode::build_with_logger,
Error, Result,
};
use tokio::sync::MutexGuard;
use xcodebuild::runner::build_settings;
use {handler::RunServiceHandler, meduim::RunMedium};

/// Run Service
pub struct RunService {
pub client: Client,
pub handler: RunServiceHandler,
pub medium: RunMedium,
}

impl RunService {
pub async fn new(state: &mut MutexGuard<'_, State>, req: RunRequest) -> Result<Self> {
let ref target = req.config.target;
let ref root = req.client.root;
let device = state.devices.from_lookup(req.device);
let build_args = req.config.args(root, &device)?;
let nvim = req.client.nvim(state)?;

let ref mut logger = nvim.logger();

logger.set_title(format!("Run:{target}"));
logger.open_win().await?;
logger.set_direction(&req.direction);
logger.set_running().await?;

let build_settings = build_settings(root, &build_args).await?;
let build_success = build_with_logger(logger, root, &build_args, false, false).await?;

if !build_success {
let msg = format!("Failed: {}", req.config);
nvim.echo_err(&msg).await?;
return Err(Error::Build(msg));
}

let medium = RunMedium::from_device_or_settings(device, build_settings, req.config)?;
let process = medium.run(logger).await?;
let handler = RunServiceHandler::new(req.client.clone(), process)?;

Ok(Self {
client: req.client,
handler,
medium,
})
}
}
42 changes: 42 additions & 0 deletions src/run/bin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#![allow(dead_code)]
use crate::types::BuildConfiguration;
use crate::{Error, Result};
use process_stream::Process;
use std::path::PathBuf;
use xcodebuild::parser::BuildSettings;

pub struct Bin {
path: PathBuf,
info: BuildSettings,
config: BuildConfiguration,
}

impl Bin {
pub fn new(info: BuildSettings, config: BuildConfiguration) -> Self {
Self {
path: info.path_to_output_binary().unwrap_or_default(),
info,
config,
}
}

pub async fn launch(&self) -> Result<Process> {
if !self.path.exists() {
return Err(Error::Run(format!("{:?} doesn't exist!", self.path)));
}

Ok(Process::new(&self.path))
}

/// Get a reference to the bin's info.
#[must_use]
pub fn info(&self) -> &BuildSettings {
&self.info
}

/// Get a reference to the bin's config.
#[must_use]
pub fn config(&self) -> &BuildConfiguration {
&self.config
}
}
63 changes: 63 additions & 0 deletions src/run/handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#![allow(dead_code)]
use crate::{client::Client, constants::DAEMON_STATE, Error, Result};
use process_stream::{Process, StreamExt};
use tokio::task::JoinHandle;

/// Run Service Task Handler
pub enum RunServiceHandler {
// Runner is running successfully
Running((Process, JoinHandle<Result<()>>)),
// Runner Errored
Errored(Error),
// Runner Stopped
Stopped(i32),
}

impl RunServiceHandler {
// Change the status of the process to running
pub fn new(client: Client, mut process: Process) -> Result<Self> {
let mut stream = process.spawn_and_stream()?;
let kill_send = process.clone_kill_sender().unwrap();

let handler = tokio::spawn(async move {
while let Some(output) = stream.next().await {
let state = DAEMON_STATE.clone();
let ref state = state.lock().await;
let ref mut logger = match client.nvim(state) {
Ok(nvim) => nvim.logger(),
Err(_) => {
// TODO: Update state to set current handler as Errored
tracing::info!("Nvim Instance closed, closing runner ..");
kill_send.send(()).await.ok();
break;
}
};

use process_stream::ProcessItem::*;
match output {
Output(msg) => {
if !msg.contains("ignoring singular matrix") {
logger.log(msg).await?;
}
}
Error(msg) => {
logger.log(format!("[Error] {msg}")).await?;
}
// TODO: this should be skipped when user re-run the app
Exit(code) => {
let success = &code == "0";
logger.log(format!("[Exit] {code}")).await?;
logger.set_status_end(success, !success).await?;
break;
}
};
}

drop(stream);

// TODO: Update state to set current handler as stopped
Ok(())
});
Ok(Self::Running((process, handler)))
}
}
Loading

0 comments on commit 7245899

Please sign in to comment.