1use std::borrow::Cow;
2use std::env;
3use std::path::{Path, PathBuf};
4
5#[inline]
6#[must_use]
7pub const fn is_appimage_build() -> bool {
8    match option_env!("JGENESIS_APPIMAGE_BUILD") {
9        Some(var) => !var.is_empty(),
10        None => false,
11    }
12}
13
14/// Fix relative input paths when running from inside an AppImage.
15///
16/// The AppImage runner changes the current working directory to a subdirectory inside the AppImage
17/// package, which leads to very confusing behavior if a user passes a relative path as input. This
18/// function prefixes relative paths with the working directory that the AppImage was launched from.
19///
20/// Returns the input path untouched if the input path is absolute or this is not an AppImage build.
21#[inline]
22#[must_use]
23pub fn fix_appimage_relative_path(path: &Path) -> Cow<'_, Path> {
24    if !is_appimage_build() || path.is_absolute() {
25        return path.into();
26    }
27
28    let Ok(owd) = env::var("OWD") else { return path.into() };
29    let converted = Path::new(&owd).join(path);
30
31    log::info!(
32        "Converted relative path '{}' to absolute path '{}'",
33        path.display(),
34        converted.display()
35    );
36
37    converted.into()
38}
39
40/// Directory containing the emulator executable
41///
42/// Returns `None` if unable to determine
43#[inline]
44#[must_use]
45pub fn determine_emulator_dir() -> Option<PathBuf> {
46    let exe_path: PathBuf = if is_appimage_build() {
47        // When running from inside an AppImage, env::current_exe() returns a path inside the mount's
48        // temp dir.
49        //
50        // APPIMAGE env var should contain the path to the AppImage file:
51        //    https://docs.appimage.org/packaging-guide/environment-variables.html
52        env::var("APPIMAGE").ok()?.into()
53    } else {
54        env::current_exe().ok()?
55    };
56
57    exe_path.parent().map(ToOwned::to_owned)
58}