// Copyright 2019-2021 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT //! Platform helper functions. use std::path::{PathBuf, MAIN_SEPARATOR}; use crate::{Env, PackageInfo}; /// Gets the path to the current executable, resolving symbolic links for security reasons. /// /// See https://doc.rust-lang.org/std/env/fn.current_exe.html#security for /// an example of what to be careful of when using `current_exe` output. /// /// We canonicalize the path we received from `current_exe` to resolve any /// soft links. it avoids the usual issue of needing the file to exist at /// the passed path because a valid `current_exe` result should always exist. pub fn current_exe() -> std::io::Result { std::env::current_exe().and_then(|path| path.canonicalize()) } /// Try to determine the current target triple. /// /// Returns a target triple (e.g. `x86_64-unknown-linux-gnu` or `i686-pc-windows-msvc`) or an /// `Error::Config` if the current config cannot be determined or is not some combination of the /// following values: /// `linux, mac, windows` -- `i686, x86, armv7` -- `gnu, musl, msvc` /// /// * Errors: /// * Unexpected system config pub fn target_triple() -> crate::Result { let arch = if cfg!(target_arch = "x86") { "i686" } else if cfg!(target_arch = "x86_64") { "x86_64" } else if cfg!(target_arch = "arm") { "armv7" } else if cfg!(target_arch = "aarch64") { "aarch64" } else { return Err(crate::Error::Architecture); }; let os = if cfg!(target_os = "linux") { "unknown-linux" } else if cfg!(target_os = "macos") { "apple-darwin" } else if cfg!(target_os = "windows") { "pc-windows" } else if cfg!(target_os = "freebsd") { "unknown-freebsd" } else { return Err(crate::Error::Os); }; let os = if cfg!(target_os = "macos") || cfg!(target_os = "freebsd") { String::from(os) } else { let env = if cfg!(target_env = "gnu") { "gnu" } else if cfg!(target_env = "musl") { "musl" } else if cfg!(target_env = "msvc") { "msvc" } else { return Err(crate::Error::Environment); }; format!("{}-{}", os, env) }; Ok(format!("{}-{}", arch, os)) } /// Computes the resource directory of the current environment. /// /// On Windows, it's the path to the executable. /// /// On Linux, when running in an AppImage the `APPDIR` variable will be set to /// the mounted location of the app, and the resource dir will be /// `${APPDIR}/usr/lib/${exe_name}`. If not running in an AppImage, the path is /// `/usr/lib/${exe_name}`. When running the app from /// `src-tauri/target/(debug|release)/`, the path is /// `${exe_dir}/../lib/${exe_name}`. /// /// On MacOS, it's `${exe_dir}../Resources` (inside .app). #[allow(unused_variables)] pub fn resource_dir(package_info: &PackageInfo, env: &Env) -> crate::Result { let exe = current_exe()?; let exe_dir = exe.parent().expect("failed to get exe directory"); let curr_dir = exe_dir.display().to_string(); if curr_dir.ends_with(format!("{S}target{S}debug", S = MAIN_SEPARATOR).as_str()) || curr_dir.ends_with(format!("{S}target{S}release", S = MAIN_SEPARATOR).as_str()) || cfg!(target_os = "windows") { // running from the out dir or windows return Ok(exe_dir.to_path_buf()); } #[allow(unused_mut, unused_assignments)] let mut res = Err(crate::Error::UnsupportedPlatform); #[cfg(target_os = "linux")] { res = if curr_dir.ends_with("/data/usr/bin") { // running from the deb bundle dir Ok(exe_dir.join(format!("../lib/{}", package_info.package_name()))) } else if let Some(appdir) = &env.appdir { let appdir: &std::path::Path = appdir.as_ref(); Ok(PathBuf::from(format!( "{}/usr/lib/{}", appdir.display(), package_info.package_name() ))) } else { // running bundle Ok(PathBuf::from(format!( "/usr/lib/{}", package_info.package_name() ))) }; } #[cfg(target_os = "macos")] { res = Ok(exe_dir.join("../Resources")); } res }