mirror of
https://github.com/sreedevk/deduplicator.git
synced 2026-08-26 18:15:33 +00:00
Compare commits
15 Commits
main
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9effdc9681 | ||
|
|
936c631623 | ||
|
|
0d62361132 | ||
|
|
b103d7d634 | ||
|
|
c42538a8c6 | ||
|
|
05437e0256 | ||
|
|
5942cf0b6c | ||
|
|
79c0c2be3d | ||
|
|
49b46f37f3 | ||
|
|
a37d59308f | ||
|
|
8a5b540e40 | ||
|
|
5ce0a2774a | ||
|
|
8d32ac5151 | ||
|
|
0c70e27835 | ||
|
|
53282c50df |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/target
|
||||
/Cargo.lock
|
||||
/.bacon-locations
|
||||
/result-bin
|
||||
|
||||
512
Cargo.lock
generated
512
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
@@ -11,6 +11,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
@@ -121,6 +127,21 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc"
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||
|
||||
[[package]]
|
||||
name = "castaway"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.104"
|
||||
@@ -203,6 +224,20 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compact_str"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32"
|
||||
dependencies = [
|
||||
"castaway",
|
||||
"cfg-if",
|
||||
"itoa",
|
||||
"rustversion",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.8"
|
||||
@@ -212,7 +247,7 @@ dependencies = [
|
||||
"encode_unicode 0.3.6",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.13",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
@@ -247,6 +282,31 @@ version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"crossterm_winapi",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"rustix 0.38.44",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.3.0"
|
||||
@@ -268,6 +328,41 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.5.3"
|
||||
@@ -275,7 +370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.5",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
@@ -295,14 +390,18 @@ dependencies = [
|
||||
"globwalk",
|
||||
"gxhash",
|
||||
"indicatif",
|
||||
"itertools",
|
||||
"itertools 0.10.5",
|
||||
"memmap2",
|
||||
"pathdiff",
|
||||
"prettytable-rs",
|
||||
"ratatui",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"threadpool",
|
||||
"unicode-segmentation",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -344,6 +443,40 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@@ -352,7 +485,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -394,6 +539,17 @@ version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -406,6 +562,12 @@ version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.60"
|
||||
@@ -429,6 +591,12 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.22"
|
||||
@@ -456,7 +624,26 @@ dependencies = [
|
||||
"number_prefix",
|
||||
"portable-atomic",
|
||||
"rayon",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
||||
|
||||
[[package]]
|
||||
name = "instability"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"indoc",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -474,7 +661,7 @@ version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"hermit-abi 0.3.9",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@@ -494,6 +681,15 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
@@ -502,10 +698,11 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.69"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -517,9 +714,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.174"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
@@ -531,6 +728,18 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
@@ -547,6 +756,15 @@ version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@@ -562,6 +780,18 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -571,6 +801,16 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
||||
dependencies = [
|
||||
"hermit-abi 0.5.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "number_prefix"
|
||||
version = "0.4.0"
|
||||
@@ -583,6 +823,16 @@ version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.10"
|
||||
@@ -596,6 +846,12 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pathdiff"
|
||||
version = "0.2.1"
|
||||
@@ -619,27 +875,54 @@ dependencies = [
|
||||
"is-terminal",
|
||||
"lazy_static",
|
||||
"term",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "ratatui"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cassowary",
|
||||
"compact_str",
|
||||
"crossterm",
|
||||
"indoc",
|
||||
"instability",
|
||||
"itertools 0.13.0",
|
||||
"lru",
|
||||
"paste",
|
||||
"strum",
|
||||
"unicode-segmentation",
|
||||
"unicode-truncate",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
@@ -675,7 +958,7 @@ version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -697,6 +980,32 @@ version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.9.4",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.17"
|
||||
@@ -755,12 +1064,48 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
@@ -768,16 +1113,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.68"
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix 1.0.7",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "0.7.0"
|
||||
@@ -809,6 +1189,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "threadpool"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
|
||||
dependencies = [
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
@@ -821,18 +1210,46 @@ version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-truncate"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
|
||||
dependencies = [
|
||||
"itertools 0.13.0",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.1.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
@@ -850,24 +1267,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.92"
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.92"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
@@ -876,9 +1303,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.92"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -886,9 +1313,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.92"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -899,9 +1326,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.92"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
@@ -961,6 +1391,15 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
@@ -1081,3 +1520,12 @@ name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
@@ -27,10 +27,14 @@ itertools = "0.10.5"
|
||||
memmap2 = "0.5.8"
|
||||
pathdiff = "0.2.1"
|
||||
prettytable-rs = "0.10.0"
|
||||
ratatui = "0.29.0"
|
||||
rayon = "1.6.1"
|
||||
serde = { version = "1.0.192", features = ["derive"] }
|
||||
serde_json = "1.0.108"
|
||||
tempfile = "3.20.0"
|
||||
threadpool = "1.8.1"
|
||||
unicode-segmentation = "1.10.0"
|
||||
uuid = { version = "1.17.0", features = ["v4"] }
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
|
||||
@@ -132,3 +132,4 @@ Memory: 31731MiB (~32GiB)
|
||||
- Tree format output for duplicate file listing
|
||||
- GUI
|
||||
- Packages for different operating system repositories (currently only installable via cargo)
|
||||
- TUI: Improve Key Handling
|
||||
|
||||
72
src/app.rs
Normal file
72
src/app.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use threadpool::ThreadPool;
|
||||
|
||||
use crate::params::Params;
|
||||
use crate::server::{Message, Server};
|
||||
use crate::tui::Tui;
|
||||
|
||||
pub struct App {
|
||||
tpool: ThreadPool,
|
||||
server: Arc<Server>,
|
||||
app_opts: Arc<Params>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new(app_opts: Arc<Params>) -> Self {
|
||||
Self {
|
||||
tpool: ThreadPool::new(8),
|
||||
server: Arc::new(Server::new().expect("server init failed")),
|
||||
app_opts,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&self) -> Result<()> {
|
||||
let (server_tx, server_rx) = channel::<Message>();
|
||||
let (app_tx, app_rx) = channel::<Message>();
|
||||
|
||||
let server_ptr = self.server.clone();
|
||||
let tui_server_ptr = self.server.clone();
|
||||
let mut ui = Tui::new(app_tx.clone(), tui_server_ptr);
|
||||
let root_dir = self
|
||||
.app_opts
|
||||
.get_directory()?
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.map_err(|_| anyhow!("path to str conv failed"))?
|
||||
.into_boxed_str();
|
||||
|
||||
self.tpool.execute(move || {
|
||||
server_ptr.start(server_rx).expect("server init failed");
|
||||
});
|
||||
|
||||
self.tpool.execute(move || {
|
||||
ui.start().expect("ui init failed");
|
||||
});
|
||||
|
||||
self.tpool.execute(move || loop {
|
||||
match app_rx.try_recv() {
|
||||
Ok(Message::Exit) => {
|
||||
server_tx
|
||||
.send(Message::Exit)
|
||||
.expect("message passing to app from ui failed.");
|
||||
break;
|
||||
}
|
||||
Ok(Message::AddScanDirectory(dir)) => {
|
||||
server_tx
|
||||
.send(Message::AddScanDirectory(dir))
|
||||
.expect("message passing to server failed.");
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
});
|
||||
|
||||
app_tx.send(Message::AddScanDirectory(root_dir))?;
|
||||
|
||||
self.tpool.join();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
0
src/cli/mod.rs
Normal file
0
src/cli/mod.rs
Normal file
37
src/main.rs
37
src/main.rs
@@ -1,3 +1,4 @@
|
||||
mod app;
|
||||
mod fileinfo;
|
||||
mod formatter;
|
||||
mod interactive;
|
||||
@@ -5,27 +6,35 @@ mod params;
|
||||
mod processor;
|
||||
mod scanner;
|
||||
|
||||
/* version 2.0 modules*/
|
||||
mod cli;
|
||||
mod server;
|
||||
mod tui;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use self::app::App;
|
||||
use clap::Parser;
|
||||
use formatter::Formatter;
|
||||
use params::Params;
|
||||
use processor::Processor;
|
||||
use scanner::Scanner;
|
||||
use std::sync::Arc;
|
||||
// use formatter::Formatter;
|
||||
// use processor::Processor;
|
||||
// use scanner::Scanner;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let app_args = Params::parse();
|
||||
let scan_results = Scanner::build(&app_args)?.scan()?;
|
||||
let processor = Processor::new(scan_results);
|
||||
let results = processor.sizewise()?.hashwise()?;
|
||||
// let scan_results = Scanner::build(&app_args)?.scan()?;
|
||||
// let processor = Processor::new(scan_results);
|
||||
// let results = processor.sizewise()?.hashwise()?;
|
||||
|
||||
match app_args.interactive {
|
||||
false => {
|
||||
Formatter::print(results.files, &app_args)?;
|
||||
}
|
||||
true => {
|
||||
interactive::init(results.files, &app_args)?;
|
||||
}
|
||||
}
|
||||
// match app_args.interactive {
|
||||
// false => Formatter::print(results.files, &app_args)?,
|
||||
// true => interactive::init(results.files, &app_args)?,
|
||||
// }
|
||||
|
||||
App::new(Arc::new(app_args))
|
||||
.start()
|
||||
.expect("app init failed.");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
44
src/server/file.rs
Normal file
44
src/server/file.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use anyhow::Result;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
const PARTIAL_SIZE: u64 = 4096;
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FileMeta {
|
||||
pub id: Uuid,
|
||||
pub path: Box<str>,
|
||||
pub size: u64,
|
||||
pub modtime: i64,
|
||||
pub partial: Arc<[u8]>,
|
||||
pub full_hash: Arc<[u8]>,
|
||||
}
|
||||
|
||||
impl FileMeta {
|
||||
fn create_partial(path: &str) -> Result<Arc<[u8]>> {
|
||||
let mut partial_take = File::open(path)?.take(PARTIAL_SIZE);
|
||||
let mut partial_buffer = Vec::with_capacity(PARTIAL_SIZE as usize);
|
||||
partial_take.read_to_end(&mut partial_buffer)?;
|
||||
|
||||
Ok(Arc::from(partial_buffer))
|
||||
}
|
||||
|
||||
pub fn new(path: Box<str>) -> Result<Self> {
|
||||
let pstr = path.to_string();
|
||||
let filemeta = std::fs::metadata(&pstr)?;
|
||||
let partial = Self::create_partial(&pstr)?;
|
||||
|
||||
Ok(Self {
|
||||
id: Uuid::new_v4(),
|
||||
size: filemeta.size(),
|
||||
modtime: filemeta.mtime(),
|
||||
full_hash: Arc::new([]),
|
||||
path,
|
||||
partial,
|
||||
})
|
||||
}
|
||||
}
|
||||
79
src/server/mod.rs
Normal file
79
src/server/mod.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
pub mod file;
|
||||
mod processor;
|
||||
mod scanner;
|
||||
mod store;
|
||||
|
||||
use anyhow::Result;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use threadpool::ThreadPool;
|
||||
|
||||
use self::processor::Processor;
|
||||
use self::scanner::Scanner;
|
||||
use self::store::Store;
|
||||
|
||||
pub type FileQueue = Arc<Mutex<Vec<Box<str>>>>;
|
||||
|
||||
pub enum Message {
|
||||
AddScanDirectory(Box<str>),
|
||||
Exit,
|
||||
None,
|
||||
}
|
||||
|
||||
pub struct Server {
|
||||
pub fq: FileQueue,
|
||||
pub dupstore: Arc<Store>,
|
||||
pub tpool: ThreadPool,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
fq: Arc::new(Mutex::new(vec![])),
|
||||
dupstore: Arc::new(Store::new()),
|
||||
tpool: ThreadPool::new(4),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn start(&self, rx: mpsc::Receiver<Message>) -> Result<()> {
|
||||
let processor_fq = self.fq.clone();
|
||||
let processor_store = self.dupstore.clone();
|
||||
let (processor_tx, processor_rx) = channel::<Message>();
|
||||
|
||||
self.tpool.execute(move || {
|
||||
Processor::new(processor_fq, processor_store, processor_rx)
|
||||
.process()
|
||||
.expect("processer execution interrupted.");
|
||||
});
|
||||
|
||||
let scanner_fq = self.fq.clone();
|
||||
let (scanner_tx, scanner_rx) = channel::<Message>();
|
||||
self.tpool.execute(move || {
|
||||
Scanner::new(scanner_fq, scanner_rx)
|
||||
.index()
|
||||
.expect("scanner indexing interrupted.");
|
||||
});
|
||||
|
||||
self.tpool.execute(move || loop {
|
||||
match rx.recv() {
|
||||
Ok(Message::AddScanDirectory(path)) => {
|
||||
scanner_tx
|
||||
.send(Message::AddScanDirectory(path))
|
||||
.expect("scanner tx message passing failed.");
|
||||
}
|
||||
Ok(Message::None) => {}
|
||||
Ok(Message::Exit) | Err(_) => {
|
||||
scanner_tx.send(Message::Exit).unwrap_or_default();
|
||||
processor_tx.send(Message::Exit).unwrap_or_default();
|
||||
break;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
self.tpool.join();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
146
src/server/processor.rs
Normal file
146
src/server/processor.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
use anyhow::Result;
|
||||
use std::sync::mpsc::{Receiver, TryRecvError};
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::file::FileMeta;
|
||||
use super::store::{Index, Store};
|
||||
use super::{FileQueue, Message};
|
||||
|
||||
pub struct Processor {
|
||||
files: FileQueue,
|
||||
duplicates: Arc<Store>,
|
||||
msg_rx: Receiver<Message>,
|
||||
}
|
||||
|
||||
impl Processor {
|
||||
pub fn new(files: FileQueue, duplicates: Arc<Store>, msg_rx: Receiver<Message>) -> Self {
|
||||
Self {
|
||||
files,
|
||||
duplicates,
|
||||
msg_rx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process(&self) -> Result<()> {
|
||||
loop {
|
||||
match self.msg_rx.try_recv() {
|
||||
Ok(Message::Exit) => break,
|
||||
Err(TryRecvError::Empty) => {},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let next_file = {
|
||||
let mut cfiles = self.files.lock().unwrap();
|
||||
cfiles.pop()
|
||||
};
|
||||
|
||||
match next_file {
|
||||
None => continue,
|
||||
Some(file_res) => match FileMeta::new(file_res) {
|
||||
Err(_) => continue,
|
||||
Ok(fm) => {
|
||||
let fm_arc = Arc::new(fm);
|
||||
self.duplicates
|
||||
.add(Index::Size(fm_arc.size), fm_arc.clone());
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use anyhow::Result;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use tempfile::TempDir;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
#[test]
|
||||
fn processor_differentiates_files_with_different_sizes() -> Result<()> {
|
||||
let file_queue = Arc::new(Mutex::new(vec![]));
|
||||
let (tx, rx) = mpsc::channel::<Message>();
|
||||
let root = TempDir::new()?;
|
||||
let store = Arc::new(Store::new());
|
||||
|
||||
let fq_c = file_queue.clone();
|
||||
let store_c = store.clone();
|
||||
let proc_thread = thread::spawn(move || {
|
||||
let processor = Processor::new(fq_c, store_c, rx);
|
||||
processor.process().expect("processor failed");
|
||||
});
|
||||
|
||||
let files =
|
||||
[("hello.txt", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat"),
|
||||
("hello_dup.txt", "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum")];
|
||||
|
||||
for (filename, content) in files.into_iter() {
|
||||
let fpath = root.path().join(filename);
|
||||
let mut tf = File::create(fpath.clone())?;
|
||||
tf.write_all(content.as_bytes())?;
|
||||
|
||||
let mut mfq = file_queue.lock().unwrap();
|
||||
mfq.push(fpath.into_os_string().into_string().unwrap().into_boxed_str());
|
||||
}
|
||||
|
||||
for _ in 0..10 {
|
||||
if store.entries().len() < 2 {
|
||||
thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
|
||||
tx.send(Message::Exit).expect("unable to send msg to processor");
|
||||
proc_thread.join().expect("failed to join on thread!");
|
||||
|
||||
assert!(store.entries().len() == 2);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn processor_groups_files_with_same_size() -> Result<()> {
|
||||
let file_queue = Arc::new(Mutex::new(vec![]));
|
||||
let (tx, rx) = mpsc::channel::<Message>();
|
||||
let root = TempDir::new()?;
|
||||
let store = Arc::new(Store::new());
|
||||
|
||||
let fq_c = file_queue.clone();
|
||||
let store_c = store.clone();
|
||||
let proc_thread = thread::spawn(move || {
|
||||
let processor = Processor::new(fq_c, store_c, rx);
|
||||
processor.process().expect("processor failed");
|
||||
});
|
||||
|
||||
let files =
|
||||
[("hello.txt", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum"),
|
||||
("hello_dup.txt", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum")];
|
||||
|
||||
for (filename, content) in files.into_iter() {
|
||||
let fpath = root.path().join(filename);
|
||||
let mut tf = File::create(fpath.clone())?;
|
||||
tf.write_all(content.as_bytes())?;
|
||||
|
||||
let mut mfq = file_queue.lock().unwrap();
|
||||
mfq.push(fpath.into_os_string().into_string().unwrap().into_boxed_str());
|
||||
}
|
||||
|
||||
for _ in 0..10 {
|
||||
if store.entries().is_empty() {
|
||||
thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
|
||||
tx.send(Message::Exit).expect("unable to send msg to processor");
|
||||
proc_thread.join().expect("failed to join on thread!");
|
||||
|
||||
assert!(store.entries().len() == 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
128
src/server/scanner.rs
Normal file
128
src/server/scanner.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use super::{FileQueue, Message};
|
||||
use anyhow::Result;
|
||||
use std::fs;
|
||||
use std::sync::mpsc::{self, Receiver};
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Scanner {
|
||||
files: FileQueue,
|
||||
proc_queue: FileQueue,
|
||||
msg_rx: Receiver<Message>,
|
||||
}
|
||||
|
||||
impl Scanner {
|
||||
pub fn new(fq: FileQueue, rx: Receiver<Message>) -> Self {
|
||||
Self {
|
||||
files: fq,
|
||||
proc_queue: Arc::new(Mutex::new(vec![])),
|
||||
msg_rx: rx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn index(&self) -> Result<()> {
|
||||
loop {
|
||||
match self.msg_rx.try_recv() {
|
||||
Ok(Message::AddScanDirectory(path)) => {
|
||||
let mut mfq = self.proc_queue.lock().unwrap();
|
||||
mfq.push(path);
|
||||
}
|
||||
Err(mpsc::TryRecvError::Empty) | Ok(Message::None) => {}
|
||||
Ok(Message::Exit) | Err(_) => break,
|
||||
}
|
||||
|
||||
let npath = {
|
||||
match self.proc_queue.try_lock() {
|
||||
Ok(mut q) => q.pop(),
|
||||
Err(_) => None,
|
||||
}
|
||||
};
|
||||
|
||||
match npath {
|
||||
None => continue,
|
||||
Some(path) => {
|
||||
std::fs::read_dir(path.as_ref())?
|
||||
.filter_map(Result::ok)
|
||||
.for_each(|entry: fs::DirEntry| {
|
||||
let mdata =
|
||||
fs::metadata(entry.path()).expect("unable to read file metadata.");
|
||||
|
||||
let mpath = entry
|
||||
.path()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.expect("invalid path conversion failed.")
|
||||
.into_boxed_str();
|
||||
|
||||
match mdata.is_dir() {
|
||||
true => {
|
||||
let mut pq = self
|
||||
.proc_queue
|
||||
.lock()
|
||||
.expect("proc queue lock acq failed.");
|
||||
pq.push(mpath);
|
||||
}
|
||||
false => {
|
||||
let mut fq = self
|
||||
.files
|
||||
.lock()
|
||||
.expect("file queue lock acq failed.");
|
||||
fq.push(mpath)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use anyhow::Result;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::sync::mpsc::channel;
|
||||
use tempfile::TempDir;
|
||||
use std::thread;
|
||||
|
||||
#[test]
|
||||
fn scanner_scans_files() -> Result<()> {
|
||||
let files =
|
||||
[("hello.txt", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum"),
|
||||
("hello_dup.txt", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum")];
|
||||
|
||||
let file_queue: FileQueue = Arc::new(Mutex::new(vec![]));
|
||||
let (tx, rx) = channel::<Message>();
|
||||
let root = TempDir::new()?;
|
||||
|
||||
for (filename, content) in files.into_iter() {
|
||||
let mut tf = File::create(root.path().join(filename))?;
|
||||
tf.write_all(content.as_bytes())?;
|
||||
}
|
||||
|
||||
let rpath = root.path().to_str().unwrap().to_string().into_boxed_str();
|
||||
let fq_clone = file_queue.clone();
|
||||
let scanner_thread = thread::spawn(move || {
|
||||
let scanner = Scanner::new(fq_clone, rx);
|
||||
scanner.index().unwrap();
|
||||
});
|
||||
|
||||
tx.send(Message::AddScanDirectory(rpath))?;
|
||||
tx.send(Message::Exit)?;
|
||||
scanner_thread.join().unwrap();
|
||||
|
||||
let fq_len = {
|
||||
let v = file_queue.lock().unwrap();
|
||||
v.len()
|
||||
};
|
||||
|
||||
assert_eq!(files.len(), fq_len);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
35
src/server/store.rs
Normal file
35
src/server/store.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use super::file::FileMeta;
|
||||
use dashmap::DashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
pub enum Index {
|
||||
Size(u64),
|
||||
Partial(Arc<[u8]>),
|
||||
Full(Box<str>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Store {
|
||||
internal: Arc<DashMap<Index, Vec<Arc<FileMeta>>>>,
|
||||
}
|
||||
|
||||
impl Store {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
internal: Arc::new(DashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn entries(&self) -> Arc<DashMap<Index, Vec<Arc<FileMeta>>>> {
|
||||
self.internal.clone()
|
||||
}
|
||||
|
||||
pub fn add(&self, index: Index, file: Arc<FileMeta>) {
|
||||
self.internal
|
||||
.entry(index)
|
||||
.and_modify(|fg| fg.push(file.clone()))
|
||||
.or_insert(vec![file]);
|
||||
}
|
||||
}
|
||||
99
src/tui/mod.rs
Normal file
99
src/tui/mod.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use ratatui::crossterm::event::{self, Event, KeyCode};
|
||||
use ratatui::layout::{Constraint, Direction, Layout};
|
||||
use ratatui::widgets::{Block, Borders, List, ListItem, Paragraph};
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
|
||||
use crate::server::{Message, Server};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Tui {
|
||||
app_tx: Sender<Message>,
|
||||
server: Arc<Server>,
|
||||
}
|
||||
|
||||
impl Tui {
|
||||
pub fn new(app_tx: Sender<Message>, server: Arc<Server>) -> Self {
|
||||
Self { app_tx, server }
|
||||
}
|
||||
|
||||
pub fn start(&mut self) -> Result<()> {
|
||||
let terminal = ratatui::init();
|
||||
self.run(terminal).expect("ui loop failed.");
|
||||
ratatui::restore();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn poll_events() -> Result<Message> {
|
||||
match event::poll(Duration::from_millis(100)).context("event polling failed.")? {
|
||||
true => match event::read().context("event read failed.")? {
|
||||
Event::Key(key) => match key.code {
|
||||
KeyCode::Char('q') => Ok(Message::Exit),
|
||||
_ => Ok(Message::None),
|
||||
},
|
||||
_ => Ok(Message::None),
|
||||
},
|
||||
false => Ok(Message::None),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_events(&self) -> Result<Message> {
|
||||
match Self::poll_events() {
|
||||
Ok(Message::Exit) => {
|
||||
self.app_tx
|
||||
.send(Message::Exit)
|
||||
.expect("app event send failed.");
|
||||
Ok(Message::Exit)
|
||||
}
|
||||
_ => Ok(Message::None),
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&mut self, frame: &mut Frame) {
|
||||
let listitems = self
|
||||
.server
|
||||
.dupstore
|
||||
.entries()
|
||||
.iter()
|
||||
.flat_map(|val| {
|
||||
let mut group = vec![ListItem::new(format!("{:?}", val.key()))];
|
||||
val.value().iter().for_each(|f| {
|
||||
group.push(ListItem::new(format!("|-{}", f.path)));
|
||||
});
|
||||
group
|
||||
})
|
||||
.collect::<Vec<ListItem>>();
|
||||
|
||||
let list = List::new(listitems.clone());
|
||||
let layout_chunks = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||
.split(frame.area());
|
||||
|
||||
frame.render_widget(
|
||||
list.block(Block::new().borders(Borders::ALL)),
|
||||
layout_chunks[0],
|
||||
);
|
||||
|
||||
frame.render_widget(
|
||||
Paragraph::new(String::new()).block(Block::new().borders(Borders::ALL)),
|
||||
layout_chunks[1],
|
||||
);
|
||||
}
|
||||
|
||||
fn run(&mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(|f| self.draw(f))?;
|
||||
match self.handle_events() {
|
||||
Ok(Message::Exit) => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user