feat!: refactor around pathbuf

This commit is contained in:
Gabriele Musco 2024-07-21 09:41:07 +02:00
parent ec191b4e60
commit b01eaf69f6
41 changed files with 461 additions and 412 deletions

7
Cargo.lock generated
View file

@ -289,6 +289,7 @@ dependencies = [
"tracker",
"uuid",
"vte4",
"xdg",
]
[[package]]
@ -2528,3 +2529,9 @@ dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "xdg"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"

View file

@ -40,3 +40,4 @@ serde_json = "1.0.106"
tracker = "0.2.1"
uuid = { version = "1.8.0", features = ["v4", "fast-rng"] }
vte4 = { version = "0.7.1", features = ["v0_72"] }
xdg = "2.5.2"

View file

@ -1,12 +1,12 @@
use crate::cmd_runner::CmdRunner;
use std::path::Path;
use std::path::PathBuf;
pub fn get_adb_install_runner(apk_path: &String) -> CmdRunner {
let path = Path::new(apk_path);
use crate::cmd_runner::CmdRunner;
pub fn get_adb_install_runner(path: &PathBuf) -> CmdRunner {
path.try_exists().expect("APK file provided does not exist");
CmdRunner::new(
None,
"adb".into(),
vec!["install".into(), path.to_str().unwrap().to_string()],
vec!["install".into(), path.to_string_lossy().to_string()],
)
}

View file

@ -1,10 +1,10 @@
use crate::ui::job_worker::job::WorkerJob;
use std::collections::HashMap;
use std::{collections::HashMap, path::PathBuf};
#[derive(Debug, Clone)]
pub struct Cmake {
pub build_dir: String,
pub source_dir: String,
pub build_dir: PathBuf,
pub source_dir: PathBuf,
pub vars: Option<HashMap<String, String>>,
pub env: Option<HashMap<String, String>>,
}
@ -13,7 +13,7 @@ impl Cmake {
pub fn get_prepare_job(&self) -> WorkerJob {
let mut args = vec![
"-B".into(),
self.build_dir.clone(),
self.build_dir.to_string_lossy().to_string(),
"-G".into(),
"Ninja".into(),
];
@ -29,7 +29,7 @@ impl Cmake {
}
}
}
args.push(self.source_dir.clone());
args.push(self.source_dir.to_string_lossy().to_string());
WorkerJob::new_cmd(self.env.clone(), "cmake".into(), Some(args))
}
@ -37,7 +37,10 @@ impl Cmake {
WorkerJob::new_cmd(
self.env.clone(),
"cmake".into(),
Some(vec!["--build".into(), self.build_dir.clone()]),
Some(vec![
"--build".into(),
self.build_dir.to_string_lossy().to_string(),
]),
)
}
@ -45,7 +48,10 @@ impl Cmake {
WorkerJob::new_cmd(
self.env.clone(),
"cmake".into(),
Some(vec!["--install".into(), self.build_dir.clone()]),
Some(vec![
"--install".into(),
self.build_dir.to_string_lossy().to_string(),
]),
)
}
}

View file

@ -1,17 +1,17 @@
use crate::ui::job_worker::job::{FuncWorkerOut, WorkerJob};
use git2::Repository;
use std::path::Path;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct Git {
pub repo: String,
pub dir: String,
pub dir: PathBuf,
pub branch: String,
}
impl Git {
fn cmd(&self, args: Vec<String>) -> WorkerJob {
let mut nargs = vec!["-C".into(), self.dir.clone()];
let mut nargs = vec!["-C".into(), self.dir.to_string_lossy().to_string()];
nargs.extend(args);
WorkerJob::new_cmd(None, "git".into(), Some(nargs))
}
@ -81,7 +81,7 @@ impl Git {
Some(vec![
"clone".into(),
self.get_repo(),
self.dir.clone(),
self.dir.to_string_lossy().to_string(),
"--recurse-submodules".into(),
]),
)
@ -101,8 +101,7 @@ impl Git {
}
pub fn clone_exists(&self) -> bool {
let path_s = format!("{}/.git", self.dir.clone());
Path::new(&path_s).is_dir()
self.dir.join(".git").is_dir()
}
pub fn get_pre_build_jobs(&self, pull_on_build: bool) -> Vec<WorkerJob> {

View file

@ -4,10 +4,7 @@ use crate::{
profile::Profile,
ui::job_worker::job::WorkerJob,
};
use std::{
collections::{HashMap, VecDeque},
path::Path,
};
use std::collections::{HashMap, VecDeque};
pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque<WorkerJob> {
let mut jobs = VecDeque::<WorkerJob>::new();
@ -32,16 +29,19 @@ pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque<W
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));
let build_dir = format!("{}/build", profile.features.basalt.path.as_ref().unwrap());
let build_dir = profile.features.basalt.path.as_ref().unwrap().join("build");
let mut cmake_vars: HashMap<String, String> = HashMap::new();
cmake_vars.insert("CMAKE_EXPORT_COMPILE_COMMANDS".into(), "ON".into());
cmake_vars.insert("CMAKE_BUILD_TYPE".into(), "RelWithDebInfo".into());
cmake_vars.insert("CMAKE_INSTALL_PREFIX".into(), profile.prefix.clone());
cmake_vars.insert(
"CMAKE_INSTALL_PREFIX".into(),
profile.prefix.to_string_lossy().to_string(),
);
cmake_vars.insert("BUILD_TESTS".into(), "OFF".into());
cmake_vars.insert("BASALT_INSTANTIATIONS_DOUBLE".into(), "OFF".into());
cmake_vars.insert(
"CMAKE_INSTALL_LIBDIR".into(),
format!("{}/lib", profile.prefix),
profile.prefix.join("lib").to_string_lossy().to_string(),
);
let mut cmake_env: HashMap<String, String> = HashMap::new();
@ -56,7 +56,7 @@ pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque<W
build_dir: build_dir.clone(),
};
if !Path::new(&build_dir).is_dir() || clean_build {
if !build_dir.is_dir() || clean_build {
rm_rf(&build_dir);
jobs.push_back(cmake.get_prepare_job());
}
@ -68,10 +68,11 @@ pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque<W
"mkdir".into(),
Some(vec![
"-p".into(),
format!(
"{}/share/basalt/thirdparty/basalt-headers/thirdparty",
profile.prefix
),
profile
.prefix
.join("share/basalt/thirdparty/basalt-headers/thirdparty")
.to_string_lossy()
.to_string(),
]),
));
jobs.push_back(WorkerJob::new_cmd(
@ -79,11 +80,20 @@ pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque<W
"cp".into(),
Some(vec![
"-Ra".into(),
format!(
"{}/thirdparty/basalt-headers/thirdparty/eigen",
profile.features.basalt.path.as_ref().unwrap().clone()
),
format!("{}/share/basalt/thirdparty", profile.prefix),
profile
.features
.basalt
.path
.as_ref()
.unwrap()
.join("thirdparty/basalt-headers/thirdparty/eigen")
.to_string_lossy()
.to_string(),
profile
.prefix
.join("share/basalt/thirdparty")
.to_string_lossy()
.to_string(),
]),
));

View file

@ -32,20 +32,26 @@ pub fn get_build_libsurvive_jobs(profile: &Profile, clean_build: bool) -> VecDeq
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));
let build_dir = format!(
"{}/build",
profile.features.libsurvive.path.as_ref().unwrap()
);
let build_dir = profile
.features
.libsurvive
.path
.as_ref()
.unwrap()
.join("build");
let mut cmake_vars: HashMap<String, String> = HashMap::new();
cmake_vars.insert("CMAKE_EXPORT_COMPILE_COMMANDS".into(), "ON".into());
cmake_vars.insert("CMAKE_BUILD_TYPE".into(), "RelWithDebInfo".into());
cmake_vars.insert("ENABLE_api_example".into(), "OFF".into());
cmake_vars.insert("USE_HIDAPI".into(), "ON".into());
cmake_vars.insert("CMAKE_SKIP_INSTALL_RPATH".into(), "YES".into());
cmake_vars.insert("CMAKE_INSTALL_PREFIX".into(), profile.prefix.clone());
cmake_vars.insert(
"CMAKE_INSTALL_PREFIX".into(),
profile.prefix.to_string_lossy().to_string(),
);
cmake_vars.insert(
"CMAKE_INSTALL_LIBDIR".into(),
format!("{}/lib", profile.prefix),
profile.prefix.join("lib").to_string_lossy().to_string(),
);
let cmake = Cmake {

View file

@ -5,10 +5,13 @@ use crate::{
pub fn get_build_mercury_job(profile: &Profile) -> WorkerJob {
WorkerJob::new_cmd(
None,
format!(
"{sysdata}/scripts/build_mercury.sh",
sysdata = pkg_data_dir()
),
Some(vec![profile.prefix.clone(), get_cache_dir()]),
pkg_data_dir()
.join("scripts/build_mercury.sh")
.to_string_lossy()
.to_string(),
Some(vec![
profile.prefix.to_string_lossy().to_string(),
get_cache_dir().to_string_lossy().to_string(),
]),
)
}

View file

@ -28,25 +28,41 @@ pub fn get_build_monado_jobs(profile: &Profile, clean_build: bool) -> VecDeque<W
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));
let build_dir = format!("{}/build", profile.xrservice_path);
let build_dir = profile.xrservice_path.join("build");
let mut env: HashMap<String, String> = HashMap::new();
env.insert(
"PKG_CONFIG_PATH".into(),
format!("{}/lib/pkgconfig", profile.prefix),
profile
.prefix
.join("lib/pkgconfig")
.to_string_lossy()
.to_string(),
);
let mut cmake_vars: HashMap<String, String> = HashMap::new();
cmake_vars.insert("CMAKE_EXPORT_COMPILE_COMMANDS".into(), "ON".into());
cmake_vars.insert("CMAKE_BUILD_TYPE".into(), "RelWithDebInfo".into());
cmake_vars.insert("XRT_HAVE_SYSTEM_CJSON".into(), "NO".into());
cmake_vars.insert("CMAKE_LIBDIR".into(), format!("{}/lib", profile.prefix));
cmake_vars.insert("CMAKE_INSTALL_PREFIX".into(), profile.prefix.clone());
cmake_vars.insert(
"CMAKE_LIBDIR".into(),
profile.prefix.join("lib").to_string_lossy().to_string(),
);
cmake_vars.insert(
"CMAKE_INSTALL_PREFIX".into(),
profile.prefix.to_string_lossy().to_string(),
);
cmake_vars.insert(
"CMAKE_C_FLAGS".into(),
format!("-Wl,-rpath='{}/lib'", profile.prefix,),
format!(
"-Wl,-rpath='{}/lib'",
profile.prefix.to_string_lossy().to_string(),
),
);
cmake_vars.insert(
"CMAKE_CXX_FLAGS".into(),
format!("-Wl,-rpath='{}/lib'", profile.prefix,),
format!(
"-Wl,-rpath='{}/lib'",
profile.prefix.to_string_lossy().to_string(),
),
);
profile.xrservice_cmake_flags.iter().for_each(|(k, v)| {
if k == "CMAKE_C_FLAGS" || k == "CMAKE_CXX_FLAGS" {

View file

@ -28,7 +28,7 @@ pub fn get_build_opencomposite_jobs(profile: &Profile, clean_build: bool) -> Vec
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));
let build_dir = format!("{}/build", profile.opencomposite_path);
let build_dir = profile.opencomposite_path.join("build");
let mut cmake_vars: HashMap<String, String> = HashMap::new();
cmake_vars.insert("CMAKE_EXPORT_COMPILE_COMMANDS".into(), "ON".into());
cmake_vars.insert("CMAKE_BUILD_TYPE".into(), "RelWithDebInfo".into());

View file

@ -32,14 +32,23 @@ pub fn get_build_openhmd_jobs(profile: &Profile, clean_build: bool) -> VecDeque<
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));
let build_dir = format!("{}/build", profile.features.openhmd.path.as_ref().unwrap());
let build_dir = profile
.features
.openhmd
.path
.as_ref()
.unwrap()
.join("build");
let mut cmake_vars: HashMap<String, String> = HashMap::new();
cmake_vars.insert("CMAKE_EXPORT_COMPILE_COMMANDS".into(), "ON".into());
cmake_vars.insert("CMAKE_BUILD_TYPE".into(), "RelWithDebInfo".into());
cmake_vars.insert("CMAKE_INSTALL_PREFIX".into(), profile.prefix.clone());
cmake_vars.insert(
"CMAKE_INSTALL_PREFIX".into(),
profile.prefix.to_string_lossy().to_string(),
);
cmake_vars.insert(
"CMAKE_INSTALL_LIBDIR".into(),
format!("{}/lib", profile.prefix),
profile.prefix.join("lib").to_string_lossy().to_string(),
);
cmake_vars.insert("OPENHMD_DRIVER_OCULUS_RIFT_S".into(), "OFF".into());

View file

@ -28,13 +28,16 @@ pub fn get_build_wivrn_jobs(profile: &Profile, clean_build: bool) -> VecDeque<Wo
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));
let build_dir = format!("{}/build", profile.xrservice_path);
let build_dir = profile.xrservice_path.join("build");
let mut cmake_vars: HashMap<String, String> = HashMap::new();
cmake_vars.insert("CMAKE_EXPORT_COMPILE_COMMANDS".into(), "ON".into());
cmake_vars.insert("CMAKE_BUILD_TYPE".into(), "RelWithDebInfo".into());
cmake_vars.insert("XRT_HAVE_SYSTEM_CJSON".into(), "NO".into());
cmake_vars.insert("WIVRN_BUILD_CLIENT".into(), "OFF".into());
cmake_vars.insert("CMAKE_INSTALL_PREFIX".into(), profile.prefix.clone());
cmake_vars.insert(
"CMAKE_INSTALL_PREFIX".into(),
profile.prefix.to_string_lossy().to_string(),
);
profile.xrservice_cmake_flags.iter().for_each(|(k, v)| {
cmake_vars.insert(k.clone(), v.clone());

View file

@ -14,6 +14,7 @@ use crate::{
use std::{
collections::HashMap,
io::{BufRead, BufReader, Write},
path::PathBuf,
process::{Child, Command, Stdio},
sync::{
mpsc::{sync_channel, Receiver, SyncSender},
@ -99,9 +100,11 @@ impl CmdRunner {
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),
},
XRServiceType::Monado => profile.prefix.join("bin/monado-service"),
XRServiceType::Wivrn => profile.prefix.join("bin/wivrn-server"),
}
.to_string_lossy()
.to_string(),
vec![],
)
}
@ -171,13 +174,13 @@ impl CmdRunner {
}
}
fn save_log(path_s: String, log: &[String]) -> Result<(), std::io::Error> {
let mut writer = get_writer(&path_s).map_err(std::io::Error::other)?;
fn save_log(path: &PathBuf, log: &[String]) -> Result<(), std::io::Error> {
let mut writer = get_writer(path).map_err(std::io::Error::other)?;
let log_s = log.concat();
writer.write_all(log_s.as_ref())
}
pub fn save_output(&mut self, path: String) -> Result<(), std::io::Error> {
pub fn save_output(&mut self, path: &PathBuf) -> Result<(), std::io::Error> {
CmdRunner::save_log(path, &self.output)
}
}
@ -251,14 +254,14 @@ mod tests {
}
runner
.save_output("./target/testout/testlog".into())
.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(),
&"./test/files/profile.json".into(),
));
}
}

View file

@ -1,3 +1,5 @@
use serde::{de::Error, Deserialize, Serialize};
use crate::{
constants::CMD_NAME,
device_prober::get_xr_usb_devices,
@ -9,8 +11,7 @@ use crate::{
survive::survive_profile, wivrn::wivrn_profile, wmr::wmr_profile,
},
};
use serde::{ser::Error, Deserialize, Serialize};
use std::{fs::File, io::BufReader};
use std::{fs::File, io::BufReader, path::PathBuf};
fn default_win_size() -> [i32; 2] {
[360, 400]
@ -56,16 +57,12 @@ impl Config {
}
}
pub fn config_file_path() -> String {
format!(
"{config}/{name}.json",
config = get_config_dir(),
name = CMD_NAME
)
pub fn config_file_path() -> PathBuf {
get_config_dir().join(format!("{CMD_NAME}.json"))
}
fn from_path(path_s: String) -> Self {
match File::open(path_s) {
fn from_path(path: &PathBuf) -> Self {
match File::open(path) {
Ok(file) => {
let reader = BufReader::new(file);
match serde_json::from_reader(reader) {
@ -77,8 +74,8 @@ impl Config {
}
}
fn save_to_path(&self, path_s: &String) -> Result<(), serde_json::Error> {
let writer = get_writer(path_s).map_err(serde_json::Error::custom)?;
fn save_to_path(&self, path: &PathBuf) -> Result<(), serde_json::Error> {
let writer = get_writer(path).map_err(serde_json::Error::custom)?;
serde_json::to_writer_pretty(writer, self)
}
@ -88,7 +85,7 @@ impl Config {
}
pub fn get_config() -> Self {
Self::from_path(Self::config_file_path())
Self::from_path(&Self::config_file_path())
}
pub fn set_profiles(&mut self, profiles: &[Profile]) {
@ -117,7 +114,7 @@ mod tests {
#[test]
fn will_load_default_if_config_does_not_exist() {
assert_eq!(
Config::from_path("/non/existing/file.json".into()).debug_view_enabled,
Config::from_path(&"/non/existing/file.json".into()).debug_view_enabled,
false
)
}

View file

@ -1,5 +1,7 @@
use crate::paths::get_exec_prefix;
use std::path::PathBuf;
pub const APP_NAME: &str = "@PRETTY_NAME@";
pub const APP_ID: &str = "@APP_ID@";
pub const RESOURCES_BASE_PATH: &str = "@RESOURCES_BASE_PATH@";
@ -17,10 +19,10 @@ pub fn get_developers() -> Vec<String> {
vec!["Gabriele Musco <gabmus@disroot.org>".to_string()]
}
pub fn pkg_data_dir() -> String {
format!("{}/share/{}", get_exec_prefix(), CMD_NAME)
pub fn pkg_data_dir() -> PathBuf {
get_exec_prefix().join("share").join(CMD_NAME)
}
pub fn resources() -> String {
format!("{}/resources.gresource", pkg_data_dir())
format!("{}/resources.gresource", pkg_data_dir().to_string_lossy().to_string())
}

View file

@ -3,7 +3,7 @@ use reqwest::{
header::{HeaderMap, USER_AGENT},
Method,
};
use std::{io::prelude::*, thread::JoinHandle};
use std::{io::prelude::*, path::PathBuf, thread::JoinHandle};
use std::{thread, time::Duration};
const TIMEOUT: Duration = Duration::from_secs(60);
@ -23,7 +23,7 @@ fn client() -> reqwest::blocking::Client {
.expect("Failed to build reqwest::Client")
}
pub fn download_file(url: String, path: String) -> JoinHandle<Result<(), reqwest::Error>> {
pub fn download_file(url: String, path: PathBuf) -> JoinHandle<Result<(), reqwest::Error>> {
thread::spawn(move || {
let client = client();
match client.request(Method::GET, url).send() {

View file

@ -1,7 +1,8 @@
use crate::{
file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly},
paths::{get_backup_dir, get_xdg_config_dir, get_xdg_data_dir, SYSTEM_PREFIX},
paths::{get_backup_dir, SYSTEM_PREFIX},
profile::{Profile, XRServiceType},
xdg::XDG,
};
use serde::{ser::Error, Deserialize, Serialize};
use std::path::{Path, PathBuf};
@ -10,9 +11,9 @@ use std::path::{Path, PathBuf};
pub struct ActiveRuntimeInnerRuntime {
#[serde(rename = "VALVE_runtime_is_steamvr")]
pub valve_runtime_is_steamvr: Option<bool>,
pub library_path: String,
#[serde(rename = "MND_libmonado_path")]
pub libmonado_path: Option<PathBuf>,
pub library_path: PathBuf,
pub name: Option<String>,
}
@ -22,26 +23,20 @@ pub struct ActiveRuntime {
pub runtime: ActiveRuntimeInnerRuntime,
}
pub fn get_openxr_conf_dir() -> String {
format!("{config}/openxr", config = get_xdg_config_dir())
pub fn get_openxr_conf_dir() -> PathBuf {
XDG.get_config_home().join("openxr")
}
fn get_active_runtime_json_path() -> String {
format!(
"{config}/1/active_runtime.json",
config = get_openxr_conf_dir()
)
fn get_active_runtime_json_path() -> PathBuf {
get_openxr_conf_dir().join("1/active_runtime.json")
}
pub fn is_steam(active_runtime: &ActiveRuntime) -> bool {
matches!(active_runtime.runtime.valve_runtime_is_steamvr, Some(true))
}
fn get_backup_steam_active_runtime_path() -> String {
format!(
"{backup}/active_runtime.json.steam.bak",
backup = get_backup_dir()
)
fn get_backup_steam_active_runtime_path() -> PathBuf {
get_backup_dir().join("active_runtime.json.steam.bak")
}
fn get_backed_up_steam_active_runtime() -> Option<ActiveRuntime> {
@ -59,8 +54,8 @@ fn backup_steam_active_runtime() {
}
}
fn get_active_runtime_from_path(path_s: &String) -> Option<ActiveRuntime> {
deserialize_file(path_s)
fn get_active_runtime_from_path(path: &PathBuf) -> Option<ActiveRuntime> {
deserialize_file(path)
}
pub fn get_current_active_runtime() -> Option<ActiveRuntime> {
@ -69,9 +64,9 @@ pub fn get_current_active_runtime() -> Option<ActiveRuntime> {
fn dump_active_runtime_to_path(
active_runtime: &ActiveRuntime,
path_s: &String,
path: &PathBuf,
) -> Result<(), serde_json::Error> {
let writer = get_writer(path_s).map_err(serde_json::Error::custom)?;
let writer = get_writer(path).map_err(serde_json::Error::custom)?;
serde_json::to_writer_pretty(writer, active_runtime)
}
@ -89,11 +84,10 @@ fn build_steam_active_runtime() -> ActiveRuntime {
file_format_version: "1.0.0".into(),
runtime: ActiveRuntimeInnerRuntime {
valve_runtime_is_steamvr: Some(true),
library_path: format!(
"{data}/Steam/steamapps/common/SteamVR/bin/linux64/vrclient.so",
data = get_xdg_data_dir()
),
libmonado_path: None,
library_path: XDG
.get_data_home()
.join("Steam/steamapps/common/SteamVR/bin/linux64/vrclient.so"),
name: Some("SteamVR".into()),
},
}
@ -144,26 +138,25 @@ pub fn build_profile_active_runtime(profile: &Profile) -> ActiveRuntime {
name: None,
valve_runtime_is_steamvr: None,
libmonado_path: monado_so,
library_path: oxr_so.to_string_lossy().into_owned(),
library_path: oxr_so,
},
}
}
// for system installs
fn relativize_active_runtime_lib_path(ar: &ActiveRuntime, dest: &str) -> ActiveRuntime {
fn relativize_active_runtime_lib_path(ar: &ActiveRuntime, path: &PathBuf) -> ActiveRuntime {
let mut res = ar.clone();
let path = Path::new(dest);
let mut rel_chain = path
.components()
.map(|_| String::from(".."))
.collect::<Vec<String>>();
rel_chain.pop();
rel_chain.pop();
res.runtime.library_path = format!(
res.runtime.library_path = PathBuf::from(format!(
"{rels}{fullpath}",
rels = rel_chain.join("/"),
fullpath = ar.runtime.library_path
);
fullpath = ar.runtime.library_path.to_string_lossy()
));
res
}
@ -174,7 +167,7 @@ pub fn set_current_active_runtime_to_profile(profile: &Profile) -> anyhow::Resul
let pfx = profile.clone().prefix;
let mut ar = build_profile_active_runtime(profile);
// hack: relativize libopenxr_monado.so path for system installs
if pfx == SYSTEM_PREFIX {
if pfx == PathBuf::from(SYSTEM_PREFIX) {
ar = relativize_active_runtime_lib_path(&ar, &dest);
}
dump_current_active_runtime(&ar)?;
@ -184,6 +177,8 @@ pub fn set_current_active_runtime_to_profile(profile: &Profile) -> anyhow::Resul
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::{
dump_active_runtime_to_path, get_active_runtime_from_path,
relativize_active_runtime_lib_path, ActiveRuntime, ActiveRuntimeInnerRuntime,
@ -197,7 +192,9 @@ mod tests {
assert!(ar.runtime.valve_runtime_is_steamvr.unwrap());
assert_eq!(
ar.runtime.library_path,
"/home/user/.local/share/Steam/steamapps/common/SteamVR/bin/linux64/vrclient.so"
PathBuf::from(
"/home/user/.local/share/Steam/steamapps/common/SteamVR/bin/linux64/vrclient.so"
)
);
assert_eq!(ar.runtime.name.unwrap(), "SteamVR");
}
@ -232,10 +229,14 @@ mod tests {
};
let relativized = relativize_active_runtime_lib_path(
&ar,
"/home/user/.config/openxr/1/active_runtime.json",
&PathBuf::from("/home/user/.config/openxr/1/active_runtime.json"),
);
assert_eq!(
relativized.runtime.library_path,
relativized
.runtime
.library_path
.to_string_lossy()
.to_string(),
"../../../../../usr/lib64/libopenxr_monado.so"
);
}

View file

@ -1,6 +1,8 @@
use std::path::PathBuf;
use crate::{
file_utils::{deserialize_file, get_writer},
paths::get_xdg_config_dir,
xdg::XDG,
};
use serde::{Deserialize, Serialize};
@ -28,15 +30,12 @@ impl Default for MonadoAutorunConfig {
}
}
fn get_monado_autorun_config_path() -> String {
format!(
"{config}/monado/autorun_v0.json",
config = get_xdg_config_dir()
)
fn get_monado_autorun_config_path() -> PathBuf {
XDG.get_config_home().join("monado/autorun_v0.json")
}
fn get_monado_autorun_config_from_path(path_s: &String) -> Option<MonadoAutorunConfig> {
deserialize_file(path_s)
fn get_monado_autorun_config_from_path(path: &PathBuf) -> Option<MonadoAutorunConfig> {
deserialize_file(path)
}
pub fn get_monado_autorun_config() -> MonadoAutorunConfig {
@ -44,8 +43,8 @@ pub fn get_monado_autorun_config() -> MonadoAutorunConfig {
.unwrap_or(MonadoAutorunConfig::default())
}
fn dump_monado_autorun_config_to_path(config: &MonadoAutorunConfig, path_s: &String) {
let writer = get_writer(path_s).expect("Unable to save Monado Autorun config");
fn dump_monado_autorun_config_to_path(config: &MonadoAutorunConfig, path: &PathBuf) {
let writer = get_writer(path).expect("Unable to save Monado Autorun config");
serde_json::to_writer_pretty(writer, config).expect("Unable to save Monado Autorun config");
}

View file

@ -1,43 +1,41 @@
use std::path::PathBuf;
use crate::{
file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly},
paths::{get_backup_dir, get_xdg_config_dir, get_xdg_data_dir},
paths::get_backup_dir,
profile::Profile,
xdg::XDG,
};
use serde::{ser::Error, Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct OpenVrPaths {
config: Vec<String>,
config: Vec<PathBuf>,
external_drivers: Option<Vec<String>>, // never seen it populated
jsonid: String,
log: Vec<String>,
runtime: Vec<String>,
log: Vec<PathBuf>,
runtime: Vec<PathBuf>,
version: u32,
}
pub fn get_openvr_conf_dir() -> String {
format!("{config}/openvr", config = get_xdg_config_dir())
pub fn get_openvr_conf_dir() -> PathBuf {
XDG.get_config_home().join("openvr")
}
fn get_openvrpaths_vrpath_path() -> String {
format!(
"{config}/openvrpaths.vrpath",
config = get_openvr_conf_dir()
)
fn get_openvrpaths_vrpath_path() -> PathBuf {
get_openvr_conf_dir().join("openvrpaths.vrpath")
}
pub fn is_steam(ovr_paths: &OpenVrPaths) -> bool {
ovr_paths.runtime.iter().any(|rt| {
rt.to_lowercase()
rt.to_string_lossy()
.to_lowercase()
.ends_with("/steam/steamapps/common/steamvr")
})
}
fn get_backup_steam_openvrpaths_path() -> String {
format!(
"{backup}/openvrpaths.vrpath.steam.bak",
backup = get_backup_dir()
)
fn get_backup_steam_openvrpaths_path() -> PathBuf {
get_backup_dir().join("openvrpaths.vrpath.steam.bak")
}
fn get_backed_up_steam_openvrpaths() -> Option<OpenVrPaths> {
@ -55,8 +53,8 @@ fn backup_steam_openvrpaths() {
}
}
fn get_openvrpaths_from_path(path_s: &String) -> Option<OpenVrPaths> {
deserialize_file(path_s)
fn get_openvrpaths_from_path(path: &PathBuf) -> Option<OpenVrPaths> {
deserialize_file(path)
}
pub fn get_current_openvrpaths() -> Option<OpenVrPaths> {
@ -65,9 +63,9 @@ pub fn get_current_openvrpaths() -> Option<OpenVrPaths> {
fn dump_openvrpaths_to_path(
ovr_paths: &OpenVrPaths,
path_s: &String,
path: &PathBuf,
) -> Result<(), serde_json::Error> {
let writer = get_writer(path_s).map_err(serde_json::Error::custom)?;
let writer = get_writer(path).map_err(serde_json::Error::custom)?;
serde_json::to_writer_pretty(writer, ovr_paths)
}
@ -79,16 +77,13 @@ fn build_steam_openvrpaths() -> OpenVrPaths {
if let Some(backup) = get_backed_up_steam_openvrpaths() {
return backup;
}
let datadir = get_xdg_data_dir();
let datadir = XDG.get_data_home();
OpenVrPaths {
config: vec![format!("{data}/Steam/config", data = datadir)],
config: vec![datadir.join("Steam/config")],
external_drivers: None,
jsonid: "vrpathreg".into(),
log: vec![format!("{data}/Steam/logs", data = datadir)],
runtime: vec![format!(
"{data}/Steam/steamapps/common/SteamVR",
data = datadir
)],
log: vec![datadir.join("Steam/logs")],
runtime: vec![datadir.join("Steam/steamapps/common/SteamVR")],
version: 1,
}
}
@ -100,16 +95,13 @@ pub fn set_current_openvrpaths_to_steam() -> anyhow::Result<()> {
}
pub fn build_profile_openvrpaths(profile: &Profile) -> OpenVrPaths {
let datadir = get_xdg_data_dir();
let datadir = XDG.get_data_home();
OpenVrPaths {
config: vec![format!("{data}/Steam/config", data = datadir)],
config: vec![datadir.join("Steam/config")],
external_drivers: None,
jsonid: "vrpathreg".into(),
log: vec![format!("{data}/Steam/logs", data = datadir)],
runtime: vec![format!(
"{opencomp_dir}/build",
opencomp_dir = profile.opencomposite_path
)],
log: vec![datadir.join("Steam/logs")],
runtime: vec![profile.opencomposite_path.join("build")],
version: 1,
}
}
@ -125,6 +117,8 @@ pub fn set_current_openvrpaths_to_profile(profile: &Profile) -> anyhow::Result<(
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::{dump_openvrpaths_to_path, get_openvrpaths_from_path, OpenVrPaths};
#[test]
@ -133,7 +127,7 @@ mod tests {
assert_eq!(ovrp.config.len(), 1);
assert_eq!(
ovrp.config.get(0).unwrap(),
"/home/user/.local/share/Steam/config"
&PathBuf::from("/home/user/.local/share/Steam/config")
);
assert_eq!(ovrp.external_drivers, None);
assert_eq!(ovrp.jsonid, "vrpathreg");

View file

@ -1,9 +1,9 @@
use crate::{
file_utils::{deserialize_file, get_writer},
paths::get_xdg_config_dir,
xdg::XDG,
};
use serde::{Deserialize, Serialize};
use std::{fmt::Display, slice::Iter};
use std::{fmt::Display, path::PathBuf, slice::Iter};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
@ -123,20 +123,20 @@ impl Default for WivrnConfig {
}
}
fn get_wivrn_config_path() -> String {
format!("{config}/wivrn/config.json", config = get_xdg_config_dir())
fn get_wivrn_config_path() -> PathBuf {
XDG.get_config_home().join("wivrn/config.json")
}
fn get_wivrn_config_from_path(path_s: &String) -> Option<WivrnConfig> {
deserialize_file(path_s)
fn get_wivrn_config_from_path(path: &PathBuf) -> Option<WivrnConfig> {
deserialize_file(path)
}
pub fn get_wivrn_config() -> WivrnConfig {
get_wivrn_config_from_path(&get_wivrn_config_path()).unwrap_or(WivrnConfig::default())
}
fn dump_wivrn_config_to_path(config: &WivrnConfig, path_s: &String) {
let writer = get_writer(path_s).expect("Unable to save WiVRn config");
fn dump_wivrn_config_to_path(config: &WivrnConfig, path: &PathBuf) {
let writer = get_writer(path).expect("Unable to save WiVRn config");
serde_json::to_writer_pretty(writer, config).expect("Unable to save WiVRn config");
}

View file

@ -6,11 +6,10 @@ use nix::{
use std::{
fs::{self, copy, create_dir_all, remove_dir_all, File, OpenOptions},
io::{BufReader, BufWriter},
path::Path,
path::{Path, PathBuf},
};
pub fn get_writer(path_s: &str) -> anyhow::Result<BufWriter<std::fs::File>> {
let path = Path::new(path_s);
pub fn get_writer(path: &PathBuf) -> anyhow::Result<BufWriter<std::fs::File>> {
if let Some(parent) = path.parent() {
if !parent.is_dir() {
create_dir_all(parent)?;
@ -24,26 +23,25 @@ pub fn get_writer(path_s: &str) -> anyhow::Result<BufWriter<std::fs::File>> {
Ok(BufWriter::new(file))
}
pub fn get_reader(path_s: &str) -> Option<BufReader<File>> {
let path = Path::new(&path_s);
pub fn get_reader(path: &PathBuf) -> Option<BufReader<File>> {
if !(path.is_file() || path.is_symlink()) {
return None;
}
match File::open(path) {
Err(e) => {
println!("Error opening {}: {}", path_s, e);
println!("Error opening {}: {}", path.to_string_lossy(), e);
None
}
Ok(fd) => Some(BufReader::new(fd)),
}
}
pub fn deserialize_file<T: serde::de::DeserializeOwned>(path_s: &String) -> Option<T> {
match get_reader(path_s) {
pub fn deserialize_file<T: serde::de::DeserializeOwned>(path: &PathBuf) -> Option<T> {
match get_reader(path) {
None => None,
Some(reader) => match serde_json::from_reader(reader) {
Err(e) => {
println!("Failed to deserialize {}: {}", path_s, e);
println!("Failed to deserialize {}: {}", path.to_string_lossy(), e);
None
}
Ok(res) => Some(res),
@ -51,8 +49,7 @@ pub fn deserialize_file<T: serde::de::DeserializeOwned>(path_s: &String) -> Opti
}
}
pub fn set_file_readonly(path_s: &str, readonly: bool) -> Result<(), std::io::Error> {
let path = Path::new(&path_s);
pub fn set_file_readonly(path: &PathBuf, readonly: bool) -> Result<(), std::io::Error> {
if !path.is_file() {
println!("WARN: trying to set readonly on a file that does not exist");
return Ok(());
@ -64,38 +61,45 @@ pub fn set_file_readonly(path_s: &str, readonly: bool) -> Result<(), std::io::Er
fs::set_permissions(path, perms)
}
pub fn setcap_cap_sys_nice_eip(file: String) {
pub fn setcap_cap_sys_nice_eip(file: &PathBuf) {
let mut runner = CmdRunner::new(
None,
"pkexec".into(),
vec!["setcap".into(), "CAP_SYS_NICE=eip".into(), file],
vec![
"setcap".into(),
"CAP_SYS_NICE=eip".into(),
file.to_string_lossy().to_string(),
],
);
runner.start();
runner.join();
}
pub fn rm_rf(path_s: &String) {
if remove_dir_all(path_s).is_err() {
println!("Failed to remove path {}", path_s);
pub fn rm_rf(path: &PathBuf) {
if remove_dir_all(path).is_err() {
println!("Failed to remove path {}", path.to_string_lossy());
}
}
pub fn copy_file(source_s: &str, dest_s: &str) {
let source = Path::new(source_s);
let dest = Path::new(dest_s);
pub fn copy_file(source: &PathBuf, dest: &PathBuf) {
if let Some(parent) = dest.parent() {
if !parent.is_dir() {
create_dir_all(parent)
.unwrap_or_else(|_| panic!("Failed to create dir {}", parent.to_str().unwrap()));
}
}
set_file_readonly(dest_s, false)
.unwrap_or_else(|_| panic!("Failed to set file {} as rw", dest_s));
copy(source, dest).unwrap_or_else(|_| panic!("Failed to copy {} to {}", source_s, dest_s));
set_file_readonly(dest, false)
.unwrap_or_else(|_| panic!("Failed to set file {} as rw", dest.to_string_lossy()));
copy(source, dest).unwrap_or_else(|_| {
panic!(
"Failed to copy {} to {}",
source.to_string_lossy(),
dest.to_string_lossy()
)
});
}
pub fn mount_has_nosuid(path_s: &str) -> Result<bool, Errno> {
let path = Path::new(path_s);
pub fn mount_has_nosuid(path: &PathBuf) -> Result<bool, Errno> {
match statvfs(path) {
Ok(fstats) => Ok(fstats.flags().contains(FsFlags::ST_NOSUID)),
Err(e) => Err(e),
@ -104,10 +108,12 @@ pub fn mount_has_nosuid(path_s: &str) -> Result<bool, Errno> {
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use crate::file_utils::mount_has_nosuid;
#[test]
fn can_get_nosuid() {
mount_has_nosuid("/tmp").expect("Error running statvfs");
mount_has_nosuid(&PathBuf::from("/tmp")).expect("Error running statvfs");
}
}

View file

@ -1,16 +1,16 @@
use crate::file_utils::get_reader;
use std::{error::Error, fmt::Display, io::Read, str::FromStr};
use std::{error::Error, fmt::Display, io::Read, path::PathBuf, str::FromStr};
// const POW_PROF_PATH: &str = "/sys/class/drm/card0/device/pp_power_profile_mode";
fn power_profile_mode_file(card_dir: &str) -> String {
format!("{}/device/pp_power_profile_mode", card_dir)
fn power_profile_mode_file(card_dir: &PathBuf) -> PathBuf {
card_dir.join("device/pp_power_profile_mode")
}
pub fn get_set_amd_vr_pow_prof_cmd(card_dir: &str) -> String {
pub fn get_set_amd_vr_pow_prof_cmd(card_dir: &PathBuf) -> String {
format!(
"sudo sh -c \"echo '4' > {}\"",
power_profile_mode_file(card_dir)
power_profile_mode_file(card_dir).to_string_lossy()
)
}
@ -93,10 +93,10 @@ const AMD_VENDOR_ID: &str = "0x1002";
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GpuSysDrm {
Amd(String),
Intel(String),
Nvidia(String),
Other(String),
Amd(PathBuf),
Intel(PathBuf),
Nvidia(PathBuf),
Other(PathBuf),
}
fn list_gpus() -> Vec<GpuSysDrm> {
@ -104,8 +104,8 @@ fn list_gpus() -> Vec<GpuSysDrm> {
for i in 0..5 {
// arbitrary range, find a better way
let card_dir = format!("/sys/class/drm/card{}", i);
let vendor_file = format!("{}/device/vendor", card_dir);
let card_dir = PathBuf::from(format!("/sys/class/drm/card{}", i));
let vendor_file = card_dir.join("device/vendor");
if let Some(mut reader) = get_reader(&vendor_file) {
let mut buf = String::new();
if reader.read_to_string(&mut buf).is_ok() {
@ -131,7 +131,7 @@ pub fn get_first_amd_gpu() -> Option<GpuSysDrm> {
pub fn get_amd_gpu_power_profile() -> Option<GpuPowerProfile> {
let amd_gpu = get_first_amd_gpu();
if let Some(GpuSysDrm::Amd(card_dir)) = amd_gpu {
if let Some(mut reader) = get_reader(&power_profile_mode_file(card_dir.as_str())) {
if let Some(mut reader) = get_reader(&power_profile_mode_file(&card_dir)) {
let mut txt = String::new();
reader.read_to_string(&mut txt).ok()?;
for line in txt.split('\n') {

View file

@ -1,5 +1,8 @@
use crate::file_utils::get_reader;
use std::io::{BufRead, Read};
use std::{
io::{BufRead, Read},
path::PathBuf,
};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum LinuxDistro {
@ -18,10 +21,10 @@ impl LinuxDistro {
}
fn get_from_etc_os_release() -> Option<Self> {
Self::get_from_etc_os_release_file("/etc/os-release")
Self::get_from_etc_os_release_file(&"/etc/os-release".into())
}
fn get_from_etc_os_release_file(fp: &str) -> Option<Self> {
fn get_from_etc_os_release_file(fp: &PathBuf) -> Option<Self> {
if let Some(mut reader) = get_reader(fp) {
let mut buf = String::new();
loop {
@ -47,7 +50,7 @@ impl LinuxDistro {
}
fn get_from_etc_issue() -> Option<Self> {
if let Some(mut reader) = get_reader("/etc/issue") {
if let Some(mut reader) = get_reader(&"/etc/issue".into()) {
let mut buf = String::new();
if reader.read_to_string(&mut buf).is_ok() {
buf = buf.trim().to_lowercase();
@ -111,7 +114,7 @@ mod tests {
#[test]
fn can_detect_arch_linux_from_etc_os_release() {
assert_eq!(
LinuxDistro::get_from_etc_os_release_file("./test/files/archlinux-os-release"),
LinuxDistro::get_from_etc_os_release_file(&"./test/files/archlinux-os-release".into()),
Some(LinuxDistro::Arch)
)
}

View file

@ -42,6 +42,7 @@ pub mod runner_pipeline;
pub mod steam_linux_runtime_injector;
pub mod steamvr_utils;
pub mod ui;
pub mod xdg;
pub mod xr_devices;
fn restore_steam_xr_files() {

View file

@ -1,32 +1,36 @@
use crate::{constants::CMD_NAME, profile::XRServiceType};
use std::{env, fs::create_dir_all, path::Path};
use crate::{constants::CMD_NAME, profile::XRServiceType, xdg::XDG};
use std::{
env,
fs::create_dir_all,
path::{Path, PathBuf},
};
pub fn data_opencomposite_path() -> String {
format!("{data}/opencomposite", data = get_data_dir())
pub fn data_opencomposite_path() -> PathBuf {
get_data_dir().join("opencomposite")
}
pub fn data_monado_path() -> String {
format!("{data}/monado", data = get_data_dir())
pub fn data_monado_path() -> PathBuf {
get_data_dir().join("monado")
}
pub fn data_wivrn_path() -> String {
format!("{data}/wivrn", data = get_data_dir())
pub fn data_wivrn_path() -> PathBuf {
get_data_dir().join("wivrn")
}
pub fn data_libsurvive_path() -> String {
format!("{data}/libsurvive", data = get_data_dir())
pub fn data_libsurvive_path() -> PathBuf {
get_data_dir().join("libsurvive")
}
pub fn data_openhmd_path() -> String {
format!("{data}/openhmd", data = get_data_dir())
pub fn data_openhmd_path() -> PathBuf {
get_data_dir().join("openhmd")
}
pub fn data_basalt_path() -> String {
format!("{data}/basalt", data = get_data_dir())
pub fn data_basalt_path() -> PathBuf {
get_data_dir().join("basalt")
}
pub fn wivrn_apk_download_path() -> String {
format!("{cache}/wivrn.apk", cache = get_cache_dir())
pub fn wivrn_apk_download_path() -> PathBuf {
get_cache_dir().join("wivrn.apk")
}
pub const SYSTEM_PREFIX: &str = "/usr";
@ -34,58 +38,24 @@ pub const SYSTEM_PREFIX: &str = "/usr";
/** System prefix inside a bubblewrap environment (flatpak or pressure vessel) */
pub const BWRAP_SYSTEM_PREFIX: &str = "/run/host/usr";
pub fn get_home_dir() -> String {
env::var("HOME").expect("HOME env var not defined")
pub fn get_home_dir() -> PathBuf {
env::var("HOME").expect("HOME env var not defined").into()
}
pub fn get_xdg_config_dir() -> String {
match env::var("XDG_CONFIG_HOME") {
Ok(conf_home) => conf_home,
Err(_) => format!("{home}/.config", home = get_home_dir()),
}
pub fn get_config_dir() -> PathBuf {
XDG.get_config_home().join(CMD_NAME)
}
pub fn get_xdg_data_dir() -> String {
match env::var("XDG_DATA_HOME") {
Ok(data_home) => data_home,
Err(_) => format!("{home}/.local/share", home = get_home_dir()),
}
pub fn get_data_dir() -> PathBuf {
XDG.get_data_home().join(CMD_NAME)
}
pub fn get_xdg_cache_dir() -> String {
match env::var("XDG_CACHE_HOME") {
Ok(cache_home) => cache_home,
Err(_) => format!("{home}/.cache", home = get_home_dir()),
}
pub fn get_cache_dir() -> PathBuf {
XDG.get_cache_home().join(CMD_NAME)
}
pub fn get_xdg_runtime_dir() -> String {
env::var("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR is not set")
}
pub fn get_config_dir() -> String {
format!(
"{config}/{name}",
config = get_xdg_config_dir(),
name = CMD_NAME
)
}
pub fn get_data_dir() -> String {
format!("{data}/{name}", data = get_xdg_data_dir(), name = CMD_NAME)
}
pub fn get_cache_dir() -> String {
format!(
"{cache}/{name}",
cache = get_xdg_cache_dir(),
name = CMD_NAME
)
}
pub fn get_backup_dir() -> String {
let p_s = format!("{data}/backups", data = get_data_dir());
let p = Path::new(&p_s);
pub fn get_backup_dir() -> PathBuf {
let p = get_data_dir().join("backups");
if !p.is_dir() {
if p.is_file() {
panic!(
@ -93,12 +63,12 @@ pub fn get_backup_dir() -> String {
p.to_str().unwrap()
);
}
create_dir_all(p).expect("Failed to create backups dir");
create_dir_all(&p).expect("Failed to create backups dir");
}
p.to_str().unwrap().to_string()
p
}
pub fn get_exec_prefix() -> String {
pub fn get_exec_prefix() -> PathBuf {
let p = Path::new("/proc/self/exe");
if !p.is_symlink() {
panic!("/proc/self/exe is not a symlink!");
@ -110,25 +80,19 @@ pub fn get_exec_prefix() -> String {
.unwrap()
.parent()
.unwrap()
.to_str()
.unwrap()
.to_string()
.into()
}
pub fn get_ipc_file_path(xrservice_type: &XRServiceType) -> String {
format!(
"{runtime}/{xrservice}_comp_ipc",
runtime = get_xdg_runtime_dir(),
xrservice = match xrservice_type {
XRServiceType::Monado => "monado",
XRServiceType::Wivrn => "wivrn",
}
)
pub fn get_ipc_file_path(xrservice_type: &XRServiceType) -> PathBuf {
XDG.get_runtime_directory()
.expect("XDG runtime directory is not available")
.join(match xrservice_type {
XRServiceType::Monado => "monado_comp_ipc",
XRServiceType::Wivrn => "wivrn_comp_ipc",
})
}
pub fn get_steamvr_bin_dir_path() -> String {
format!(
"{data}/Steam/steamapps/common/SteamVR/bin/linux64",
data = get_xdg_data_dir()
)
pub fn get_steamvr_bin_dir_path() -> PathBuf {
XDG.get_data_home()
.join("Steam/steamapps/common/SteamVR/bin/linux64")
}

View file

@ -2,8 +2,16 @@ use crate::{
file_utils::get_writer,
paths::{get_data_dir, get_ipc_file_path, BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX},
};
use nix::NixPath;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fmt::Display, fs::File, io::BufReader, path::Path, slice::Iter};
use std::{
collections::HashMap,
fmt::Display,
fs::File,
io::BufReader,
path::{Path, PathBuf},
slice::Iter,
};
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -85,7 +93,7 @@ impl Display for ProfileFeatureType {
pub struct ProfileFeature {
pub feature_type: ProfileFeatureType,
pub enabled: bool,
pub path: Option<String>,
pub path: Option<PathBuf>,
pub repo: Option<String>,
pub branch: Option<String>,
}
@ -207,18 +215,18 @@ pub struct Profile {
pub uuid: String,
pub name: String,
pub xrservice_type: XRServiceType,
pub xrservice_path: String,
pub xrservice_path: PathBuf,
pub xrservice_repo: Option<String>,
pub xrservice_branch: Option<String>,
#[serde(default = "HashMap::<String, String>::default")]
pub xrservice_cmake_flags: HashMap<String, String>,
pub opencomposite_path: String,
pub opencomposite_path: PathBuf,
pub opencomposite_repo: Option<String>,
pub opencomposite_branch: Option<String>,
pub features: ProfileFeatures,
pub environment: HashMap<String, String>,
/** Install prefix */
pub prefix: String,
pub prefix: PathBuf,
pub can_be_built: bool,
pub editable: bool,
pub pull_on_build: bool,
@ -239,10 +247,10 @@ impl Display for Profile {
impl Default for Profile {
fn default() -> Self {
let uuid = Uuid::new_v4().to_string();
let profile_dir = format!("{}/{}", get_data_dir(), uuid);
let profile_dir = get_data_dir().join(&uuid);
Self {
name: "Default profile name".into(),
xrservice_path: format!("{}/xrservice", profile_dir),
xrservice_path: profile_dir.join("xrservice"),
xrservice_type: XRServiceType::Monado,
xrservice_repo: None,
xrservice_branch: None,
@ -250,21 +258,21 @@ impl Default for Profile {
features: ProfileFeatures {
libsurvive: ProfileFeature {
enabled: false,
path: Some(format!("{}/libsurvive", profile_dir)),
path: Some(profile_dir.join("libsurvive")),
repo: None,
branch: None,
feature_type: ProfileFeatureType::Libsurvive,
},
basalt: ProfileFeature {
enabled: false,
path: Some(format!("{}/basalt", profile_dir)),
path: Some(profile_dir.join("basalt")),
repo: None,
branch: None,
feature_type: ProfileFeatureType::Basalt,
},
openhmd: ProfileFeature {
enabled: false,
path: Some(format!("{}/openhmd", profile_dir)),
path: Some(profile_dir.join("openhmd")),
repo: None,
branch: None,
feature_type: ProfileFeatureType::OpenHmd,
@ -272,10 +280,10 @@ impl Default for Profile {
mercury_enabled: false,
},
environment: HashMap::new(),
prefix: format!("{}/prefixes/{}", get_data_dir(), uuid),
prefix: get_data_dir().join("prefixes").join(&uuid),
can_be_built: true,
pull_on_build: true,
opencomposite_path: format!("{}/opencomposite", profile_dir),
opencomposite_path: profile_dir.join("opencomposite"),
opencomposite_repo: None,
opencomposite_branch: None,
editable: true,
@ -291,7 +299,7 @@ impl Profile {
pub fn xr_runtime_json_env_var(&self) -> String {
format!(
"XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"",
prefix = match self.prefix.as_str() {
prefix = match self.prefix.to_string_lossy().to_string().as_str() {
SYSTEM_PREFIX => BWRAP_SYSTEM_PREFIX,
other => other,
},
@ -312,7 +320,7 @@ impl Profile {
self.xr_runtime_json_env_var(),
format!(
"PRESSURE_VESSEL_FILESYSTEMS_RW=\"{path}\"",
path = get_ipc_file_path(&self.xrservice_type),
path = get_ipc_file_path(&self.xrservice_type).to_string_lossy(),
),
]
}
@ -332,22 +340,22 @@ impl Profile {
vars.join(" ")
}
pub fn get_survive_cli_path(&self) -> Option<String> {
let path_s = format!("{pfx}/bin/survive-cli", pfx = self.prefix);
if Path::new(&path_s).is_file() {
return Some(path_s);
pub fn get_survive_cli_path(&self) -> Option<PathBuf> {
let path = self.prefix.join("bin/survive-cli");
if path.is_file() {
return Some(path);
}
None
}
pub fn load_profile(path: &String) -> Self {
pub fn load_profile(path: &PathBuf) -> Self {
let file = File::open(path).expect("Unable to open profile");
let reader = BufReader::new(file);
serde_json::from_reader(reader).expect("Faiuled to deserialize profile")
}
pub fn dump_profile(&self, path_s: &String) {
let writer = get_writer(path_s).expect("Could not write profile");
pub fn dump_profile(&self, path: &PathBuf) {
let writer = get_writer(path).expect("Could not write profile");
serde_json::to_writer_pretty(writer, self).expect("Could not write profile")
}
@ -398,53 +406,46 @@ impl Profile {
&& !self.xrservice_path.is_empty()
&& !self.prefix.is_empty()
&& (!self.features.libsurvive.enabled
|| !self
|| self
.features
.libsurvive
.path
.as_ref()
.unwrap_or(&"".to_string())
.is_empty())
.is_some_and(|p| !p.is_empty()))
&& (!self.features.basalt.enabled
|| !self
|| self
.features
.basalt
.path
.as_ref()
.unwrap_or(&"".to_string())
.is_empty())
.is_some_and(|p| !p.is_empty()))
&& (!self.features.openhmd.enabled
|| !self
|| self
.features
.openhmd
.path
.as_ref()
.unwrap_or(&"".to_string())
.is_empty())
.is_some_and(|p| !p.is_empty()))
}
pub fn xrservice_binary(&self) -> String {
format!(
"{}/bin/{}",
self.prefix,
match self.xrservice_type {
XRServiceType::Monado => "monado-service",
XRServiceType::Wivrn => "wivrn-server",
}
)
pub fn xrservice_binary(&self) -> PathBuf {
self.prefix.join("bin").join(match self.xrservice_type {
XRServiceType::Monado => "monado-service",
XRServiceType::Wivrn => "wivrn-server",
})
}
pub fn can_start(&self) -> bool {
Path::new(&self.xrservice_binary()).is_file()
}
pub fn libmonado_so(&self) -> Option<String> {
let mut res = format!("{}/lib/libmonado.so", self.prefix);
if Path::new(&res).is_file() {
pub fn libmonado_so(&self) -> Option<PathBuf> {
let res = self.prefix.join("lib/libmonado.so");
if res.is_file() {
return Some(res);
}
res = format!("{}/lib64/libmonado.so", self.prefix);
if Path::new(&res).is_file() {
let res = self.prefix.join("lib64/libmonado.so");
if res.is_file() {
return Some(res);
}
@ -458,7 +459,7 @@ impl Profile {
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use std::{collections::HashMap, path::PathBuf};
use crate::profile::{ProfileFeature, ProfileFeatureType, ProfileFeatures, XRServiceType};
@ -466,14 +467,17 @@ mod tests {
#[test]
fn profile_can_be_loaded() {
let profile = Profile::load_profile(&"./test/files/profile.json".to_string());
let profile = Profile::load_profile(&"./test/files/profile.json".into());
assert_eq!(profile.name, "Demo profile");
assert_eq!(profile.xrservice_path, "/home/user/monado");
assert_eq!(profile.opencomposite_path, "/home/user/opencomposite");
assert_eq!(profile.prefix, "/home/user/envisionprefix");
assert_eq!(profile.xrservice_path, PathBuf::from("/home/user/monado"));
assert_eq!(
profile.features.libsurvive.path.as_deref(),
Some("/home/user/libsurvive")
profile.opencomposite_path,
PathBuf::from("/home/user/opencomposite")
);
assert_eq!(profile.prefix, PathBuf::from("/home/user/envisionprefix"));
assert_eq!(
profile.features.libsurvive.path,
Some(PathBuf::from("/home/user/libsurvive"))
);
assert_eq!(profile.features.basalt.path, None);
assert_eq!(profile.features.libsurvive.enabled, true);
@ -496,14 +500,14 @@ mod tests {
let p = Profile {
uuid: "demo".into(),
name: "Demo profile".into(),
xrservice_path: String::from("/home/user/monado"),
xrservice_path: PathBuf::from("/home/user/monado"),
xrservice_type: XRServiceType::Monado,
opencomposite_path: String::from("/home/user/opencomposite"),
opencomposite_path: PathBuf::from("/home/user/opencomposite"),
features: ProfileFeatures {
libsurvive: ProfileFeature {
feature_type: ProfileFeatureType::Libsurvive,
enabled: true,
path: Some(String::from("/home/user/libsurvive")),
path: Some(PathBuf::from("/home/user/libsurvive")),
repo: None,
branch: None,
},
@ -512,17 +516,17 @@ mod tests {
mercury_enabled: false,
},
environment: env,
prefix: String::from("/home/user/envisionprefix"),
prefix: PathBuf::from("/home/user/envisionprefix"),
editable: true,
..Default::default()
};
let fpath = String::from("./target/testout/testprofile.json");
let fpath = PathBuf::from("./target/testout/testprofile.json");
p.dump_profile(&fpath);
let loaded = Profile::load_profile(&fpath);
assert_eq!(loaded.name, "Demo profile");
assert_eq!(
loaded.features.libsurvive.path,
Some(String::from("/home/user/libsurvive"))
Some(PathBuf::from("/home/user/libsurvive"))
);
assert_eq!(
loaded
@ -534,6 +538,6 @@ mod tests {
}
}
pub fn prepare_ld_library_path(prefix: &str) -> String {
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix)
pub fn prepare_ld_library_path(prefix: &PathBuf) -> String {
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix.to_string_lossy())
}

View file

@ -7,7 +7,7 @@ use std::collections::HashMap;
pub fn lighthouse_profile() -> Profile {
let data_dir = get_data_dir();
let prefix = format!("{data}/prefixes/lighthouse_default", data = data_dir);
let prefix = data_dir.join("prefixes/lighthouse_default");
let mut environment: HashMap<String, String> = HashMap::new();
environment.insert("XRT_JSON_LOG".into(), "1".into());
environment.insert("XRT_COMPOSITOR_SCALE_PERCENTAGE".into(), "140".into());

View file

@ -10,7 +10,7 @@ use std::collections::HashMap;
pub fn openhmd_profile() -> Profile {
let data_dir = get_data_dir();
let prefix = format!("{data}/prefixes/openhmd_default", data = data_dir);
let prefix = data_dir.join("prefixes/openhmd_default");
let mut environment: HashMap<String, String> = HashMap::new();
environment.insert("XRT_JSON_LOG".into(), "1".into());
environment.insert("XRT_COMPOSITOR_SCALE_PERCENTAGE".into(), "140".into());

View file

@ -7,7 +7,7 @@ use std::collections::HashMap;
pub fn simulated_profile() -> Profile {
let data_dir = get_data_dir();
let prefix = format!("{data}/prefixes/simulated_default", data = data_dir);
let prefix = data_dir.join("prefixes/simulated_default");
let mut environment: HashMap<String, String> = HashMap::new();
environment.insert("QWERTY_ENABLE".into(), "1".into());
environment.insert("XRT_JSON_LOG".into(), "1".into());
@ -18,7 +18,7 @@ pub fn simulated_profile() -> Profile {
environment.insert("U_PACING_APP_USE_MIN_FRAME_PERIOD".into(), "1".into());
environment.insert(
"LD_LIBRARY_PATH".into(),
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix),
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix.to_string_lossy()),
);
Profile {
uuid: "simulated-default".into(),

View file

@ -10,7 +10,7 @@ use std::collections::HashMap;
pub fn survive_profile() -> Profile {
let data_dir = get_data_dir();
let prefix = format!("{data}/prefixes/survive_default", data = data_dir);
let prefix = data_dir.join("prefixes/survive_default");
let mut environment: HashMap<String, String> = HashMap::new();
environment.insert("XRT_JSON_LOG".into(), "1".into());
environment.insert("XRT_COMPOSITOR_SCALE_PERCENTAGE".into(), "140".into());

View file

@ -7,7 +7,7 @@ use std::collections::HashMap;
pub fn wivrn_profile() -> Profile {
let data_dir = get_data_dir();
let prefix = format!("{data}/prefixes/wivrn_default", data = data_dir);
let prefix = data_dir.join("prefixes/wivrn_default");
let mut environment: HashMap<String, String> = HashMap::new();
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
environment.insert("XRT_DEBUG_GUI".into(), "1".into());

View file

@ -10,7 +10,7 @@ use std::collections::HashMap;
pub fn wmr_profile() -> Profile {
let data_dir = get_data_dir();
let prefix = format!("{data}/prefixes/wmr_default", data = data_dir);
let prefix = data_dir.join("prefixes/wmr_default");
let mut environment: HashMap<String, String> = HashMap::new();
environment.insert("XRT_JSON_LOG".into(), "1".into());
environment.insert("XRT_COMPOSITOR_SCALE_PERCENTAGE".into(), "140".into());

View file

@ -1,26 +1,28 @@
use crate::{
file_utils::{copy_file, get_writer},
paths::{get_backup_dir, get_home_dir, get_xdg_data_dir},
paths::{get_backup_dir, get_home_dir},
profile::Profile,
};
use anyhow::bail;
use std::{fs::read_to_string, io::Write, path::Path};
use std::{
fs::read_to_string,
io::Write,
path::{Path, PathBuf},
};
fn get_runtime_entrypoint_path() -> Option<String> {
vec![format!(
"{home}/.steam/steam/steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point",
home = get_home_dir(),
)]
fn get_runtime_entrypoint_path() -> Option<PathBuf> {
vec![get_home_dir()
.join(".steam/steam/steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point")]
.iter()
.find(|path| Path::new(&path).is_file())
.find(|p| p.is_file())
.cloned()
}
fn get_backup_runtime_entrypoint_location() -> String {
format!("{backup}/_v2-entry-point.bak", backup = get_backup_dir())
fn get_backup_runtime_entrypoint_location() -> PathBuf {
get_backup_dir().join("_v2-entry-point.bak")
}
fn backup_runtime_entrypoint(path: &str) {
fn backup_runtime_entrypoint(path: &PathBuf) {
copy_file(&path, &get_backup_runtime_entrypoint_location());
}
@ -33,7 +35,7 @@ pub fn restore_runtime_entrypoint() {
}
}
fn append_to_runtime_entrypoint(data: &str, path: &str) -> anyhow::Result<()> {
fn append_to_runtime_entrypoint(data: &str, path: &PathBuf) -> anyhow::Result<()> {
let existing = read_to_string(path)?;
let new = existing.replace(
"exec \"${here}/${run}\" \"$@\"\nexit 125",

View file

@ -1,11 +1,7 @@
use crate::paths::get_home_dir;
use std::path::Path;
pub fn chaperone_info_exists() -> bool {
let path_s = format!(
"{}/.steam/steam/config/chaperone_info.vrchap",
get_home_dir()
);
let path = Path::new(&path_s);
path.is_file()
get_home_dir()
.join(".steam/steam/config/chaperone_info.vrchap")
.is_file()
}

View file

@ -644,10 +644,7 @@ impl SimpleComponent for App {
println!("pkexec not found, skipping setcap");
} else {
let profile = self.get_selected_profile();
setcap_cap_sys_nice_eip(format!(
"{pfx}/bin/monado-service",
pfx = profile.prefix
));
setcap_cap_sys_nice_eip(&profile.prefix.join("bin/monado-service"));
}
}
Msg::ProfileSelected(prof) => {
@ -692,12 +689,12 @@ impl SimpleComponent for App {
self.application.quit();
}
Msg::DebugOpenData => {
open_with_default_handler(&format!("file://{}", get_data_dir()));
open_with_default_handler(&format!("file://{}", get_data_dir().to_string_lossy()));
}
Msg::DebugOpenPrefix => {
open_with_default_handler(&format!(
"file://{}",
self.get_selected_profile().prefix
self.get_selected_profile().prefix.to_string_lossy()
));
}
Msg::DebugCopyEnvVars => {

View file

@ -196,14 +196,21 @@ impl InternalJobWorker {
match launch_opts.contains(LAUNCH_OPTS_CMD_PLACEHOLDER) {
true => launch_opts.replacen(
LAUNCH_OPTS_CMD_PLACEHOLDER,
prof.xrservice_binary().as_str(),
&prof.xrservice_binary().to_string_lossy().to_string(),
1,
),
false => format!("{} {}", prof.xrservice_binary(), launch_opts),
false => format!(
"{} {}",
prof.xrservice_binary().to_string_lossy(),
launch_opts
),
},
],
),
true => (prof.xrservice_binary(), vec![]),
true => (
prof.xrservice_binary().to_string_lossy().to_string(),
vec![],
),
};
let data = CmdWorkerData {
environment: env,

View file

@ -7,7 +7,13 @@ use crate::{
use adw::prelude::*;
use gtk::glib;
use relm4::prelude::*;
use std::{cell::Cell, collections::HashMap, path::Path, rc::Rc, time::Duration};
use std::{
cell::Cell,
collections::HashMap,
path::{Path, PathBuf},
rc::Rc,
time::Duration,
};
const NO_FILE_MSG: &str = "(No file selected)";
const CALIBRATION_RUN_TIME_SECONDS: f64 = 30.0;
@ -57,7 +63,7 @@ pub enum LibsurviveSetupMsg {
}
impl LibsurviveSetupWindow {
fn create_calibration_runner(&mut self, survive_cli_path: String) -> CmdRunner {
fn create_calibration_runner(&mut self, survive_cli_path: &PathBuf) -> CmdRunner {
let lh_path = self.steam_lighthouse_path.clone();
let mut env = HashMap::new();
let profile_prefix = &self.profile.as_ref().unwrap().prefix;
@ -67,7 +73,7 @@ impl LibsurviveSetupWindow {
);
CmdRunner::new(
Some(env),
survive_cli_path,
survive_cli_path.to_string_lossy().to_string(),
vec!["--steamvr-calibration".into(), lh_path],
)
}
@ -369,7 +375,7 @@ impl SimpleComponent for LibsurviveSetupWindow {
if let Some(survive_cli_path) =
self.profile.as_ref().unwrap().get_survive_cli_path()
{
let mut runner = self.create_calibration_runner(survive_cli_path);
let mut runner = self.create_calibration_runner(&survive_cli_path);
self.calibration_running.set(true);
self.first_run_done = false;
self.calibration_seconds_elapsed = 0.0;
@ -444,7 +450,8 @@ impl SimpleComponent for LibsurviveSetupWindow {
let runner = self.calibration_runner.as_mut().unwrap();
runner.terminate();
let mut n_runner = self.create_calibration_runner(
self.profile
&self
.profile
.as_ref()
.unwrap()
.get_survive_cli_path()

View file

@ -188,13 +188,13 @@ impl SimpleComponent for MainView {
add_css_class: "card",
add_css_class: "padded",
#[track = "model.changed(Self::selected_profile())"]
set_visible: match mount_has_nosuid(model.selected_profile.prefix.as_str()) {
set_visible: match mount_has_nosuid(&model.selected_profile.prefix) {
Ok(b) => b,
Err(_) => {
// TODO: handle this error better
println!(
eprintln!(
"Warning: could not get stat on path {}",
model.selected_profile.prefix);
model.selected_profile.prefix.to_string_lossy());
false
},
},

View file

@ -13,7 +13,7 @@ use crate::{
use adw::prelude::*;
use gtk::glib::clone;
use relm4::{factory::AsyncFactoryVecDeque, prelude::*};
use std::{cell::RefCell, rc::Rc};
use std::{cell::RefCell, path::PathBuf, rc::Rc};
#[tracker::track]
pub struct ProfileEditor {
@ -110,10 +110,10 @@ impl SimpleComponent for ProfileEditor {
add: &path_row(
"Install Prefix",
None,
Some(model.profile.borrow().prefix.clone()),
Some(model.profile.borrow().prefix.to_string_lossy().to_string()),
Some(init.root_win.clone()),
clone!(@strong prof => move |n_path| {
prof.borrow_mut().prefix = n_path.unwrap_or_default()
prof.borrow_mut().prefix = n_path.unwrap_or_default().into();
}),
),
add: &entry_row("Autostart Command",
@ -171,10 +171,10 @@ impl SimpleComponent for ProfileEditor {
add: &path_row(
"XR Service Path",
None,
Some(model.profile.borrow().xrservice_path.clone()),
Some(model.profile.borrow().xrservice_path.clone().to_string_lossy().to_string()),
Some(init.root_win.clone()),
clone!(@strong prof => move |n_path| {
prof.borrow_mut().xrservice_path = n_path.unwrap_or_default()
prof.borrow_mut().xrservice_path = n_path.unwrap_or_default().into();
}),
),
add: &entry_row(
@ -200,10 +200,10 @@ impl SimpleComponent for ProfileEditor {
set_description: Some("OpenVR driver built on top of OpenXR"),
add: &path_row(
"OpenComposite Path", None,
Some(model.profile.borrow().opencomposite_path.clone()),
Some(model.profile.borrow().opencomposite_path.clone().to_string_lossy().to_string()),
Some(init.root_win.clone()),
clone!(@strong prof => move |n_path| {
prof.borrow_mut().opencomposite_path = n_path.unwrap_or_default();
prof.borrow_mut().opencomposite_path = n_path.unwrap_or_default().into();
})
),
add: &entry_row(
@ -236,10 +236,10 @@ impl SimpleComponent for ProfileEditor {
),
add: &path_row(
"Libsurvive Path", None,
model.profile.borrow().features.libsurvive.path.clone(),
model.profile.borrow().features.libsurvive.path.clone().map(|p| p.to_string_lossy().to_string()),
Some(init.root_win.clone()),
clone!(@strong prof => move |n_path| {
prof.borrow_mut().features.libsurvive.path = n_path;
prof.borrow_mut().features.libsurvive.path = n_path.map(PathBuf::from);
})
),
add: &entry_row(
@ -272,10 +272,10 @@ impl SimpleComponent for ProfileEditor {
),
add: &path_row(
"OpenHMD Path", None,
model.profile.borrow().features.openhmd.path.clone(),
model.profile.borrow().features.openhmd.path.clone().map(|p| p.to_string_lossy().to_string()),
Some(init.root_win.clone()),
clone!(@strong prof => move |n_path| {
prof.borrow_mut().features.openhmd.path = n_path;
prof.borrow_mut().features.openhmd.path = n_path.map(PathBuf::from);
})
),
add: &entry_row(
@ -308,10 +308,10 @@ impl SimpleComponent for ProfileEditor {
),
add: &path_row(
"Basalt Path", None,
model.profile.borrow().features.basalt.path.clone(),
model.profile.borrow().features.basalt.path.clone().map(|p| p.to_string_lossy().to_string()),
Some(init.root_win.clone()),
clone!(@strong prof => move |n_path| {
prof.borrow_mut().features.basalt.path = n_path;
prof.borrow_mut().features.basalt.path = n_path.map(PathBuf::from);
})
),
add: &entry_row(

View file

@ -5,7 +5,6 @@ use super::job_worker::{
};
use crate::paths::get_steamvr_bin_dir_path;
use relm4::{
binding::{Binding, ConnectBinding, StringBinding},
gtk::{self, prelude::*},
ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent,
};
@ -145,7 +144,7 @@ impl SimpleComponent for SteamVrCalibrationBox {
}
Self::Input::RunCalibration => {
self.set_calibration_result(None);
let steamvr_bin_dir = get_steamvr_bin_dir_path();
let steamvr_bin_dir = get_steamvr_bin_dir_path().to_string_lossy().to_string();
if !Path::new(&steamvr_bin_dir).is_dir() {
self.set_calibration_success(false);
self.set_calibration_result(Some("SteamVR not found".into()));
@ -154,7 +153,7 @@ impl SimpleComponent for SteamVrCalibrationBox {
let mut env: HashMap<String, String> = HashMap::new();
env.insert("LD_LIBRARY_PATH".into(), steamvr_bin_dir.clone());
let vrcmd = format!("{steamvr_bin_dir}/vrcmd");
let mut server_worker = {
let server_worker = {
let mut jobs: VecDeque<WorkerJob> = VecDeque::new();
jobs.push_back(WorkerJob::new_cmd(
Some(env.clone()),
@ -166,7 +165,7 @@ impl SimpleComponent for SteamVrCalibrationBox {
JobWorkerOut::Exit(code) => Self::Input::OnServerWorkerExit(code),
})
};
let mut cal_worker = {
let cal_worker = {
let mut jobs: VecDeque<WorkerJob> = VecDeque::new();
jobs.push_back(WorkerJob::new_func(Box::new(move || {
sleep(Duration::from_secs(2));

7
src/xdg.rs Normal file
View file

@ -0,0 +1,7 @@
use lazy_static::lazy_static;
use xdg::BaseDirectories;
lazy_static! {
pub static ref XDG: BaseDirectories =
BaseDirectories::new().expect("Failed to get XDG base directories");
}