diff --git a/.changes/config.json b/.changes/config.json index 0969381b1..7fb05912e 100644 --- a/.changes/config.json +++ b/.changes/config.json @@ -8,7 +8,8 @@ "pref": "Performance Improvements", "changes": "What's Changed", "sec": "Security fixes", - "deps": "Dependencies" + "deps": "Dependencies", + "breaking": "Breaking Changes" }, "defaultChangeTag": "changes", "pkgManagers": { diff --git a/.changes/core-remove-file-dir-semver-apis.md b/.changes/core-remove-file-dir-semver-apis.md new file mode 100644 index 000000000..a94a03816 --- /dev/null +++ b/.changes/core-remove-file-dir-semver-apis.md @@ -0,0 +1,6 @@ +--- +'tauri': 'patch:breaking' +--- + +- Removed `tauri::api::file` and `tauri::api::dir` modules, use `std::fs` instead. +- Removed `tauri::api::version` module, use `semver` crate instead. diff --git a/core/tauri/Cargo.toml b/core/tauri/Cargo.toml index 9eb70daf4..8ccb6dcd6 100644 --- a/core/tauri/Cargo.toml +++ b/core/tauri/Cargo.toml @@ -52,10 +52,8 @@ tauri-macros = { version = "2.0.0-alpha.6", path = "../tauri-macros" } tauri-utils = { version = "2.0.0-alpha.6", features = [ "resources" ], path = "../tauri-utils" } tauri-runtime-wry = { version = "0.13.0-alpha.6", path = "../tauri-runtime-wry", optional = true } rand = "0.8" -semver = { version = "1.0", features = [ "serde" ] } serde_repr = "0.1" state = "0.6" -tempfile = "3" http = "0.2" dirs-next = "2.0" percent-encoding = "2.2" diff --git a/core/tauri/src/api/dir.rs b/core/tauri/src/api/dir.rs deleted file mode 100644 index 7a23eec70..000000000 --- a/core/tauri/src/api/dir.rs +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2019-2023 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -//! Types and functions related to file system directory management. - -use serde::Serialize; -use std::{ - fs::{self, metadata, symlink_metadata}, - path::{Path, PathBuf}, -}; -use tempfile::{self, tempdir}; - -/// A disk entry which is either a file or a directory. -/// -/// This is the result of the [`read_dir`]. The `children` field is always `Some` if the entry is a directory. -#[derive(Debug, Serialize)] -#[non_exhaustive] -pub struct DiskEntry { - /// The path to the entry. - pub path: PathBuf, - /// The name of the entry (file name with extension or directory name). - pub name: Option, - /// The children of this entry if it's a directory. - #[serde(skip_serializing_if = "Option::is_none")] - pub children: Option>, -} - -/// Checks if the given path is a directory. -pub fn is_dir>(path: P) -> crate::api::Result { - metadata(path).map(|md| md.is_dir()).map_err(Into::into) -} - -fn is_symlink>(path: P) -> crate::api::Result { - // TODO: remove the different implementation once we raise tauri's MSRV to at least 1.58 - #[cfg(windows)] - let ret = symlink_metadata(path) - .map(|md| md.is_symlink()) - .map_err(Into::into); - - #[cfg(not(windows))] - let ret = symlink_metadata(path) - .map(|md| md.file_type().is_symlink()) - .map_err(Into::into); - - ret -} - -/// Reads a directory. Can perform recursive operations. -pub fn read_dir>(path: P, recursive: bool) -> crate::api::Result> { - read_dir_with_options(path, recursive, ReadDirOptions { scope: None }) -} - -#[derive(Clone, Copy)] -pub(crate) struct ReadDirOptions<'a> { - pub scope: Option<&'a crate::FsScope>, -} - -pub(crate) fn read_dir_with_options>( - path: P, - recursive: bool, - options: ReadDirOptions<'_>, -) -> crate::api::Result> { - let mut files_and_dirs: Vec = vec![]; - for entry in fs::read_dir(path)? { - let path = entry?.path(); - let path_as_string = path.display().to_string(); - - if let Ok(flag) = is_dir(&path_as_string) { - files_and_dirs.push(DiskEntry { - path: path.clone(), - children: if flag { - Some( - if recursive - && (!is_symlink(&path_as_string)? - || options.scope.map(|s| s.is_allowed(&path)).unwrap_or(true)) - { - read_dir_with_options(&path_as_string, true, options)? - } else { - vec![] - }, - ) - } else { - None - }, - name: path - .file_name() - .map(|name| name.to_string_lossy()) - .map(|name| name.to_string()), - }); - } - } - Result::Ok(files_and_dirs) -} - -/// Runs a closure with a temporary directory argument. -pub fn with_temp_dir(callback: F) -> crate::api::Result<()> { - let dir = tempdir()?; - callback(&dir); - dir.close()?; - Ok(()) -} - -#[cfg(test)] -mod test { - use super::*; - use quickcheck_macros::quickcheck; - use std::{ffi::OsStr, path::PathBuf}; - - // check is dir function by passing in arbitrary strings - #[quickcheck] - fn qc_is_dir(f: String) -> bool { - // if the string runs through is_dir and comes out as an OK result then it must be a DIR. - if is_dir(f.clone()).is_ok() { - PathBuf::from(f).is_dir() - } else { - true - } - } - - fn name_from_path(path: PathBuf) -> Option { - path - .file_name() - .map(|name| name.to_string_lossy()) - .map(|name| name.to_string()) - } - - #[test] - // check the read_dir function with recursive = true - fn check_read_dir_recursively() { - // define a relative directory string test/api/ - let dir = PathBuf::from("test/api/"); - // add the files to this directory - let mut file_one = dir.clone(); - file_one.push("test.txt"); - let mut file_two = dir.clone(); - file_two.push("test_binary"); - - // call walk_dir on the directory - let res = read_dir(dir, true); - - // assert that the result is Ok() - assert!(res.is_ok()); - - // destruct the OK into a vector of DiskEntry Structs - if let Ok(vec) = res { - // assert that the vector length is only 3 - assert_eq!(vec.len(), 2); - - // get the first DiskEntry - let first = &vec[0]; - // get the second DiskEntry - let second = &vec[1]; - - if first.path.extension() == Some(OsStr::new("txt")) { - // check the fields for the first DiskEntry - assert_eq!(first.path, file_one); - assert!(first.children.is_none()); - assert_eq!(first.name, name_from_path(file_one)); - - // check the fields for the third DiskEntry - assert_eq!(second.path, file_two); - assert!(second.children.is_none()); - assert_eq!(second.name, name_from_path(file_two)); - } else { - // check the fields for the second DiskEntry - assert_eq!(first.path, file_two); - assert!(first.children.is_none()); - assert_eq!(first.name, name_from_path(file_two)); - - // check the fields for the third DiskEntry - assert_eq!(second.path, file_one); - assert!(second.children.is_none()); - assert_eq!(second.name, name_from_path(file_one)); - } - } - } - - #[test] - // check the read_dir function with recursive = false - fn check_read_dir() { - // define a relative directory test/api/ - let dir = PathBuf::from("test/api/"); - - // call list_dir_contents on the dir - let res = read_dir(dir, false); - - // assert that the result is Ok() - assert!(res.is_ok()); - - // destruct the vector from the Ok() - if let Ok(vec) = res { - // assert the length of the vector is 2 - assert_eq!(vec.len(), 2); - - // get the two DiskEntry structs in this vector - let first = &vec[0]; - let second = &vec[1]; - - if first.path.extension() == Some(OsStr::new("txt")) { - // check the fields for the first DiskEntry - assert_eq!(first.path, PathBuf::from("test/api/test.txt")); - assert!(first.children.is_none()); - assert_eq!(first.name, Some("test.txt".to_string())); - - // check the fields for the second DiskEntry - assert_eq!(second.path, PathBuf::from("test/api/test_binary")); - assert!(second.children.is_none()); - assert_eq!(second.name, Some("test_binary".to_string())); - } else { - // check the fields for the first DiskEntry - assert_eq!(second.path, PathBuf::from("test/api/test.txt")); - assert!(second.children.is_none()); - assert_eq!(second.name, Some("test.txt".to_string())); - - // check the fields for the second DiskEntry - assert_eq!(first.path, PathBuf::from("test/api/test_binary")); - assert!(first.children.is_none()); - assert_eq!(first.name, Some("test_binary".to_string())); - } - } - } - - #[test] - // test the with_temp_dir function - fn check_test_dir() { - // create a callback closure that takes in a TempDir type and prints it. - let callback = |td: &tempfile::TempDir| { - println!("{td:?}"); - }; - - // execute the with_temp_dir function on the callback - let res = with_temp_dir(callback); - - // assert that the result is an OK type. - assert!(res.is_ok()); - } -} diff --git a/core/tauri/src/api/error.rs b/core/tauri/src/api/error.rs index 0fce6a32c..fe9f3d1a4 100644 --- a/core/tauri/src/api/error.rs +++ b/core/tauri/src/api/error.rs @@ -2,17 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -/// The error types. +/// The result type of Tauri API module. +pub type Result = std::result::Result; + +/// The error type of Tauri API module. #[derive(thiserror::Error, Debug)] #[non_exhaustive] pub enum Error { - /// Semver error. - #[error(transparent)] - Semver(#[from] semver::Error), /// JSON error. #[error(transparent)] Json(#[from] serde_json::Error), - /// IO error. - #[error(transparent)] - Io(#[from] std::io::Error), } diff --git a/core/tauri/src/api/file.rs b/core/tauri/src/api/file.rs deleted file mode 100644 index 46ace7fa3..000000000 --- a/core/tauri/src/api/file.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019-2023 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -//! Types and functions related to file operations. - -use std::{fs, path::Path}; - -/// Reads the entire contents of a file into a string. -pub fn read_string>(file: P) -> crate::api::Result { - fs::read_to_string(file).map_err(Into::into) -} - -/// Reads the entire contents of a file into a bytes vector. -pub fn read_binary>(file: P) -> crate::api::Result> { - fs::read(file).map_err(Into::into) -} - -#[cfg(test)] -mod test { - use super::*; - #[cfg(not(windows))] - use crate::api::Error; - - #[test] - fn check_read_string() { - let file = String::from("test/api/test.txt"); - - let res = read_string(file); - - assert!(res.is_ok()); - - if let Ok(s) = res { - assert_eq!(s, "This is a test doc!".to_string()); - } - } - - #[test] - fn check_read_string_fail() { - let file = String::from("test/api/"); - - let res = read_string(file); - - assert!(res.is_err()); - - #[cfg(not(windows))] - if let Error::Io(e) = res.unwrap_err() { - #[cfg(not(windows))] - assert_eq!(e.to_string(), "Is a directory (os error 21)".to_string()); - } - } - - #[test] - fn check_read_binary() { - let file = String::from("test/api/test_binary"); - - let expected_vec = vec![ - 71, 73, 70, 56, 57, 97, 1, 0, 1, 0, 128, 0, 0, 255, 255, 255, 0, 0, 0, 33, 249, 4, 1, 0, 0, - 0, 0, 44, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 2, 68, 1, 0, 59, - ]; - - let res = read_binary(file); - - assert!(res.is_ok()); - - if let Ok(vec) = res { - assert_eq!(vec, expected_vec); - } - } - - #[test] - fn check_read_binary_fail() { - let file = String::from("test/api/"); - - let res = read_binary(file); - - assert!(res.is_err()); - - #[cfg(not(windows))] - if let Error::Io(e) = res.unwrap_err() { - #[cfg(not(windows))] - assert_eq!(e.to_string(), "Is a directory (os error 21)".to_string()); - } - } -} diff --git a/core/tauri/src/api/mod.rs b/core/tauri/src/api/mod.rs index f3d24f4c3..5dd153960 100644 --- a/core/tauri/src/api/mod.rs +++ b/core/tauri/src/api/mod.rs @@ -4,18 +4,11 @@ //! The Tauri API interface. -pub mod dir; -pub mod file; pub mod ipc; -pub mod version; mod error; -/// The error type of Tauri API module. -pub use error::Error; -/// The result type of Tauri API module. -pub type Result = std::result::Result; - +pub use error::{Error, Result}; // Not public API #[doc(hidden)] pub mod private { diff --git a/core/tauri/src/api/version.rs b/core/tauri/src/api/version.rs deleted file mode 100644 index 3a192ae2e..000000000 --- a/core/tauri/src/api/version.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019-2023 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -//! Compare two semantic versions. -//! -//! [Semantic Versioning](https://semver.org) is a guideline for how version numbers are assigned and incremented. -//! The functions on this module are helpers around [semver](https://docs.rs/semver/latest/semver/). - -use semver::Version; -use std::cmp::Ordering; - -/// Compare two semver versions. -/// -/// If the `first` semver is greater, returns -1. -/// If the `second` semver is greater, returns 1. -/// If they are equal, returns 0. -/// -/// # Examples -/// -/// ``` -/// use tauri::api::version::compare; -/// assert_eq!(compare("0.15.0", "0.15.5").unwrap(), 1); -/// assert_eq!(compare("0.15.10", "0.15.9").unwrap(), -1); -/// assert_eq!(compare("0.15.10", "0.16.10").unwrap(), 1); -/// assert_eq!(compare("1.57.0", "2.17.4").unwrap(), 1); -/// assert_eq!(compare("0.0.0", "0.0.0").unwrap(), 0); -/// ``` -pub fn compare(first: &str, second: &str) -> crate::api::Result { - let v1 = Version::parse(first)?; - let v2 = Version::parse(second)?; - match v1.cmp(&v2) { - Ordering::Greater => Ok(-1), - Ordering::Less => Ok(1), - Ordering::Equal => Ok(0), - } -} - -/// Check if the "second" semver is compatible with the "first". -/// -/// # Examples -/// -/// ``` -/// use tauri::api::version::is_compatible; -/// assert!(is_compatible("0.15.0", "0.15.5").unwrap()); -/// assert!(!is_compatible("0.15.0", "0.16.5").unwrap()); -/// -/// assert!(is_compatible("1.5.0", "1.5.10").unwrap()); -/// assert!(is_compatible("1.54.0", "1.55.0").unwrap()); -/// assert!(!is_compatible("2.17.0", "3.17.0").unwrap()); -/// ``` -pub fn is_compatible(first: &str, second: &str) -> crate::api::Result { - let first = Version::parse(first)?; - let second = Version::parse(second)?; - Ok(if second.major == 0 && first.major == 0 { - first.minor == second.minor && second.patch > first.patch - } else if second.major > 0 { - first.major == second.major - && ((second.minor > first.minor) - || (first.minor == second.minor && second.patch > first.patch)) - } else { - false - }) -} - -/// Check if a the "other" version is a major bump from the "current". -/// -/// # Examples -/// -/// ``` -/// use tauri::api::version::is_major; -/// assert!(is_major("1.0.0", "2.0.0").unwrap()); -/// assert!(is_major("1.5.0", "2.17.10").unwrap()); -/// assert!(is_major("0.5.0", "2.17.10").unwrap()); -/// assert!(!is_major("1.1.5", "1.2.5").unwrap()); -/// assert!(!is_major("0.14.0", "0.15.0").unwrap()); -/// ``` -pub fn is_major(current: &str, other: &str) -> crate::api::Result { - let current = Version::parse(current)?; - let other = Version::parse(other)?; - Ok(other.major > current.major) -} - -/// Check if a the "other" version is a minor bump from the "current". -/// -/// # Examples -/// -/// ``` -/// use tauri::api::version::is_minor; -/// assert!(is_minor("0.15.10", "0.16.110").unwrap()); -/// assert!(is_minor("1.0.0", "1.1.1").unwrap()); -/// assert!(!is_minor("2.1.9", "3.2.0").unwrap()); -/// assert!(!is_minor("1.0.0", "1.0.10").unwrap()); -/// ``` -pub fn is_minor(current: &str, other: &str) -> crate::api::Result { - let current = Version::parse(current)?; - let other = Version::parse(other)?; - Ok(current.major == other.major && other.minor > current.minor) -} - -/// Check if a the "other" version is a patch bump from the "current". -/// -/// # Examples -/// -/// ``` -/// use tauri::api::version::is_patch; -/// assert!(is_patch("0.15.0", "0.15.1").unwrap()); -/// assert!(is_patch("1.0.0", "1.0.1").unwrap()); -/// assert!(!is_patch("2.2.0", "2.3.1").unwrap()); -/// assert!(!is_patch("2.2.1", "1.1.0").unwrap()); -/// ``` -pub fn is_patch(current: &str, other: &str) -> crate::api::Result { - let current = Version::parse(current)?; - let other = Version::parse(other)?; - Ok(current.major == other.major && current.minor == other.minor && other.patch > current.patch) -} - -/// Check if a version is greater than the current. -/// -/// # Examples -/// -/// ``` -/// use tauri::api::version::is_greater; -/// assert!(is_greater("0.15.10", "0.16.0").unwrap()); -/// assert!(is_greater("1.0.0", "1.0.1").unwrap()); -/// assert!(is_greater("1.1.9", "1.2.0").unwrap()); -/// assert!(is_greater("1.0.0", "2.0.0").unwrap()); -/// ``` -pub fn is_greater(current: &str, other: &str) -> crate::api::Result { - Ok(Version::parse(other)? > Version::parse(current)?) -}