瀏覽代碼

refactor(api) rewrite readDir API (#722)

Lucas Fernandes Nogueira 5 年之前
父節點
當前提交
dd1bffe91e

+ 5 - 0
.changes/fs-read-dir-api.md

@@ -0,0 +1,5 @@
+---
+"tauri-api": minor
+---
+
+readDir API refactor. Now returns `path`, `name` and `children`. 

+ 5 - 3
cli/tauri.js/api-src/types/fs.ts

@@ -35,7 +35,9 @@ export interface FsBinaryFileOption {
 
 export interface FileEntry {
   path: string
-  // TODO why not camelCase ?
-  is_dir: boolean
-  name: string
+  // name of the directory/file
+  // can be null if the path terminates with `..`
+  name?: string
+  // children of this entry if it's a directory; null otherwise
+  children?: FileEntry[]
 }

+ 0 - 1
tauri-api/Cargo.toml

@@ -18,7 +18,6 @@ serde = { version = "1.0", features = [ "derive" ] }
 serde_json = "1.0"
 serde_repr = "0.1"
 dirs = "3.0.0"
-ignore = "0.4.16"
 zip = "0.5.6"
 semver = "0.10"
 tempfile = "3"

+ 83 - 93
tauri-api/src/dir.rs

@@ -1,62 +1,48 @@
-mod utils;
-
-use ignore::Walk;
 use serde::Serialize;
-use tempfile::{self, tempdir};
-
-use utils::get_dir_name_from_path;
-
 use std::fs::{self, metadata};
+use std::path::{Path, PathBuf};
+use tempfile::{self, tempdir};
 
 #[derive(Debug, Serialize)]
 pub struct DiskEntry {
-  pub path: String,
-  pub is_dir: bool,
-  pub name: String,
+  pub path: PathBuf,
+  pub name: Option<String>,
+  #[serde(skip_serializing_if = "Option::is_none")]
+  pub children: Option<Vec<DiskEntry>>,
 }
 
-fn is_dir(file_name: String) -> crate::Result<bool> {
-  match metadata(file_name) {
-    Ok(md) => Result::Ok(md.is_dir()),
-    Err(err) => Result::Err(err.into()),
-  }
+pub fn is_dir<P: AsRef<Path>>(path: P) -> crate::Result<bool> {
+  metadata(path).map(|md| md.is_dir()).map_err(|e| e.into())
 }
 
-pub fn walk_dir(path_copy: String) -> crate::Result<Vec<DiskEntry>> {
-  println!("Trying to walk: {}", path_copy.as_str());
+pub fn read_dir<P: AsRef<Path>>(path: P, recursive: bool) -> crate::Result<Vec<DiskEntry>> {
   let mut files_and_dirs: Vec<DiskEntry> = vec![];
-  for result in Walk::new(path_copy) {
-    if let Ok(entry) = result {
-      let display_value = entry.path().display();
-      let _dir_name = display_value.to_string();
-
-      if let Ok(flag) = is_dir(display_value.to_string()) {
-        files_and_dirs.push(DiskEntry {
-          path: display_value.to_string(),
-          is_dir: flag,
-          name: display_value.to_string(),
-        });
-      }
+  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 {
+            read_dir(&path_as_string, true)?
+          } else {
+            vec![]
+          })
+        } else {
+          None
+        },
+        name: path
+          .file_name()
+          .map(|name| name.to_string_lossy())
+          .map(|name| name.to_string()),
+      });
     }
   }
   Result::Ok(files_and_dirs)
 }
 
-pub fn list_dir_contents(dir_path: String) -> crate::Result<Vec<DiskEntry>> {
-  let paths = fs::read_dir(dir_path)?;
-  let mut dirs: Vec<DiskEntry> = vec![];
-  for path in paths {
-    let dir_path = path.expect("dirpath error").path();
-    let _dir_name = dir_path.display();
-    dirs.push(DiskEntry {
-      path: format!("{}", _dir_name),
-      is_dir: true,
-      name: get_dir_name_from_path(_dir_name.to_string()),
-    });
-  }
-  Ok(dirs)
-}
-
 pub fn with_temp_dir<F: FnOnce(&tempfile::TempDir) -> ()>(callback: F) -> crate::Result<()> {
   let dir = tempdir()?;
   callback(&dir);
@@ -68,30 +54,41 @@ pub fn with_temp_dir<F: FnOnce(&tempfile::TempDir) -> ()>(callback: F) -> crate:
 mod test {
   use super::*;
   use quickcheck_macros::quickcheck;
+  use std::ffi::OsStr;
+  use std::path::PathBuf;
   use totems::assert_ok;
 
   // check is dir function by passing in arbitrary strings
   #[quickcheck]
   fn qc_is_dir(f: String) -> bool {
-    // is the string runs through is_dir and comes out as an OK result then it must be a DIR.
+    // if the string runs through is_dir and comes out as an OK result then it must be a DIR.
     if let Ok(_) = is_dir(f.clone()) {
-      std::path::PathBuf::from(f).exists()
+      PathBuf::from(f).is_dir()
     } else {
       true
     }
   }
 
+  fn name_from_path(path: PathBuf) -> Option<String> {
+    path
+      .file_name()
+      .map(|name| name.to_string_lossy())
+      .map(|name| name.to_string())
+  }
+
   #[test]
-  // check the walk_dir function
-  fn check_walk_dir() {
+  // check the read_dir function with recursive = true
+  fn check_read_dir_recursively() {
     // define a relative directory string test/
-    let dir = String::from("test/");
+    let dir = PathBuf::from("test/");
     // add the files to this directory
-    let file_one = format!("{}test.txt", &dir).to_string();
-    let file_two = format!("{}test_binary", &dir).to_string();
+    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 = walk_dir(dir.clone());
+    let res = read_dir(dir.clone(), true);
 
     // assert that the result is Ok()
     assert_ok!(&res);
@@ -99,52 +96,45 @@ mod test {
     // 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(), 3);
+      assert_eq!(vec.len(), 2);
 
       // get the first DiskEntry
       let first = &vec[0];
       // get the second DiskEntry
       let second = &vec[1];
-      // get the third DiskEntry
-      let third = &vec[2];
-
-      // check the fields for the first DiskEntry
-      assert_eq!(first.path, dir);
-      assert_eq!(first.is_dir, true);
-      assert_eq!(first.name, dir);
 
-      if second.path.contains(".txt") {
-        // check the fields for the second DiskEntry
-        assert_eq!(second.path, file_one);
-        assert_eq!(second.is_dir, false);
-        assert_eq!(second.name, file_one);
+      if first.path.extension() == Some(OsStr::new("txt")) {
+        // check the fields for the first DiskEntry
+        assert_eq!(first.path, file_one);
+        assert_eq!(first.children.is_some(), false);
+        assert_eq!(first.name, name_from_path(file_one));
 
         // check the fields for the third DiskEntry
-        assert_eq!(third.path, file_two);
-        assert_eq!(third.is_dir, false);
-        assert_eq!(third.name, file_two);
+        assert_eq!(second.path, file_two);
+        assert_eq!(second.children.is_some(), false);
+        assert_eq!(second.name, name_from_path(file_two));
       } else {
         // check the fields for the second DiskEntry
-        assert_eq!(second.path, file_two);
-        assert_eq!(second.is_dir, false);
-        assert_eq!(second.name, file_two);
+        assert_eq!(first.path, file_two);
+        assert_eq!(first.children.is_some(), false);
+        assert_eq!(first.name, name_from_path(file_two));
 
         // check the fields for the third DiskEntry
-        assert_eq!(third.path, file_one);
-        assert_eq!(third.is_dir, false);
-        assert_eq!(third.name, file_one);
+        assert_eq!(second.path, file_one);
+        assert_eq!(second.children.is_some(), false);
+        assert_eq!(second.name, name_from_path(file_one));
       }
     }
   }
 
   #[test]
-  // check the list_dir_contents function
-  fn check_list_dir_contents() {
-    // define a relative directory string test/
-    let dir = String::from("test/");
+  // check the read_dir function with recursive = false
+  fn check_read_dir() {
+    // define a relative directory test/
+    let dir = PathBuf::from("test/");
 
-    // call list_dir_contents on the dir string
-    let res = list_dir_contents(dir);
+    // call list_dir_contents on the dir
+    let res = read_dir(dir, false);
 
     // assert that the result is Ok()
     assert_ok!(&res);
@@ -158,26 +148,26 @@ mod test {
       let first = &vec[0];
       let second = &vec[1];
 
-      if first.path.contains(".txt") {
+      if first.path.extension() == Some(OsStr::new("txt")) {
         // check the fields for the first DiskEntry
-        assert_eq!(first.path, "test/test.txt".to_string());
-        assert_eq!(first.is_dir, true);
-        assert_eq!(first.name, "test.txt".to_string());
+        assert_eq!(first.path, PathBuf::from("test/test.txt"));
+        assert_eq!(first.children.is_some(), false);
+        assert_eq!(first.name, Some("test.txt".to_string()));
 
         // check the fields for the second DiskEntry
-        assert_eq!(second.path, "test/test_binary".to_string());
-        assert_eq!(second.is_dir, true);
-        assert_eq!(second.name, "test_binary".to_string());
+        assert_eq!(second.path, PathBuf::from("test/test_binary"));
+        assert_eq!(second.children.is_some(), false);
+        assert_eq!(second.name, Some("test_binary".to_string()));
       } else {
         // check the fields for the first DiskEntry
-        assert_eq!(second.path, "test/test.txt".to_string());
-        assert_eq!(second.is_dir, true);
-        assert_eq!(second.name, "test.txt".to_string());
+        assert_eq!(second.path, PathBuf::from("test/test.txt"));
+        assert_eq!(second.children.is_some(), false);
+        assert_eq!(second.name, Some("test.txt".to_string()));
 
         // check the fields for the second DiskEntry
-        assert_eq!(first.path, "test/test_binary".to_string());
-        assert_eq!(first.is_dir, true);
-        assert_eq!(first.name, "test_binary".to_string());
+        assert_eq!(first.path, PathBuf::from("test/test_binary"));
+        assert_eq!(first.children.is_some(), false);
+        assert_eq!(first.name, Some("test_binary".to_string()));
       }
     }
   }

+ 0 - 4
tauri-api/src/dir/utils.rs

@@ -1,4 +0,0 @@
-pub fn get_dir_name_from_path(path: String) -> String {
-  let path_collect: Vec<&str> = path.split('/').collect();
-  path_collect[path_collect.len() - 1].to_string()
-}

+ 9 - 14
tauri/src/endpoints/file_system.rs

@@ -26,13 +26,8 @@ pub fn read_dir<T: 'static>(
       } else {
         (false, None)
       };
-      if recursive {
-        dir::walk_dir(resolve_path(path, dir)?)
-          .and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
-      } else {
-        dir::list_dir_contents(resolve_path(path, dir)?)
-          .and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
-      }
+      dir::read_dir(resolve_path(path, dir)?, recursive)
+        .and_then(|f| serde_json::to_string(&f).map_err(|err| err.into()))
     },
     callback,
     error,
@@ -216,14 +211,14 @@ pub fn write_binary_file<T: 'static>(
       base64::decode(contents)
         .map_err(|e| e.into())
         .and_then(|c| {
-        File::create(resolve_path(file, options.and_then(|o| o.dir))?)
-          .map_err(|e| e.into())
-          .and_then(|mut f| {
-          f.write_all(&c)
-            .map_err(|err| err.into())
-            .map(|_| "".to_string())
+          File::create(resolve_path(file, options.and_then(|o| o.dir))?)
+            .map_err(|e| e.into())
+            .and_then(|mut f| {
+              f.write_all(&c)
+                .map_err(|err| err.into())
+                .map(|_| "".to_string())
+            })
         })
-      })
     },
     callback,
     error,