Kaynağa Gözat

feat(tauri) extend file system API (#512)

* feat(tauri) extend file system API

* chore(deps) pin web-view deps
Lucas Fernandes Nogueira 5 yıl önce
ebeveyn
işleme
8ac066700a

+ 63 - 1
cli/tauri.js/api/fs.js

@@ -51,9 +51,71 @@ function readDir (dir, options = {}) {
   return tauri.readDir(dir, options)
 }
 
+/**
+ * Creates a directory
+ * If one of the path's parent components doesn't exist and the `recursive` option isn't set to true, it will be rejected
+ *
+ * @param {string} dir path to the directory to create
+ * @param {object} [options] configuration object
+ * @param {boolean} [options.recursive] whether to create the directory's parent components or not
+ * @return {Promise<void>}
+ */
+function createDir (dir, options = {}) {
+  return tauri.createDir(dir, options)
+}
+
+/**
+ * Removes a directory
+ * If the directory is not empty and the `recursive` option isn't set to true, it will be rejected
+ *
+ * @param {string} dir path to the directory to remove
+ * @param {object} [options] configuration object
+ * @param {boolean} [options.recursive] whether to remove all of the directory's content or not
+ * @return {Promise<void>}
+ */
+function removeDir (dir, options = {}) {
+  return tauri.removeDir(dir, options)
+}
+
+/**
+ * Copy file
+ *
+ * @param {string} source
+ * @param {string} destination
+ * @return {Promise<void>}
+ */
+function copyFile (source, destination) {
+  return tauri.copyFile(source, destination)
+}
+
+/**
+ * Removes a file
+ *
+ * @param {string} file path to the file to remove
+ * @return {Promise<void>}
+ */
+function removeFile (file) {
+  return tauri.removeFile(file)
+}
+
+/**
+ * Renames a file
+ *
+ * @param {string} oldPath
+ * @param {string} newPath
+ * @return {Promise<void>}
+ */
+function renameFile (oldPath, newPath) {
+  return tauri.renameFile(oldPath, newPath)
+}
+
 export {
   readTextFile,
   readBinaryFile,
   writeFile,
-  readDir
+  readDir,
+  createDir,
+  removeDir,
+  copyFile,
+  removeFile
 }

+ 124 - 0
cli/tauri.js/templates/tauri.js

@@ -306,6 +306,130 @@ window.tauri = {
         <% } %>
   },
 
+  <% if (ctx.dev) { %>
+    /**
+     * @name createDir
+     * @description Creates a directory
+     * Permissions based on the app's PID owner
+     * @param {String} path
+     * @param {Object} [options]
+     * @param {Boolean} [options.recursive]
+     * @returns {*|Promise<any>|Promise}
+     */
+  <% } %>
+  createDir: function createDir(path, options) {
+    <% if (tauri.whitelist.createDir === true || tauri.whitelist.all === true) { %>
+      return this.promisified({
+        cmd: 'createDir',
+        path: path,
+        options: options
+      });
+    <% } else { %>
+      <% if (ctx.dev) { %>
+          return __whitelistWarning('createDir')
+          <% } %>
+        return __reject()
+        <% } %>
+  },
+
+  <% if (ctx.dev) { %>
+    /**
+     * @name removeDir
+     * @description Removes a directory
+     * Permissions based on the app's PID owner
+     * @param {String} path
+     * @param {Object} [options]
+     * @param {Boolean} [options.recursive]
+     * @returns {*|Promise<any>|Promise}
+     */
+  <% } %>
+  removeDir: function removeDir(path, options) {
+    <% if (tauri.whitelist.removeDir === true || tauri.whitelist.all === true) { %>
+      return this.promisified({
+        cmd: 'removeDir',
+        path: path,
+        options: options
+      });
+    <% } else { %>
+      <% if (ctx.dev) { %>
+          return __whitelistWarning('removeDir')
+          <% } %>
+        return __reject()
+        <% } %>
+  },
+
+  <% if (ctx.dev) { %>
+    /**
+     * @name copyFile
+     * @description Copy file
+     * Permissions based on the app's PID owner
+     * @param {String} source
+     * @param {String} destination
+     * @returns {*|Promise<any>|Promise}
+     */
+  <% } %>
+  copyFile: function copyFile(source, destination) {
+    <% if (tauri.whitelist.copyFile === true || tauri.whitelist.all === true) { %>
+      return this.promisified({
+        cmd: 'copyFile',
+        source: source,
+        destination: destination
+      });
+    <% } else { %>
+      <% if (ctx.dev) { %>
+          return __whitelistWarning('copyFile')
+          <% } %>
+        return __reject()
+        <% } %>
+  },
+
+  <% if (ctx.dev) { %>
+    /**
+     * @name removeFile
+     * @description Removes a file
+     * Permissions based on the app's PID owner
+     * @param {String} path
+     * @returns {*|Promise<any>|Promise}
+     */
+  <% } %>
+  removeFile: function removeFile(path) {
+    <% if (tauri.whitelist.removeFile === true || tauri.whitelist.all === true) { %>
+      return this.promisified({
+        cmd: 'removeFile',
+        path: path
+      });
+    <% } else { %>
+      <% if (ctx.dev) { %>
+          return __whitelistWarning('removeFile')
+          <% } %>
+        return __reject()
+        <% } %>
+  },
+
+  <% if (ctx.dev) { %>
+    /**
+     * @name renameFile
+     * @description Renames a file
+     * Permissions based on the app's PID owner
+     * @param {String} path
+     * @returns {*|Promise<any>|Promise}
+     */
+  <% } %>
+  renameFile: function renameFile(oldPath, newPath) {
+    <% if (tauri.whitelist.renameFile === true || tauri.whitelist.all === true) { %>
+      return this.promisified({
+        cmd: 'renameFile',
+        old_path: oldPath,
+        new_path: newPath
+      });
+    <% } else { %>
+      <% if (ctx.dev) { %>
+          return __whitelistWarning('renameFile')
+          <% } %>
+        return __reject()
+        <% } %>
+  },
+
   <% if (ctx.dev) { %>
     /**
      * @name setTitle

+ 1 - 1
tauri-api/src/dir.rs

@@ -44,7 +44,7 @@ pub fn walk_dir(path_copy: String) -> crate::Result<Vec<DiskEntry>> {
 
 pub fn list_dir_contents(dir_path: String) -> crate::Result<Vec<DiskEntry>> {
   fs::read_dir(dir_path)
-    .map_err(|err| crate::Error::with_chain(err, "read string failed"))
+    .map_err(|err| crate::Error::with_chain(err, "read dir failed"))
     .and_then(|paths| {
       let mut dirs: Vec<DiskEntry> = vec![];
       for path in paths {

+ 7 - 1
tauri/Cargo.toml

@@ -12,7 +12,8 @@ exclude = ["test/fixture/**"]
 [dependencies]
 serde_json = "1.0"
 serde = { version = "1.0", features = ["derive"] }
-web-view = "0.6.0"
+webview-sys = "=0.4.0"
+web-view = "=0.6.0"
 tauri_includedir = "0.5.0"
 phf = "0.8.0"
 base64 = "0.12.0"
@@ -44,6 +45,11 @@ read-text-file = []
 read-binary-file = []
 write-file = []
 read-dir = []
+copy-file = []
+create-dir = []
+remove-dir = []
+remove-file = []
+rename-file = []
 set-title = []
 execute = []
 open = []

+ 99 - 0
tauri/examples/communication/dist/index.tauri.html

@@ -277,6 +277,105 @@ window.tauri = {
   },
 
   
+    /**
+     * @name createDir
+     * @description Creates a directory
+     * Permissions based on the app's PID owner
+     * @param {String} path
+     * @param {Object} [options]
+     * @param {Boolean} [options.recursive]
+     * @returns {*|Promise<any>|Promise}
+     */
+  
+  createDir: function createDir(path, options) {
+    
+      return this.promisified({
+        cmd: 'createDir',
+        path: path,
+        options: options
+      });
+    
+  },
+
+  
+    /**
+     * @name removeDir
+     * @description Removes a directory
+     * Permissions based on the app's PID owner
+     * @param {String} path
+     * @param {Object} [options]
+     * @param {Boolean} [options.recursive]
+     * @returns {*|Promise<any>|Promise}
+     */
+  
+  removeDir: function removeDir(path, options) {
+    
+      return this.promisified({
+        cmd: 'removeDir',
+        path: path,
+        options: options
+      });
+    
+  },
+
+  
+    /**
+     * @name copyFile
+     * @description Copy file
+     * Permissions based on the app's PID owner
+     * @param {String} source
+     * @param {String} destination
+     * @returns {*|Promise<any>|Promise}
+     */
+  
+  copyFile: function copyFile(source, destination) {
+    
+      return this.promisified({
+        cmd: 'copyFile',
+        source: source,
+        destination: destination
+      });
+    
+  },
+
+  
+    /**
+     * @name removeFile
+     * @description Removes a file
+     * Permissions based on the app's PID owner
+     * @param {String} path
+     * @returns {*|Promise<any>|Promise}
+     */
+  
+  removeFile: function removeFile(path) {
+    
+      return this.promisified({
+        cmd: 'removeFile',
+        path: path
+      });
+    
+  },
+
+  
+    /**
+     * @name renameFile
+     * @description Renames a file
+     * Permissions based on the app's PID owner
+     * @param {String} path
+     * @returns {*|Promise<any>|Promise}
+     */
+  
+  renameFile: function renameFile(oldPath, newPath) {
+    
+      return this.promisified({
+        cmd: 'renameFile',
+        old_path: oldPath,
+        new_path: newPath
+      });
+    
+  },
+
+  
     /**
      * @name setTitle
      * @description Set the application's title

+ 44 - 0
tauri/src/endpoints.rs

@@ -58,6 +58,50 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
         } => {
           file_system::read_dir(webview, path, options, callback, error);
         }
+        #[cfg(any(feature = "all-api", feature = "copy-file"))]
+        CopyFile {
+          source,
+          destination,
+          callback,
+          error,
+        } => {
+          file_system::copy_file(webview, source, destination, callback, error);
+        }
+        #[cfg(any(feature = "all-api", feature = "create-dir"))]
+        CreateDir {
+          path,
+          options,
+          callback,
+          error,
+        } => {
+          file_system::create_dir(webview, path, options, callback, error);
+        }
+        #[cfg(any(feature = "all-api", feature = "remove-dir"))]
+        RemoveDir {
+          path,
+          options,
+          callback,
+          error,
+        } => {
+          file_system::remove_dir(webview, path, options, callback, error);
+        }
+        #[cfg(any(feature = "all-api", feature = "remove-file"))]
+        RemoveFile {
+          path,
+          callback,
+          error,
+        } => {
+          file_system::remove_file(webview, path, callback, error);
+        }
+        #[cfg(any(feature = "all-api", feature = "rename-file"))]
+        RenameFile {
+          old_path,
+          new_path,
+          callback,
+          error,
+        } => {
+          file_system::rename_file(webview, old_path, new_path, callback, error);
+        }
         #[cfg(any(feature = "all-api", feature = "set-title"))]
         SetTitle { title } => {
           webview.set_title(&title)?;

+ 36 - 2
tauri/src/endpoints/cmd.rs

@@ -1,7 +1,7 @@
 use serde::Deserialize;
 
 #[derive(Deserialize)]
-pub struct ReadDirOptions {
+pub struct DirOperationOptions {
   #[serde(default)]
   pub recursive: bool
 }
@@ -48,7 +48,41 @@ pub enum Cmd {
   #[cfg(any(feature = "all-api", feature = "read-dir"))]
   ReadDir {
     path: String,
-    options: Option<ReadDirOptions>,
+    options: Option<DirOperationOptions>,
+    callback: String,
+    error: String,
+  },
+  #[cfg(any(feature = "all-api", feature = "copy-file"))]
+  CopyFile {
+    source: String,
+    destination: String,
+    callback: String,
+    error: String,
+  },
+  #[cfg(any(feature = "all-api", feature = "create-dir"))]
+  CreateDir {
+    path: String,
+    options: Option<DirOperationOptions>,
+    callback: String,
+    error: String,
+  },
+  #[cfg(any(feature = "all-api", feature = "remove-dir"))]
+  RemoveDir {
+    path: String,
+    options: Option<DirOperationOptions>,
+    callback: String,
+    error: String,
+  },
+  #[cfg(any(feature = "all-api", feature = "remove-file"))]
+  RemoveFile {
+    path: String,
+    callback: String,
+    error: String,
+  },
+  #[cfg(any(feature = "all-api", feature = "rename-file"))]
+  RenameFile {
+    old_path: String,
+    new_path: String,
     callback: String,
     error: String,
   },

+ 124 - 7
tauri/src/endpoints/file_system.rs

@@ -3,15 +3,16 @@ use web_view::WebView;
 use tauri_api::dir;
 use tauri_api::file;
 
+use std::fs;
 use std::fs::File;
 use std::io::Write;
 
-use super::cmd::{ReadDirOptions};
+use super::cmd::{DirOperationOptions};
 
 pub fn read_dir<T: 'static>(
   webview: &mut WebView<'_, T>,
   path: String,
-  options: Option<ReadDirOptions>,
+  options: Option<DirOperationOptions>,
   callback: String,
   error: String,
 ) {
@@ -25,11 +26,11 @@ pub fn read_dir<T: 'static>(
       };
       if recursive {
         dir::walk_dir(path)
-          .map_err(|e| crate::ErrorKind::Command(e.to_string()).into())
+          .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
           .and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
       } else {
         dir::list_dir_contents(path)
-          .map_err(|e| crate::ErrorKind::Command(e.to_string()).into())
+          .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
           .and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
       }
     },
@@ -38,6 +39,122 @@ pub fn read_dir<T: 'static>(
   );
 }
 
+pub fn copy_file<T: 'static>(
+  webview: &mut WebView<'_, T>,
+  source: String,
+  destination: String,
+  callback: String,
+  error: String,
+) {
+  crate::execute_promise(
+    webview,
+    move || {
+      fs::copy(source, destination)
+         .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
+         .map(|_| "".to_string())
+    },
+    callback,
+    error,
+  );
+}
+
+pub fn create_dir<T: 'static>(
+  webview: &mut WebView<'_, T>,
+  path: String,
+  options: Option<DirOperationOptions>,
+  callback: String,
+  error: String,
+) {
+  crate::execute_promise(
+    webview,
+    move || {
+      let recursive = if let Some(options_value) = options {
+        options_value.recursive
+      } else {
+        false
+      };
+      let response = if recursive {
+        fs::create_dir_all(path)
+      } else {
+        fs::create_dir(path)
+      };
+
+      response
+        .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
+         .map(|_| "".to_string())
+    },
+    callback,
+    error,
+  );
+}
+
+pub fn remove_dir<T: 'static>(
+  webview: &mut WebView<'_, T>,
+  path: String,
+  options: Option<DirOperationOptions>,
+  callback: String,
+  error: String,
+) {
+  crate::execute_promise(
+    webview,
+    move || {
+      let recursive = if let Some(options_value) = options {
+        options_value.recursive
+      } else {
+        false
+      };
+      let response = if recursive {
+        fs::remove_dir_all(path)
+      } else {
+        fs::remove_dir(path)
+      };
+
+      response
+        .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
+        .map(|_| "".to_string())
+    },
+    callback,
+    error,
+  );
+}
+
+pub fn remove_file<T: 'static>(
+  webview: &mut WebView<'_, T>,
+  path: String,
+  callback: String,
+  error: String,
+) {
+  crate::execute_promise(
+    webview,
+    move || {
+      fs::remove_file(path)
+        .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
+        .map(|_| "".to_string())
+    },
+    callback,
+    error,
+  );
+}
+
+pub fn rename_file<T: 'static>(
+  webview: &mut WebView<'_, T>,
+  old_path: String,
+  new_path: String,
+  callback: String,
+  error: String,
+) {
+  crate::execute_promise(
+    webview,
+    move || {
+      fs::rename(old_path, new_path)
+        .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
+        .map(|_| "".to_string())
+    },
+    callback,
+    error,
+  );
+}
+
 pub fn write_file<T: 'static>(
   webview: &mut WebView<'_, T>,
   file: String,
@@ -49,7 +166,7 @@ pub fn write_file<T: 'static>(
     webview,
     move || {
       File::create(file)
-        .map_err(|e| crate::ErrorKind::Command(e.to_string()).into())
+        .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
         .and_then(|mut f| {
           f.write_all(contents.as_bytes())
             .map_err(|err| err.into())
@@ -71,7 +188,7 @@ pub fn read_text_file<T: 'static>(
     webview,
     move || {
       file::read_string(path)
-        .map_err(|e| crate::ErrorKind::Command(e.to_string()).into())
+        .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
         .and_then(|f| {
           serde_json::to_string(&f)
             .map_err(|err| err.into())
@@ -92,7 +209,7 @@ pub fn read_binary_file<T: 'static>(
     webview,
     move || {
       file::read_binary(path)
-        .map_err(|e| crate::ErrorKind::Command(e.to_string()).into())
+        .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
         .and_then(|f| {
           serde_json::to_string(&f)
             .map_err(|err| err.into())

+ 4 - 0
tauri/src/lib.rs

@@ -42,6 +42,10 @@ error_chain! {
       description("Command Error")
       display("Command Error: '{}'", t)
     }
+    FileSystem(t: String) {
+      description("FileSystem Error")
+      display("FileSystem Error: '{}'", t)
+    }
     Dialog(t: String) {
       description("Dialog Error")
       display("Dialog Error: '{}'", t)