diff --git a/Cargo.toml b/Cargo.toml index dd0d29f..890a5c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "spielrs_diff" description= "It is a library which compare two tree direcories asynchronously" -version = "0.1.0" -documentation = "https://docs.rs/crate/spielrs_diff/0.1.0" +version = "0.2.0" +documentation = "https://docs.rs/crate/spielrs_diff/0.2.0" authors = ["Francisco Jesus Navarro Cortes "] readme = "README.md" repository = "https://github.com/spielrs/spielrs-diff" diff --git a/mocks/dir_five/hello.py b/mocks/dir_five/hello.py new file mode 100644 index 0000000..5f3948a --- /dev/null +++ b/mocks/dir_five/hello.py @@ -0,0 +1 @@ +print("This line will be printed.") \ No newline at end of file diff --git a/mocks/dir_five/hello.txt b/mocks/dir_five/hello.txt new file mode 100644 index 0000000..70c379b --- /dev/null +++ b/mocks/dir_five/hello.txt @@ -0,0 +1 @@ +Hello world \ No newline at end of file diff --git a/mocks/dir_five/vlang/hello.v b/mocks/dir_five/vlang/hello.v new file mode 100644 index 0000000..a24a3bb --- /dev/null +++ b/mocks/dir_five/vlang/hello.v @@ -0,0 +1,3 @@ +fn main() { + println("hello world") +} diff --git a/mocks/dir_five/vlang/purpose/feature.txt b/mocks/dir_five/vlang/purpose/feature.txt new file mode 100644 index 0000000..86c4c4c --- /dev/null +++ b/mocks/dir_five/vlang/purpose/feature.txt @@ -0,0 +1 @@ +new feature \ No newline at end of file diff --git a/src/diff.rs b/src/diff.rs new file mode 100644 index 0000000..2f0e8b6 --- /dev/null +++ b/src/diff.rs @@ -0,0 +1,10 @@ +pub struct Diff { + /// directory to compare + pub dir: String, + /// comparation directory + pub dir_comp: String, + /// exclude directories or files from the comparation + pub excluding: Option>, + /// exclude recursively or only the from the root path + pub recursive_excluding: bool, +} diff --git a/src/lib.rs b/src/lib.rs index 621cd81..8a19f76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,14 +12,16 @@ //! //! ## Example //! ```rust -//! use spielrs_diff::dir_diff; +//! use spielrs_diff::{dir_diff, diff::Diff}; //! //! #[tokio::test] //! async fn should_return_true_if_both_dir_tree_are_different() { -//! let diff = dir_diff( -//! "./mocks/dir_one".to_string(), -//! "./mocks/dir_three".to_string(), -//! ) +//! let diff = dir_diff(Diff { +//! dir: "./mocks/dir_one".to_string(), +//! dir_comp: "./mocks/dir_five".to_string(), +//! excluding: Some(vec!["purpose".to_string()]), +//! recursive_excluding: true, +//! }) //! .await; //! //! assert_eq!(diff, true); @@ -27,31 +29,47 @@ //! ``` //! //! +pub mod diff; pub mod tree; +use diff::Diff; use tree::{Tree, TreeBuilder}; /// Compare two tree directories and return true if both are different +/// You can exclude directories or files in the comparation only from the root path +/// of both or recursively /// /// # Example /// ```rust -/// use spielrs_diff::dir_diff; +/// use spielrs_diff::{dir_diff, diff::Diff}; /// /// #[tokio::test] /// async fn should_return_true_if_both_dir_tree_are_different() { -/// let diff = dir_diff( -/// "./mocks/dir_one".to_string(), -/// "./mocks/dir_three".to_string(), -/// ) +/// let diff = dir_diff(Diff { +/// dir: "./mocks/dir_one".to_string(), +/// dir_comp: "./mocks/dir_five".to_string(), +/// excluding: Some(vec!["purpose".to_string()]), +/// recursive_excluding: true, +/// }) /// .await; /// /// assert_eq!(diff, true); /// } /// ``` /// -pub async fn dir_diff(dir_path: String, dir_path_comp: String) -> bool { - let tree_one: Vec = Tree::build_tree(dir_path).await; - let tree_two: Vec = Tree::build_tree(dir_path_comp).await; +pub async fn dir_diff(diff_options: Diff) -> bool { + let tree_one: Vec = Tree::build_tree( + diff_options.dir, + diff_options.excluding.clone(), + diff_options.recursive_excluding, + ) + .await; + let tree_two: Vec = Tree::build_tree( + diff_options.dir_comp, + diff_options.excluding, + diff_options.recursive_excluding, + ) + .await; if Tree::tree_diff(tree_one.clone(), tree_two.clone()) { return true; } @@ -63,26 +81,60 @@ pub async fn dir_diff(dir_path: String, dir_path_comp: String) -> bool { #[tokio::test] async fn should_return_true_if_both_dir_tree_are_different() { - let diff = dir_diff( - "./mocks/dir_one".to_string(), - "./mocks/dir_three".to_string(), - ) + let diff = dir_diff(Diff { + dir: "./mocks/dir_one".to_string(), + dir_comp: "./mocks/dir_three".to_string(), + excluding: None, + recursive_excluding: false, + }) .await; assert_eq!(diff, true); } #[tokio::test] async fn should_return_false_if_both_dir_tree_are_equal() { - let diff = dir_diff("./mocks/dir_one".to_string(), "./mocks/dir_two".to_string()).await; + let diff = dir_diff(Diff { + dir: "./mocks/dir_one".to_string(), + dir_comp: "./mocks/dir_two".to_string(), + excluding: None, + recursive_excluding: false, + }) + .await; assert_eq!(diff, false); } #[tokio::test] async fn should_return_true_if_both_dir_tree_have_different_content() { - let diff = dir_diff( - "./mocks/dir_one".to_string(), - "./mocks/dir_four".to_string(), - ) + let diff = dir_diff(Diff { + dir: "./mocks/dir_one".to_string(), + dir_comp: "./mocks/dir_four".to_string(), + excluding: None, + recursive_excluding: false, + }) + .await; + assert_eq!(diff, true); +} + +#[tokio::test] +async fn should_return_false_if_both_dir_have_different_subdir_excluded_recursively() { + let diff = dir_diff(Diff { + dir: "./mocks/dir_one".to_string(), + dir_comp: "./mocks/dir_five".to_string(), + excluding: Some(vec!["purpose".to_string()]), + recursive_excluding: true, + }) + .await; + assert_eq!(diff, false); +} + +#[tokio::test] +async fn should_return_true_if_both_dir_have_different_subdir_excluded_not_recursively() { + let diff = dir_diff(Diff { + dir: "./mocks/dir_one".to_string(), + dir_comp: "./mocks/dir_five".to_string(), + excluding: Some(vec!["purpose".to_string()]), + recursive_excluding: false, + }) .await; assert_eq!(diff, true); } diff --git a/src/tree.rs b/src/tree.rs index 1c5b00c..4b0b92d 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -8,7 +8,11 @@ use tokio::stream; #[async_trait] pub trait TreeBuilder { /// Build a vector of `Tree` - async fn build_tree(dir_path: String) -> Vec; + async fn build_tree( + dir_path: String, + excluding: Option>, + recursive_excluding: bool, + ) -> Vec; /// Compare two tree directories and return true if are different fn tree_diff(dir_tree: Vec, dir_tree_comp: Vec) -> bool; /// Get the content by string of all the files in one tree directory @@ -87,6 +91,8 @@ impl From for TreeComp { #[async_trait] impl TreeBuilder for Tree { /// Build a vector of `Tree` + /// You can exclude directories or files only from the root path + /// of the directory or recursively in the building /// /// # Example /// @@ -95,25 +101,53 @@ impl TreeBuilder for Tree { /// /// #[tokio::main] /// async fn main() { - /// let dir_one = Tree::build_tree("./mocks/dir_one".to_string()).await; + /// let dir_one = Tree::build_tree( + /// "./mocks/dir_one".to_string(), + /// Some(vec!["purpose".to_string()]), + /// true + /// ).await; /// /// println!("{:#?}", dir_one); /// } /// ``` - async fn build_tree(dir_path: String) -> Vec { + async fn build_tree( + dir_path: String, + excluding: Option>, + recursive_excluding: bool, + ) -> Vec { let mut entries = fs::read_dir(dir_path).await.unwrap(); let mut tree: Vec = vec![]; + let mut exclude: Vec = vec![]; + if let Some(mut item) = excluding { + exclude.append(&mut item); + } + while let Some(entry) = entries.next_entry().await.unwrap() { - let path: String = entry.path().into_os_string().into_string().unwrap(); - tree.push(Tree { - name: entry.file_name().into_string().unwrap(), - path: path.clone(), - subdir: if entry.path().is_dir() { - Some(Tree::build_tree(path).await) - } else { - None - }, - }); + let file_name = entry.file_name().into_string().unwrap(); + + if !exclude.clone().into_iter().any(|item| item == file_name) { + let path: String = entry.path().into_os_string().into_string().unwrap(); + tree.push(Tree { + name: entry.file_name().into_string().unwrap(), + path: path.clone(), + subdir: if entry.path().is_dir() { + Some( + Tree::build_tree( + path, + if recursive_excluding { + Some(exclude.clone()) + } else { + None + }, + recursive_excluding, + ) + .await, + ) + } else { + None + }, + }); + } } tree @@ -128,8 +162,8 @@ impl TreeBuilder for Tree { /// /// #[tokio::test] /// async fn should_return_false_equal_dir_tree() { - /// let dir_one = Tree::build_tree("./mocks/dir_one".to_string()).await; - /// let dir_two = Tree::build_tree("./mocks/dir_two".to_string()).await; + /// let dir_one = Tree::build_tree("./mocks/dir_one".to_string(), None, false).await; + /// let dir_two = Tree::build_tree("./mocks/dir_two".to_string(), None, false).await; /// /// let diff = Tree::tree_diff(dir_one, dir_two); /// @@ -153,7 +187,7 @@ impl TreeBuilder for Tree { /// /// #[tokio::test] /// async fn should_return_all_file_content() { - /// let dir_one = Tree::build_tree("./mocks/dir_one".to_string()).await; + /// let dir_one = Tree::build_tree("./mocks/dir_one".to_string(), None, false).await; /// let content = Tree::get_content_files(dir_one).await; /// /// assert_eq!( @@ -188,10 +222,10 @@ impl TreeBuilder for Tree { /// /// #[tokio::test] /// async fn should_return_true_if_both_dir_content_are_equal() { - /// let dir_one = Tree::build_tree("./mocks/dir_one".to_string()).await; + /// let dir_one = Tree::build_tree("./mocks/dir_one".to_string(), None, false).await; /// let content_one = Tree::get_content_files(dir_one).await; /// - /// let dir_two = Tree::build_tree("./mocks/dir_two".to_string()).await; + /// let dir_two = Tree::build_tree("./mocks/dir_two".to_string(), None, false).await; /// let content_two = Tree::get_content_files(dir_two).await; /// /// assert_eq!(Tree::compare_dir_content(content_one, content_two), true); @@ -209,8 +243,8 @@ impl TreeBuilder for Tree { #[tokio::test] async fn should_return_false_equal_dir_tree() { - let dir_one = Tree::build_tree("./mocks/dir_one".to_string()).await; - let dir_two = Tree::build_tree("./mocks/dir_two".to_string()).await; + let dir_one = Tree::build_tree("./mocks/dir_one".to_string(), None, false).await; + let dir_two = Tree::build_tree("./mocks/dir_two".to_string(), None, false).await; let diff = Tree::tree_diff(dir_one, dir_two); @@ -219,8 +253,8 @@ async fn should_return_false_equal_dir_tree() { #[tokio::test] async fn should_return_true_different_dir_tree() { - let dir_one = Tree::build_tree("./mocks/dir_one".to_string()).await; - let dir_three = Tree::build_tree("./mocks/dir_three".to_string()).await; + let dir_one = Tree::build_tree("./mocks/dir_one".to_string(), None, false).await; + let dir_three = Tree::build_tree("./mocks/dir_three".to_string(), None, false).await; let diff = Tree::tree_diff(dir_one, dir_three); @@ -229,7 +263,7 @@ async fn should_return_true_different_dir_tree() { #[tokio::test] async fn should_return_all_file_content() { - let dir_one = Tree::build_tree("./mocks/dir_one".to_string()).await; + let dir_one = Tree::build_tree("./mocks/dir_one".to_string(), None, false).await; let content = Tree::get_content_files(dir_one).await; assert_eq!( @@ -245,10 +279,10 @@ async fn should_return_all_file_content() { #[tokio::test] async fn should_return_true_if_both_dir_content_are_equal() { - let dir_one = Tree::build_tree("./mocks/dir_one".to_string()).await; + let dir_one = Tree::build_tree("./mocks/dir_one".to_string(), None, false).await; let content_one = Tree::get_content_files(dir_one).await; - let dir_two = Tree::build_tree("./mocks/dir_two".to_string()).await; + let dir_two = Tree::build_tree("./mocks/dir_two".to_string(), None, false).await; let content_two = Tree::get_content_files(dir_two).await; assert_eq!(Tree::compare_dir_content(content_one, content_two), true); @@ -256,11 +290,53 @@ async fn should_return_true_if_both_dir_content_are_equal() { #[tokio::test] async fn should_return_false_if_both_dir_content_are_differents() { - let dir_one = Tree::build_tree("./mocks/dir_one".to_string()).await; + let dir_one = Tree::build_tree("./mocks/dir_one".to_string(), None, false).await; let content_one = Tree::get_content_files(dir_one).await; - let dir_four = Tree::build_tree("./mocks/dir_four".to_string()).await; + let dir_four = Tree::build_tree("./mocks/dir_four".to_string(), None, false).await; let content_four = Tree::get_content_files(dir_four).await; assert_eq!(Tree::compare_dir_content(content_one, content_four), false); } + +#[tokio::test] +async fn should_return_true_if_both_dir_tree_have_different_subdir_excluded_recursively() { + let dir_one = Tree::build_tree( + "./mocks/dir_one".to_string(), + Some(vec!["purpose".to_string()]), + true, + ) + .await; + let content_one = Tree::get_content_files(dir_one).await; + + let dir_five = Tree::build_tree( + "./mocks/dir_five".to_string(), + Some(vec!["purpose".to_string()]), + true, + ) + .await; + let content_five = Tree::get_content_files(dir_five).await; + + assert_eq!(Tree::compare_dir_content(content_one, content_five), true); +} + +#[tokio::test] +async fn should_return_false_if_both_dir_tree_have_different_subdir_excluded_not_recursively() { + let dir_one = Tree::build_tree( + "./mocks/dir_one".to_string(), + Some(vec!["purpose".to_string()]), + false, + ) + .await; + let content_one = Tree::get_content_files(dir_one).await; + + let dir_five = Tree::build_tree( + "./mocks/dir_five".to_string(), + Some(vec!["purpose".to_string()]), + false, + ) + .await; + let content_five = Tree::get_content_files(dir_five).await; + + assert_eq!(Tree::compare_dir_content(content_one, content_five), false); +}