lib.rs 6.1 KB

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