mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-04-19 19:14:53 +00:00
feat: prefer symlinks over generating files for openxr active runtime json file
This commit is contained in:
parent
a9fa4f8cf4
commit
4ea0ce53b0
5 changed files with 102 additions and 94 deletions
|
@ -1,18 +1,17 @@
|
|||
use crate::{
|
||||
paths::{get_backup_dir, SYSTEM_PREFIX},
|
||||
paths::SYSTEM_PREFIX,
|
||||
profile::Profile,
|
||||
util::{
|
||||
file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly},
|
||||
steam_library_folder::SteamLibraryFolder,
|
||||
},
|
||||
util::file_utils::{deserialize_file, get_writer, set_file_readonly},
|
||||
xdg::XDG,
|
||||
};
|
||||
use anyhow::bail;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fs::remove_file,
|
||||
fs::{remove_file, rename},
|
||||
os::unix::fs::symlink,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tracing::error;
|
||||
use tracing::{info, warn};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ActiveRuntimeInnerRuntime {
|
||||
|
@ -38,46 +37,6 @@ 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))
|
||||
}
|
||||
|
||||
pub const STEAMVR_STEAM_APPID: u32 = 250820;
|
||||
|
||||
pub fn find_steam_openxr_json() -> Option<PathBuf> {
|
||||
match SteamLibraryFolder::get_folders() {
|
||||
Ok(libraryfolders) => libraryfolders
|
||||
.iter()
|
||||
.find(|(_, folder)| folder.apps.contains_key(&STEAMVR_STEAM_APPID))
|
||||
.map(|(_, folder)| {
|
||||
PathBuf::from(&folder.path).join("steamapps/common/SteamVR/steamxr_linux64.json")
|
||||
}),
|
||||
Err(e) => {
|
||||
error!("unable to find steam openxr json: unable to load steam libraryfolders: {e}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
get_active_runtime_from_path(&get_backup_steam_active_runtime_path())
|
||||
}
|
||||
|
||||
fn backup_steam_active_runtime() {
|
||||
if let Some(ar) = get_current_active_runtime() {
|
||||
if is_steam(&ar) {
|
||||
copy_file(
|
||||
&get_active_runtime_json_path(),
|
||||
&get_backup_steam_active_runtime_path(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_active_runtime_from_path(path: &Path) -> Option<ActiveRuntime> {
|
||||
deserialize_file(path)
|
||||
}
|
||||
|
@ -99,29 +58,6 @@ pub fn dump_current_active_runtime(active_runtime: &ActiveRuntime) -> anyhow::Re
|
|||
dump_active_runtime_to_path(active_runtime, &get_active_runtime_json_path())
|
||||
}
|
||||
|
||||
fn build_steam_active_runtime() -> ActiveRuntime {
|
||||
if let Some(backup) = get_backed_up_steam_active_runtime() {
|
||||
return backup;
|
||||
}
|
||||
ActiveRuntime {
|
||||
file_format_version: "1.0.0".into(),
|
||||
runtime: ActiveRuntimeInnerRuntime {
|
||||
valve_runtime_is_steamvr: Some(true),
|
||||
libmonado_path: None,
|
||||
library_path: XDG
|
||||
.get_data_home()
|
||||
.join("Steam/steamapps/common/SteamVR/bin/linux64/vrclient.so"),
|
||||
name: Some("SteamVR".into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_current_active_runtime_to_steam() -> anyhow::Result<()> {
|
||||
set_file_readonly(&get_active_runtime_json_path(), false)?;
|
||||
dump_current_active_runtime(&build_steam_active_runtime())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build_profile_active_runtime(profile: &Profile) -> anyhow::Result<ActiveRuntime> {
|
||||
let Some(libopenxr_path) = profile.libopenxr_so() else {
|
||||
anyhow::bail!(
|
||||
|
@ -158,18 +94,66 @@ fn relativize_active_runtime_lib_path(ar: &ActiveRuntime, path: &Path) -> Active
|
|||
res
|
||||
}
|
||||
|
||||
const ACTIVE_RUNTIME_BAK: &str = "active_runtime.json.envision.bak";
|
||||
|
||||
pub fn set_current_active_runtime_to_profile(profile: &Profile) -> anyhow::Result<()> {
|
||||
let dest = get_active_runtime_json_path();
|
||||
set_file_readonly(&dest, false)?;
|
||||
backup_steam_active_runtime();
|
||||
let pfx = profile.clone().prefix;
|
||||
let mut ar = build_profile_active_runtime(profile)?;
|
||||
// hack: relativize libopenxr_monado.so path for system installs
|
||||
if pfx == PathBuf::from(SYSTEM_PREFIX) {
|
||||
ar = relativize_active_runtime_lib_path(&ar, &dest);
|
||||
if dest.is_dir() {
|
||||
bail!("{} is a directory", dest.to_string_lossy());
|
||||
}
|
||||
dump_current_active_runtime(&ar)?;
|
||||
set_file_readonly(&dest, true)?;
|
||||
if !dest.is_symlink() {
|
||||
set_file_readonly(&dest, false)?;
|
||||
}
|
||||
if dest.is_file() || dest.is_symlink() {
|
||||
rename(&dest, dest.parent().unwrap().join(ACTIVE_RUNTIME_BAK))?;
|
||||
} else {
|
||||
info!("no active_runtime.json file to backup")
|
||||
}
|
||||
|
||||
let profile_openxr_json = profile.openxr_json_path();
|
||||
if profile_openxr_json.is_file() {
|
||||
symlink(profile_openxr_json, &dest)?;
|
||||
} else {
|
||||
warn!("profile openxr json file doesn't exist");
|
||||
// fallback: build the file from scratch
|
||||
let pfx = profile.clone().prefix;
|
||||
let mut ar = build_profile_active_runtime(profile)?;
|
||||
// hack: relativize libopenxr_monado.so path for system installs
|
||||
if pfx == PathBuf::from(SYSTEM_PREFIX) {
|
||||
ar = relativize_active_runtime_lib_path(&ar, &dest);
|
||||
}
|
||||
dump_current_active_runtime(&ar)?;
|
||||
set_file_readonly(&dest, true)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_current_active_runtime() -> anyhow::Result<()> {
|
||||
let dest = get_active_runtime_json_path();
|
||||
if dest.is_dir() {
|
||||
bail!("{} is a directory", dest.to_string_lossy());
|
||||
}
|
||||
if !dest.exists() {
|
||||
info!("no current active_runtime.json to remove")
|
||||
}
|
||||
Ok(remove_file(dest)?)
|
||||
}
|
||||
|
||||
pub fn restore_active_runtime_backup() -> anyhow::Result<()> {
|
||||
let dest = get_active_runtime_json_path();
|
||||
let bak = dest.parent().unwrap().join(ACTIVE_RUNTIME_BAK);
|
||||
if bak.is_file() || bak.is_symlink() {
|
||||
if dest.is_dir() {
|
||||
bail!("{} is a directory", dest.to_string_lossy());
|
||||
}
|
||||
if !dest.is_symlink() {
|
||||
set_file_readonly(&dest, false)?;
|
||||
}
|
||||
rename(&bak, &dest)?;
|
||||
} else {
|
||||
info!("{ACTIVE_RUNTIME_BAK} does not exist, nothing to restore");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -1,7 +1,7 @@
|
|||
use anyhow::Result;
|
||||
use constants::{resources, APP_ID, APP_NAME, GETTEXT_PACKAGE, LOCALE_DIR, RESOURCES_BASE_PATH};
|
||||
use file_builders::{
|
||||
active_runtime_json::{get_current_active_runtime, set_current_active_runtime_to_steam},
|
||||
active_runtime_json::restore_active_runtime_backup,
|
||||
openvrpaths_vrpath::{get_current_openvrpaths, set_current_openvrpaths_to_steam},
|
||||
};
|
||||
use gettextrs::LocaleCategory;
|
||||
|
@ -48,14 +48,9 @@ pub mod xdg;
|
|||
pub mod xr_devices;
|
||||
|
||||
fn restore_steam_xr_files() {
|
||||
let active_runtime = get_current_active_runtime();
|
||||
let openvrpaths = get_current_openvrpaths();
|
||||
if let Some(ar) = active_runtime {
|
||||
if !file_builders::active_runtime_json::is_steam(&ar) {
|
||||
if let Err(e) = set_current_active_runtime_to_steam() {
|
||||
warn!("failed to restore active runtime to steam: {e}");
|
||||
}
|
||||
}
|
||||
if let Err(e) = restore_active_runtime_backup() {
|
||||
warn!("failed to restore active runtime to steam: {e}");
|
||||
}
|
||||
if let Some(ovrp) = openvrpaths {
|
||||
if !file_builders::openvrpaths_vrpath::is_steam(&ovrp) {
|
||||
|
|
|
@ -47,6 +47,13 @@ impl XRServiceType {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn openxr_json_rel_path(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Monado => "share/openxr/1/openxr_monado.json",
|
||||
Self::Wivrn => "share/openxr/1/openxr_wivrn.json",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ipc_file_path(&self) -> PathBuf {
|
||||
XDG.get_runtime_directory()
|
||||
.expect("XDG runtime directory is not available")
|
||||
|
@ -586,6 +593,12 @@ impl Profile {
|
|||
missing_deps.dedup(); // dedup only works if sorted, hence the above
|
||||
missing_deps
|
||||
}
|
||||
|
||||
/// the file that will become active_runtime.json, as installed in the
|
||||
/// prefix
|
||||
pub fn openxr_json_path(&self) -> PathBuf {
|
||||
self.prefix.join(self.xrservice_type.openxr_json_rel_path())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_ld_library_path(prefix: &Path) -> String {
|
||||
|
|
|
@ -26,7 +26,8 @@ use crate::{
|
|||
depcheck::common::dep_pkexec,
|
||||
file_builders::{
|
||||
active_runtime_json::{
|
||||
set_current_active_runtime_to_profile, set_current_active_runtime_to_steam,
|
||||
remove_current_active_runtime, restore_active_runtime_backup,
|
||||
set_current_active_runtime_to_profile,
|
||||
},
|
||||
openvrpaths_vrpath::{
|
||||
set_current_openvrpaths_to_profile, set_current_openvrpaths_to_steam,
|
||||
|
@ -250,9 +251,16 @@ impl App {
|
|||
|
||||
pub fn restore_openxr_openvr_files(&self) {
|
||||
restore_runtime_entrypoint();
|
||||
if let Err(e) = set_current_active_runtime_to_steam() {
|
||||
if let Err(e) = remove_current_active_runtime() {
|
||||
alert(
|
||||
"Could not restore Steam active runtime",
|
||||
"Could not remove profile active runtime",
|
||||
Some(&format!("{e}")),
|
||||
Some(&self.app_win.clone().upcast::<gtk::Window>()),
|
||||
);
|
||||
}
|
||||
if let Err(e) = restore_active_runtime_backup() {
|
||||
alert(
|
||||
"Could not restore previous active runtime",
|
||||
Some(&format!("{e}")),
|
||||
Some(&self.app_win.clone().upcast::<gtk::Window>()),
|
||||
);
|
||||
|
|
|
@ -57,7 +57,13 @@ pub fn deserialize_file<T: serde::de::DeserializeOwned>(path: &Path) -> Option<T
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_file_readonly(path: &Path, readonly: bool) -> Result<(), std::io::Error> {
|
||||
pub fn set_file_readonly(path: &Path, readonly: bool) -> anyhow::Result<()> {
|
||||
if path.is_symlink() {
|
||||
bail!(
|
||||
"path {} is a symlink, trying to change its write permission will only change the original file",
|
||||
path.to_string_lossy()
|
||||
);
|
||||
}
|
||||
if !path.is_file() {
|
||||
debug!(
|
||||
"trying to set readonly on a file that does not exist: {}",
|
||||
|
@ -69,7 +75,7 @@ pub fn set_file_readonly(path: &Path, readonly: bool) -> Result<(), std::io::Err
|
|||
.expect("Could not get metadata for file")
|
||||
.permissions();
|
||||
perms.set_readonly(readonly);
|
||||
fs::set_permissions(path, perms)
|
||||
Ok(fs::set_permissions(path, perms)?)
|
||||
}
|
||||
|
||||
pub fn setcap_cap_sys_nice_eip_cmd(profile: &Profile) -> Vec<String> {
|
||||
|
@ -104,8 +110,10 @@ pub fn copy_file(source: &Path, dest: &Path) {
|
|||
.unwrap_or_else(|_| panic!("Failed to create dir {}", parent.to_str().unwrap()));
|
||||
}
|
||||
}
|
||||
set_file_readonly(dest, false)
|
||||
.unwrap_or_else(|_| panic!("Failed to set file {} as rw", dest.to_string_lossy()));
|
||||
if !dest.is_symlink() {
|
||||
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(|e| {
|
||||
panic!(
|
||||
"Failed to copy {} to {}: {e}",
|
||||
|
|
Loading…
Add table
Reference in a new issue