diff --git a/src/adb.rs b/src/adb.rs index ba6c2fb..6be82df 100644 --- a/src/adb.rs +++ b/src/adb.rs @@ -1,10 +1,10 @@ -use crate::runner::Runner; +use crate::runner::CmdRunner; use std::path::Path; -pub fn get_adb_install_runner(apk_path: &String) -> Runner { +pub fn get_adb_install_runner(apk_path: &String) -> CmdRunner { let path = Path::new(apk_path); path.try_exists().expect("APK file provided does not exist"); - Runner::new( + CmdRunner::new( None, "adb".into(), vec!["install".into(), path.to_str().unwrap().to_string()], diff --git a/src/build_tools/cmake.rs b/src/build_tools/cmake.rs index 6d69cd3..436b99e 100644 --- a/src/build_tools/cmake.rs +++ b/src/build_tools/cmake.rs @@ -1,4 +1,4 @@ -use crate::runner::Runner; +use crate::runner::CmdRunner; use std::collections::HashMap; #[derive(Debug, Clone)] @@ -10,7 +10,7 @@ pub struct Cmake { } impl Cmake { - pub fn get_prepare_runner(&self) -> Runner { + pub fn get_prepare_runner(&self) -> CmdRunner { let mut args = vec![ "-B".into(), self.build_dir.clone(), @@ -30,19 +30,19 @@ impl Cmake { } } args.push(self.source_dir.clone()); - Runner::new(self.env.clone(), "cmake".into(), args) + CmdRunner::new(self.env.clone(), "cmake".into(), args) } - pub fn get_build_runner(&self) -> Runner { - Runner::new( + pub fn get_build_runner(&self) -> CmdRunner { + CmdRunner::new( self.env.clone(), "cmake".into(), vec!["--build".into(), self.build_dir.clone()], ) } - pub fn get_install_runner(&self) -> Runner { - Runner::new( + pub fn get_install_runner(&self) -> CmdRunner { + CmdRunner::new( self.env.clone(), "cmake".into(), vec!["--install".into(), self.build_dir.clone()], diff --git a/src/build_tools/git.rs b/src/build_tools/git.rs index 31bd66b..2d6da13 100644 --- a/src/build_tools/git.rs +++ b/src/build_tools/git.rs @@ -1,4 +1,8 @@ -use crate::{profile::Profile, runner::Runner}; +use crate::{ + func_runner::{FuncRunner, FuncRunnerOut}, + profile::Profile, + runner::CmdRunner, +}; use git2::Repository; use std::path::Path; @@ -23,8 +27,8 @@ impl Git { split.next().map(|s| s.into()) } - pub fn get_reset_runner(&self) -> Runner { - Runner::new( + pub fn get_reset_runner(&self) -> CmdRunner { + CmdRunner::new( None, "git".into(), vec![ @@ -36,30 +40,52 @@ impl Git { ) } - fn override_remote_url(&self) -> Result<(), git2::Error> { - if let Ok(repo) = Repository::open(&self.dir) { - let current_remote_url = self.get_repo(); - let remote = repo.find_remote("origin")?; - if remote.url().unwrap_or("") != current_remote_url { - repo.remote_set_url("origin", ¤t_remote_url)?; + pub fn get_override_remote_url_runner(&self) -> FuncRunner { + let dir = self.dir.clone(); + let n_remote_url = self.get_repo(); + FuncRunner::new(Box::new(move || { + if let Ok(repo) = Repository::open(dir) { + if let Ok(remote) = repo.find_remote("origin") { + if remote.url().unwrap_or("") != n_remote_url { + if repo.remote_set_url("origin", &n_remote_url).is_ok() { + return FuncRunnerOut { + success: true, + out: vec![], + }; + } + return FuncRunnerOut { + success: false, + out: vec!["Failed to set origin remote url".into()], + }; + } + } else { + return FuncRunnerOut { + success: false, + out: vec!["Could not find remote origin".into()], + }; + } + return FuncRunnerOut { + success: true, + out: vec![], + }; } - } - Ok(()) + FuncRunnerOut { + success: true, + out: vec![], + } + })) } - pub fn get_pull_runner(&self) -> Runner { - if self.override_remote_url().is_err() { - println!("Warning: failed to override git repo remote URL!") - } - Runner::new( + pub fn get_pull_runner(&self) -> CmdRunner { + CmdRunner::new( None, "git".into(), vec!["-C".into(), self.dir.clone(), "pull".into()], ) } - pub fn get_clone_runner(&self) -> Runner { - Runner::new( + pub fn get_clone_runner(&self) -> CmdRunner { + CmdRunner::new( None, "git".into(), vec![ @@ -71,9 +97,9 @@ impl Git { ) } - pub fn get_checkout_ref_runner(&self) -> Option { + pub fn get_checkout_ref_runner(&self) -> Option { self.get_ref().map(|r| { - Runner::new( + CmdRunner::new( None, "git".into(), vec!["-C".into(), self.dir.clone(), "checkout".into(), r], @@ -81,7 +107,7 @@ impl Git { }) } - pub fn get_clone_or_not_runner(&self) -> Option { + pub fn get_clone_or_not_runner(&self) -> Option { let path_s = format!("{}/.git", self.dir.clone()); let path = Path::new(&path_s); if path.is_dir() { @@ -90,7 +116,7 @@ impl Git { Some(self.get_clone_runner()) } - pub fn clone_or_pull(&self, profile: &Profile) -> Option { + pub fn clone_or_pull(&self, profile: &Profile) -> Option { match self.get_clone_or_not_runner() { Some(r) => Some(r), None => match profile.pull_on_build { diff --git a/src/builders/build_basalt.rs b/src/builders/build_basalt.rs index 470947b..a16cbb2 100644 --- a/src/builders/build_basalt.rs +++ b/src/builders/build_basalt.rs @@ -2,12 +2,12 @@ use crate::{ build_tools::{cmake::Cmake, git::Git}, file_utils::rm_rf, profile::Profile, - runner::Runner, + runner::{CmdRunner, Runner}, }; use std::{collections::HashMap, path::Path}; -pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec { - let mut runners: Vec = vec![]; +pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec> { + let mut runners: Vec> = vec![]; let git = Git { repo: match profile.features.basalt.repo.as_ref() { Some(r) => r.clone(), @@ -15,13 +15,14 @@ pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec Vec\\n/' include/pangolin/platform.h", repo = git.dir ), - ])); + ]))); if !Path::new(&build_dir).is_dir() || clean_build { rm_rf(&build_dir); - runners.push(cmake.get_prepare_runner()); + runners.push(Box::new(cmake.get_prepare_runner())); } - runners.push(cmake.get_build_runner()); - runners.push(cmake.get_install_runner()); + runners.push(Box::new(cmake.get_build_runner())); + runners.push(Box::new(cmake.get_install_runner())); - runners.push(Runner::new( + runners.push(Box::new(CmdRunner::new( None, "mkdir".into(), vec![ @@ -69,8 +70,8 @@ pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec Vec Vec { - let mut runners: Vec = vec![]; +pub fn get_build_libsurvive_runners(profile: &Profile, clean_build: bool) -> Vec> { + let mut runners: Vec> = vec![]; let git = Git { repo: match profile.features.libsurvive.repo.as_ref() { Some(r) => r.clone(), @@ -15,13 +15,14 @@ pub fn get_build_libsurvive_runners(profile: &Profile, clean_build: bool) -> Vec }, dir: profile.features.libsurvive.path.as_ref().unwrap().clone(), }; + runners.push(Box::new(git.get_override_remote_url_runner())); if let Some(r) = git.clone_or_pull(profile) { - runners.push(r); + runners.push(Box::new(r)); }; if let Some(r) = git.get_checkout_ref_runner() { - runners.push(r); + runners.push(Box::new(r)); if profile.pull_on_build { - runners.push(git.get_pull_runner()); + runners.push(Box::new(git.get_pull_runner())); } } @@ -47,10 +48,10 @@ pub fn get_build_libsurvive_runners(profile: &Profile, clean_build: bool) -> Vec }; if !Path::new(&build_dir).is_dir() || clean_build { rm_rf(&build_dir); - runners.push(cmake.get_prepare_runner()); + runners.push(Box::new(cmake.get_prepare_runner())); } - runners.push(cmake.get_build_runner()); - runners.push(cmake.get_install_runner()); + runners.push(Box::new(cmake.get_build_runner())); + runners.push(Box::new(cmake.get_install_runner())); runners } diff --git a/src/builders/build_mercury.rs b/src/builders/build_mercury.rs index acb1320..bd9df1d 100644 --- a/src/builders/build_mercury.rs +++ b/src/builders/build_mercury.rs @@ -1,8 +1,8 @@ -use crate::{constants::pkg_data_dir, paths::get_cache_dir, profile::Profile, runner::Runner}; +use crate::{constants::pkg_data_dir, paths::get_cache_dir, profile::Profile, runner::CmdRunner}; -pub fn get_build_mercury_runner(profile: &Profile) -> Runner { +pub fn get_build_mercury_runner(profile: &Profile) -> CmdRunner { let args = vec![profile.prefix.clone(), get_cache_dir()]; - Runner::new( + CmdRunner::new( None, format!( "{sysdata}/scripts/build_mercury.sh", diff --git a/src/builders/build_monado.rs b/src/builders/build_monado.rs index cd9b60a..809cb00 100644 --- a/src/builders/build_monado.rs +++ b/src/builders/build_monado.rs @@ -6,8 +6,8 @@ use crate::{ }; use std::{collections::HashMap, path::Path}; -pub fn get_build_monado_runners(profile: &Profile, clean_build: bool) -> Vec { - let mut runners: Vec = vec![]; +pub fn get_build_monado_runners(profile: &Profile, clean_build: bool) -> Vec> { + let mut runners: Vec> = vec![]; let git = Git { repo: match profile.xrservice_repo.as_ref() { Some(r) => r.clone(), @@ -15,13 +15,14 @@ pub fn get_build_monado_runners(profile: &Profile, clean_build: bool) -> Vec Vec Vec { - let mut runners: Vec = vec![]; +pub fn get_build_opencomposite_runners( + profile: &Profile, + clean_build: bool, +) -> Vec> { + let mut runners: Vec> = vec![]; let git = Git { repo: match profile.opencomposite_repo.as_ref() { Some(r) => r.clone(), @@ -15,13 +18,14 @@ pub fn get_build_opencomposite_runners(profile: &Profile, clean_build: bool) -> }, dir: profile.opencomposite_path.clone(), }; + runners.push(Box::new(git.get_override_remote_url_runner())); if let Some(r) = git.clone_or_pull(profile) { - runners.push(r); + runners.push(Box::new(r)); }; if let Some(r) = git.get_checkout_ref_runner() { - runners.push(r); + runners.push(Box::new(r)); if profile.pull_on_build { - runners.push(git.get_pull_runner()); + runners.push(Box::new(git.get_pull_runner())); } } @@ -36,9 +40,9 @@ pub fn get_build_opencomposite_runners(profile: &Profile, clean_build: bool) -> }; if !Path::new(&build_dir).is_dir() || clean_build { rm_rf(&build_dir); - runners.push(cmake.get_prepare_runner()); + runners.push(Box::new(cmake.get_prepare_runner())); } - runners.push(cmake.get_build_runner()); + runners.push(Box::new(cmake.get_build_runner())); runners } diff --git a/src/builders/build_wivrn.rs b/src/builders/build_wivrn.rs index 5d25aa2..01e67fd 100644 --- a/src/builders/build_wivrn.rs +++ b/src/builders/build_wivrn.rs @@ -6,8 +6,8 @@ use crate::{ }; use std::{collections::HashMap, path::Path}; -pub fn get_build_wivrn_runners(profile: &Profile, clean_build: bool) -> Vec { - let mut runners: Vec = vec![]; +pub fn get_build_wivrn_runners(profile: &Profile, clean_build: bool) -> Vec> { + let mut runners: Vec> = vec![]; let git = Git { repo: match profile.xrservice_repo.as_ref() { Some(r) => r.clone(), @@ -15,13 +15,14 @@ pub fn get_build_wivrn_runners(profile: &Profile, clean_build: bool) -> Vec Vec Result<(), std::io: } pub fn setcap_cap_sys_nice_eip(file: String) { - let mut runner = Runner::new( + let mut runner = CmdRunner::new( None, "pkexec".into(), vec!["setcap".into(), "CAP_SYS_NICE=eip".into(), file], diff --git a/src/func_runner.rs b/src/func_runner.rs new file mode 100644 index 0000000..1397e74 --- /dev/null +++ b/src/func_runner.rs @@ -0,0 +1,70 @@ +use std::{ + mem, + thread::{self, JoinHandle}, +}; + +use crate::runner::{Runner, RunnerStatus}; + +#[derive(Debug, Clone, Default)] +pub struct FuncRunnerOut { + pub success: bool, + pub out: Vec, +} + +pub struct FuncRunner { + output: Vec, + res: Option, + thread: Option>, + func: Box FuncRunnerOut + Send + Sync + 'static>, +} + +impl FuncRunner { + pub fn new(func: Box FuncRunnerOut + Send + Sync + 'static>) -> Self { + FuncRunner { + output: Vec::new(), + thread: None, + res: None, + func, + } + } +} + +impl Runner for FuncRunner { + fn start(&mut self) { + if self.res.is_some() { + panic!("Cannot start a FuncRunner twice!"); + } + let f = mem::replace(&mut self.func, Box::new(move || FuncRunnerOut::default())); + self.thread = Some(thread::spawn(move || f())); + } + + fn status(&mut self) -> RunnerStatus { + if let Some(res) = self.res { + if res { + return RunnerStatus::Stopped(Some(0)); + } + return RunnerStatus::Stopped(Some(1)); + } + if let Some(t) = self.thread.take() { + if t.is_finished() { + let out = t.join().expect("Failed to join thread"); + self.res = Some(out.success); + self.output = out.out; + return self.status(); + } + self.thread = Some(t); + return RunnerStatus::Running; + } + RunnerStatus::Stopped(None) + } + + fn consume_output(&mut self) -> String { + self.consume_rows().concat() + } + + fn consume_rows(&mut self) -> Vec { + let res = self.output.clone(); + self.output.clear(); + res + } +} diff --git a/src/main.rs b/src/main.rs index 840e970..6774891 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ pub mod downloader; pub mod env_var_descriptions; pub mod file_builders; pub mod file_utils; +pub mod func_runner; pub mod log_level; pub mod log_parser; pub mod paths; diff --git a/src/runner.rs b/src/runner.rs index 10fb64e..5bdc2e6 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -18,7 +18,14 @@ use std::{ vec, }; -pub struct Runner { +pub trait Runner { + fn start(&mut self); + fn status(&mut self) -> RunnerStatus; + fn consume_output(&mut self) -> String; + fn consume_rows(&mut self) -> Vec; +} + +pub struct CmdRunner { pub environment: HashMap, pub command: String, pub args: Vec, @@ -67,7 +74,7 @@ macro_rules! logger_thread { }; } -impl Runner { +impl CmdRunner { pub fn new( environment: Option>, command: String, @@ -125,10 +132,6 @@ impl Runner { Ok(()) } - pub fn start(&mut self) { - self.try_start().expect("Failed to execute runner"); - } - fn join_threads(&mut self) { loop { match self.threads.pop() { @@ -163,7 +166,39 @@ impl Runner { self.join_threads(); } - pub fn status(&mut self) -> RunnerStatus { + fn receive_output(&mut self) { + while let Ok(data) = self.receiver.try_recv() { + self.output.push(data); + } + } + + fn save_log(path_s: String, log: &[String]) -> Result<(), std::io::Error> { + let mut writer = get_writer(&path_s); + let log_s = log.concat(); + writer.write_all(log_s.as_ref()) + } + + pub fn save_output(&mut self, path: String) -> Result<(), std::io::Error> { + CmdRunner::save_log(path, &self.output) + } +} + +impl Runner for CmdRunner { + fn consume_output(&mut self) -> String { + self.receive_output(); + let res = self.output.concat(); + self.output.clear(); + res + } + + fn consume_rows(&mut self) -> Vec { + self.receive_output(); + let res = self.output.clone(); + self.output.clear(); + res + } + + fn status(&mut self) -> RunnerStatus { match &mut self.process { None => RunnerStatus::Stopped(None), Some(proc) => match proc.try_wait() { @@ -174,42 +209,16 @@ impl Runner { } } - fn receive_output(&mut self) { - while let Ok(data) = self.receiver.try_recv() { - self.output.push(data); - } - } - - pub fn consume_output(&mut self) -> String { - self.receive_output(); - let res = self.output.concat(); - self.output.clear(); - res - } - - pub fn consume_rows(&mut self) -> Vec { - self.receive_output(); - let res = self.output.clone(); - self.output.clear(); - res - } - - fn save_log(path_s: String, log: &[String]) -> Result<(), std::io::Error> { - let mut writer = get_writer(&path_s); - let log_s = log.concat(); - writer.write_all(log_s.as_ref()) - } - - pub fn save_output(&mut self, path: String) -> Result<(), std::io::Error> { - Runner::save_log(path, &self.output) + fn start(&mut self) { + self.try_start().expect("Failed to execute runner"); } } #[cfg(test)] mod tests { + use super::{CmdRunner, RunnerStatus}; use crate::profile::Profile; - - use super::{Runner, RunnerStatus}; + use crate::runner::Runner; use core::time; use std::{collections::HashMap, thread::sleep}; @@ -217,7 +226,7 @@ mod tests { fn can_run_command_and_read_env() { let mut env = HashMap::new(); env.insert("REX2TEST".to_string(), "Lorem ipsum dolor".to_string()); - let mut runner = Runner::new( + let mut runner = CmdRunner::new( Some(env), "bash".into(), vec!["-c".into(), "echo \"REX2TEST: $REX2TEST\"".into()], @@ -232,7 +241,7 @@ mod tests { #[test] fn can_save_log() { - let mut runner = Runner::new( + let mut runner = CmdRunner::new( None, "bash".into(), vec!["-c".into(), "echo \"Lorem ipsum dolor sit amet\"".into()], @@ -249,7 +258,7 @@ mod tests { #[test] fn can_create_from_profile() { - Runner::xrservice_runner_from_profile(&Profile::load_profile( + CmdRunner::xrservice_runner_from_profile(&Profile::load_profile( &"./test/files/profile.json".to_string(), )); } diff --git a/src/runner_pipeline.rs b/src/runner_pipeline.rs index c2a0a44..09e874b 100644 --- a/src/runner_pipeline.rs +++ b/src/runner_pipeline.rs @@ -1,9 +1,8 @@ +use crate::runner::{Runner, RunnerStatus}; use std::cell::RefCell; -use crate::runner::{Runner, RunnerStatus}; - pub struct RunnerPipeline { - runners: Vec>, + runners: Vec>>, current_index: usize, last_exit_status: Option, has_started: bool, @@ -11,8 +10,8 @@ pub struct RunnerPipeline { } impl RunnerPipeline { - pub fn new(runners: Vec) -> Self { - let mut c_runners: Vec> = vec![]; + pub fn new(runners: Vec>) -> Self { + let mut c_runners: Vec>> = vec![]; for runner in runners { c_runners.push(RefCell::new(runner)); } @@ -25,7 +24,7 @@ impl RunnerPipeline { } } - pub fn get_current_runner(&self) -> Option<&RefCell> { + pub fn get_current_runner(&self) -> Option<&RefCell>> { self.runners.get(self.current_index) } diff --git a/src/ui/app.rs b/src/ui/app.rs index 007b917..5ba8a11 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -32,7 +32,7 @@ use crate::profiles::lighthouse::lighthouse_profile; use crate::profiles::system_valve_index::system_valve_index_profile; use crate::profiles::valve_index::valve_index_profile; use crate::profiles::wivrn::wivrn_profile; -use crate::runner::{Runner, RunnerStatus}; +use crate::runner::{CmdRunner, Runner, RunnerStatus}; use crate::runner_pipeline::RunnerPipeline; use crate::ui::build_window::BuildWindowMsg; use crate::ui::debug_view::DebugViewInit; @@ -76,7 +76,7 @@ pub struct App { #[tracker::do_not_track] config: Config, #[tracker::do_not_track] - xrservice_runner: Option, + xrservice_runner: Option, #[tracker::do_not_track] build_pipeline: Option, #[tracker::do_not_track] @@ -149,7 +149,7 @@ impl App { XRServiceType::Wivrn => true, // no device from log in wivrn }; self.debug_view.sender().emit(DebugViewMsg::ClearLog); - let mut runner = Runner::xrservice_runner_from_profile(&prof); + let mut runner = CmdRunner::xrservice_runner_from_profile(&prof); match runner.try_start() { Ok(_) => { self.xrservice_runner = Some(runner); @@ -400,7 +400,7 @@ impl SimpleComponent for App { Msg::BuildProfile(clean_build) => { let profile = self.get_selected_profile(); let mut missing_deps = vec![]; - let mut runners: Vec = vec![]; + let mut runners: Vec> = vec![]; // profile per se can't be built, but we still need opencomp if profile.can_be_built { missing_deps.extend(match profile.xrservice_type { @@ -417,7 +417,7 @@ impl SimpleComponent for App { } if profile.features.mercury_enabled { missing_deps.extend(get_missing_mercury_deps()); - runners.push(get_build_mercury_runner(&profile)); + runners.push(Box::new(get_build_mercury_runner(&profile))); } runners.extend(match profile.xrservice_type { XRServiceType::Monado => get_build_monado_runners(&profile, clean_build), diff --git a/src/ui/install_wivrn_box.rs b/src/ui/install_wivrn_box.rs index 3053513..5b74650 100644 --- a/src/ui/install_wivrn_box.rs +++ b/src/ui/install_wivrn_box.rs @@ -5,7 +5,7 @@ use crate::{ downloader::download_file, paths::wivrn_apk_download_path, profile::{Profile, XRServiceType}, - runner::{Runner, RunnerStatus}, + runner::{CmdRunner, Runner, RunnerStatus}, }; use gtk::prelude::*; use relm4::{ @@ -31,7 +31,7 @@ pub struct InstallWivrnBox { #[tracker::do_not_track] download_thread: Option>>, #[tracker::do_not_track] - install_runner: Option, + install_runner: Option, #[tracker::do_not_track] root_win: gtk::Window, } diff --git a/src/ui/libsurvive_setup_window.rs b/src/ui/libsurvive_setup_window.rs index ab929d1..4b7565d 100644 --- a/src/ui/libsurvive_setup_window.rs +++ b/src/ui/libsurvive_setup_window.rs @@ -1,4 +1,7 @@ -use crate::{profile::Profile, runner::Runner}; +use crate::{ + profile::Profile, + runner::{CmdRunner, Runner}, +}; use adw::prelude::*; use gtk::glib; use relm4::prelude::*; @@ -40,7 +43,7 @@ pub struct LibsurviveSetupWindow { #[tracker::do_not_track] profile: Option, #[tracker::do_not_track] - calibration_runner: Option, + calibration_runner: Option, } #[derive(Debug)] @@ -54,14 +57,14 @@ pub enum LibsurviveSetupMsg { } impl LibsurviveSetupWindow { - fn create_calibration_runner(&mut self, survive_cli_path: String) -> Runner { + fn create_calibration_runner(&mut self, survive_cli_path: String) -> CmdRunner { let lh_path = self.steam_lighthouse_path.clone(); let mut env = HashMap::new(); env.insert( "LD_LIBRARY_PATH".to_string(), format!("{pfx}/lib", pfx = self.profile.as_ref().unwrap().prefix), ); - Runner::new( + CmdRunner::new( Some(env), survive_cli_path, vec!["--steamvr-calibration".into(), lh_path],