├── .envrc ├── .gitignore ├── flake.nix ├── flake.lock ├── Cargo.toml ├── LICENSE ├── src ├── lib.rs ├── main.rs └── nmuidi.rs ├── .github └── workflows │ └── build.yml ├── README.md └── Cargo.lock /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #VS Code 2 | .vscode/ 3 | 4 | # Generated by Cargo 5 | # will have compiled files and executables 6 | debug/ 7 | target/ 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | # MSVC Windows builds of rustc generate these, which store debugging information 13 | *.pdb 14 | 15 | # Tmp files and directories used for testing 16 | tmp/ 17 | 18 | # Direnv metadata 19 | .direnv 20 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 3 | 4 | outputs = { self, nixpkgs }: 5 | let 6 | supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; 7 | forAllSystems = nixpkgs.lib.genAttrs supportedSystems; 8 | pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system}); 9 | in 10 | { 11 | devShells = forAllSystems (system: { 12 | default = pkgs.${system}.mkShell { 13 | buildInputs = with pkgs.${system}; [ cargo rustc rust-analyzer ]; 14 | }; 15 | }); 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1753750875, 6 | "narHash": "sha256-J1P0aQymehe8AHsID9wwoMjbaYrIB2eH5HftoXhF9xk=", 7 | "owner": "NixOS", 8 | "repo": "nixpkgs", 9 | "rev": "871381d997e4a063f25a3994ce8a9ac595246610", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "NixOS", 14 | "ref": "nixpkgs-unstable", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs" 22 | } 23 | } 24 | }, 25 | "root": "root", 26 | "version": 7 27 | } 28 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nmuidi" 3 | version = "0.1.5" 4 | edition = "2021" 5 | description = "Parallelizes deleting directories which can significantly speed up deleting large deeply nested directories with a large number of files on Windows" 6 | readme = "README.md" 7 | homepage = "https://github.com/Dillonb/nmuidi" 8 | documentation = "https://docs.rs/nmuidi" 9 | repository = "https://github.com/Dillonb/nmuidi" 10 | license = "MIT" 11 | keywords = ["windows", "delete", "parallel"] 12 | categories = ["command-line-utilities", "filesystem"] 13 | 14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15 | 16 | [dependencies] 17 | jwalk = "0.8.1" 18 | num_cpus = "1.16.0" 19 | itertools = "0.11.0" 20 | log = "0.4.20" 21 | pretty_env_logger = "0.5.0" 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Al Dente Software 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Deletes stuff, hopefully quickly 2 | //! 3 | //! ## Installation 4 | //! - [Download for Windows](https://nightly.link/Dillonb/nmuidi/workflows/build/main/nmuidi-windows.zip) 5 | //! - Or just use `cargo` 6 | //! 7 | //! ## Benchmarks 8 | //! - [This video](https://www.youtube.com/watch?v=G8BdXgBdaOA) benchmarks several popular suggestions for deleting files quickly on Windows and compares them to nmuidi. 9 | //! 10 | //! ## How to use 11 | //! ### As a command-line tool 12 | //! - You can download using the link above. The easiest way to use it in Windows is to make a folder (something like `C:\bin`) 13 | //! - Add that folder to your path 14 | //! - Then add `nmuidi.exe` file you downloaded to that folder and restart any terminals you have open 15 | //! 16 | //! Then you can run `nmuidi /path/to/some/dir` and you should see some output like the following: 17 | //! ```PS 18 | //! → ~\repos\nmuidi [main ≡ +0 ~1 -0 !]› nmuidi test 19 | //! Cleaning test 20 | //! ``` 21 | //! 22 | //! ### As a library 23 | //! ``` 24 | //! use nmuidi::prelude::*; 25 | //! 26 | //! let dir = "path/to/something"; 27 | //! Cleaner::new(dir).clean(); 28 | //! ``` 29 | //! 30 | 31 | /// All nmuidi `Cleaner` functionality 32 | pub mod prelude { 33 | pub use crate::nmuidi::Cleaner; 34 | } 35 | 36 | /// Module containing basic libray functionality 37 | #[doc(hidden)] 38 | pub mod nmuidi; 39 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | RUST_LOG: debug 8 | 9 | jobs: 10 | format: 11 | runs-on: windows-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: cargo-fmt 16 | run: cargo fmt --verbose 17 | 18 | clippy: 19 | runs-on: windows-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v3 23 | - name: cargo-clippy 24 | run: cargo clippy -- -Dwarnings 25 | - name: cargo-clippy-pedantic 26 | continue-on-error: true 27 | run: cargo clippy -- -W clippy::pedantic 28 | 29 | test: 30 | runs-on: windows-latest 31 | 32 | steps: 33 | - uses: actions/checkout@v3 34 | - name: cargo-test 35 | run: cargo test 36 | 37 | build-windows: 38 | runs-on: windows-latest 39 | needs: [format, clippy, test] 40 | 41 | steps: 42 | - uses: actions/checkout@v1 43 | - uses: dtolnay/rust-toolchain@stable 44 | 45 | - name: Build 46 | run: cargo build --all --release 47 | 48 | - name: Upload to artifacts 49 | uses: actions/upload-artifact@master 50 | with: 51 | name: nmuidi-windows 52 | path: target/release/nmuidi.exe 53 | 54 | - name: Create release 55 | uses: softprops/action-gh-release@v2 56 | if: startsWith(github.ref, 'refs/tags/') 57 | with: 58 | files: | 59 | target/release/nmuidi.exe 60 | LICENSE 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nmuidi 2 | 3 | Deletes stuff, hopefully quickly 4 | 5 | To download, check out the [releases page](https://github.com/Dillonb/nmuidi/releases) or download [the latest development build](https://nightly.link/Dillonb/nmuidi/workflows/build/main/nmuidi-windows.zip). 6 | 7 | [This video](https://www.youtube.com/watch?v=G8BdXgBdaOA) benchmarks several popular suggestions for deleting files quickly on Windows and compares them to nmuidi. 8 | 9 | ## How to use 10 | 11 | ### As a command-line tool 12 | 13 | You can download using the link above. The easiest way to use it in Windows is to make a folder (something like `C:\bin`) and add that folder to your path. Then add `nmuidi.exe` file you downloaded to that folder and restart any terminals you have open. 14 | 15 | Then you can run `nmuidi /path/to/some/dir` and you should see some output like the following: 16 | 17 | ```PS 18 | → ~\repos\nmuidi [main ≡ +0 ~1 -0 !]› nmuidi test 19 | Cleaning test 20 | ``` 21 | 22 | To change the log level, set the `RUST_LOG` environment variable: 23 | 24 | PowerShell: `$env:RUST_LOG = 'trace'` 25 | 26 | CMD: `set RUST_LOG=trace` 27 | 28 | The output will then look something like: 29 | 30 | ```PS 31 | → ~\repos\nmuidi [main ≡ +0 ~1 -0 !]› nmuidi test1 test2 32 | Cleaning test1 33 | Cleaning test2 34 | Total time: 10.00s 35 | Directory timings: 36 | dir test1 took 5.00s 37 | dir test2 took 5.00s 38 | Done. 39 | ``` 40 | 41 | ### As a package 42 | 43 | 1. `cargo add nmuidi` 44 | 2. add `use nmuidi::nmuidi::Cleaner;` 45 | 3. Create a cleaner and clean `Cleaner::new("some/path").clean();` 46 | 47 | 48 | ## Why the dumb name 49 | 50 | 1. It's an inside joke 51 | 2. Having a complicated name makes it harder to accidentally nuke a folder. This program does NOT ask you to confirm, if you tell it to delete something it will start deleting things immediately. 52 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use log::{debug, trace}; 2 | #[doc(inline)] 3 | use nmuidi::prelude::*; 4 | use std::{env, time::Instant}; 5 | 6 | fn main() { 7 | pretty_env_logger::init(); 8 | 9 | let mut directory_timings = Vec::new(); 10 | let start_time = Instant::now(); 11 | for dir in env::args().skip(1) { 12 | println!("Cleaning {dir}"); 13 | let start = Instant::now(); 14 | 15 | Cleaner::new(&dir).clean(); 16 | directory_timings.push((dir, start.elapsed())); 17 | } 18 | 19 | let elapsed_time = start_time.elapsed(); 20 | debug!("Total time: {:.2?}", elapsed_time); 21 | debug!("Directory timings:"); 22 | for (dir, time_spent) in directory_timings { 23 | debug!(" dir {dir} took {:.2?}", time_spent); 24 | } 25 | trace!("Done."); 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::*; 31 | use jwalk::WalkDir; 32 | use std::fs; 33 | 34 | #[test] 35 | fn test_nested() { 36 | fs::create_dir_all("tmp/nested/dir1").unwrap(); 37 | fs::write("tmp/nested/dir1/file1.txt", "File 1 content").unwrap(); 38 | 39 | fs::create_dir_all("tmp/nested/dir1/dir2").unwrap(); 40 | fs::write("tmp/nested/dir1/dir2/file2.txt", "File 2 content").unwrap(); 41 | 42 | fs::create_dir_all("tmp/nested/dir1/dir2/dir3").unwrap(); 43 | fs::write("tmp/nested/dir1/dir2/dir3/file3.txt", "File 3 content").unwrap(); 44 | 45 | Cleaner::new("tmp/nested").clean(); 46 | 47 | let num_files = WalkDir::new("tmp/nested") 48 | .skip_hidden(false) 49 | .into_iter() 50 | .collect::>() 51 | .len(); 52 | assert_eq!(num_files, 1); 53 | } 54 | 55 | #[test] 56 | fn test_dirs() { 57 | fs::create_dir_all("tmp/dirs/dir1").unwrap(); 58 | fs::create_dir_all("tmp/dirs/dir1a").unwrap(); 59 | fs::create_dir_all("tmp/dirs/dir1/dir2").unwrap(); 60 | fs::create_dir_all("tmp/dirs/dir1/dir2a").unwrap(); 61 | fs::create_dir_all("tmp/dirs/dir1/dir2/dir3").unwrap(); 62 | fs::create_dir_all("tmp/dirs/dir1/dir2/dir3a").unwrap(); 63 | 64 | Cleaner::new("tmp/dirs").clean(); 65 | 66 | let num_files = WalkDir::new("tmp/dirs") 67 | .skip_hidden(false) 68 | .into_iter() 69 | .collect::>() 70 | .len(); 71 | assert_eq!(num_files, 1); 72 | } 73 | 74 | #[test] 75 | fn test_files() { 76 | fs::create_dir_all("tmp/files").unwrap(); 77 | fs::write("tmp/files/file1.txt", "File 1 content").unwrap(); 78 | fs::write("tmp/files/file2.txt", "File 2 content").unwrap(); 79 | fs::write("tmp/files/file3.txt", "File 3 content").unwrap(); 80 | fs::write("tmp/files/file4.txt", "File 4 content").unwrap(); 81 | fs::write("tmp/files/file5.txt", "File 5 content").unwrap(); 82 | fs::write("tmp/files/file6.txt", "File 6 content").unwrap(); 83 | 84 | Cleaner::new("tmp/files").clean(); 85 | 86 | let num_files = WalkDir::new("tmp/files") 87 | .skip_hidden(false) 88 | .into_iter() 89 | .collect::>() 90 | .len(); 91 | assert_eq!(num_files, 1); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/nmuidi.rs: -------------------------------------------------------------------------------- 1 | use std::{fs, path::PathBuf}; 2 | 3 | use itertools::Itertools; 4 | use jwalk::{ 5 | rayon::prelude::{IntoParallelRefIterator, ParallelBridge, ParallelIterator}, 6 | WalkDir, 7 | }; 8 | use log::error; 9 | 10 | /// `Cleaner` is a lazily executed framework for nmuidi. 11 | /// # Examples 12 | /// ``` 13 | /// use nmuidi::prelude::*; 14 | /// let cleaner = Cleaner::new("some/path").clean(); 15 | /// ``` 16 | pub struct Cleaner { 17 | path: PathBuf, 18 | dirs: Vec<(PathBuf, usize)>, // (path, depth) 19 | threads: usize, 20 | } 21 | 22 | impl Cleaner { 23 | /// Form a new `Cleaner` stuct, does not execute anything until `.clean()` is called 24 | pub fn new(path: T) -> Self 25 | where 26 | std::path::PathBuf: std::convert::From, 27 | { 28 | Self { 29 | path: path.into(), 30 | dirs: Vec::new(), 31 | threads: num_cpus::get() * 100, 32 | } 33 | } 34 | 35 | /// Perform the deletion of the selected directory 36 | pub fn clean(&mut self) { 37 | self.remove_files(); 38 | self.remove_dirs(); 39 | } 40 | 41 | fn remove_dirs(&mut self) { 42 | let dirs_by_depth = self.dirs.iter().group_by(|x| x.1); 43 | for (_, level) in &dirs_by_depth { 44 | level 45 | .collect::>() 46 | .par_iter() 47 | .map(|(dir, _group)| dir) 48 | .for_each(|dir| { 49 | if let Err(e) = fs::remove_dir_all(dir.as_path()) { 50 | println!("Error removing directory {}: {e}", dir.display()); 51 | } 52 | }); 53 | } 54 | } 55 | 56 | fn is_reparse_point(meta: &std::fs::Metadata) -> bool { 57 | use std::os::windows::fs::MetadataExt; 58 | const FILE_ATTRIBUTE_REPARSE_POINT: u32 = 0x0400; 59 | meta.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT != 0 60 | } 61 | 62 | fn remove_files(&mut self) { 63 | let mut dirs: Vec<(std::path::PathBuf, usize)> = WalkDir::new(&self.path) 64 | .skip_hidden(false) 65 | .parallelism(jwalk::Parallelism::RayonNewPool(self.threads)) 66 | .into_iter() 67 | .par_bridge() 68 | .flat_map(|entry| { 69 | match entry { 70 | Ok(entry) => { 71 | let path = entry.path(); 72 | 73 | // Get metdata while avoiding walking into junctions 74 | let metadata = match fs::symlink_metadata(&path) { 75 | Ok(m) => m, 76 | Err(e) => { 77 | error!("Failed to get metadata for {}: {e}", path.display()); 78 | return None; 79 | } 80 | }; 81 | 82 | let f_type = metadata.file_type(); 83 | 84 | // if this is a directory *and* reparse point then it's a junction, 85 | // delete it like a directory but skip walking inside 86 | if f_type.is_dir() && Cleaner::is_reparse_point(&metadata) { 87 | fs::remove_dir(&path).unwrap_or_else(|e| { 88 | error!("Failed to remove reparse point {}: {e}", path.display()); 89 | }); 90 | return None; 91 | } 92 | 93 | let mut perm = metadata.permissions(); 94 | if perm.readonly() { 95 | #[allow(clippy::permissions_set_readonly_false)] 96 | perm.set_readonly(false); 97 | fs::set_permissions(&path, perm).unwrap_or_else(|e| { 98 | error!("Error making {} write-accessible: {e}", path.display()); 99 | }); 100 | } 101 | if f_type.is_file() { 102 | fs::remove_file(&path).unwrap_or_else(|e| { 103 | error!("Failed to remove file {}: {e}", path.display()); 104 | }); 105 | } else if f_type.is_dir() { 106 | return Some((path, entry.depth)); 107 | } 108 | } 109 | Err(error) => error!("Error processing directory entry: {error}"), 110 | } 111 | None 112 | }) 113 | .collect(); 114 | dirs.sort_by(|a, b| b.1.cmp(&a.1)); // Note reverse sort 115 | self.dirs = dirs; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "autocfg" 16 | version = "1.1.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 19 | 20 | [[package]] 21 | name = "bitflags" 22 | version = "2.4.2" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" 25 | 26 | [[package]] 27 | name = "cfg-if" 28 | version = "1.0.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 31 | 32 | [[package]] 33 | name = "crossbeam" 34 | version = "0.8.2" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" 37 | dependencies = [ 38 | "cfg-if", 39 | "crossbeam-channel", 40 | "crossbeam-deque", 41 | "crossbeam-epoch", 42 | "crossbeam-queue", 43 | "crossbeam-utils", 44 | ] 45 | 46 | [[package]] 47 | name = "crossbeam-channel" 48 | version = "0.5.8" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" 51 | dependencies = [ 52 | "cfg-if", 53 | "crossbeam-utils", 54 | ] 55 | 56 | [[package]] 57 | name = "crossbeam-deque" 58 | version = "0.8.3" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" 61 | dependencies = [ 62 | "cfg-if", 63 | "crossbeam-epoch", 64 | "crossbeam-utils", 65 | ] 66 | 67 | [[package]] 68 | name = "crossbeam-epoch" 69 | version = "0.9.15" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" 72 | dependencies = [ 73 | "autocfg", 74 | "cfg-if", 75 | "crossbeam-utils", 76 | "memoffset", 77 | "scopeguard", 78 | ] 79 | 80 | [[package]] 81 | name = "crossbeam-queue" 82 | version = "0.3.8" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" 85 | dependencies = [ 86 | "cfg-if", 87 | "crossbeam-utils", 88 | ] 89 | 90 | [[package]] 91 | name = "crossbeam-utils" 92 | version = "0.8.16" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" 95 | dependencies = [ 96 | "cfg-if", 97 | ] 98 | 99 | [[package]] 100 | name = "either" 101 | version = "1.9.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" 104 | 105 | [[package]] 106 | name = "env_logger" 107 | version = "0.10.2" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" 110 | dependencies = [ 111 | "humantime", 112 | "is-terminal", 113 | "log", 114 | "regex", 115 | "termcolor", 116 | ] 117 | 118 | [[package]] 119 | name = "errno" 120 | version = "0.3.8" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 123 | dependencies = [ 124 | "libc", 125 | "windows-sys", 126 | ] 127 | 128 | [[package]] 129 | name = "hermit-abi" 130 | version = "0.3.2" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 133 | 134 | [[package]] 135 | name = "humantime" 136 | version = "2.1.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 139 | 140 | [[package]] 141 | name = "is-terminal" 142 | version = "0.4.10" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" 145 | dependencies = [ 146 | "hermit-abi", 147 | "rustix", 148 | "windows-sys", 149 | ] 150 | 151 | [[package]] 152 | name = "itertools" 153 | version = "0.11.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" 156 | dependencies = [ 157 | "either", 158 | ] 159 | 160 | [[package]] 161 | name = "jwalk" 162 | version = "0.8.1" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56" 165 | dependencies = [ 166 | "crossbeam", 167 | "rayon", 168 | ] 169 | 170 | [[package]] 171 | name = "libc" 172 | version = "0.2.152" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" 175 | 176 | [[package]] 177 | name = "linux-raw-sys" 178 | version = "0.4.13" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 181 | 182 | [[package]] 183 | name = "log" 184 | version = "0.4.20" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 187 | 188 | [[package]] 189 | name = "memchr" 190 | version = "2.7.1" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" 193 | 194 | [[package]] 195 | name = "memoffset" 196 | version = "0.9.0" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 199 | dependencies = [ 200 | "autocfg", 201 | ] 202 | 203 | [[package]] 204 | name = "nmuidi" 205 | version = "0.1.5" 206 | dependencies = [ 207 | "itertools", 208 | "jwalk", 209 | "log", 210 | "num_cpus", 211 | "pretty_env_logger", 212 | ] 213 | 214 | [[package]] 215 | name = "num_cpus" 216 | version = "1.16.0" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 219 | dependencies = [ 220 | "hermit-abi", 221 | "libc", 222 | ] 223 | 224 | [[package]] 225 | name = "pretty_env_logger" 226 | version = "0.5.0" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" 229 | dependencies = [ 230 | "env_logger", 231 | "log", 232 | ] 233 | 234 | [[package]] 235 | name = "rayon" 236 | version = "1.7.0" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" 239 | dependencies = [ 240 | "either", 241 | "rayon-core", 242 | ] 243 | 244 | [[package]] 245 | name = "rayon-core" 246 | version = "1.11.0" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" 249 | dependencies = [ 250 | "crossbeam-channel", 251 | "crossbeam-deque", 252 | "crossbeam-utils", 253 | "num_cpus", 254 | ] 255 | 256 | [[package]] 257 | name = "regex" 258 | version = "1.10.3" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" 261 | dependencies = [ 262 | "aho-corasick", 263 | "memchr", 264 | "regex-automata", 265 | "regex-syntax", 266 | ] 267 | 268 | [[package]] 269 | name = "regex-automata" 270 | version = "0.4.4" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" 273 | dependencies = [ 274 | "aho-corasick", 275 | "memchr", 276 | "regex-syntax", 277 | ] 278 | 279 | [[package]] 280 | name = "regex-syntax" 281 | version = "0.8.2" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" 284 | 285 | [[package]] 286 | name = "rustix" 287 | version = "0.38.30" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" 290 | dependencies = [ 291 | "bitflags", 292 | "errno", 293 | "libc", 294 | "linux-raw-sys", 295 | "windows-sys", 296 | ] 297 | 298 | [[package]] 299 | name = "scopeguard" 300 | version = "1.2.0" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 303 | 304 | [[package]] 305 | name = "termcolor" 306 | version = "1.4.1" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 309 | dependencies = [ 310 | "winapi-util", 311 | ] 312 | 313 | [[package]] 314 | name = "winapi" 315 | version = "0.3.9" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 318 | dependencies = [ 319 | "winapi-i686-pc-windows-gnu", 320 | "winapi-x86_64-pc-windows-gnu", 321 | ] 322 | 323 | [[package]] 324 | name = "winapi-i686-pc-windows-gnu" 325 | version = "0.4.0" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 328 | 329 | [[package]] 330 | name = "winapi-util" 331 | version = "0.1.6" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" 334 | dependencies = [ 335 | "winapi", 336 | ] 337 | 338 | [[package]] 339 | name = "winapi-x86_64-pc-windows-gnu" 340 | version = "0.4.0" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 343 | 344 | [[package]] 345 | name = "windows-sys" 346 | version = "0.52.0" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 349 | dependencies = [ 350 | "windows-targets", 351 | ] 352 | 353 | [[package]] 354 | name = "windows-targets" 355 | version = "0.52.0" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 358 | dependencies = [ 359 | "windows_aarch64_gnullvm", 360 | "windows_aarch64_msvc", 361 | "windows_i686_gnu", 362 | "windows_i686_msvc", 363 | "windows_x86_64_gnu", 364 | "windows_x86_64_gnullvm", 365 | "windows_x86_64_msvc", 366 | ] 367 | 368 | [[package]] 369 | name = "windows_aarch64_gnullvm" 370 | version = "0.52.0" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 373 | 374 | [[package]] 375 | name = "windows_aarch64_msvc" 376 | version = "0.52.0" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 379 | 380 | [[package]] 381 | name = "windows_i686_gnu" 382 | version = "0.52.0" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 385 | 386 | [[package]] 387 | name = "windows_i686_msvc" 388 | version = "0.52.0" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 391 | 392 | [[package]] 393 | name = "windows_x86_64_gnu" 394 | version = "0.52.0" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 397 | 398 | [[package]] 399 | name = "windows_x86_64_gnullvm" 400 | version = "0.52.0" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 403 | 404 | [[package]] 405 | name = "windows_x86_64_msvc" 406 | version = "0.52.0" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 409 | --------------------------------------------------------------------------------