Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): add app-specific directory APIs, closes #5263 #5272

Merged
merged 13 commits into from Sep 28, 2022
5 changes: 5 additions & 0 deletions .changes/app-dirs-api.md
@@ -0,0 +1,5 @@
---
"tauri": minor
---

Add new app-specific directory APIs and deprecate existing `app_dir` and `log_dir` APIs.
caesar marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 4 additions & 2 deletions core/tauri-utils/src/config.rs
Expand Up @@ -1126,7 +1126,8 @@ macro_rules! check_feature {
/// Each pattern can start with a variable that resolves to a system base directory.
/// The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,
/// `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,
/// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`.
/// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,
/// `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(untagged)]
Expand Down Expand Up @@ -1452,7 +1453,8 @@ pub struct ShellAllowedCommand {
/// It can start with a variable that resolves to a system base directory.
/// The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,
/// `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,
/// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`.
/// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,
/// `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.
#[serde(rename = "cmd", default)] // use default just so the schema doesn't flag it as required
pub command: PathBuf,

Expand Down
245 changes: 178 additions & 67 deletions core/tauri/src/api/path.rs
Expand Up @@ -13,61 +13,94 @@ 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,
// we have to wrap the BaseDirectory enum in a module for #[allow(deprecated)]
// to work, because the procedural macros on the enum prevent it from working directly
caesar marked this conversation as resolved.
Show resolved Hide resolved
// TODO: remove this workaround in v2 along with deprecated variants
#[allow(deprecated)]
mod base_directory {
use super::*;

/// 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`]`/{bundle_identifier}`.
#[deprecated(
since = "1.2.0",
note = "Will be removed in 2.0.0. Use `BaseDirectory::AppConfig` or BaseDirectory::AppData` instead."
)]
App,
/// The default app log directory.
/// Resolves to [`BaseDirectory::Home`]`/Library/Logs/{bundle_identifier}` on macOS
/// and [`BaseDirectory::Config`]`/{bundle_identifier}/logs` on linux and Windows.
#[deprecated(
since = "1.2.0",
note = "Will be removed in 2.0.0. Use `BaseDirectory::AppLog` instead."
)]
Log,
/// A temporary directory.
/// Resolves to [`temp_dir`].
Temp,
/// The default app config directory.
/// Resolves to [`BaseDirectory::Config`]`/{bundle_identifier}`.
AppConfig,
/// The default app data directory.
/// Resolves to [`BaseDirectory::Data`]`/{bundle_identifier}`.
AppData,
/// The default app local data directory.
/// Resolves to [`BaseDirectory::LocalData`]`/{bundle_identifier}`.
AppLocalData,
/// The default app cache directory.
/// Resolves to [`BaseDirectory::Cache`]`/{bundle_identifier}`.
AppCache,
/// The default app log directory.
/// Resolves to [`BaseDirectory::Home`]`/Library/Logs/{bundle_identifier}` on macOS
/// and [`BaseDirectory::Config`]`/{bundle_identifier}/logs` on linux and Windows.
AppLog,
}
}
pub use base_directory::BaseDirectory;

impl BaseDirectory {
/// Gets the variable that represents this [`BaseDirectory`] for string paths.
Expand All @@ -90,9 +123,16 @@ impl BaseDirectory {
Self::Template => "$TEMPLATE",
Self::Video => "$VIDEO",
Self::Resource => "$RESOURCE",
#[allow(deprecated)]
Self::App => "$APP",
#[allow(deprecated)]
Self::Log => "$LOG",
Self::Temp => "$TEMP",
Self::AppConfig => "$APPCONFIG",
Self::AppData => "$APPDATA",
Self::AppLocalData => "$APPLOCALDATA",
Self::AppCache => "$APPCACHE",
Self::AppLog => "$APPLOG",
}
}

Expand All @@ -116,9 +156,16 @@ impl BaseDirectory {
"$TEMPLATE" => Self::Template,
"$VIDEO" => Self::Video,
"$RESOURCE" => Self::Resource,
#[allow(deprecated)]
"$APP" => Self::App,
#[allow(deprecated)]
"$LOG" => Self::Log,
"$TEMP" => Self::Temp,
"$APPCONFIG" => Self::AppConfig,
"$APPDATA" => Self::AppData,
"$APPLOCALDATA" => Self::AppLocalData,
"$APPCACHE" => Self::AppCache,
"$APPLOG" => Self::AppLog,
_ => return None,
};
Some(res)
Expand Down Expand Up @@ -192,7 +239,7 @@ pub fn parse<P: AsRef<Path>>(
/// context.package_info(),
/// &Env::default(),
/// "db/tauri.sqlite",
/// Some(BaseDirectory::App))
/// Some(BaseDirectory::AppData))
/// .expect("failed to resolve path");
/// assert_eq!(path.to_str().unwrap(), "/home/${whoami}/.config/com.tauri.app/db/tauri.sqlite");
///
Expand Down Expand Up @@ -242,9 +289,16 @@ pub fn resolve_path<P: AsRef<Path>>(
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),
#[allow(deprecated)]
BaseDirectory::App => app_config_dir(config),
#[allow(deprecated)]
BaseDirectory::Log => app_log_dir(config),
BaseDirectory::Temp => Some(temp_dir()),
BaseDirectory::AppConfig => app_config_dir(config),
BaseDirectory::AppData => app_data_dir(config),
BaseDirectory::AppLocalData => app_local_data_dir(config),
BaseDirectory::AppCache => app_cache_dir(config),
BaseDirectory::AppLog => app_log_dir(config),
};
if let Some(mut base_dir_path_value) = base_dir_path {
// use the same path resolution mechanism as the bundler's resource injection algorithm
Expand Down Expand Up @@ -459,25 +513,52 @@ 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.
/// Returns the path to the suggested directory for your app's config files.
///
/// Resolves to `${config_dir}/${bundle_identifier}`.
/// Resolves to [`config_dir`]`/${bundle_identifier}`.
///
/// See [`PathResolver::app_dir`](crate::PathResolver#method.app_dir) for a more convenient helper function.
pub fn app_dir(config: &Config) -> Option<PathBuf> {
/// See [`PathResolver::app_config_dir`](crate::PathResolver#method.app_config_dir) for a more convenient helper function.
pub fn app_config_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.
/// Returns the path to the suggested directory for your app's data files.
///
/// Resolves to [`data_dir`]`/${bundle_identifier}`.
///
/// See [`PathResolver::app_data_dir`](crate::PathResolver#method.app_data_dir) for a more convenient helper function.
pub fn app_data_dir(config: &Config) -> Option<PathBuf> {
dirs_next::data_dir().map(|dir| dir.join(&config.tauri.bundle.identifier))
}

/// Returns the path to the suggested directory for your app's local data files.
///
/// Resolves to [`local_data_dir`]`/${bundle_identifier}`.
///
/// See [`PathResolver::app_data_dir`](crate::PathResolver#method.app_data_dir) for a more convenient helper function.
pub fn app_local_data_dir(config: &Config) -> Option<PathBuf> {
dirs_next::data_local_dir().map(|dir| dir.join(&config.tauri.bundle.identifier))
}

/// Returns the path to the suggested directory for your app's cache files.
///
/// Resolves to [`cache_dir`]`/${bundle_identifier}`.
///
/// See [`PathResolver::app_cache_dir`](crate::PathResolver#method.app_cache_dir) for a more convenient helper function.
pub fn app_cache_dir(config: &Config) -> Option<PathBuf> {
dirs_next::cache_dir().map(|dir| dir.join(&config.tauri.bundle.identifier))
}

/// Returns the path to the suggested directory for your app's log files.
///
/// ## Platform-specific
///
/// - **Linux:** Resolves to `${config_dir}/${bundle_identifier}`.
/// - **macOS:** Resolves to `${home_dir}//Library/Logs/{bundle_identifier}`
/// - **Windows:** Resolves to `${config_dir}/${bundle_identifier}`.
/// - **Linux:** Resolves to [`config_dir`]`/${bundle_identifier}`.
/// - **macOS:** Resolves to [`home_dir`]`/Library/Logs/${bundle_identifier}`
/// - **Windows:** Resolves to [`config_dir`]`/${bundle_identifier}`.
///
/// See [`PathResolver::log_dir`](crate::PathResolver#method.log_dir) for a more convenient helper function.
pub fn log_dir(config: &Config) -> Option<PathBuf> {
/// See [`PathResolver::app_log_dir`](crate::PathResolver#method.app_log_dir) for a more convenient helper function.
pub fn app_log_dir(config: &Config) -> Option<PathBuf> {
#[cfg(target_os = "macos")]
let path = dirs_next::home_dir().map(|dir| {
dir
Expand All @@ -491,3 +572,33 @@ pub fn log_dir(config: &Config) -> Option<PathBuf> {

path
}

/// Returns the path to the suggested directory for your app's config files.
///
/// Resolves to [`config_dir`]`/${bundle_identifier}`.
///
/// See [`PathResolver::app_config_dir`](crate::PathResolver#method.app_config_dir) for a more convenient helper function.
#[deprecated(
since = "1.2.0",
note = "Will be removed in 2.0.0. Use `app_config_dir` or `app_data_dir` instead."
)]
pub fn app_dir(config: &Config) -> Option<PathBuf> {
app_config_dir(config)
}

/// Returns the path to the suggested directory for your app's log files.
///
/// ## Platform-specific
///
/// - **Linux:** Resolves to [`config_dir`]`/${bundle_identifier}`.
/// - **macOS:** Resolves to [`home_dir`]`/Library/Logs/${bundle_identifier}`
/// - **Windows:** Resolves to [`config_dir`]`/${bundle_identifier}`.
///
/// See [`PathResolver::app_log_dir`](crate::PathResolver#method.app_log_dir) for a more convenient helper function.
#[deprecated(
since = "1.2.0",
note = "Will be removed in 2.0.0. Use `app_log_dir` instead."
)]
pub fn log_dir(config: &Config) -> Option<PathBuf> {
app_log_dir(config)
}
41 changes: 37 additions & 4 deletions core/tauri/src/app.rs
Expand Up @@ -288,14 +288,47 @@ impl PathResolver {
.map(|dir| dir.join(resource_relpath(path.as_ref())))
}

/// Returns the path to the suggested directory for your app config files.
/// Returns the path to the suggested directory for your app's config files.
pub fn app_config_dir(&self) -> Option<PathBuf> {
crate::api::path::app_config_dir(&self.config)
}

/// Returns the path to the suggested directory for your app's data files.
pub fn app_data_dir(&self) -> Option<PathBuf> {
crate::api::path::app_data_dir(&self.config)
}

/// Returns the path to the suggested directory for your app's local data files.
pub fn app_local_data_dir(&self) -> Option<PathBuf> {
crate::api::path::app_local_data_dir(&self.config)
}

/// Returns the path to the suggested directory for your app's cache files.
pub fn app_cache_dir(&self) -> Option<PathBuf> {
crate::api::path::app_cache_dir(&self.config)
}

/// Returns the path to the suggested directory for your app's log files.
pub fn app_log_dir(&self) -> Option<PathBuf> {
crate::api::path::app_log_dir(&self.config)
}

/// Returns the path to the suggested directory for your app's config files.
#[deprecated(
since = "1.2.0",
note = "Will be removed in 2.0.0. Use `app_config_dir` or `app_data_dir` instead."
)]
pub fn app_dir(&self) -> Option<PathBuf> {
crate::api::path::app_dir(&self.config)
self.app_config_dir()
}

/// Returns the path to the suggested log directory.
/// Returns the path to the suggested directory for your app's log files.
#[deprecated(
since = "1.2.0",
note = "Will be removed in 2.0.0. Use `app_log_dir` instead."
)]
pub fn log_dir(&self) -> Option<PathBuf> {
crate::api::path::log_dir(&self.config)
self.app_log_dir()
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/tauri/src/endpoints/file_system.rs
Expand Up @@ -399,7 +399,7 @@ mod tests {
impl Arbitrary for BaseDirectory {
fn arbitrary(g: &mut Gen) -> Self {
if bool::arbitrary(g) {
BaseDirectory::App
BaseDirectory::AppData
} else {
BaseDirectory::Resource
}
Expand Down