Skip to content

Commit

Permalink
Rework locate() failures (#49)
Browse files Browse the repository at this point in the history
* Move unsupported OS failure to runtime

* Move `locate()` behind a feature flag
  • Loading branch information
CosmicHorrorDev authored Nov 27, 2023
1 parent 676ccbb commit 64cd466
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 74 deletions.
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ readme = "README.md"
keywords = ["steam", "vdf", "appmanifest", "directory", "steamapps"]
categories = ["os", "hardware-support", "filesystem", "accessibility"]

# TODO: test more features in CI

[features]
default = []
default = ["locate"]
locate = ["locate_backend"]
shortcuts_extras = ["crc"]

[dependencies]
Expand All @@ -22,9 +25,9 @@ serde = { version = "1.0", features = ["derive"] }
crc = { version = "3.0", optional = true }

[target.'cfg(target_os="windows")'.dependencies]
winreg = "0.51"
locate_backend = { package = "winreg", version = "0.51", optional = true }
[target.'cfg(not(target_os="windows"))'.dependencies]
dirs = "5"
locate_backend = { package = "dirs", version = "5", optional = true }

[dev-dependencies]
insta = { version = "1.34.0", features = ["redactions", "ron"] }
Expand Down
75 changes: 4 additions & 71 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,11 @@
clippy::print_stderr, clippy::print_stdout
)]

#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
compile_error!("Unsupported operating system!");

pub mod app;
pub mod error;
pub mod library;
#[cfg(feature = "locate")]
mod locate;
pub mod shortcut;
#[cfg(any(test, doctest))]
pub mod tests;
Expand Down Expand Up @@ -225,76 +224,10 @@ impl InstallDir {
/// Locates the Steam installation directory on the filesystem and initializes a `InstallDir` (Windows)
///
/// Returns `None` if no Steam installation can be located.
#[cfg(feature = "locate")]
pub fn locate() -> Result<InstallDir> {
let path = Self::locate_steam_dir().ok_or(Error::FailedLocatingInstallDir)?;
let path = locate::locate_steam_dir().ok_or(Error::FailedLocatingInstallDir)?;

Ok(Self { path })
}

#[cfg(target_os = "windows")]
fn locate_steam_dir() -> Option<PathBuf> {
use winreg::{
enums::{HKEY_LOCAL_MACHINE, KEY_READ},
RegKey,
};

// Locating the Steam installation location is a bit more complicated on Windows

// Steam's installation location can be found in the registry
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
let installation_regkey = hklm
// 32-bit
.open_subkey_with_flags("SOFTWARE\\Wow6432Node\\Valve\\Steam", KEY_READ)
.or_else(|_| {
// 64-bit
hklm.open_subkey_with_flags("SOFTWARE\\Valve\\Steam", KEY_READ)
})
.ok()?;

// The InstallPath key will contain the full path to the Steam directory
let install_path_str: String = installation_regkey.get_value("InstallPath").ok()?;

let install_path = PathBuf::from(install_path_str);
install_path.is_dir().then_some(install_path)
}

#[cfg(target_os = "macos")]
fn locate_steam_dir() -> Option<PathBuf> {
// Steam's installation location is pretty easy to find on macOS, as it's always in $USER/Library/Application Support
let home_dir = dirs::home_dir()?;

// Find Library/Application Support/Steam
let install_path = home_dir.join("Library/Application Support/Steam");
install_path.is_dir().then_some(install_path)
}

#[cfg(target_os = "linux")]
fn locate_steam_dir() -> Option<PathBuf> {
use std::env;

// Steam's installation location is pretty easy to find on Linux, too, thanks to the symlink in $USER
let home_dir = dirs::home_dir()?;
let snap_dir = match env::var("SNAP_USER_DATA") {
Ok(snap_dir) => PathBuf::from(snap_dir),
Err(_) => home_dir.join("snap"),
};

let steam_paths = vec![
// Flatpak steam install directories
home_dir.join(".var/app/com.valvesoftware.Steam/.local/share/Steam"),
home_dir.join(".var/app/com.valvesoftware.Steam/.steam/steam"),
home_dir.join(".var/app/com.valvesoftware.Steam/.steam/root"),
// Standard install directories
home_dir.join(".local/share/Steam"),
home_dir.join(".steam/steam"),
home_dir.join(".steam/root"),
home_dir.join(".steam"),
// Snap steam install directories
snap_dir.join("steam/common/.local/share/Steam"),
snap_dir.join("steam/common/.steam/steam"),
snap_dir.join("steam/common/.steam/root"),
];

steam_paths.into_iter().find(|x| x.is_dir())
}
}
82 changes: 82 additions & 0 deletions src/locate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use std::path::PathBuf;

pub fn locate_steam_dir() -> Option<PathBuf> {
locate_steam_dir_helper()
}

// TODO(cosmic): return an error with actual context in this case
#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
fn locate_steam_dir_helper() -> Option<PathBuf> {
None
}

#[cfg(target_os = "windows")]
fn locate_steam_dir_helper() -> Option<PathBuf> {
use locate_backend as winreg;
use winreg::{
enums::{HKEY_LOCAL_MACHINE, KEY_READ},
RegKey,
};

// Locating the Steam installation location is a bit more complicated on Windows

// Steam's installation location can be found in the registry
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
let installation_regkey = hklm
// 32-bit
.open_subkey_with_flags("SOFTWARE\\Wow6432Node\\Valve\\Steam", KEY_READ)
.or_else(|_| {
// 64-bit
hklm.open_subkey_with_flags("SOFTWARE\\Valve\\Steam", KEY_READ)
})
.ok()?;

// The InstallPath key will contain the full path to the Steam directory
let install_path_str: String = installation_regkey.get_value("InstallPath").ok()?;

let install_path = PathBuf::from(install_path_str);
install_path.is_dir().then_some(install_path)
}

#[cfg(target_os = "macos")]
fn locate_steam_dir_helper() -> Option<PathBuf> {
use locate_backend as dirs;
// Steam's installation location is pretty easy to find on macOS, as it's always in $USER/Library/Application Support
let home_dir = dirs::home_dir()?;

// Find Library/Application Support/Steam
let install_path = home_dir.join("Library/Application Support/Steam");
install_path.is_dir().then_some(install_path)
}

#[cfg(target_os = "linux")]
fn locate_steam_dir_helper() -> Option<PathBuf> {
use std::env;

use locate_backend as dirs;

// Steam's installation location is pretty easy to find on Linux, too, thanks to the symlink in $USER
let home_dir = dirs::home_dir()?;
let snap_dir = match env::var("SNAP_USER_DATA") {
Ok(snap_dir) => PathBuf::from(snap_dir),
Err(_) => home_dir.join("snap"),
};

let steam_paths = vec![
// Flatpak steam install directories
home_dir.join(".var/app/com.valvesoftware.Steam/.local/share/Steam"),
home_dir.join(".var/app/com.valvesoftware.Steam/.steam/steam"),
home_dir.join(".var/app/com.valvesoftware.Steam/.steam/root"),
// Standard install directories
home_dir.join(".local/share/Steam"),
home_dir.join(".steam/steam"),
home_dir.join(".steam/root"),
home_dir.join(".steam"),
// Snap steam install directories
snap_dir.join("steam/common/.local/share/Steam"),
snap_dir.join("steam/common/.steam/steam"),
snap_dir.join("steam/common/.steam/root"),
];

steam_paths.into_iter().find(|x| x.is_dir())
}

0 comments on commit 64cd466

Please sign in to comment.