Bläddra i källkod

feat(tauri) add path API (#513)

* feat(tauri) extend file system API

* chore(deps) pin web-view deps

* feat(tauri) add path API

* feat(tauri.js) add Dir definition and usage

* fix(tauri) correctly determine app_name

* feat(example) add Dir select to the communication example

* chore(tauri) wrap comment line

* fix(tauri) build works
Lucas Fernandes Nogueira 5 år sedan
förälder
incheckning
b2e28f39fe

+ 30 - 0
cli/tauri.js/api/fs/dir.js

@@ -0,0 +1,30 @@
+/**
+ * @typedef {number} BaseDirectory
+ */
+/**
+ * @enum {BaseDirectory}
+ */
+const Dir = {
+  Audio: 1,
+  Cache: 2,
+  Config: 3,
+  Data: 4,
+  LocalData: 5,
+  Desktop: 6,
+  Document: 7,
+  Download: 8,
+  Executable: 9,
+  Font: 10,
+  Home: 11,
+  Picture: 12,
+  Public: 13,
+  Runtime: 14,
+  Template: 15,
+  Video: 16,
+  Resource: 17,
+  App: 18
+}
+
+export {
+  Dir
+}

+ 33 - 14
cli/tauri.js/api/fs.js → cli/tauri.js/api/fs/index.js

@@ -1,23 +1,28 @@
 import tauri from './tauri'
+import { Dir } from './dir'
 
 /**
  * reads a file as text
  *
  * @param {string} filePath path to the file
+ * @param {object} [options] configuration object
+ * @param {BaseDirectory} [options.dir] base directory
  * @return {Promise<string>}
  */
-function readTextFile (filePath) {
-  return tauri.readTextFile(filePath)
+function readTextFile (filePath, options = {}) {
+  return tauri.readTextFile(filePath, options)
 }
 
 /**
  * reads a file as binary
  *
  * @param {string} filePath path to the file
+ * @param {object} [options] configuration object
+ * @param {BaseDirectory} [options.dir] base directory
  * @return {Promise<int[]>}
  */
-function readBinaryFile (filePath) {
-  return tauri.readBinaryFile(filePath)
+function readBinaryFile (filePath, options = {}) {
+  return tauri.readBinaryFile(filePath, options)
 }
 
 /**
@@ -26,10 +31,12 @@ function readBinaryFile (filePath) {
  * @param {object} file
  * @param {string} file.path path of the file
  * @param {string} file.contents contents of the file
+ * @param {object} [options] configuration object
+ * @param {BaseDirectory} [options.dir] base directory
  * @return {Promise<void>}
  */
-function writeFile (file) {
-  return tauri.writeFile(file)
+function writeFile (file, options = {}) {
+  return tauri.writeFile(file, options)
 }
 
 /**
@@ -45,6 +52,7 @@ function writeFile (file) {
  * @param {string} dir path to the directory to read
  * @param {object} [options] configuration object
  * @param {boolean} [options.recursive] whether to list dirs recursively or not
+ * @param {BaseDirectory} [options.dir] base directory
  * @return {Promise<FileEntry[]>}
  */
 function readDir (dir, options = {}) {
@@ -53,11 +61,13 @@ function 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
+ * 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
+ * @param {BaseDirectory} [options.dir] base directory
  * @return {Promise<void>}
  */
 function createDir (dir, options = {}) {
@@ -71,6 +81,7 @@ function createDir (dir, options = {}) {
  * @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
+ * @param {BaseDirectory} [options.dir] base directory
  * @return {Promise<void>}
  */
 function removeDir (dir, options = {}) {
@@ -82,20 +93,24 @@ function removeDir (dir, options = {}) {
  *
  * @param {string} source
  * @param {string} destination
+ * @param {object} [options] configuration object
+ * @param {BaseDirectory} [options.dir] base directory
  * @return {Promise<void>}
  */
-function copyFile (source, destination) {
-  return tauri.copyFile(source, destination)
+function copyFile (source, destination, options = {}) {
+  return tauri.copyFile(source, destination, options)
 }
 
 /**
  * Removes a file
  *
  * @param {string} file path to the file to remove
+ * @param {object} [options] configuration object
+ * @param {BaseDirectory} [options.dir] base directory
  * @return {Promise<void>}
  */
-function removeFile (file) {
-  return tauri.removeFile(file)
+function removeFile (file, options = {}) {
+  return tauri.removeFile(file, options)
 }
 
 /**
@@ -103,13 +118,16 @@ function removeFile (file) {
  *
  * @param {string} oldPath
  * @param {string} newPath
+ * @param {object} [options] configuration object
+ * @param {BaseDirectory} [options.dir] base directory
  * @return {Promise<void>}
  */
-function renameFile (oldPath, newPath) {
-  return tauri.renameFile(oldPath, newPath)
+function renameFile (oldPath, newPath, options = {}) {
+  return tauri.renameFile(oldPath, newPath, options)
 }
 
 export {
+  Dir,
   readTextFile,
   readBinaryFile,
   writeFile,
@@ -117,5 +135,6 @@ export {
   createDir,
   removeDir,
   copyFile,
-  removeFile
+  removeFile,
+  renameFile
 }

+ 3 - 2
cli/tauri.js/api/tauri.js

@@ -21,10 +21,11 @@ const proxy = new Proxy({
       }
     }
     initialized = true
-  }
+  },
+  Dir: require('./fs/dir').Dir
 }, {
   get(obj, prop) {
-    if (prop === '__consume') {
+    if (prop === '__consume' || prop === 'Dir') {
       return obj[prop]
     }
 

+ 3 - 0
cli/tauri.js/src/runner.ts

@@ -113,6 +113,9 @@ class Runner {
       .on(
         'change',
         debounce((changedPath: string) => {
+          if (changedPath.startsWith(path.join(tauriDir, 'target'))) {
+            return
+          }
           (this.pid ? this.__stopCargo() : Promise.resolve())
             .then(() => {
               const shouldTriggerRun = changedPath.includes('tauri.conf.json') ||

+ 61 - 12
cli/tauri.js/templates/tauri.js

@@ -72,6 +72,33 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
 
 function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
+/**
+ * @typedef {number} BaseDirectory
+ */
+/**
+ * @enum {BaseDirectory}
+ */
+var Dir = {
+  Audio: 1,
+  Cache: 2,
+  Config: 3, 
+  Data: 4,
+  LocalData: 5,
+  Desktop: 6,
+  Document: 7,
+  Download: 8,
+  Executable: 9,
+  Font: 10,
+  Home: 11,
+  Picture: 12,
+  Public: 13,
+  Runtime: 14,
+  Template: 15,
+  Video: 16,
+  Resource: 17,
+  App: 18
+}
+
 <% if (ctx.dev) { %>
 /**
  * @name return __whitelistWarning
@@ -103,6 +130,7 @@ var __reject = function () {
 }
 
 window.tauri = {
+  Dir: Dir,
   <% if (ctx.dev) { %>
     /**
      * @name invoke
@@ -212,14 +240,17 @@ window.tauri = {
      * @description Accesses a non-binary file on the user's filesystem
      * and returns the content. Permissions based on the app's PID owner
      * @param {String} path
+     * @param {Object} [options]
+     * @param {BaseDirectory} [options.dir]
      * @returns {*|Promise<any>|Promise}
      */
   <% } %>
-  readTextFile: function readTextFile(path) {
+  readTextFile: function readTextFile(path, options) {
     <% if (tauri.whitelist.readTextFile === true || tauri.whitelist.all === true) { %>
       return this.promisified({
         cmd: 'readTextFile',
-        path: path
+        path: path,
+        options: options
       });
     <% } else { %>
       <% if (ctx.dev) { %>
@@ -235,14 +266,17 @@ window.tauri = {
      * @description Accesses a binary file on the user's filesystem
      * and returns the content. Permissions based on the app's PID owner
      * @param {String} path
+     * @param {Object} [options]
+     * @param {BaseDirectory} [options.dir]
      * @returns {*|Promise<any>|Promise}
      */
   <% } %>
-  readBinaryFile: function readBinaryFile(path) {
+  readBinaryFile: function readBinaryFile(path, options) {
     <% if (tauri.whitelist.readBinaryFile === true || tauri.whitelist.all === true) { %>
       return this.promisified({
         cmd: 'readBinaryFile',
-        path: path
+        path: path,
+        options: options
       });
     <% } else { %>
       <% if (ctx.dev) { %>
@@ -260,9 +294,11 @@ window.tauri = {
      * @param {Object} cfg
      * @param {String} cfg.file
      * @param {String|Binary} cfg.contents
+     * @param {Object} [options]
+     * @param {BaseDirectory} [options.dir]
      */
   <% } %>
-  writeFile: function writeFile(cfg) {
+  writeFile: function writeFile(cfg, options) {
     <% if (tauri.whitelist.writeFile === true || tauri.whitelist.all === true) { %>
       if (_typeof(cfg) === 'object') {
         Object.freeze(cfg);
@@ -270,7 +306,8 @@ window.tauri = {
       return this.promisified({
         cmd: 'writeFile',
         file: cfg.file,
-        contents: cfg.contents
+        contents: cfg.contents,
+        options: options
       });
     <% } else { %>
       <% if (ctx.dev) { %>
@@ -288,6 +325,7 @@ window.tauri = {
      * @param {String} path
      * @param {Object} [options]
      * @param {Boolean} [options.recursive]
+     * @param {BaseDirectory} [options.dir]
      * @returns {*|Promise<any>|Promise}
      */
   <% } %>
@@ -314,6 +352,7 @@ window.tauri = {
      * @param {String} path
      * @param {Object} [options]
      * @param {Boolean} [options.recursive]
+     * @param {BaseDirectory} [options.dir]
      * @returns {*|Promise<any>|Promise}
      */
   <% } %>
@@ -340,6 +379,7 @@ window.tauri = {
      * @param {String} path
      * @param {Object} [options]
      * @param {Boolean} [options.recursive]
+     * @param {BaseDirectory} [options.dir]
      * @returns {*|Promise<any>|Promise}
      */
   <% } %>
@@ -365,15 +405,18 @@ window.tauri = {
      * Permissions based on the app's PID owner
      * @param {String} source
      * @param {String} destination
+     * @param {Object} [options]
+     * @param {BaseDirectory} [options.dir]
      * @returns {*|Promise<any>|Promise}
      */
   <% } %>
-  copyFile: function copyFile(source, destination) {
+  copyFile: function copyFile(source, destination, options) {
     <% if (tauri.whitelist.copyFile === true || tauri.whitelist.all === true) { %>
       return this.promisified({
         cmd: 'copyFile',
         source: source,
-        destination: destination
+        destination: destination,
+        options: options
       });
     <% } else { %>
       <% if (ctx.dev) { %>
@@ -389,14 +432,17 @@ window.tauri = {
      * @description Removes a file
      * Permissions based on the app's PID owner
      * @param {String} path
+     * @param {Object} [options]
+     * @param {BaseDirectory} [options.dir]
      * @returns {*|Promise<any>|Promise}
      */
   <% } %>
-  removeFile: function removeFile(path) {
+  removeFile: function removeFile(path, options) {
     <% if (tauri.whitelist.removeFile === true || tauri.whitelist.all === true) { %>
       return this.promisified({
         cmd: 'removeFile',
-        path: path
+        path: path,
+        options: options
       });
     <% } else { %>
       <% if (ctx.dev) { %>
@@ -412,15 +458,18 @@ window.tauri = {
      * @description Renames a file
      * Permissions based on the app's PID owner
      * @param {String} path
+     * @param {Object} [options]
+     * @param {BaseDirectory} [options.dir]
      * @returns {*|Promise<any>|Promise}
      */
   <% } %>
-  renameFile: function renameFile(oldPath, newPath) {
+  renameFile: function renameFile(oldPath, newPath, options) {
     <% if (tauri.whitelist.renameFile === true || tauri.whitelist.all === true) { %>
       return this.promisified({
         cmd: 'renameFile',
         old_path: oldPath,
-        new_path: newPath
+        new_path: newPath,
+        options: options
       });
     <% } else { %>
       <% if (ctx.dev) { %>

+ 1 - 0
tauri-api/Cargo.toml

@@ -11,6 +11,7 @@ exclude = ["test/fixture/**"]
 
 [dependencies]
 serde = { version = "1.0", features = ["derive"] }
+serde_repr = "0.1"
 dirs = "2.0.2"
 ignore = "0.4.11"
 zip = "0.5.4"

+ 5 - 0
tauri-api/src/lib.rs

@@ -10,6 +10,7 @@ pub mod rpc;
 pub mod version;
 pub mod tcp;
 pub mod dialog;
+pub mod path;
 
 pub use tauri_utils::*;
 
@@ -35,5 +36,9 @@ error_chain! {
             description("File function Error")
             display("File Error: {}", t)
         }
+        Path(t: String) {
+            description("Path function Error")
+            display("Path Error: {}", t)
+        }
     }
 }

+ 163 - 0
tauri-api/src/path.rs

@@ -0,0 +1,163 @@
+use std::path::PathBuf;
+use serde_repr::{Serialize_repr, Deserialize_repr};
+
+#[derive(Serialize_repr, Deserialize_repr, Clone, Debug)]
+#[repr(u16)]
+pub enum BaseDirectory {
+  Audio = 1,
+  Cache,
+  Config,
+  Data,
+  LocalData,
+  Desktop,
+  Document,
+  Download,
+  Executable,
+  Font,
+  Home,
+  Picture,
+  Public,
+  Runtime,
+  Template,
+  Video,
+  Resource,
+  App,
+}
+
+pub fn resolve_path(path: String, dir: Option<BaseDirectory>) -> crate::Result<String> {
+  if let Some(base_dir) = dir {
+    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(),
+      BaseDirectory::App => app_dir(),
+    };
+    if let Some(mut base_dir_path_value) = base_dir_path {
+      base_dir_path_value.push(path);
+      Ok(base_dir_path_value.to_string_lossy().to_string())
+    } else {
+      Err(crate::Error::from(crate::ErrorKind::Path("unable to determine base dir path".to_string())))
+    }
+  } else {
+    Ok(path)
+  }
+}
+
+// Returns the path to the user's audio directory.
+pub fn audio_dir() -> Option<PathBuf> {
+  dirs::audio_dir()
+}
+
+// Returns the path to the user's cache directory.
+pub fn cache_dir() -> Option<PathBuf> {
+  dirs::cache_dir()
+}
+
+// Returns the path to the user's config directory.
+pub fn config_dir() -> Option<PathBuf> {
+  dirs::config_dir()
+}
+
+// Returns the path to the user's data directory.
+pub fn data_dir() -> Option<PathBuf> {
+  dirs::data_dir()
+}
+
+// Returns the path to the user's local data directory.
+pub fn local_data_dir() -> Option<PathBuf> {
+  dirs::data_local_dir()
+}
+
+// Returns the path to the user's desktop directory.
+pub fn desktop_dir() -> Option<PathBuf> {
+  dirs::desktop_dir()
+}
+
+// Returns the path to the user's document directory.
+pub fn document_dir() -> Option<PathBuf> {
+  dirs::document_dir()
+}
+
+// Returns the path to the user's download directory.
+pub fn download_dir() -> Option<PathBuf> {
+  dirs::download_dir()
+}
+
+// Returns the path to the user's executable directory.
+pub fn executable_dir() -> Option<PathBuf> {
+  dirs::executable_dir()
+}
+
+// Returns the path to the user's font directory.
+pub fn font_dir() -> Option<PathBuf> {
+  dirs::font_dir()
+}
+
+// Returns the path to the user's home directory.
+pub fn home_dir() -> Option<PathBuf> {
+  dirs::home_dir()
+}
+
+// Returns the path to the user's picture directory.
+pub fn picture_dir() -> Option<PathBuf> {
+  dirs::picture_dir()
+}
+
+// Returns the path to the user's public directory.
+pub fn public_dir() -> Option<PathBuf> {
+  dirs::public_dir()
+}
+
+// Returns the path to the user's runtime directory.
+pub fn runtime_dir() -> Option<PathBuf> {
+  dirs::runtime_dir()
+}
+
+// Returns the path to the user's template directory.
+pub fn template_dir() -> Option<PathBuf> {
+  dirs::template_dir()
+}
+
+// Returns the path to the user's video dir
+pub fn video_dir() -> Option<PathBuf> {
+  dirs::video_dir()
+}
+
+pub fn resource_dir() -> Option<PathBuf> {
+  crate::platform::resource_dir().ok()
+}
+
+fn app_name() -> crate::Result<String> {
+  let exe = std::env::current_exe()?;
+  let app_name = exe
+    .file_name().expect("failed to get exe filename")
+    .to_string_lossy();
+
+  Ok(app_name.to_string())
+}
+
+pub fn app_dir() -> Option<PathBuf> {
+  dirs::config_dir()
+    .and_then(|mut dir| {
+      if let Ok(app_name) = app_name() {
+        dir.push(app_name);
+        Some(dir)
+      } else {
+        None
+      }
+    })
+}

+ 0 - 6
tauri/examples/communication/dist/communication.js

@@ -1,9 +1,3 @@
-window.onTauriInit = function () {
-  window.tauri.listen('rust-event', function (res) {
-    document.getElementById('response').innerHTML = JSON.stringify(res)
-  })
-}
-
 document.getElementById('log').addEventListener('click', function () {
   window.tauri.invoke({
     cmd: 'logOperation',

+ 9 - 1
tauri/examples/communication/dist/fs.js

@@ -1,3 +1,8 @@
+var dirSelect = document.getElementById('dir')
+function getDir () {
+  return dirSelect.value ? parseInt(dir.value) : null
+}
+
 function arrayBufferToBase64(buffer, callback) {
   var blob = new Blob([buffer], {
     type: 'application/octet-binary'
@@ -18,7 +23,8 @@ addClickEnterHandler(
   function () {
     var pathToRead = pathInput.value
     var isFile = pathToRead.match(/\S+\.\S+$/g)
-    var promise = isFile ? window.tauri.readBinaryFile(pathToRead) : window.tauri.readDir(pathToRead)
+    var opts = { dir: getDir() }
+    var promise = isFile ? window.tauri.readBinaryFile(pathToRead, opts) : window.tauri.readDir(pathToRead, opts)
     promise.then(function (response) {
       if (isFile) {
         if (pathToRead.includes('.png') || pathToRead.includes('.jpg')) {
@@ -35,6 +41,8 @@ addClickEnterHandler(
             window.tauri.writeFile({
               file: pathToRead,
               contents: fileInput.value
+            }, {
+              dir: getDir()
             }).catch(registerResponse)
           })
         }

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

@@ -8,6 +8,9 @@
     </div>
 
     <div style="margin-top: 24px">
+      <select id="dir">
+        <option value="">None</option>
+      </select>
       <input id="path-to-read" placeholder="Type the path to read...">
       <button id="read">Read</button>
     </div>
@@ -55,6 +58,21 @@
           }
         })
       }
+
+      window.onTauriInit = function () {
+        window.tauri.listen('rust-event', function (res) {
+          document.getElementById('response').innerHTML = JSON.stringify(res)
+        })
+
+        var dirSelect = document.getElementById('dir')
+        for (var key in window.tauri.Dir) {
+          var value = window.tauri.Dir[key]
+          var opt = document.createElement("option")
+          opt.value = value
+          opt.innerHTML = key
+          dirSelect.appendChild(opt)
+        }
+      }
     </script>
     <script src="communication.js"></script>
     <script src="fs.js"></script>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 61 - 12
tauri/examples/communication/dist/index.tauri.html


+ 12 - 6
tauri/src/endpoints.rs

@@ -27,27 +27,30 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
         #[cfg(any(feature = "all-api", feature = "read-text-file"))]
         ReadTextFile {
           path,
+          options,
           callback,
           error,
         } => {
-          file_system::read_text_file(webview, path, callback, error);
+          file_system::read_text_file(webview, path, options, callback, error);
         }
         #[cfg(any(feature = "all-api", feature = "read-binary-file"))]
         ReadBinaryFile {
           path,
+          options,
           callback,
           error,
         } => {
-          file_system::read_binary_file(webview, path, callback, error);
+          file_system::read_binary_file(webview, path, options, callback, error);
         }
         #[cfg(any(feature = "all-api", feature = "write-file"))]
         WriteFile {
           file,
           contents,
+          options,
           callback,
           error,
         } => {
-          file_system::write_file(webview, file, contents, callback, error);
+          file_system::write_file(webview, file, contents, options, callback, error);
         }
         #[cfg(any(feature = "all-api", feature = "read-dir"))]
         ReadDir {
@@ -62,10 +65,11 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
         CopyFile {
           source,
           destination,
+          options,
           callback,
           error,
         } => {
-          file_system::copy_file(webview, source, destination, callback, error);
+          file_system::copy_file(webview, source, destination, options, callback, error);
         }
         #[cfg(any(feature = "all-api", feature = "create-dir"))]
         CreateDir {
@@ -88,19 +92,21 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> cra
         #[cfg(any(feature = "all-api", feature = "remove-file"))]
         RemoveFile {
           path,
+          options,
           callback,
           error,
         } => {
-          file_system::remove_file(webview, path, callback, error);
+          file_system::remove_file(webview, path, options, callback, error);
         }
         #[cfg(any(feature = "all-api", feature = "rename-file"))]
         RenameFile {
           old_path,
           new_path,
+          options,
           callback,
           error,
         } => {
-          file_system::rename_file(webview, old_path, new_path, callback, error);
+          file_system::rename_file(webview, old_path, new_path, options, callback, error);
         }
         #[cfg(any(feature = "all-api", feature = "set-title"))]
         SetTitle { title } => {

+ 14 - 1
tauri/src/endpoints/cmd.rs

@@ -1,9 +1,16 @@
 use serde::Deserialize;
+use crate::api::path::BaseDirectory;
 
 #[derive(Deserialize)]
 pub struct DirOperationOptions {
   #[serde(default)]
-  pub recursive: bool
+  pub recursive: bool,
+  pub dir: Option<BaseDirectory>,
+}
+
+#[derive(Deserialize)]
+pub struct FileOperationOptions {
+  pub dir: Option<BaseDirectory>,
 }
 
 #[derive(Deserialize)]
@@ -29,12 +36,14 @@ pub enum Cmd {
   #[cfg(any(feature = "all-api", feature = "read-text-file"))]
   ReadTextFile {
     path: String,
+    options: Option<FileOperationOptions>,
     callback: String,
     error: String,
   },
   #[cfg(any(feature = "all-api", feature = "read-binary-file"))]
   ReadBinaryFile {
     path: String,
+    options: Option<FileOperationOptions>,
     callback: String,
     error: String,
   },
@@ -42,6 +51,7 @@ pub enum Cmd {
   WriteFile {
     file: String,
     contents: String,
+    options: Option<FileOperationOptions>,
     callback: String,
     error: String,
   },
@@ -56,6 +66,7 @@ pub enum Cmd {
   CopyFile {
     source: String,
     destination: String,
+    options: Option<FileOperationOptions>,
     callback: String,
     error: String,
   },
@@ -76,6 +87,7 @@ pub enum Cmd {
   #[cfg(any(feature = "all-api", feature = "remove-file"))]
   RemoveFile {
     path: String,
+    options: Option<FileOperationOptions>,
     callback: String,
     error: String,
   },
@@ -83,6 +95,7 @@ pub enum Cmd {
   RenameFile {
     old_path: String,
     new_path: String,
+    options: Option<FileOperationOptions>,
     callback: String,
     error: String,
   },

+ 44 - 22
tauri/src/endpoints/file_system.rs

@@ -2,12 +2,13 @@ use web_view::WebView;
 
 use tauri_api::dir;
 use tauri_api::file;
+use tauri_api::path::resolve_path;
 
 use std::fs;
 use std::fs::File;
 use std::io::Write;
 
-use super::cmd::{DirOperationOptions};
+use super::cmd::{DirOperationOptions, FileOperationOptions};
 
 pub fn read_dir<T: 'static>(
   webview: &mut WebView<'_, T>,
@@ -19,17 +20,17 @@ pub fn read_dir<T: 'static>(
   crate::execute_promise(
     webview,
     move || {
-      let recursive = if let Some(options_value) = options {
-        options_value.recursive
+      let (recursive, dir) = if let Some(options_value) = options {
+        (options_value.recursive, options_value.dir)
       } else {
-        false
+        (false, None)
       };
       if recursive {
-        dir::walk_dir(path)
+        dir::walk_dir(resolve_path(path, dir)?)
           .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)
+        dir::list_dir_contents(resolve_path(path, dir)?)
           .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
           .and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
       }
@@ -43,13 +44,20 @@ pub fn copy_file<T: 'static>(
   webview: &mut WebView<'_, T>,
   source: String,
   destination: String,
+  options: Option<FileOperationOptions>,
   callback: String,
   error: String,
 ) {
   crate::execute_promise(
     webview,
     move || {
-      fs::copy(source, destination)
+      let (src, dest) = match options.and_then(|o| o.dir) {
+        Some(dir) => {
+          (resolve_path(source, Some(dir.clone()))?, resolve_path(destination, Some(dir))?)
+        }
+        None => (source, destination)
+      };
+      fs::copy(src, dest)
          .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
          .map(|_| "".to_string())
     },
@@ -68,15 +76,16 @@ pub fn create_dir<T: 'static>(
   crate::execute_promise(
     webview,
     move || {
-      let recursive = if let Some(options_value) = options {
-        options_value.recursive
+      let (recursive, dir) = if let Some(options_value) = options {
+        (options_value.recursive, options_value.dir)
       } else {
-        false
+        (false, None)
       };
+      let resolved_path = resolve_path(path, dir)?;
       let response = if recursive {
-        fs::create_dir_all(path)
+        fs::create_dir_all(resolved_path)
       } else {
-        fs::create_dir(path)
+        fs::create_dir(resolved_path)
       };
 
       response
@@ -98,15 +107,16 @@ pub fn remove_dir<T: 'static>(
   crate::execute_promise(
     webview,
     move || {
-      let recursive = if let Some(options_value) = options {
-        options_value.recursive
+      let (recursive, dir) = if let Some(options_value) = options {
+        (options_value.recursive, options_value.dir)
       } else {
-        false
+        (false, None)
       };
+      let resolved_path = resolve_path(path, dir)?;
       let response = if recursive {
-        fs::remove_dir_all(path)
+        fs::remove_dir_all(resolved_path)
       } else {
-        fs::remove_dir(path)
+        fs::remove_dir(resolved_path)
       };
 
       response
@@ -121,13 +131,15 @@ pub fn remove_dir<T: 'static>(
 pub fn remove_file<T: 'static>(
   webview: &mut WebView<'_, T>,
   path: String,
+  options: Option<FileOperationOptions>,
   callback: String,
   error: String,
 ) {
   crate::execute_promise(
     webview,
     move || {
-      fs::remove_file(path)
+      let resolved_path = resolve_path(path, options.and_then(|o| o.dir))?;
+      fs::remove_file(resolved_path)
         .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
         .map(|_| "".to_string())
     },
@@ -140,13 +152,20 @@ pub fn rename_file<T: 'static>(
   webview: &mut WebView<'_, T>,
   old_path: String,
   new_path: String,
+  options: Option<FileOperationOptions>,
   callback: String,
   error: String,
 ) {
   crate::execute_promise(
     webview,
     move || {
-      fs::rename(old_path, new_path)
+      let (old, new) = match options.and_then(|o| o.dir) {
+        Some(dir) => {
+          (resolve_path(old_path, Some(dir.clone()))?, resolve_path(new_path, Some(dir))?)
+        }
+        None => (old_path, new_path)
+      };
+      fs::rename(old, new)
         .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
         .map(|_| "".to_string())
     },
@@ -159,13 +178,14 @@ pub fn write_file<T: 'static>(
   webview: &mut WebView<'_, T>,
   file: String,
   contents: String,
+  options: Option<FileOperationOptions>,
   callback: String,
   error: String,
 ) {
   crate::execute_promise(
     webview,
     move || {
-      File::create(file)
+      File::create(resolve_path(file, options.and_then(|o| o.dir))?)
         .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
         .and_then(|mut f| {
           f.write_all(contents.as_bytes())
@@ -181,13 +201,14 @@ pub fn write_file<T: 'static>(
 pub fn read_text_file<T: 'static>(
   webview: &mut WebView<'_, T>,
   path: String,
+  options: Option<FileOperationOptions>,
   callback: String,
   error: String,
 ) {
   crate::execute_promise(
     webview,
     move || {
-      file::read_string(path)
+      file::read_string(resolve_path(path, options.and_then(|o| o.dir))?)
         .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
         .and_then(|f| {
           serde_json::to_string(&f)
@@ -202,13 +223,14 @@ pub fn read_text_file<T: 'static>(
 pub fn read_binary_file<T: 'static>(
   webview: &mut WebView<'_, T>,
   path: String,
+  options: Option<FileOperationOptions>,
   callback: String,
   error: String,
 ) {
   crate::execute_promise(
     webview,
     move || {
-      file::read_binary(path)
+      file::read_binary(resolve_path(path, options.and_then(|o| o.dir))?)
         .map_err(|e| crate::ErrorKind::FileSystem(e.to_string()).into())
         .and_then(|f| {
           serde_json::to_string(&f)

+ 4 - 4
tauri/src/lib.rs

@@ -42,14 +42,14 @@ 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)
     }
+    FileSystem(t: String) {
+      description("FileSystem Error")
+      display("FileSystem Error: '{}'", t)
+    }
   }
 }
 

Vissa filer visades inte eftersom för många filer har ändrats