123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
- // SPDX-License-Identifier: Apache-2.0
- // SPDX-License-Identifier: MIT
- //! Types and functions related to file system path operations.
- use std::{
- env::temp_dir,
- path::{Component, Path, PathBuf},
- };
- use crate::{Config, Env, PackageInfo};
- use serde_repr::{Deserialize_repr, Serialize_repr};
- /// A base directory to be used in [`resolve_path`].
- ///
- /// The base directory is the optional root of a file system operation.
- /// If informed by the API call, all paths will be relative to the path of the given directory.
- ///
- /// For more information, check the [`dirs_next` documentation](https://docs.rs/dirs_next/).
- #[derive(Serialize_repr, Deserialize_repr, Clone, Copy, Debug)]
- #[repr(u16)]
- #[non_exhaustive]
- pub enum BaseDirectory {
- /// The Audio directory.
- Audio = 1,
- /// The Cache directory.
- Cache,
- /// The Config directory.
- Config,
- /// The Data directory.
- Data,
- /// The LocalData directory.
- LocalData,
- /// The Desktop directory.
- Desktop,
- /// The Document directory.
- Document,
- /// The Download directory.
- Download,
- /// The Executable directory.
- Executable,
- /// The Font directory.
- Font,
- /// The Home directory.
- Home,
- /// The Picture directory.
- Picture,
- /// The Public directory.
- Public,
- /// The Runtime directory.
- Runtime,
- /// The Template directory.
- Template,
- /// The Video directory.
- Video,
- /// The Resource directory.
- Resource,
- /// The default App config directory.
- /// Resolves to [`BaseDirectory::Config`].
- App,
- /// The Log directory.
- /// Resolves to `BaseDirectory::Home/Library/Logs/{bundle_identifier}` on macOS
- /// and `BaseDirectory::Config/{bundle_identifier}/logs` on linux and windows.
- Log,
- /// A temporary directory.
- /// Resolves to [`temp_dir`].
- Temp,
- }
- impl BaseDirectory {
- /// Gets the variable that represents this [`BaseDirectory`] for string paths.
- pub fn variable(self) -> &'static str {
- match self {
- Self::Audio => "$AUDIO",
- Self::Cache => "$CACHE",
- Self::Config => "$CONFIG",
- Self::Data => "$DATA",
- Self::LocalData => "$LOCALDATA",
- Self::Desktop => "$DESKTOP",
- Self::Document => "$DOCUMENT",
- Self::Download => "$DOWNLOAD",
- Self::Executable => "$EXE",
- Self::Font => "$FONT",
- Self::Home => "$HOME",
- Self::Picture => "$PICTURE",
- Self::Public => "$PUBLIC",
- Self::Runtime => "$RUNTIME",
- Self::Template => "$TEMPLATE",
- Self::Video => "$VIDEO",
- Self::Resource => "$RESOURCE",
- Self::App => "$APP",
- Self::Log => "$LOG",
- Self::Temp => "$TEMP",
- }
- }
- /// Gets the [`BaseDirectory`] associated with the given variable, or [`None`] if the variable doesn't match any.
- pub fn from_variable(variable: &str) -> Option<Self> {
- let res = match variable {
- "$AUDIO" => Self::Audio,
- "$CACHE" => Self::Cache,
- "$CONFIG" => Self::Config,
- "$DATA" => Self::Data,
- "$LOCALDATA" => Self::LocalData,
- "$DESKTOP" => Self::Desktop,
- "$DOCUMENT" => Self::Document,
- "$DOWNLOAD" => Self::Download,
- "$EXE" => Self::Executable,
- "$FONT" => Self::Font,
- "$HOME" => Self::Home,
- "$PICTURE" => Self::Picture,
- "$PUBLIC" => Self::Public,
- "$RUNTIME" => Self::Runtime,
- "$TEMPLATE" => Self::Template,
- "$VIDEO" => Self::Video,
- "$RESOURCE" => Self::Resource,
- "$APP" => Self::App,
- "$LOG" => Self::Log,
- "$TEMP" => Self::Temp,
- _ => return None,
- };
- Some(res)
- }
- }
- /// Parse the given path, resolving a [`BaseDirectory`] variable if the path starts with one.
- ///
- /// # Examples
- ///
- /// ```rust,no_run
- /// use tauri::Manager;
- /// tauri::Builder::default()
- /// .setup(|app| {
- /// let path = tauri::api::path::parse(&app.config(), app.package_info(), &app.env(), "$HOME/.bashrc")?;
- /// assert_eq!(path.to_str().unwrap(), "/home/${whoami}/.bashrc");
- /// Ok(())
- /// });
- /// ```
- pub fn parse<P: AsRef<Path>>(
- config: &Config,
- package_info: &PackageInfo,
- env: &Env,
- path: P,
- ) -> crate::api::Result<PathBuf> {
- let mut p = PathBuf::new();
- let mut components = path.as_ref().components();
- match components.next() {
- Some(Component::Normal(str)) => {
- if let Some(base_directory) = BaseDirectory::from_variable(&str.to_string_lossy()) {
- p.push(resolve_path(
- config,
- package_info,
- env,
- "",
- Some(base_directory),
- )?);
- } else {
- p.push(str);
- }
- }
- Some(component) => p.push(component),
- None => (),
- }
- for component in components {
- if let Component::ParentDir = component {
- continue;
- }
- p.push(component);
- }
- println!("res {:?}", p);
- Ok(p)
- }
- /// Resolves the path with the optional base directory.
- ///
- /// This is a low level API. If the application has been built,
- /// prefer the [path resolver API](`crate::AppHandle#method.path_resolver`).
- ///
- /// # Examples
- ///
- /// ## Before initializing the application
- ///
- /// ```rust,no_run
- /// use tauri::{api::path::{BaseDirectory, resolve_path}, Env};
- /// // on an actual app, remove the string argument
- /// let context = tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json");
- /// let path = resolve_path(
- /// context.config(),
- /// context.package_info(),
- /// &Env::default(),
- /// "db/tauri.sqlite",
- /// Some(BaseDirectory::App))
- /// .expect("failed to resolve path");
- /// assert_eq!(path.to_str().unwrap(), "/home/${whoami}/.config/com.tauri.app/db/tauri.sqlite");
- ///
- /// tauri::Builder::default().run(context).expect("error while running tauri application");
- /// ```
- ///
- /// ## With an initialized app
- /// ```rust,no_run
- /// use tauri::{api::path::{BaseDirectory, resolve_path}, Manager};
- /// tauri::Builder::default()
- /// .setup(|app| {
- /// let path = resolve_path(
- /// &app.config(),
- /// app.package_info(),
- /// &app.env(),
- /// "path/to/something",
- /// Some(BaseDirectory::Config)
- /// )?;
- /// assert_eq!(path.to_str().unwrap(), "/home/${whoami}/.config/path/to/something");
- /// Ok(())
- /// });
- /// ```
- pub fn resolve_path<P: AsRef<Path>>(
- config: &Config,
- package_info: &PackageInfo,
- env: &Env,
- path: P,
- dir: Option<BaseDirectory>,
- ) -> crate::api::Result<PathBuf> {
- if let Some(base_dir) = dir {
- let resolve_resource = matches!(base_dir, BaseDirectory::Resource);
- let base_dir_path = match base_dir {
- BaseDirectory::Audio => audio_dir(),
- BaseDirectory::Cache => cache_dir(),
- BaseDirectory::Config => config_dir(),
- BaseDirectory::Data => data_dir(),
- BaseDirectory::LocalData => local_data_dir(),
- BaseDirectory::Desktop => desktop_dir(),
- BaseDirectory::Document => document_dir(),
- BaseDirectory::Download => download_dir(),
- BaseDirectory::Executable => executable_dir(),
- BaseDirectory::Font => font_dir(),
- BaseDirectory::Home => home_dir(),
- BaseDirectory::Picture => picture_dir(),
- BaseDirectory::Public => public_dir(),
- BaseDirectory::Runtime => runtime_dir(),
- BaseDirectory::Template => template_dir(),
- BaseDirectory::Video => video_dir(),
- BaseDirectory::Resource => resource_dir(package_info, env),
- BaseDirectory::App => app_dir(config),
- BaseDirectory::Log => log_dir(config),
- BaseDirectory::Temp => Some(temp_dir()),
- };
- if let Some(mut base_dir_path_value) = base_dir_path {
- // use the same path resolution mechanism as the bundler's resource injection algorithm
- if resolve_resource {
- let mut resource_path = PathBuf::new();
- for component in path.as_ref().components() {
- match component {
- Component::Prefix(_) => {}
- Component::RootDir => resource_path.push("_root_"),
- Component::CurDir => {}
- Component::ParentDir => resource_path.push("_up_"),
- Component::Normal(p) => resource_path.push(p),
- }
- }
- base_dir_path_value.push(resource_path);
- } else {
- base_dir_path_value.push(path);
- }
- Ok(base_dir_path_value)
- } else {
- Err(crate::api::Error::Path(
- "unable to determine base dir path".to_string(),
- ))
- }
- } else {
- let mut dir_path = PathBuf::new();
- dir_path.push(path);
- Ok(dir_path)
- }
- }
- /// Returns the path to the user's audio directory.
- pub fn audio_dir() -> Option<PathBuf> {
- dirs_next::audio_dir()
- }
- /// Returns the path to the user's cache directory.
- pub fn cache_dir() -> Option<PathBuf> {
- dirs_next::cache_dir()
- }
- /// Returns the path to the user's config directory.
- pub fn config_dir() -> Option<PathBuf> {
- dirs_next::config_dir()
- }
- /// Returns the path to the user's data directory.
- pub fn data_dir() -> Option<PathBuf> {
- dirs_next::data_dir()
- }
- /// Returns the path to the user's local data directory.
- pub fn local_data_dir() -> Option<PathBuf> {
- dirs_next::data_local_dir()
- }
- /// Returns the path to the user's desktop directory.
- pub fn desktop_dir() -> Option<PathBuf> {
- dirs_next::desktop_dir()
- }
- /// Returns the path to the user's document directory.
- pub fn document_dir() -> Option<PathBuf> {
- dirs_next::document_dir()
- }
- /// Returns the path to the user's download directory.
- pub fn download_dir() -> Option<PathBuf> {
- dirs_next::download_dir()
- }
- /// Returns the path to the user's executable directory.
- pub fn executable_dir() -> Option<PathBuf> {
- dirs_next::executable_dir()
- }
- /// Returns the path to the user's font directory.
- pub fn font_dir() -> Option<PathBuf> {
- dirs_next::font_dir()
- }
- /// Returns the path to the user's home directory.
- pub fn home_dir() -> Option<PathBuf> {
- dirs_next::home_dir()
- }
- /// Returns the path to the user's picture directory.
- pub fn picture_dir() -> Option<PathBuf> {
- dirs_next::picture_dir()
- }
- /// Returns the path to the user's public directory.
- pub fn public_dir() -> Option<PathBuf> {
- dirs_next::public_dir()
- }
- /// Returns the path to the user's runtime directory.
- pub fn runtime_dir() -> Option<PathBuf> {
- dirs_next::runtime_dir()
- }
- /// Returns the path to the user's template directory.
- pub fn template_dir() -> Option<PathBuf> {
- dirs_next::template_dir()
- }
- /// Returns the path to the user's video dir
- pub fn video_dir() -> Option<PathBuf> {
- dirs_next::video_dir()
- }
- /// Returns the path to the resource directory of this app.
- pub fn resource_dir(package_info: &PackageInfo, env: &Env) -> Option<PathBuf> {
- crate::utils::platform::resource_dir(package_info, env).ok()
- }
- /// Returns the path to the suggested directory for your app config files.
- pub fn app_dir(config: &Config) -> Option<PathBuf> {
- dirs_next::config_dir().map(|dir| dir.join(&config.tauri.bundle.identifier))
- }
- /// Returns the path to the suggested log directory.
- pub fn log_dir(config: &Config) -> Option<PathBuf> {
- #[cfg(target_os = "macos")]
- let path = dirs_next::home_dir().map(|dir| {
- dir
- .join("Library/Logs")
- .join(&config.tauri.bundle.identifier)
- });
- #[cfg(not(target_os = "macos"))]
- let path =
- dirs_next::config_dir().map(|dir| dir.join(&config.tauri.bundle.identifier).join("logs"));
- path
- }
|