diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-08 03:30:04 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-08 03:30:04 -0500 |
| commit | 3de4056df4ea5d0afbcea388ad8d681daea1aac3 (patch) | |
| tree | fc5978451f9f51b84268f45bd2fa6f5d4a17baaf /libs/nak/src/deps | |
| parent | 5ba23a6d7a40052d9e1d4bd0cf018cfe7814d03a (diff) | |
Remove NaK/Rust dependency, port remaining functionality to native C++
Replace NaK Rust crate and nak_ffi with native C++ implementations:
- Game detection (Steam, Heroic, Bottles), VDF parser, icon extraction
- Prefix symlinks, SLR manager, Steam path detection
- Known games database
Add FUSE VFS optimizations: zero-copy reads via fuse_reply_data,
default_permissions mount option, FUSE_CAP_ASYNC_DIO, FUSE_CAP_EXPIRE_ONLY,
lookup cache parent index, cached mode bits, increased I/O buffer sizes.
Update build system, prefix setup, and various fixes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'libs/nak/src/deps')
| -rw-r--r-- | libs/nak/src/deps/mod.rs | 177 | ||||
| -rw-r--r-- | libs/nak/src/deps/tools.rs | 166 |
2 files changed, 0 insertions, 343 deletions
diff --git a/libs/nak/src/deps/mod.rs b/libs/nak/src/deps/mod.rs deleted file mode 100644 index a055eb7..0000000 --- a/libs/nak/src/deps/mod.rs +++ /dev/null @@ -1,177 +0,0 @@ -//! Dependency management via winetricks -//! -//! Uses winetricks for all Windows dependency installation. - -pub mod tools; - -use std::error::Error; -use std::path::Path; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; - -use crate::config::AppConfig; -use crate::logging::{log_error, log_install}; -use crate::runtime_wrap; -use crate::steam::SteamProton; - -// Re-export tools -pub use tools::{check_command_available, ensure_cabextract, ensure_winetricks, get_winetricks_path}; - -/// Standard winetricks verbs for MO2 prefix -pub const STANDARD_VERBS: &[&str] = &[ - "vcrun2022", // Visual C++ 2015-2022 Runtime - "dotnet6", // .NET 6.0 - "dotnet7", // .NET 7.0 - "dotnet8", // .NET 8.0 - "dotnetdesktop6", // .NET Desktop Runtime 6.0 - "d3dcompiler_47", // DirectX Compiler 47 - "d3dcompiler_43", // DirectX Compiler 43 - "d3dx9", // DirectX 9 (all versions) - "d3dx11_43", // DirectX 11 - "xact", // XACT Audio (32-bit) - "xact_x64", // XACT Audio (64-bit) -]; - - -/// Run winetricks to install dependencies -pub fn run_winetricks( - prefix_path: &Path, - proton: &SteamProton, - verbs: &[&str], - log_callback: impl Fn(String), -) -> Result<(), Box<dyn Error>> { - if verbs.is_empty() { - return Ok(()); - } - - let winetricks_path = ensure_winetricks()?; - ensure_cabextract()?; - - let Some(wine_bin) = proton.wine_binary() else { - return Err("Wine binary not found in Proton".into()); - }; - - let Some(wineserver_bin) = proton.wineserver_binary() else { - return Err("Wineserver binary not found in Proton".into()); - }; - - let cache_dir = AppConfig::get_default_cache_dir(); - std::fs::create_dir_all(&cache_dir)?; - - let verbs_str = verbs.join(" "); - log_callback(format!("Installing dependencies via winetricks: {}", verbs_str)); - log_install(&format!("Running winetricks with verbs: {}", verbs_str)); - - let nak_bin = tools::get_nak_bin_path(); - let current_path = std::env::var("PATH").unwrap_or_default(); - let new_path = format!("{}:{}", nak_bin.display(), current_path); - - let envs: Vec<(&str, String)> = vec![ - ("PATH", new_path), - ("WINE", wine_bin.display().to_string()), - ("WINESERVER", wineserver_bin.display().to_string()), - ("WINEPREFIX", prefix_path.display().to_string()), - ("WINETRICKS_CACHE", cache_dir.display().to_string()), - ]; - let status = runtime_wrap::build_command(&winetricks_path, &envs) - .arg("-q") - .args(verbs) - .status()?; - - if !status.success() { - let err_msg = format!("Winetricks failed with exit code: {:?}", status.code()); - log_error(&err_msg); - return Err(err_msg.into()); - } - - log_install("Winetricks completed successfully"); - Ok(()) -} - -/// Install all standard dependencies to a prefix -pub fn install_standard_deps( - prefix_path: &Path, - proton: &SteamProton, - log_callback: impl Fn(String), -) -> Result<(), Box<dyn Error>> { - run_winetricks(prefix_path, proton, STANDARD_VERBS, log_callback) -} - -/// Run winetricks with cancellation support. -pub fn run_winetricks_cancellable( - prefix_path: &Path, - proton: &SteamProton, - verbs: &[&str], - log_callback: impl Fn(String), - cancel_flag: &Arc<AtomicBool>, -) -> Result<(), Box<dyn Error>> { - if verbs.is_empty() { - return Ok(()); - } - - let winetricks_path = ensure_winetricks()?; - ensure_cabextract()?; - - let Some(wine_bin) = proton.wine_binary() else { - return Err("Wine binary not found in Proton".into()); - }; - - let Some(wineserver_bin) = proton.wineserver_binary() else { - return Err("Wineserver binary not found in Proton".into()); - }; - - let cache_dir = AppConfig::get_default_cache_dir(); - std::fs::create_dir_all(&cache_dir)?; - - let verbs_str = verbs.join(" "); - log_callback(format!("Installing dependencies via winetricks: {}", verbs_str)); - log_install(&format!("Running winetricks with verbs: {}", verbs_str)); - - let nak_bin = tools::get_nak_bin_path(); - let current_path = std::env::var("PATH").unwrap_or_default(); - let new_path = format!("{}:{}", nak_bin.display(), current_path); - - let envs: Vec<(&str, String)> = vec![ - ("PATH", new_path), - ("WINE", wine_bin.display().to_string()), - ("WINESERVER", wineserver_bin.display().to_string()), - ("WINEPREFIX", prefix_path.display().to_string()), - ("WINETRICKS_CACHE", cache_dir.display().to_string()), - ]; - let mut child = runtime_wrap::build_command(&winetricks_path, &envs) - .arg("-q") - .args(verbs) - .spawn()?; - - loop { - match child.try_wait()? { - Some(status) => { - if !status.success() { - let err_msg = format!("Winetricks failed with exit code: {:?}", status.code()); - log_error(&err_msg); - return Err(err_msg.into()); - } - log_install("Winetricks completed successfully"); - return Ok(()); - } - None => { - if cancel_flag.load(Ordering::Relaxed) { - let _ = child.kill(); - let _ = child.wait(); - return Err("Cancelled".into()); - } - std::thread::sleep(std::time::Duration::from_millis(250)); - } - } - } -} - -/// Install standard deps with cancellation support -pub fn install_standard_deps_cancellable( - prefix_path: &Path, - proton: &SteamProton, - log_callback: impl Fn(String), - cancel_flag: &Arc<AtomicBool>, -) -> Result<(), Box<dyn Error>> { - run_winetricks_cancellable(prefix_path, proton, STANDARD_VERBS, log_callback, cancel_flag) -} diff --git a/libs/nak/src/deps/tools.rs b/libs/nak/src/deps/tools.rs deleted file mode 100644 index 03dbe9a..0000000 --- a/libs/nak/src/deps/tools.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! Linux tool management (winetricks, cabextract) -//! -//! Handles downloading and managing Linux CLI tools. -//! Tools are stored in ~/.local/share/fluorine/bin/ for Fluorine Manager. - -use std::error::Error; -use std::fs; -use std::io::Read; -use std::os::unix::fs::PermissionsExt; -use std::path::PathBuf; -use std::process::Command; - -use crate::logging::{log_error, log_info, log_warning}; - -// ============================================================================ -// NaK Bin Directory (~/.local/share/fluorine/bin/) -// ============================================================================ - -/// Get the tool bin directory path (~/.local/share/fluorine/bin/) -/// This is accessible from both native and Flatpak environments. -pub fn get_nak_bin_path() -> PathBuf { - crate::paths::data_dir().join("bin") -} - -/// Check if a command exists (either in system PATH or tool bin) -pub fn check_command_available(cmd: &str) -> bool { - // Check system PATH first - if Command::new("which") - .arg(cmd) - .output() - .map(|o| o.status.success()) - .unwrap_or(false) - { - return true; - } - - // Check tool bin directory - let nak_bin = get_nak_bin_path().join(cmd); - nak_bin.exists() -} - -// ============================================================================ -// Winetricks -// ============================================================================ - -const WINETRICKS_URL: &str = - "https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks"; - -/// Get the path to winetricks (without downloading) -pub fn get_winetricks_path() -> PathBuf { - get_nak_bin_path().join("winetricks") -} - -/// Ensures winetricks is downloaded and up-to-date. -pub fn ensure_winetricks() -> Result<PathBuf, Box<dyn Error>> { - let bin_dir = get_nak_bin_path(); - let winetricks_path = bin_dir.join("winetricks"); - - fs::create_dir_all(&bin_dir)?; - - log_info("Checking for winetricks updates..."); - - match ureq::get(WINETRICKS_URL).call() { - Ok(response) => { - let mut new_content = Vec::new(); - response.into_reader().read_to_end(&mut new_content)?; - - let should_update = if winetricks_path.exists() { - let existing = fs::read(&winetricks_path).unwrap_or_default(); - existing != new_content - } else { - true - }; - - if should_update { - fs::write(&winetricks_path, &new_content)?; - - let mut perms = fs::metadata(&winetricks_path)?.permissions(); - perms.set_mode(0o755); - fs::set_permissions(&winetricks_path, perms)?; - - if winetricks_path.exists() { - log_info("Winetricks updated to latest version"); - } else { - log_info(&format!("Winetricks downloaded to {:?}", winetricks_path)); - } - } - } - Err(e) => { - if winetricks_path.exists() { - log_warning(&format!("Failed to check winetricks updates: {}", e)); - } else { - return Err(format!("Failed to download winetricks: {}", e).into()); - } - } - } - - Ok(winetricks_path) -} - -// ============================================================================ -// Cabextract (required by winetricks for DirectX cabs) -// ============================================================================ - -const CABEXTRACT_URL: &str = - "https://github.com/SulfurNitride/NaK/releases/download/Cabextract/cabextract-linux-x86_64.zip"; - -/// Ensures cabextract is available in our bin directory. -/// -/// Always downloads to ~/.local/share/fluorine/bin/ because winetricks runs -/// inside pressure-vessel where system binaries under /usr are not visible. -pub fn ensure_cabextract() -> Result<PathBuf, Box<dyn Error>> { - // Check if we already downloaded it to our bin dir - let bin_dir = get_nak_bin_path(); - let cabextract_path = bin_dir.join("cabextract"); - - if cabextract_path.exists() { - return Ok(cabextract_path); - } - - // Download cabextract zip — system copy is unusable inside pressure-vessel - log_info("Downloading cabextract for use inside container..."); - fs::create_dir_all(&bin_dir)?; - - let response = ureq::get(CABEXTRACT_URL).call().map_err(|e| { - format!( - "Failed to download cabextract: {}. Please install cabextract manually.", - e - ) - })?; - - let zip_path = bin_dir.join("cabextract.zip"); - let mut zip_file = fs::File::create(&zip_path)?; - std::io::copy(&mut response.into_reader(), &mut zip_file)?; - - let status = Command::new("unzip") - .arg("-o") - .arg(&zip_path) - .arg("-d") - .arg(&bin_dir) - .status()?; - - if !status.success() { - let _ = Command::new("python3") - .arg("-c") - .arg(format!( - "import zipfile; zipfile.ZipFile('{}').extractall('{}')", - zip_path.display(), - bin_dir.display() - )) - .status(); - } - - let _ = fs::remove_file(&zip_path); - - if cabextract_path.exists() { - let mut perms = fs::metadata(&cabextract_path)?.permissions(); - perms.set_mode(0o755); - fs::set_permissions(&cabextract_path, perms)?; - log_info(&format!("cabextract downloaded to {:?}", cabextract_path)); - Ok(cabextract_path) - } else { - log_error("Failed to extract cabextract from zip"); - Err("Failed to extract cabextract from zip".into()) - } -} |
