lib.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Copyright 2019-2022 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. //! Tauri utility helpers
  5. #![warn(missing_docs, rust_2018_idioms)]
  6. use std::fmt::Display;
  7. use semver::Version;
  8. use serde::{Deserialize, Deserializer, Serialize, Serializer};
  9. pub mod assets;
  10. pub mod config;
  11. pub mod html;
  12. pub mod io;
  13. pub mod mime_type;
  14. pub mod platform;
  15. /// Prepare application resources and sidecars.
  16. #[cfg(feature = "resources")]
  17. pub mod resources;
  18. /// Application pattern.
  19. pub mod pattern;
  20. /// `tauri::App` package information.
  21. #[derive(Debug, Clone)]
  22. pub struct PackageInfo {
  23. /// App name
  24. pub name: String,
  25. /// App version
  26. pub version: Version,
  27. /// The crate authors.
  28. pub authors: &'static str,
  29. /// The crate description.
  30. pub description: &'static str,
  31. }
  32. impl PackageInfo {
  33. /// Returns the application package name.
  34. /// On macOS and Windows it's the `name` field, and on Linux it's the `name` in `kebab-case`.
  35. pub fn package_name(&self) -> String {
  36. #[cfg(target_os = "linux")]
  37. {
  38. use heck::ToKebabCase;
  39. self.name.clone().to_kebab_case()
  40. }
  41. #[cfg(not(target_os = "linux"))]
  42. self.name.clone()
  43. }
  44. }
  45. /// System theme.
  46. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  47. #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
  48. #[non_exhaustive]
  49. pub enum Theme {
  50. /// Light theme.
  51. Light,
  52. /// Dark theme.
  53. Dark,
  54. }
  55. impl Serialize for Theme {
  56. fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
  57. where
  58. S: Serializer,
  59. {
  60. serializer.serialize_str(self.to_string().as_ref())
  61. }
  62. }
  63. impl<'de> Deserialize<'de> for Theme {
  64. fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
  65. where
  66. D: Deserializer<'de>,
  67. {
  68. let s = String::deserialize(deserializer)?;
  69. Ok(match s.to_lowercase().as_str() {
  70. "dark" => Self::Dark,
  71. _ => Self::Light,
  72. })
  73. }
  74. }
  75. impl Display for Theme {
  76. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  77. write!(
  78. f,
  79. "{}",
  80. match self {
  81. Self::Light => "light",
  82. Self::Dark => "dark",
  83. }
  84. )
  85. }
  86. }
  87. /// Information about environment variables.
  88. #[derive(Debug, Clone)]
  89. #[non_exhaustive]
  90. pub struct Env {
  91. /// The APPIMAGE environment variable.
  92. #[cfg(target_os = "linux")]
  93. pub appimage: Option<std::ffi::OsString>,
  94. /// The APPDIR environment variable.
  95. #[cfg(target_os = "linux")]
  96. pub appdir: Option<std::ffi::OsString>,
  97. /// The command line arguments of the current process.
  98. pub args: Vec<String>,
  99. }
  100. #[allow(clippy::derivable_impls)]
  101. impl Default for Env {
  102. fn default() -> Self {
  103. let args = std::env::args().skip(1).collect();
  104. #[cfg(target_os = "linux")]
  105. {
  106. let env = Self {
  107. #[cfg(target_os = "linux")]
  108. appimage: std::env::var_os("APPIMAGE"),
  109. #[cfg(target_os = "linux")]
  110. appdir: std::env::var_os("APPDIR"),
  111. args,
  112. };
  113. if env.appimage.is_some() || env.appdir.is_some() {
  114. // validate that we're actually running on an AppImage
  115. // an AppImage is mounted to `/$TEMPDIR/.mount_${appPrefix}${hash}`
  116. // see https://github.com/AppImage/AppImageKit/blob/1681fd84dbe09c7d9b22e13cdb16ea601aa0ec47/src/runtime.c#L501
  117. // note that it is safe to use `std::env::current_exe` here since we just loaded an AppImage.
  118. let is_temp = std::env::current_exe()
  119. .map(|p| {
  120. p.display()
  121. .to_string()
  122. .starts_with(&format!("{}/.mount_", std::env::temp_dir().display()))
  123. })
  124. .unwrap_or(true);
  125. if !is_temp {
  126. panic!("`APPDIR` or `APPIMAGE` environment variable found but this application was not detected as an AppImage; this might be a security issue.");
  127. }
  128. }
  129. env
  130. }
  131. #[cfg(not(target_os = "linux"))]
  132. {
  133. Self { args }
  134. }
  135. }
  136. }
  137. /// The result type of `tauri-utils`.
  138. pub type Result<T> = std::result::Result<T, Error>;
  139. /// The error type of `tauri-utils`.
  140. #[derive(Debug, thiserror::Error)]
  141. #[non_exhaustive]
  142. pub enum Error {
  143. /// Target triple architecture error
  144. #[error("Unable to determine target-architecture")]
  145. Architecture,
  146. /// Target triple OS error
  147. #[error("Unable to determine target-os")]
  148. Os,
  149. /// Target triple environment error
  150. #[error("Unable to determine target-environment")]
  151. Environment,
  152. /// Tried to get resource on an unsupported platform
  153. #[error("Unsupported platform for reading resources")]
  154. UnsupportedPlatform,
  155. /// Get parent process error
  156. #[error("Could not get parent process")]
  157. ParentProcess,
  158. /// Get parent process PID error
  159. #[error("Could not get parent PID")]
  160. ParentPid,
  161. /// Get child process error
  162. #[error("Could not get child process")]
  163. ChildProcess,
  164. /// IO error
  165. #[error("{0}")]
  166. Io(#[from] std::io::Error),
  167. /// Invalid pattern.
  168. #[error("invalid pattern `{0}`. Expected either `brownfield` or `isolation`.")]
  169. InvalidPattern(String),
  170. /// Invalid glob pattern.
  171. #[cfg(feature = "resources")]
  172. #[error("{0}")]
  173. GlobPattern(#[from] glob::PatternError),
  174. /// Failed to use glob pattern.
  175. #[cfg(feature = "resources")]
  176. #[error("`{0}`")]
  177. Glob(#[from] glob::GlobError),
  178. /// Glob pattern did not find any results.
  179. #[cfg(feature = "resources")]
  180. #[error("path matching {0} not found.")]
  181. GlobPathNotFound(String),
  182. /// Error walking directory.
  183. #[cfg(feature = "resources")]
  184. #[error("{0}")]
  185. WalkdirError(#[from] walkdir::Error),
  186. /// Not allowed to walk dir.
  187. #[cfg(feature = "resources")]
  188. #[error("could not walk directory `{0}`, try changing `allow_walk` to true on the `ResourcePaths` constructor.")]
  189. NotAllowedToWalkDir(std::path::PathBuf),
  190. }
  191. /// Suppresses the unused-variable warnings of the given inputs.
  192. ///
  193. /// This does not move any values. Instead, it just suppresses the warning by taking a
  194. /// reference to the value.
  195. #[macro_export]
  196. macro_rules! consume_unused_variable {
  197. ($($arg:expr),*) => {
  198. $(
  199. let _ = &$arg;
  200. )*
  201. ()
  202. };
  203. }
  204. /// Prints to the standard error, with a newline.
  205. ///
  206. /// Equivalent to the [`eprintln!`] macro, except that it's only effective for debug builds.
  207. #[macro_export]
  208. macro_rules! debug_eprintln {
  209. () => ($crate::debug_eprintln!(""));
  210. ($($arg:tt)*) => {
  211. #[cfg(debug_assertions)]
  212. eprintln!($($arg)*);
  213. #[cfg(not(debug_assertions))]
  214. $crate::consume_unused_variable!($($arg)*);
  215. };
  216. }