mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-02 06:08:42 +00:00
Merge branch 'fix/overrideRemoteUrl' into 'main'
fix: override remote url if it changes on pull See merge request gabmus/rex2!10
This commit is contained in:
commit
9918912992
20 changed files with 538 additions and 336 deletions
68
Cargo.lock
generated
68
Cargo.lock
generated
|
@ -139,6 +139,9 @@ name = "cc"
|
||||||
version = "1.0.79"
|
version = "1.0.79"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||||
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-expr"
|
name = "cfg-expr"
|
||||||
|
@ -497,6 +500,21 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "git2"
|
||||||
|
version = "0.17.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
"libgit2-sys",
|
||||||
|
"log",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glib"
|
name = "glib"
|
||||||
version = "0.17.10"
|
version = "0.17.10"
|
||||||
|
@ -843,6 +861,15 @@ version = "1.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
|
checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.64"
|
version = "0.3.64"
|
||||||
|
@ -897,6 +924,34 @@ version = "0.2.147"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libgit2-sys"
|
||||||
|
version = "0.15.2+1.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a80df2e11fb4a61f4ba2ab42dbe7f74468da143f1a75c74e11dee7c813f694fa"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"libssh2-sys",
|
||||||
|
"libz-sys",
|
||||||
|
"openssl-sys",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libssh2-sys"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"libz-sys",
|
||||||
|
"openssl-sys",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libusb"
|
name = "libusb"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -918,6 +973,18 @@ dependencies = [
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libz-sys"
|
||||||
|
version = "1.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
@ -1471,6 +1538,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"gettext-rs",
|
"gettext-rs",
|
||||||
|
"git2",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
"libusb",
|
"libusb",
|
||||||
"nix",
|
"nix",
|
||||||
|
|
|
@ -10,6 +10,7 @@ anyhow = "1.0.71"
|
||||||
gettext-rs = { version = "0.7.0", features = [
|
gettext-rs = { version = "0.7.0", features = [
|
||||||
"gettext-system"
|
"gettext-system"
|
||||||
] }
|
] }
|
||||||
|
git2 = "0.17.2"
|
||||||
gtk4 = { version = "0.6.6", features = [
|
gtk4 = { version = "0.6.6", features = [
|
||||||
"v4_10",
|
"v4_10",
|
||||||
] }
|
] }
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::runner::Runner;
|
use crate::cmd_runner::CmdRunner;
|
||||||
use std::path::Path;
|
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);
|
let path = Path::new(apk_path);
|
||||||
path.try_exists().expect("APK file provided does not exist");
|
path.try_exists().expect("APK file provided does not exist");
|
||||||
Runner::new(
|
CmdRunner::new(
|
||||||
None,
|
None,
|
||||||
"adb".into(),
|
"adb".into(),
|
||||||
vec!["install".into(), path.to_str().unwrap().to_string()],
|
vec!["install".into(), path.to_str().unwrap().to_string()],
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::runner::Runner;
|
use crate::cmd_runner::CmdRunner;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -10,7 +10,7 @@ pub struct Cmake {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cmake {
|
impl Cmake {
|
||||||
pub fn get_prepare_runner(&self) -> Runner {
|
pub fn get_prepare_runner(&self) -> CmdRunner {
|
||||||
let mut args = vec![
|
let mut args = vec![
|
||||||
"-B".into(),
|
"-B".into(),
|
||||||
self.build_dir.clone(),
|
self.build_dir.clone(),
|
||||||
|
@ -30,19 +30,19 @@ impl Cmake {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args.push(self.source_dir.clone());
|
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 {
|
pub fn get_build_runner(&self) -> CmdRunner {
|
||||||
Runner::new(
|
CmdRunner::new(
|
||||||
self.env.clone(),
|
self.env.clone(),
|
||||||
"cmake".into(),
|
"cmake".into(),
|
||||||
vec!["--build".into(), self.build_dir.clone()],
|
vec!["--build".into(), self.build_dir.clone()],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_install_runner(&self) -> Runner {
|
pub fn get_install_runner(&self) -> CmdRunner {
|
||||||
Runner::new(
|
CmdRunner::new(
|
||||||
self.env.clone(),
|
self.env.clone(),
|
||||||
"cmake".into(),
|
"cmake".into(),
|
||||||
vec!["--install".into(), self.build_dir.clone()],
|
vec!["--install".into(), self.build_dir.clone()],
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
use crate::{
|
||||||
|
cmd_runner::CmdRunner,
|
||||||
|
func_runner::{FuncRunner, FuncRunnerOut},
|
||||||
|
profile::Profile,
|
||||||
|
};
|
||||||
|
use git2::Repository;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::{profile::Profile, runner::Runner};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Git {
|
pub struct Git {
|
||||||
pub repo: String,
|
pub repo: String,
|
||||||
|
@ -23,8 +27,8 @@ impl Git {
|
||||||
split.next().map(|s| s.into())
|
split.next().map(|s| s.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_reset_runner(&self) -> Runner {
|
pub fn get_reset_runner(&self) -> CmdRunner {
|
||||||
Runner::new(
|
CmdRunner::new(
|
||||||
None,
|
None,
|
||||||
"git".into(),
|
"git".into(),
|
||||||
vec![
|
vec![
|
||||||
|
@ -36,16 +40,52 @@ impl Git {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pull_runner(&self) -> Runner {
|
pub fn get_override_remote_url_runner(&self) -> FuncRunner {
|
||||||
Runner::new(
|
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![],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
FuncRunnerOut {
|
||||||
|
success: true,
|
||||||
|
out: vec![],
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pull_runner(&self) -> CmdRunner {
|
||||||
|
CmdRunner::new(
|
||||||
None,
|
None,
|
||||||
"git".into(),
|
"git".into(),
|
||||||
vec!["-C".into(), self.dir.clone(), "pull".into()],
|
vec!["-C".into(), self.dir.clone(), "pull".into()],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_clone_runner(&self) -> Runner {
|
pub fn get_clone_runner(&self) -> CmdRunner {
|
||||||
Runner::new(
|
CmdRunner::new(
|
||||||
None,
|
None,
|
||||||
"git".into(),
|
"git".into(),
|
||||||
vec![
|
vec![
|
||||||
|
@ -57,9 +97,9 @@ impl Git {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_checkout_ref_runner(&self) -> Option<Runner> {
|
pub fn get_checkout_ref_runner(&self) -> Option<CmdRunner> {
|
||||||
self.get_ref().map(|r| {
|
self.get_ref().map(|r| {
|
||||||
Runner::new(
|
CmdRunner::new(
|
||||||
None,
|
None,
|
||||||
"git".into(),
|
"git".into(),
|
||||||
vec!["-C".into(), self.dir.clone(), "checkout".into(), r],
|
vec!["-C".into(), self.dir.clone(), "checkout".into(), r],
|
||||||
|
@ -67,7 +107,7 @@ impl Git {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_clone_or_not_runner(&self) -> Option<Runner> {
|
pub fn get_clone_or_not_runner(&self) -> Option<CmdRunner> {
|
||||||
let path_s = format!("{}/.git", self.dir.clone());
|
let path_s = format!("{}/.git", self.dir.clone());
|
||||||
let path = Path::new(&path_s);
|
let path = Path::new(&path_s);
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
|
@ -76,7 +116,7 @@ impl Git {
|
||||||
Some(self.get_clone_runner())
|
Some(self.get_clone_runner())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_or_pull(&self, profile: &Profile) -> Option<Runner> {
|
pub fn clone_or_pull(&self, profile: &Profile) -> Option<CmdRunner> {
|
||||||
match self.get_clone_or_not_runner() {
|
match self.get_clone_or_not_runner() {
|
||||||
Some(r) => Some(r),
|
Some(r) => Some(r),
|
||||||
None => match profile.pull_on_build {
|
None => match profile.pull_on_build {
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
build_tools::{cmake::Cmake, git::Git},
|
build_tools::{cmake::Cmake, git::Git},
|
||||||
|
cmd_runner::CmdRunner,
|
||||||
file_utils::rm_rf,
|
file_utils::rm_rf,
|
||||||
profile::Profile,
|
profile::Profile,
|
||||||
runner::Runner,
|
runner::Runner,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec<Runner> {
|
pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec<Box<dyn Runner>> {
|
||||||
let mut runners: Vec<Runner> = vec![];
|
let mut runners: Vec<Box<dyn Runner>> = vec![];
|
||||||
let git = Git {
|
let git = Git {
|
||||||
repo: match profile.features.basalt.repo.as_ref() {
|
repo: match profile.features.basalt.repo.as_ref() {
|
||||||
Some(r) => r.clone(),
|
Some(r) => r.clone(),
|
||||||
|
@ -15,13 +16,14 @@ pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec<Run
|
||||||
},
|
},
|
||||||
dir: profile.features.basalt.path.as_ref().unwrap().clone(),
|
dir: profile.features.basalt.path.as_ref().unwrap().clone(),
|
||||||
};
|
};
|
||||||
|
runners.push(Box::new(git.get_override_remote_url_runner()));
|
||||||
if let Some(r) = git.clone_or_pull(profile) {
|
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() {
|
if let Some(r) = git.get_checkout_ref_runner() {
|
||||||
runners.push(r);
|
runners.push(Box::new(r));
|
||||||
if profile.pull_on_build {
|
if profile.pull_on_build {
|
||||||
runners.push(git.get_pull_runner());
|
runners.push(Box::new(git.get_pull_runner()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,21 +47,21 @@ pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec<Run
|
||||||
source_dir: profile.features.basalt.path.as_ref().unwrap().clone(),
|
source_dir: profile.features.basalt.path.as_ref().unwrap().clone(),
|
||||||
build_dir: build_dir.clone(),
|
build_dir: build_dir.clone(),
|
||||||
};
|
};
|
||||||
runners.push(Runner::new(None, "bash".into(), vec![
|
runners.push(Box::new(CmdRunner::new(None, "bash".into(), vec![
|
||||||
"-c".into(),
|
"-c".into(),
|
||||||
format!(
|
format!(
|
||||||
"cd {repo}/thirdparty/Pangolin && git checkout include/pangolin/utils/picojson.h && curl -sSL 'https://aur.archlinux.org/cgit/aur.git/plain/279c17d9c9eb9374c89489b449f92cb93350e8cd.patch?h=basalt-monado-git' -o picojson_fix.patch && git apply picojson_fix.patch && sed -i '1s/^/#include <stdint.h>\\n/' include/pangolin/platform.h",
|
"cd {repo}/thirdparty/Pangolin && git checkout include/pangolin/utils/picojson.h && curl -sSL 'https://aur.archlinux.org/cgit/aur.git/plain/279c17d9c9eb9374c89489b449f92cb93350e8cd.patch?h=basalt-monado-git' -o picojson_fix.patch && git apply picojson_fix.patch && sed -i '1s/^/#include <stdint.h>\\n/' include/pangolin/platform.h",
|
||||||
repo = git.dir
|
repo = git.dir
|
||||||
),
|
),
|
||||||
]));
|
])));
|
||||||
if !Path::new(&build_dir).is_dir() || clean_build {
|
if !Path::new(&build_dir).is_dir() || clean_build {
|
||||||
rm_rf(&build_dir);
|
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.push(cmake.get_install_runner());
|
runners.push(Box::new(cmake.get_install_runner()));
|
||||||
|
|
||||||
runners.push(Runner::new(
|
runners.push(Box::new(CmdRunner::new(
|
||||||
None,
|
None,
|
||||||
"mkdir".into(),
|
"mkdir".into(),
|
||||||
vec![
|
vec![
|
||||||
|
@ -69,8 +71,8 @@ pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec<Run
|
||||||
profile.prefix
|
profile.prefix
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
));
|
)));
|
||||||
runners.push(Runner::new(
|
runners.push(Box::new(CmdRunner::new(
|
||||||
None,
|
None,
|
||||||
"cp".into(),
|
"cp".into(),
|
||||||
vec![
|
vec![
|
||||||
|
@ -81,7 +83,7 @@ pub fn get_build_basalt_runners(profile: &Profile, clean_build: bool) -> Vec<Run
|
||||||
),
|
),
|
||||||
format!("{}/share/basalt/thirdparty", profile.prefix),
|
format!("{}/share/basalt/thirdparty", profile.prefix),
|
||||||
],
|
],
|
||||||
));
|
)));
|
||||||
|
|
||||||
runners
|
runners
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
pub fn get_build_libsurvive_runners(profile: &Profile, clean_build: bool) -> Vec<Runner> {
|
pub fn get_build_libsurvive_runners(profile: &Profile, clean_build: bool) -> Vec<Box<dyn Runner>> {
|
||||||
let mut runners: Vec<Runner> = vec![];
|
let mut runners: Vec<Box<dyn Runner>> = vec![];
|
||||||
let git = Git {
|
let git = Git {
|
||||||
repo: match profile.features.libsurvive.repo.as_ref() {
|
repo: match profile.features.libsurvive.repo.as_ref() {
|
||||||
Some(r) => r.clone(),
|
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(),
|
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) {
|
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() {
|
if let Some(r) = git.get_checkout_ref_runner() {
|
||||||
runners.push(r);
|
runners.push(Box::new(r));
|
||||||
if profile.pull_on_build {
|
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 {
|
if !Path::new(&build_dir).is_dir() || clean_build {
|
||||||
rm_rf(&build_dir);
|
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.push(cmake.get_install_runner());
|
runners.push(Box::new(cmake.get_install_runner()));
|
||||||
|
|
||||||
runners
|
runners
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use crate::{constants::pkg_data_dir, paths::get_cache_dir, profile::Profile, runner::Runner};
|
use crate::{
|
||||||
|
cmd_runner::CmdRunner, constants::pkg_data_dir, paths::get_cache_dir, profile::Profile,
|
||||||
|
};
|
||||||
|
|
||||||
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()];
|
let args = vec![profile.prefix.clone(), get_cache_dir()];
|
||||||
Runner::new(
|
CmdRunner::new(
|
||||||
None,
|
None,
|
||||||
format!(
|
format!(
|
||||||
"{sysdata}/scripts/build_mercury.sh",
|
"{sysdata}/scripts/build_mercury.sh",
|
||||||
|
|
|
@ -6,8 +6,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
pub fn get_build_monado_runners(profile: &Profile, clean_build: bool) -> Vec<Runner> {
|
pub fn get_build_monado_runners(profile: &Profile, clean_build: bool) -> Vec<Box<dyn Runner>> {
|
||||||
let mut runners: Vec<Runner> = vec![];
|
let mut runners: Vec<Box<dyn Runner>> = vec![];
|
||||||
let git = Git {
|
let git = Git {
|
||||||
repo: match profile.xrservice_repo.as_ref() {
|
repo: match profile.xrservice_repo.as_ref() {
|
||||||
Some(r) => r.clone(),
|
Some(r) => r.clone(),
|
||||||
|
@ -15,13 +15,14 @@ pub fn get_build_monado_runners(profile: &Profile, clean_build: bool) -> Vec<Run
|
||||||
},
|
},
|
||||||
dir: profile.xrservice_path.clone(),
|
dir: profile.xrservice_path.clone(),
|
||||||
};
|
};
|
||||||
|
runners.push(Box::new(git.get_override_remote_url_runner()));
|
||||||
if let Some(r) = git.clone_or_pull(profile) {
|
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() {
|
if let Some(r) = git.get_checkout_ref_runner() {
|
||||||
runners.push(r);
|
runners.push(Box::new(r));
|
||||||
if profile.pull_on_build {
|
if profile.pull_on_build {
|
||||||
runners.push(git.get_pull_runner());
|
runners.push(Box::new(git.get_pull_runner()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,10 +54,10 @@ pub fn get_build_monado_runners(profile: &Profile, clean_build: bool) -> Vec<Run
|
||||||
};
|
};
|
||||||
if !Path::new(&build_dir).is_dir() || clean_build {
|
if !Path::new(&build_dir).is_dir() || clean_build {
|
||||||
rm_rf(&build_dir);
|
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.push(cmake.get_install_runner());
|
runners.push(Box::new(cmake.get_install_runner()));
|
||||||
|
|
||||||
runners
|
runners
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,11 @@ use crate::{
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
pub fn get_build_opencomposite_runners(profile: &Profile, clean_build: bool) -> Vec<Runner> {
|
pub fn get_build_opencomposite_runners(
|
||||||
let mut runners: Vec<Runner> = vec![];
|
profile: &Profile,
|
||||||
|
clean_build: bool,
|
||||||
|
) -> Vec<Box<dyn Runner>> {
|
||||||
|
let mut runners: Vec<Box<dyn Runner>> = vec![];
|
||||||
let git = Git {
|
let git = Git {
|
||||||
repo: match profile.opencomposite_repo.as_ref() {
|
repo: match profile.opencomposite_repo.as_ref() {
|
||||||
Some(r) => r.clone(),
|
Some(r) => r.clone(),
|
||||||
|
@ -15,13 +18,14 @@ pub fn get_build_opencomposite_runners(profile: &Profile, clean_build: bool) ->
|
||||||
},
|
},
|
||||||
dir: profile.opencomposite_path.clone(),
|
dir: profile.opencomposite_path.clone(),
|
||||||
};
|
};
|
||||||
|
runners.push(Box::new(git.get_override_remote_url_runner()));
|
||||||
if let Some(r) = git.clone_or_pull(profile) {
|
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() {
|
if let Some(r) = git.get_checkout_ref_runner() {
|
||||||
runners.push(r);
|
runners.push(Box::new(r));
|
||||||
if profile.pull_on_build {
|
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 {
|
if !Path::new(&build_dir).is_dir() || clean_build {
|
||||||
rm_rf(&build_dir);
|
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
|
runners
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
pub fn get_build_wivrn_runners(profile: &Profile, clean_build: bool) -> Vec<Runner> {
|
pub fn get_build_wivrn_runners(profile: &Profile, clean_build: bool) -> Vec<Box<dyn Runner>> {
|
||||||
let mut runners: Vec<Runner> = vec![];
|
let mut runners: Vec<Box<dyn Runner>> = vec![];
|
||||||
let git = Git {
|
let git = Git {
|
||||||
repo: match profile.xrservice_repo.as_ref() {
|
repo: match profile.xrservice_repo.as_ref() {
|
||||||
Some(r) => r.clone(),
|
Some(r) => r.clone(),
|
||||||
|
@ -15,13 +15,14 @@ pub fn get_build_wivrn_runners(profile: &Profile, clean_build: bool) -> Vec<Runn
|
||||||
},
|
},
|
||||||
dir: profile.xrservice_path.clone(),
|
dir: profile.xrservice_path.clone(),
|
||||||
};
|
};
|
||||||
|
runners.push(Box::new(git.get_override_remote_url_runner()));
|
||||||
if let Some(r) = git.clone_or_pull(profile) {
|
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() {
|
if let Some(r) = git.get_checkout_ref_runner() {
|
||||||
runners.push(r);
|
runners.push(Box::new(r));
|
||||||
if profile.pull_on_build {
|
if profile.pull_on_build {
|
||||||
runners.push(git.get_pull_runner());
|
runners.push(Box::new(git.get_pull_runner()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,10 +41,10 @@ pub fn get_build_wivrn_runners(profile: &Profile, clean_build: bool) -> Vec<Runn
|
||||||
};
|
};
|
||||||
if !Path::new(&build_dir).is_dir() || clean_build {
|
if !Path::new(&build_dir).is_dir() || clean_build {
|
||||||
rm_rf(&build_dir);
|
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.push(cmake.get_install_runner());
|
runners.push(Box::new(cmake.get_install_runner()));
|
||||||
|
|
||||||
runners
|
runners
|
||||||
}
|
}
|
||||||
|
|
253
src/cmd_runner.rs
Normal file
253
src/cmd_runner.rs
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
use nix::{
|
||||||
|
sys::signal::{kill, Signal::SIGTERM},
|
||||||
|
unistd::Pid,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
file_utils::get_writer,
|
||||||
|
profile::{Profile, XRServiceType},
|
||||||
|
runner::{Runner, RunnerStatus},
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
io::{BufRead, BufReader, Write},
|
||||||
|
process::{Child, Command, Stdio},
|
||||||
|
sync::{
|
||||||
|
mpsc::{sync_channel, Receiver, SyncSender},
|
||||||
|
Arc, Mutex,
|
||||||
|
},
|
||||||
|
thread::{self, JoinHandle},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct CmdRunner {
|
||||||
|
pub environment: HashMap<String, String>,
|
||||||
|
pub command: String,
|
||||||
|
pub args: Vec<String>,
|
||||||
|
pub output: Vec<String>,
|
||||||
|
sender: Arc<Mutex<SyncSender<String>>>,
|
||||||
|
receiver: Receiver<String>,
|
||||||
|
threads: Vec<JoinHandle<()>>,
|
||||||
|
process: Option<Child>,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! logger_thread {
|
||||||
|
($buf_fd: expr, $sender: expr) => {
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut reader = BufReader::new($buf_fd);
|
||||||
|
loop {
|
||||||
|
let mut buf = String::new();
|
||||||
|
match reader.read_line(&mut buf) {
|
||||||
|
Err(_) => return,
|
||||||
|
Ok(bytes_read) => {
|
||||||
|
if bytes_read == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if buf.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
print!("{}", buf);
|
||||||
|
match $sender
|
||||||
|
.clone()
|
||||||
|
.lock()
|
||||||
|
.expect("Could not lock sender")
|
||||||
|
.send(buf)
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmdRunner {
|
||||||
|
pub fn new(
|
||||||
|
environment: Option<HashMap<String, String>>,
|
||||||
|
command: String,
|
||||||
|
args: Vec<String>,
|
||||||
|
) -> Self {
|
||||||
|
let (sender, receiver) = sync_channel(64000);
|
||||||
|
Self {
|
||||||
|
environment: match environment {
|
||||||
|
None => HashMap::new(),
|
||||||
|
Some(e) => e.clone(),
|
||||||
|
},
|
||||||
|
command,
|
||||||
|
args,
|
||||||
|
output: Vec::new(),
|
||||||
|
process: None,
|
||||||
|
sender: Arc::new(Mutex::new(sender)),
|
||||||
|
threads: Vec::new(),
|
||||||
|
receiver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn xrservice_runner_from_profile(profile: &Profile) -> Self {
|
||||||
|
let mut env = profile.environment.clone();
|
||||||
|
if !env.contains_key("LH_DRIVER") {
|
||||||
|
env.insert(
|
||||||
|
"LH_DRIVER".into(),
|
||||||
|
profile.lighthouse_driver.to_string().to_lowercase(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Self::new(
|
||||||
|
Some(env),
|
||||||
|
match profile.xrservice_type {
|
||||||
|
XRServiceType::Monado => format!("{pfx}/bin/monado-service", pfx = profile.prefix),
|
||||||
|
XRServiceType::Wivrn => format!("{pfx}/bin/wivrn-server", pfx = profile.prefix),
|
||||||
|
},
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_start(&mut self) -> Result<(), std::io::Error> {
|
||||||
|
self.threads = Vec::new();
|
||||||
|
let cmd = Command::new(self.command.clone())
|
||||||
|
.args(self.args.clone())
|
||||||
|
.envs(self.environment.clone())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()?;
|
||||||
|
self.process = Some(cmd);
|
||||||
|
let stdout = self.process.as_mut().unwrap().stdout.take().unwrap();
|
||||||
|
let stderr = self.process.as_mut().unwrap().stderr.take().unwrap();
|
||||||
|
let stdout_sender = self.sender.clone();
|
||||||
|
let stderr_sender = self.sender.clone();
|
||||||
|
self.threads.push(logger_thread!(stdout, stdout_sender));
|
||||||
|
self.threads.push(logger_thread!(stderr, stderr_sender));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn join_threads(&mut self) {
|
||||||
|
loop {
|
||||||
|
match self.threads.pop() {
|
||||||
|
None => break,
|
||||||
|
Some(thread) => thread.join().expect("Failed to join reader thread"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn terminate(&mut self) {
|
||||||
|
if self.status() != RunnerStatus::Running {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let process = self.process.take();
|
||||||
|
if process.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut proc = process.unwrap();
|
||||||
|
let child_pid = Pid::from_raw(proc.id().try_into().expect("Could not convert pid to u32"));
|
||||||
|
kill(child_pid, SIGTERM).expect("Could not send sigterm to process");
|
||||||
|
self.join_threads();
|
||||||
|
proc.wait().expect("Failed to wait for process");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn join(&mut self) {
|
||||||
|
let process = self.process.take();
|
||||||
|
if process.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut proc = process.unwrap();
|
||||||
|
proc.wait().expect("Failed to wait for process");
|
||||||
|
self.join_threads();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<String> {
|
||||||
|
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() {
|
||||||
|
Err(_) => RunnerStatus::Running,
|
||||||
|
Ok(Some(code)) => RunnerStatus::Stopped(code.code()),
|
||||||
|
Ok(None) => RunnerStatus::Running,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 crate::runner::Runner;
|
||||||
|
use core::time;
|
||||||
|
use std::{collections::HashMap, thread::sleep};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
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 = CmdRunner::new(
|
||||||
|
Some(env),
|
||||||
|
"bash".into(),
|
||||||
|
vec!["-c".into(), "echo \"REX2TEST: $REX2TEST\"".into()],
|
||||||
|
);
|
||||||
|
runner.start();
|
||||||
|
sleep(time::Duration::from_millis(1000)); // TODO: ugly, fix
|
||||||
|
runner.terminate();
|
||||||
|
assert_eq!(runner.status(), RunnerStatus::Stopped(Some(0)));
|
||||||
|
let out = runner.consume_output();
|
||||||
|
assert_eq!(out, "REX2TEST: Lorem ipsum dolor\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_save_log() {
|
||||||
|
let mut runner = CmdRunner::new(
|
||||||
|
None,
|
||||||
|
"bash".into(),
|
||||||
|
vec!["-c".into(), "echo \"Lorem ipsum dolor sit amet\"".into()],
|
||||||
|
);
|
||||||
|
runner.start();
|
||||||
|
while runner.status() == RunnerStatus::Running {
|
||||||
|
sleep(time::Duration::from_millis(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
runner
|
||||||
|
.save_output("./target/testout/testlog".into())
|
||||||
|
.expect("Failed to save output file");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_create_from_profile() {
|
||||||
|
CmdRunner::xrservice_runner_from_profile(&Profile::load_profile(
|
||||||
|
&"./test/files/profile.json".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::runner::Runner;
|
use crate::{cmd_runner::CmdRunner, runner::Runner};
|
||||||
use nix::{
|
use nix::{
|
||||||
errno::Errno,
|
errno::Errno,
|
||||||
sys::statvfs::{statvfs, FsFlags},
|
sys::statvfs::{statvfs, FsFlags},
|
||||||
|
@ -66,7 +66,7 @@ pub fn set_file_readonly(path_s: &String, readonly: bool) -> Result<(), std::io:
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setcap_cap_sys_nice_eip(file: String) {
|
pub fn setcap_cap_sys_nice_eip(file: String) {
|
||||||
let mut runner = Runner::new(
|
let mut runner = CmdRunner::new(
|
||||||
None,
|
None,
|
||||||
"pkexec".into(),
|
"pkexec".into(),
|
||||||
vec!["setcap".into(), "CAP_SYS_NICE=eip".into(), file],
|
vec!["setcap".into(), "CAP_SYS_NICE=eip".into(), file],
|
||||||
|
|
70
src/func_runner.rs
Normal file
70
src/func_runner.rs
Normal file
|
@ -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<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FuncRunner {
|
||||||
|
output: Vec<String>,
|
||||||
|
res: Option<bool>,
|
||||||
|
thread: Option<JoinHandle<FuncRunnerOut>>,
|
||||||
|
func: Box<dyn FnOnce() -> FuncRunnerOut + Send + Sync + 'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FuncRunner {
|
||||||
|
pub fn new(func: Box<dyn FnOnce() -> 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<String> {
|
||||||
|
let res = self.output.clone();
|
||||||
|
self.output.clear();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ pub mod adb;
|
||||||
pub mod build_tools;
|
pub mod build_tools;
|
||||||
pub mod builders;
|
pub mod builders;
|
||||||
pub mod checkerr;
|
pub mod checkerr;
|
||||||
|
pub mod cmd_runner;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod depcheck;
|
pub mod depcheck;
|
||||||
|
@ -25,6 +26,7 @@ pub mod downloader;
|
||||||
pub mod env_var_descriptions;
|
pub mod env_var_descriptions;
|
||||||
pub mod file_builders;
|
pub mod file_builders;
|
||||||
pub mod file_utils;
|
pub mod file_utils;
|
||||||
|
pub mod func_runner;
|
||||||
pub mod log_level;
|
pub mod log_level;
|
||||||
pub mod log_parser;
|
pub mod log_parser;
|
||||||
pub mod paths;
|
pub mod paths;
|
||||||
|
|
254
src/runner.rs
254
src/runner.rs
|
@ -1,256 +1,12 @@
|
||||||
use crate::{
|
|
||||||
file_utils::get_writer,
|
|
||||||
profile::{Profile, XRServiceType},
|
|
||||||
};
|
|
||||||
use nix::{
|
|
||||||
sys::signal::{kill, Signal::SIGTERM},
|
|
||||||
unistd::Pid,
|
|
||||||
};
|
|
||||||
use std::{
|
|
||||||
collections::HashMap,
|
|
||||||
io::{BufRead, BufReader, Write},
|
|
||||||
process::{Child, Command, Stdio},
|
|
||||||
sync::{
|
|
||||||
mpsc::{sync_channel, Receiver, SyncSender},
|
|
||||||
Arc, Mutex,
|
|
||||||
},
|
|
||||||
thread::{self, JoinHandle},
|
|
||||||
vec,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Runner {
|
|
||||||
pub environment: HashMap<String, String>,
|
|
||||||
pub command: String,
|
|
||||||
pub args: Vec<String>,
|
|
||||||
pub output: Vec<String>,
|
|
||||||
sender: Arc<Mutex<SyncSender<String>>>,
|
|
||||||
receiver: Receiver<String>,
|
|
||||||
threads: Vec<JoinHandle<()>>,
|
|
||||||
process: Option<Child>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub enum RunnerStatus {
|
pub enum RunnerStatus {
|
||||||
Running,
|
Running,
|
||||||
Stopped(Option<i32>),
|
Stopped(Option<i32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! logger_thread {
|
pub trait Runner {
|
||||||
($buf_fd: expr, $sender: expr) => {
|
fn start(&mut self);
|
||||||
thread::spawn(move || {
|
fn status(&mut self) -> RunnerStatus;
|
||||||
let mut reader = BufReader::new($buf_fd);
|
fn consume_output(&mut self) -> String;
|
||||||
loop {
|
fn consume_rows(&mut self) -> Vec<String>;
|
||||||
let mut buf = String::new();
|
|
||||||
match reader.read_line(&mut buf) {
|
|
||||||
Err(_) => return,
|
|
||||||
Ok(bytes_read) => {
|
|
||||||
if bytes_read == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if buf.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
print!("{}", buf);
|
|
||||||
match $sender
|
|
||||||
.clone()
|
|
||||||
.lock()
|
|
||||||
.expect("Could not lock sender")
|
|
||||||
.send(buf)
|
|
||||||
{
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(_) => return,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Runner {
|
|
||||||
pub fn new(
|
|
||||||
environment: Option<HashMap<String, String>>,
|
|
||||||
command: String,
|
|
||||||
args: Vec<String>,
|
|
||||||
) -> Self {
|
|
||||||
let (sender, receiver) = sync_channel(64000);
|
|
||||||
Self {
|
|
||||||
environment: match environment {
|
|
||||||
None => HashMap::new(),
|
|
||||||
Some(e) => e.clone(),
|
|
||||||
},
|
|
||||||
command,
|
|
||||||
args,
|
|
||||||
output: Vec::new(),
|
|
||||||
process: None,
|
|
||||||
sender: Arc::new(Mutex::new(sender)),
|
|
||||||
threads: Vec::new(),
|
|
||||||
receiver,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn xrservice_runner_from_profile(profile: &Profile) -> Self {
|
|
||||||
let mut env = profile.environment.clone();
|
|
||||||
if !env.contains_key("LH_DRIVER") {
|
|
||||||
env.insert(
|
|
||||||
"LH_DRIVER".into(),
|
|
||||||
profile.lighthouse_driver.to_string().to_lowercase(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Self::new(
|
|
||||||
Some(env),
|
|
||||||
match profile.xrservice_type {
|
|
||||||
XRServiceType::Monado => format!("{pfx}/bin/monado-service", pfx = profile.prefix),
|
|
||||||
XRServiceType::Wivrn => format!("{pfx}/bin/wivrn-server", pfx = profile.prefix),
|
|
||||||
},
|
|
||||||
vec![],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_start(&mut self) -> Result<(), std::io::Error> {
|
|
||||||
self.threads = Vec::new();
|
|
||||||
let cmd = Command::new(self.command.clone())
|
|
||||||
.args(self.args.clone())
|
|
||||||
.envs(self.environment.clone())
|
|
||||||
.stderr(Stdio::piped())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.spawn()?;
|
|
||||||
self.process = Some(cmd);
|
|
||||||
let stdout = self.process.as_mut().unwrap().stdout.take().unwrap();
|
|
||||||
let stderr = self.process.as_mut().unwrap().stderr.take().unwrap();
|
|
||||||
let stdout_sender = self.sender.clone();
|
|
||||||
let stderr_sender = self.sender.clone();
|
|
||||||
self.threads.push(logger_thread!(stdout, stdout_sender));
|
|
||||||
self.threads.push(logger_thread!(stderr, stderr_sender));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(&mut self) {
|
|
||||||
self.try_start().expect("Failed to execute runner");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn join_threads(&mut self) {
|
|
||||||
loop {
|
|
||||||
match self.threads.pop() {
|
|
||||||
None => break,
|
|
||||||
Some(thread) => thread.join().expect("Failed to join reader thread"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn terminate(&mut self) {
|
|
||||||
if self.status() != RunnerStatus::Running {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let process = self.process.take();
|
|
||||||
if process.is_none() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut proc = process.unwrap();
|
|
||||||
let child_pid = Pid::from_raw(proc.id().try_into().expect("Could not convert pid to u32"));
|
|
||||||
kill(child_pid, SIGTERM).expect("Could not send sigterm to process");
|
|
||||||
self.join_threads();
|
|
||||||
proc.wait().expect("Failed to wait for process");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn join(&mut self) {
|
|
||||||
let process = self.process.take();
|
|
||||||
if process.is_none() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut proc = process.unwrap();
|
|
||||||
proc.wait().expect("Failed to wait for process");
|
|
||||||
self.join_threads();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn status(&mut self) -> RunnerStatus {
|
|
||||||
match &mut self.process {
|
|
||||||
None => RunnerStatus::Stopped(None),
|
|
||||||
Some(proc) => match proc.try_wait() {
|
|
||||||
Err(_) => RunnerStatus::Running,
|
|
||||||
Ok(Some(code)) => RunnerStatus::Stopped(code.code()),
|
|
||||||
Ok(None) => RunnerStatus::Running,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<String> {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::profile::Profile;
|
|
||||||
|
|
||||||
use super::{Runner, RunnerStatus};
|
|
||||||
use core::time;
|
|
||||||
use std::{collections::HashMap, thread::sleep};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
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(
|
|
||||||
Some(env),
|
|
||||||
"bash".into(),
|
|
||||||
vec!["-c".into(), "echo \"REX2TEST: $REX2TEST\"".into()],
|
|
||||||
);
|
|
||||||
runner.start();
|
|
||||||
sleep(time::Duration::from_millis(1000)); // TODO: ugly, fix
|
|
||||||
runner.terminate();
|
|
||||||
assert_eq!(runner.status(), RunnerStatus::Stopped(Some(0)));
|
|
||||||
let out = runner.consume_output();
|
|
||||||
assert_eq!(out, "REX2TEST: Lorem ipsum dolor\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_save_log() {
|
|
||||||
let mut runner = Runner::new(
|
|
||||||
None,
|
|
||||||
"bash".into(),
|
|
||||||
vec!["-c".into(), "echo \"Lorem ipsum dolor sit amet\"".into()],
|
|
||||||
);
|
|
||||||
runner.start();
|
|
||||||
while runner.status() == RunnerStatus::Running {
|
|
||||||
sleep(time::Duration::from_millis(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
runner
|
|
||||||
.save_output("./target/testout/testlog".into())
|
|
||||||
.expect("Failed to save output file");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_create_from_profile() {
|
|
||||||
Runner::xrservice_runner_from_profile(&Profile::load_profile(
|
|
||||||
&"./test/files/profile.json".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
|
use crate::runner::{Runner, RunnerStatus};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use crate::runner::{Runner, RunnerStatus};
|
|
||||||
|
|
||||||
pub struct RunnerPipeline {
|
pub struct RunnerPipeline {
|
||||||
runners: Vec<RefCell<Runner>>,
|
runners: Vec<RefCell<Box<dyn Runner>>>,
|
||||||
current_index: usize,
|
current_index: usize,
|
||||||
last_exit_status: Option<i32>,
|
last_exit_status: Option<i32>,
|
||||||
has_started: bool,
|
has_started: bool,
|
||||||
|
@ -11,8 +10,8 @@ pub struct RunnerPipeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunnerPipeline {
|
impl RunnerPipeline {
|
||||||
pub fn new(runners: Vec<Runner>) -> Self {
|
pub fn new(runners: Vec<Box<dyn Runner>>) -> Self {
|
||||||
let mut c_runners: Vec<RefCell<Runner>> = vec![];
|
let mut c_runners: Vec<RefCell<Box<dyn Runner>>> = vec![];
|
||||||
for runner in runners {
|
for runner in runners {
|
||||||
c_runners.push(RefCell::new(runner));
|
c_runners.push(RefCell::new(runner));
|
||||||
}
|
}
|
||||||
|
@ -25,7 +24,7 @@ impl RunnerPipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_runner(&self) -> Option<&RefCell<Runner>> {
|
pub fn get_current_runner(&self) -> Option<&RefCell<Box<dyn Runner>>> {
|
||||||
self.runners.get(self.current_index)
|
self.runners.get(self.current_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::builders::build_mercury::get_build_mercury_runner;
|
||||||
use crate::builders::build_monado::get_build_monado_runners;
|
use crate::builders::build_monado::get_build_monado_runners;
|
||||||
use crate::builders::build_opencomposite::get_build_opencomposite_runners;
|
use crate::builders::build_opencomposite::get_build_opencomposite_runners;
|
||||||
use crate::builders::build_wivrn::get_build_wivrn_runners;
|
use crate::builders::build_wivrn::get_build_wivrn_runners;
|
||||||
|
use crate::cmd_runner::CmdRunner;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::constants::APP_NAME;
|
use crate::constants::APP_NAME;
|
||||||
use crate::depcheck::check_dependency;
|
use crate::depcheck::check_dependency;
|
||||||
|
@ -76,7 +77,7 @@ pub struct App {
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
config: Config,
|
config: Config,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
xrservice_runner: Option<Runner>,
|
xrservice_runner: Option<CmdRunner>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
build_pipeline: Option<RunnerPipeline>,
|
build_pipeline: Option<RunnerPipeline>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
|
@ -149,7 +150,7 @@ impl App {
|
||||||
XRServiceType::Wivrn => true, // no device from log in wivrn
|
XRServiceType::Wivrn => true, // no device from log in wivrn
|
||||||
};
|
};
|
||||||
self.debug_view.sender().emit(DebugViewMsg::ClearLog);
|
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() {
|
match runner.try_start() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.xrservice_runner = Some(runner);
|
self.xrservice_runner = Some(runner);
|
||||||
|
@ -400,7 +401,7 @@ impl SimpleComponent for App {
|
||||||
Msg::BuildProfile(clean_build) => {
|
Msg::BuildProfile(clean_build) => {
|
||||||
let profile = self.get_selected_profile();
|
let profile = self.get_selected_profile();
|
||||||
let mut missing_deps = vec![];
|
let mut missing_deps = vec![];
|
||||||
let mut runners: Vec<Runner> = vec![];
|
let mut runners: Vec<Box<dyn Runner>> = vec![];
|
||||||
// profile per se can't be built, but we still need opencomp
|
// profile per se can't be built, but we still need opencomp
|
||||||
if profile.can_be_built {
|
if profile.can_be_built {
|
||||||
missing_deps.extend(match profile.xrservice_type {
|
missing_deps.extend(match profile.xrservice_type {
|
||||||
|
@ -417,7 +418,7 @@ impl SimpleComponent for App {
|
||||||
}
|
}
|
||||||
if profile.features.mercury_enabled {
|
if profile.features.mercury_enabled {
|
||||||
missing_deps.extend(get_missing_mercury_deps());
|
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 {
|
runners.extend(match profile.xrservice_type {
|
||||||
XRServiceType::Monado => get_build_monado_runners(&profile, clean_build),
|
XRServiceType::Monado => get_build_monado_runners(&profile, clean_build),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
adb::get_adb_install_runner,
|
adb::get_adb_install_runner,
|
||||||
|
cmd_runner::CmdRunner,
|
||||||
depcheck::check_dependency,
|
depcheck::check_dependency,
|
||||||
dependencies::adb_dep::adb_dep,
|
dependencies::adb_dep::adb_dep,
|
||||||
downloader::download_file,
|
downloader::download_file,
|
||||||
|
@ -31,7 +32,7 @@ pub struct InstallWivrnBox {
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
download_thread: Option<JoinHandle<Result<(), reqwest::Error>>>,
|
download_thread: Option<JoinHandle<Result<(), reqwest::Error>>>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
install_runner: Option<Runner>,
|
install_runner: Option<CmdRunner>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
root_win: gtk::Window,
|
root_win: gtk::Window,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{profile::Profile, runner::Runner};
|
use crate::{cmd_runner::CmdRunner, profile::Profile, runner::Runner};
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
|
@ -40,7 +40,7 @@ pub struct LibsurviveSetupWindow {
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
profile: Option<Profile>,
|
profile: Option<Profile>,
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
calibration_runner: Option<Runner>,
|
calibration_runner: Option<CmdRunner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -54,14 +54,14 @@ pub enum LibsurviveSetupMsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LibsurviveSetupWindow {
|
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 lh_path = self.steam_lighthouse_path.clone();
|
||||||
let mut env = HashMap::new();
|
let mut env = HashMap::new();
|
||||||
env.insert(
|
env.insert(
|
||||||
"LD_LIBRARY_PATH".to_string(),
|
"LD_LIBRARY_PATH".to_string(),
|
||||||
format!("{pfx}/lib", pfx = self.profile.as_ref().unwrap().prefix),
|
format!("{pfx}/lib", pfx = self.profile.as_ref().unwrap().prefix),
|
||||||
);
|
);
|
||||||
Runner::new(
|
CmdRunner::new(
|
||||||
Some(env),
|
Some(env),
|
||||||
survive_cli_path,
|
survive_cli_path,
|
||||||
vec!["--steamvr-calibration".into(), lh_path],
|
vec!["--steamvr-calibration".into(), lh_path],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue