1
0
Fork 0
mirror of synced 2024-04-28 01:22:53 +12:00

Allocation decrease (#1156)

This commit is contained in:
Rafał Mikrut 2023-12-11 19:12:26 +01:00 committed by GitHub
parent 739e2a9860
commit 219f9f058b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 453 additions and 399 deletions

243
Cargo.lock generated
View file

@ -113,9 +113,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.6.4"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
dependencies = [
"anstyle",
"anstyle-parse",
@ -133,30 +133,30 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.1"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [
"anstyle",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@ -324,7 +324,7 @@ dependencies = [
"futures-lite 2.1.0",
"parking",
"polling 3.3.1",
"rustix 0.38.26",
"rustix 0.38.28",
"slab",
"tracing",
"windows-sys 0.52.0",
@ -363,7 +363,7 @@ dependencies = [
"cfg-if",
"event-listener 3.1.0",
"futures-lite 1.13.0",
"rustix 0.38.26",
"rustix 0.38.28",
"windows-sys 0.48.0",
]
@ -390,7 +390,7 @@ dependencies = [
"cfg-if",
"futures-core",
"futures-io",
"rustix 0.38.26",
"rustix 0.38.28",
"signal-hook-registry",
"slab",
"windows-sys 0.48.0",
@ -439,15 +439,6 @@ dependencies = [
"syn 2.0.39",
]
[[package]]
name = "atomic-polyfill"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
dependencies = [
"critical-section",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
@ -724,7 +715,7 @@ dependencies = [
"bitflags 2.4.1",
"log",
"polling 3.3.1",
"rustix 0.38.26",
"rustix 0.38.28",
"slab",
"thiserror",
]
@ -736,7 +727,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02"
dependencies = [
"calloop",
"rustix 0.38.26",
"rustix 0.38.28",
"wayland-backend",
"wayland-client",
]
@ -854,9 +845,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.4.10"
version = "4.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272"
checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
dependencies = [
"clap_builder",
"clap_derive",
@ -864,9 +855,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.4.9"
version = "4.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1"
checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
dependencies = [
"anstream",
"anstyle",
@ -1096,6 +1087,15 @@ dependencies = [
"libc",
]
[[package]]
name = "core2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
dependencies = [
"memchr",
]
[[package]]
name = "countme"
version = "3.0.1"
@ -1343,6 +1343,12 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "dary_heap"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca"
[[package]]
name = "dashmap"
version = "5.5.3"
@ -1803,14 +1809,14 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.22"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.3.5",
"windows-sys 0.48.0",
"redox_syscall 0.4.1",
"windows-sys 0.52.0",
]
[[package]]
@ -2258,9 +2264,9 @@ dependencies = [
[[package]]
name = "gio"
version = "0.18.3"
version = "0.18.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d809baf02bdf1b5ef4ad3bf60dd9d4977149db4612b7bbb58e56aef168193b"
checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73"
dependencies = [
"futures-channel",
"futures-core",
@ -2301,9 +2307,9 @@ dependencies = [
[[package]]
name = "glib"
version = "0.18.3"
version = "0.18.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58cf801b6f7829fa76db37449ab67c9c98a2b1bf21076d9113225621e61a0fa6"
checksum = "951bbd7fdc5c044ede9f05170f05a3ae9479239c3afdfe2d22d537a3add15c4e"
dependencies = [
"bitflags 2.4.1",
"futures-channel",
@ -2605,6 +2611,15 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
@ -3111,15 +3126,6 @@ dependencies = [
"cfb",
]
[[package]]
name = "inflate"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
dependencies = [
"adler32",
]
[[package]]
name = "inout"
version = "0.1.3"
@ -3249,9 +3255,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.9"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "jni"
@ -3384,6 +3390,30 @@ version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "libflate"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7d5654ae1795afc7ff76f4365c2c8791b0feb18e8996a96adad8ffd7c3b2bf"
dependencies = [
"adler32",
"core2",
"crc32fast",
"dary_heap",
"libflate_lz77",
]
[[package]]
name = "libflate_lz77"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be5f52fb8c451576ec6b79d3f4deb327398bc05bbdbd99021a6e77a4c855d524"
dependencies = [
"core2",
"hashbrown 0.13.2",
"rle-decode-fast",
]
[[package]]
name = "libheif-rs"
version = "0.18.0"
@ -3553,9 +3583,9 @@ dependencies = [
[[package]]
name = "lofty"
version = "0.16.1"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c18ba58211b3c3557970755d7afc3a7438c2d4557bcd684470b2195c0ae66e53"
checksum = "e9d514acc39ec2bee7392e451db35e5f5eb06ab26e1cae83746c3017e8c95099"
dependencies = [
"base64",
"byteorder",
@ -3955,9 +3985,9 @@ dependencies = [
[[package]]
name = "objc-sys"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99e1d07c6eab1ce8b6382b8e3c7246fe117ff3f8b34be065f5ebace6749fe845"
checksum = "c7c71324e4180d0899963fc83d9d241ac39e699609fc1025a850aadac8257459"
[[package]]
name = "objc2"
@ -4004,12 +4034,12 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.18.0"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
dependencies = [
"atomic-polyfill",
"critical-section",
"portable-atomic",
]
[[package]]
@ -4158,9 +4188,9 @@ dependencies = [
[[package]]
name = "pdf"
version = "0.8.1"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e375ec076445f61d4dbc4636e9e788f841d279c65d6fea8a3875caddd4f2dd82"
checksum = "3afc7e745846405d572daba57a429f30a198d955602aff8a1a9e437c2abfcaa2"
dependencies = [
"aes",
"bitflags 1.3.2",
@ -4169,10 +4199,11 @@ dependencies = [
"deflate",
"fax",
"globalcache",
"inflate",
"indexmap 2.1.0",
"istring",
"itertools 0.10.5",
"jpeg-decoder",
"libflate",
"log",
"md5",
"once_cell",
@ -4185,9 +4216,9 @@ dependencies = [
[[package]]
name = "pdf_derive"
version = "0.1.22"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4007262775d0798de87b15cbc64cf1aed5f7ee87eec847e297b69d8ed4b4f8"
checksum = "1038b9cb38dec35eeee9f23eacfb2480087982f9b7e9221efa8034eea9ca2360"
dependencies = [
"proc-macro2",
"quote",
@ -4305,7 +4336,7 @@ dependencies = [
"cfg-if",
"concurrent-queue",
"pin-project-lite",
"rustix 0.38.26",
"rustix 0.38.28",
"tracing",
"windows-sys 0.52.0",
]
@ -4318,9 +4349,9 @@ checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
[[package]]
name = "portable-atomic"
version = "1.5.1"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b"
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
dependencies = [
"critical-section",
]
@ -4650,9 +4681,9 @@ dependencies = [
[[package]]
name = "ring"
version = "0.17.6"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "684d5e6e18f669ccebf64a92236bb7db9a34f07be010e3627368182027180866"
checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
dependencies = [
"cc",
"getrandom",
@ -4663,13 +4694,19 @@ dependencies = [
]
[[package]]
name = "rowan"
version = "0.15.13"
name = "rle-decode-fast"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "906057e449592587bf6724f00155bf82a6752c868d78a8fb3aa41f4e6357cfe8"
checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
[[package]]
name = "rowan"
version = "0.15.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49"
dependencies = [
"countme",
"hashbrown 0.12.3",
"hashbrown 0.14.3",
"memoffset 0.9.0",
"rustc-hash",
"text-size",
@ -4698,9 +4735,9 @@ dependencies = [
[[package]]
name = "rust-embed"
version = "8.0.0"
version = "8.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40"
checksum = "810294a8a4a0853d4118e3b94bb079905f2107c7fe979d8f0faae98765eb6378"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
@ -4709,9 +4746,9 @@ dependencies = [
[[package]]
name = "rust-embed-impl"
version = "8.0.0"
version = "8.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29"
checksum = "bfc144a1273124a67b8c1d7cd19f5695d1878b31569c0512f6086f0f4676604e"
dependencies = [
"proc-macro2",
"quote",
@ -4722,9 +4759,9 @@ dependencies = [
[[package]]
name = "rust-embed-utils"
version = "8.0.0"
version = "8.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada"
checksum = "816ccd4875431253d6bb54b804bcff4369cbde9bae33defde25fdf6c2ef91d40"
dependencies = [
"sha2",
"walkdir",
@ -4808,9 +4845,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.26"
version = "0.38.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
dependencies = [
"bitflags 2.4.1",
"errno",
@ -4821,9 +4858,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.21.9"
version = "0.21.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9"
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
dependencies = [
"log",
"ring",
@ -4891,9 +4928,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.15"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "same-file"
@ -5211,7 +5248,7 @@ dependencies = [
"libc",
"log",
"memmap2 0.9.0",
"rustix 0.38.26",
"rustix 0.38.28",
"thiserror",
"wayland-backend",
"wayland-client",
@ -5295,7 +5332,7 @@ dependencies = [
"objc",
"raw-window-handle 0.5.2",
"redox_syscall 0.4.1",
"rustix 0.38.26",
"rustix 0.38.28",
"tiny-xlib",
"wasm-bindgen",
"wayland-backend",
@ -5659,7 +5696,7 @@ dependencies = [
"cfg-if",
"fastrand 2.0.1",
"redox_syscall 0.4.1",
"rustix 0.38.26",
"rustix 0.38.28",
"windows-sys 0.48.0",
]
@ -5752,9 +5789,9 @@ dependencies = [
[[package]]
name = "tiny-skia"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b72a92a05db376db09fe6d50b7948d106011761c05a6a45e23e17ee9b556222"
checksum = "b6a067b809476893fce6a254cf285850ff69c847e6cfbade6a20b655b6c7e80d"
dependencies = [
"arrayref",
"arrayvec",
@ -5767,9 +5804,9 @@ dependencies = [
[[package]]
name = "tiny-skia-path"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac3865b9708fc7e1961a65c3a4fa55e984272f33092d3c859929f887fceb647"
checksum = "5de35e8a90052baaaf61f171680ac2f8e925a1e43ea9d2e3a00514772250e541"
dependencies = [
"arrayref",
"bytemuck",
@ -6039,18 +6076,18 @@ dependencies = [
[[package]]
name = "unic-langid"
version = "0.9.1"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f"
checksum = "887622f8e7b723780c5e64b04dcc0c9b8f426ada7cca6790cd3ea3bf0f08037a"
dependencies = [
"unic-langid-impl",
]
[[package]]
name = "unic-langid-impl"
version = "0.9.1"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff"
checksum = "5adeb847e35eed4efbffd9fb2e4d078b91ece56e4d6a3c0d2df55b3a1dac07d5"
dependencies = [
"serde",
"tinystr",
@ -6067,9 +6104,9 @@ dependencies = [
[[package]]
name = "unicode-bidi"
version = "0.3.13"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
[[package]]
name = "unicode-bidi-mirroring"
@ -6581,7 +6618,7 @@ dependencies = [
"either",
"home",
"once_cell",
"rustix 0.38.26",
"rustix 0.38.28",
]
[[package]]
@ -6878,7 +6915,7 @@ dependencies = [
"percent-encoding",
"raw-window-handle 0.5.2",
"redox_syscall 0.3.5",
"rustix 0.38.26",
"rustix 0.38.28",
"sctk-adwaita",
"smithay-client-toolkit",
"smol_str",
@ -6899,9 +6936,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.5.19"
version = "0.5.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff"
dependencies = [
"memchr",
]
@ -6963,9 +7000,9 @@ dependencies = [
[[package]]
name = "xattr"
version = "1.0.1"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985"
checksum = "fbc6ab6ec1907d1a901cdbcd2bd4cb9e7d64ce5c9739cbb97d3c391acd8c7fae"
dependencies = [
"libc",
]
@ -7120,18 +7157,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.7.28"
version = "0.7.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d6f15f7ade05d2a4935e34a457b936c23dc70a05cc1d97133dc99e7a3fe0f0e"
checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.28"
version = "0.7.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbbad221e3f78500350ecbd7dfa4e63ef945c05f4c61cb7f4d3f84cd0bba649b"
checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba"
dependencies = [
"proc-macro2",
"quote",

View file

@ -316,17 +316,18 @@ fn collect_all_files_and_dirs(dir: &str) -> std::io::Result<CollectedFiles> {
let rd = fs::read_dir(folder)?;
for entry in rd {
let entry = entry?;
let path = entry.path();
let file_type = entry.file_type()?;
let path_str = entry.path().to_string_lossy().to_string();
if path.is_dir() {
folders.insert(path.to_string_lossy().to_string());
folders_to_check.push(path.to_string_lossy().to_string());
} else if path.is_symlink() {
symlinks.insert(path.to_string_lossy().to_string());
} else if path.is_file() {
files.insert(path.to_string_lossy().to_string());
if file_type.is_dir() {
folders.insert(path_str.clone());
folders_to_check.push(path_str);
} else if file_type.is_symlink() {
symlinks.insert(path_str);
} else if file_type.is_file() {
files.insert(path_str);
} else {
panic!("Unknown type of file {:?}", path);
panic!("Unknown type of file {path_str:?}");
}
}
}

View file

@ -10,14 +10,14 @@ homepage = "https://github.com/qarmin/czkawka"
repository = "https://github.com/qarmin/czkawka"
[dependencies]
clap = { version = "4.3", features = ["derive"] }
clap = { version = "4.4", features = ["derive"] }
# For enum types
image_hasher = "1.2"
log = "0.4.20"
handsome_logger = "0.8"
fun_time = { version = "0.3.1", features = ["log"] }
fun_time = { version = "0.3", features = ["log"] }
czkawka_core = { path = "../czkawka_core", version = "6.1.0", features = [] }
[features]

View file

@ -8,7 +8,7 @@ description = "Core of Czkawka app"
license = "MIT"
homepage = "https://github.com/qarmin/czkawka"
repository = "https://github.com/qarmin/czkawka"
build = "build.rs"
[dependencies]
humansize = "2.1"
@ -26,12 +26,12 @@ hamming = "0.1"
# Needed by same music
bitflags = "2.4"
lofty = "0.16"
lofty = "0.17"
# Needed by broken files
zip = { version = "0.6", features = ["aes-crypto", "bzip2", "deflate", "time"], default-features = false }
audio_checker = "0.1"
pdf = "0.8"
pdf = "0.9"
# Needed by audio similarity feature
rusty-chromaprint = "0.1"
@ -56,8 +56,8 @@ serde_json = "1.0"
# Language
i18n-embed = { version = "0.14", features = ["fluent-system", "desktop-requester"] }
i18n-embed-fl = "0.7"
rust-embed = { version = "8.0", features = ["debug-embed"] }
once_cell = "1.18"
rust-embed = { version = "8.1", features = ["debug-embed"] }
once_cell = "1.19"
# Raw image files
rawloader = "0.37"
@ -77,12 +77,14 @@ anyhow = { version = "1.0" }
state = "0.6"
os_info = { version = "3", default-features = false }
rustc_version = "0.4"
log = "0.4.20"
handsome_logger = "0.8"
fun_time = { version = "0.3.1", features = ["log"] }
fun_time = { version = "0.3", features = ["log"] }
[build-dependencies]
rustc_version = "0.4"
[features]
default = []
heif = ["dep:libheif-rs", "dep:libheif-sys"]
libraw = ["dep:libraw-rs"]
libraw = ["dep:libraw-rs"]

18
czkawka_core/build.rs Normal file
View file

@ -0,0 +1,18 @@
fn main() {
let rust_version = match rustc_version::version_meta() {
Ok(meta) => {
let rust_v = meta.semver.to_string();
let rust_date = meta.commit_date.unwrap_or_default();
format!("{rust_v} ({rust_date})")
}
Err(_) => "<unknown>".to_string(),
};
println!("cargo:rustc-env=RUST_VERSION_INTERNAL={rust_version}");
// Find if app is build with cranelift
if let Ok(codegen) = std::env::var("CARGO_PROFILE_RELEASE_CODEGEN_UNITS") {
if codegen == "1" {
println!("cargo:rustc-env=USING_CRANELIFT=1");
}
}
}

View file

@ -231,9 +231,7 @@ impl BadExtensions {
true
}
DirTraversalResult::SuccessFolders { .. } => {
unreachable!()
}
DirTraversalResult::Stopped => false,
}
}

View file

@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use std::fs;
use std::fs::DirEntry;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
@ -106,14 +106,13 @@ impl BigFile {
check_folder_children(
&mut dir_result,
&mut warnings,
&current_folder,
&entry_data,
self.common_data.recursive_search,
&self.common_data.directories,
&self.common_data.excluded_items,
);
} else if file_type.is_file() {
self.collect_file_entry(&atomic_counter, &entry_data, &mut fe_result, &mut warnings, &current_folder);
self.collect_file_entry(&atomic_counter, &entry_data, &mut fe_result, &mut warnings);
}
}
(dir_result, warnings, fe_result)
@ -142,20 +141,13 @@ impl BigFile {
true
}
pub fn collect_file_entry(
&self,
atomic_counter: &Arc<AtomicUsize>,
entry_data: &DirEntry,
fe_result: &mut Vec<(u64, FileEntry)>,
warnings: &mut Vec<String>,
current_folder: &Path,
) {
pub fn collect_file_entry(&self, atomic_counter: &Arc<AtomicUsize>, entry_data: &DirEntry, fe_result: &mut Vec<(u64, FileEntry)>, warnings: &mut Vec<String>) {
atomic_counter.fetch_add(1, Ordering::Relaxed);
if !self.common_data.allowed_extensions.check_if_entry_ends_with_extension(entry_data) {
return;
}
let current_file_name = current_folder.join(entry_data.file_name());
let current_file_name = entry_data.path();
if self.common_data.excluded_items.is_excluded(&current_file_name) {
return;
}

View file

@ -144,14 +144,13 @@ impl BrokenFiles {
check_folder_children(
&mut dir_result,
&mut warnings,
&current_folder,
&entry_data,
self.common_data.recursive_search,
&self.common_data.directories,
&self.common_data.excluded_items,
);
} else if file_type.is_file() {
if let Some(file_entry) = self.get_file_entry(&atomic_counter, &entry_data, &mut warnings, &current_folder) {
if let Some(file_entry) = self.get_file_entry(&atomic_counter, &entry_data, &mut warnings) {
fe_result.push((file_entry.path.to_string_lossy().to_string(), file_entry));
}
}
@ -178,7 +177,7 @@ impl BrokenFiles {
true
}
fn get_file_entry(&self, atomic_counter: &Arc<AtomicUsize>, entry_data: &DirEntry, warnings: &mut Vec<String>, current_folder: &Path) -> Option<FileEntry> {
fn get_file_entry(&self, atomic_counter: &Arc<AtomicUsize>, entry_data: &DirEntry, warnings: &mut Vec<String>) -> Option<FileEntry> {
atomic_counter.fetch_add(1, Ordering::Relaxed);
if !self.common_data.allowed_extensions.check_if_entry_ends_with_extension(entry_data) {
return None;
@ -191,7 +190,7 @@ impl BrokenFiles {
return None;
}
let current_file_name = current_folder.join(entry_data.file_name());
let current_file_name = entry_data.path();
if self.common_data.excluded_items.is_excluded(&current_file_name) {
return None;
}

View file

@ -75,10 +75,7 @@ pub fn get_available_threads() -> usize {
}
pub fn print_version_mode() {
let rust_version = match rustc_version::version_meta() {
Ok(meta) => meta.semver.to_string(),
Err(_) => "<unknown>".to_string(),
};
let rust_version = env!("RUST_VERSION_INTERNAL");
let debug_release = if cfg!(debug_assertions) { "debug" } else { "release" };
let processors = get_available_threads();
@ -94,6 +91,10 @@ pub fn print_version_mode() {
if cfg!(debug_assertions) {
warn!("You are running debug version of app which is a lot of slower than release version.");
}
if option_env!("USING_CRANELIFT").is_some() {
warn!("You are running app with cranelift which is intended only for fast compilation, not runtime performance.");
}
}
pub fn set_default_number_of_threads() {
@ -173,7 +174,11 @@ pub fn remove_folder_if_contains_only_empty_folders(path: impl AsRef<Path>) -> b
let Some(entry) = entries_to_check.pop() else {
break;
};
if !entry.path().is_dir() {
let Some(file_type) = entry.file_type().ok() else {
return false;
};
if !file_type.is_dir() {
return false;
}
let Ok(internal_read_dir) = entry.path().read_dir() else {
@ -421,7 +426,6 @@ pub fn normalize_windows_path(path_to_change: impl AsRef<Path>) -> PathBuf {
pub fn check_folder_children(
dir_result: &mut Vec<PathBuf>,
warnings: &mut Vec<String>,
current_folder: &Path,
entry_data: &DirEntry,
recursive_search: bool,
directories: &Directories,
@ -431,25 +435,25 @@ pub fn check_folder_children(
return;
}
let next_folder = current_folder.join(entry_data.file_name());
if directories.is_excluded(&next_folder) {
let next_item = entry_data.path();
if directories.is_excluded(&next_item) {
return;
}
if excluded_items.is_excluded(&next_folder) {
if excluded_items.is_excluded(&next_item) {
return;
}
#[cfg(target_family = "unix")]
if directories.exclude_other_filesystems() {
match directories.is_on_other_filesystems(&next_folder) {
match directories.is_on_other_filesystems(&next_item) {
Ok(true) => return,
Err(e) => warnings.push(e),
_ => (),
}
}
dir_result.push(next_folder);
dir_result.push(next_item);
}
// Here we assume, that internal Vec<> have at least 1 object

View file

@ -1,4 +1,4 @@
use std::collections::{BTreeMap, HashMap};
use std::collections::BTreeMap;
use std::fs;
use std::fs::{DirEntry, FileType, Metadata, ReadDir};
use std::path::{Path, PathBuf};
@ -95,31 +95,8 @@ pub enum ErrorType {
NonExistentFile,
}
// Empty folders
/// Enum with values which show if folder is empty.
/// In function "`optimize_folders`" automatically "Maybe" is changed to "Yes", so it is not necessary to put it here
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub(crate) enum FolderEmptiness {
No,
Maybe,
}
/// Struct assigned to each checked folder with parent path(used to ignore parent if children are not empty) and flag which shows if folder is empty
#[derive(Clone, Debug)]
pub struct FolderEntry {
pub path: PathBuf,
pub(crate) parent_path: Option<String>,
// Usable only when finding
pub(crate) is_empty: FolderEmptiness,
pub modified_date: u64,
}
// Collection mode (files / empty folders)
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Collect {
EmptyFolders,
InvalidSymlinks,
Files,
}
@ -315,10 +292,6 @@ pub enum DirTraversalResult<T: Ord + PartialOrd> {
warnings: Vec<String>,
grouped_file_entries: BTreeMap<T, Vec<FileEntry>>,
},
SuccessFolders {
warnings: Vec<String>,
folder_entries: HashMap<String, FolderEntry>, // Path, FolderEntry
},
Stopped,
}
@ -345,22 +318,7 @@ where
let mut all_warnings = vec![];
let mut grouped_file_entries: BTreeMap<T, Vec<FileEntry>> = BTreeMap::new();
let mut folder_entries: HashMap<String, FolderEntry> = HashMap::new();
// Add root folders into result (only for empty folder collection)
if self.collect == Collect::EmptyFolders {
for dir in &self.root_dirs {
folder_entries.insert(
dir.to_string_lossy().to_string(),
FolderEntry {
path: dir.clone(),
parent_path: None,
is_empty: FolderEmptiness::Maybe,
modified_date: 0,
},
);
}
}
// Add root folders for finding
let mut folders_to_check: Vec<PathBuf> = self.root_dirs.clone();
@ -391,19 +349,14 @@ where
let mut dir_result = vec![];
let mut warnings = vec![];
let mut fe_result = vec![];
let mut set_as_not_empty_folder_list = vec![];
let mut folder_entries_list = vec![];
let Some(read_dir) = common_read_dir(&current_folder, &mut warnings) else {
if collect == Collect::EmptyFolders {
set_as_not_empty_folder_list.push(current_folder);
}
return (dir_result, warnings, fe_result, set_as_not_empty_folder_list, folder_entries_list);
return (dir_result, warnings, fe_result);
};
let mut counter = 0;
// Check every sub folder/file/link etc.
'dir: for entry in read_dir {
for entry in read_dir {
let Some(entry_data) = common_get_entry_data(&entry, &mut warnings, &current_folder) else {
continue;
};
@ -411,20 +364,7 @@ where
match (entry_type(file_type), collect) {
(EntryType::Dir, Collect::Files | Collect::InvalidSymlinks) => {
process_dir_in_file_symlink_mode(recursive_search, &current_folder, entry_data, &directories, &mut dir_result, &mut warnings, &excluded_items);
}
(EntryType::Dir, Collect::EmptyFolders) => {
counter += 1;
process_dir_in_dir_mode(
&current_folder,
entry_data,
&directories,
&mut dir_result,
&mut warnings,
&excluded_items,
&mut set_as_not_empty_folder_list,
&mut folder_entries_list,
);
process_dir_in_file_symlink_mode(recursive_search, entry_data, &directories, &mut dir_result, &mut warnings, &excluded_items);
}
(EntryType::File, Collect::Files) => {
counter += 1;
@ -433,39 +373,18 @@ where
&mut warnings,
&mut fe_result,
&allowed_extensions,
&current_folder,
&directories,
&excluded_items,
minimal_file_size,
maximal_file_size,
);
}
(EntryType::File | EntryType::Symlink, Collect::EmptyFolders) => {
#[cfg(target_family = "unix")]
if directories.exclude_other_filesystems() {
match directories.is_on_other_filesystems(&current_folder) {
Ok(true) => continue 'dir,
Err(e) => warnings.push(e.to_string()),
_ => (),
}
}
set_as_not_empty_folder_list.push(current_folder.clone());
}
(EntryType::File, Collect::InvalidSymlinks) => {
counter += 1;
}
(EntryType::Symlink, Collect::InvalidSymlinks) => {
counter += 1;
process_symlink_in_symlink_mode(
entry_data,
&mut warnings,
&mut fe_result,
&allowed_extensions,
&current_folder,
&directories,
&excluded_items,
);
process_symlink_in_symlink_mode(entry_data, &mut warnings, &mut fe_result, &allowed_extensions, &directories, &excluded_items);
}
(EntryType::Symlink, Collect::Files) | (EntryType::Other, _) => {
// nothing to do
@ -476,47 +395,33 @@ where
// Increase counter in batch, because usually it may be slow to add multiple times atomic value
atomic_counter.fetch_add(counter, Ordering::Relaxed);
}
(dir_result, warnings, fe_result, set_as_not_empty_folder_list, folder_entries_list)
(dir_result, warnings, fe_result)
})
.collect();
let required_size = segments.iter().map(|(segment, _, _, _, _)| segment.len()).sum::<usize>();
let required_size = segments.iter().map(|(segment, _, _)| segment.len()).sum::<usize>();
folders_to_check = Vec::with_capacity(required_size);
// Process collected data
for (segment, warnings, fe_result, set_as_not_empty_folder_list, fe_list) in segments {
for (segment, warnings, fe_result) in segments {
folders_to_check.extend(segment);
all_warnings.extend(warnings);
for fe in fe_result {
let key = (self.group_by)(&fe);
grouped_file_entries.entry(key).or_default().push(fe);
}
for current_folder in &set_as_not_empty_folder_list {
set_as_not_empty_folder(&mut folder_entries, current_folder);
}
for (path, entry) in fe_list {
folder_entries.insert(path.to_string_lossy().to_string(), entry);
}
}
}
send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle);
debug!(
"Collected {} files, {} folders",
grouped_file_entries.values().map(Vec::len).sum::<usize>(),
folder_entries.len()
);
debug!("Collected {} files", grouped_file_entries.values().map(Vec::len).sum::<usize>());
match collect {
Collect::Files | Collect::InvalidSymlinks => DirTraversalResult::SuccessFiles {
grouped_file_entries,
warnings: all_warnings,
},
Collect::EmptyFolders => DirTraversalResult::SuccessFolders {
folder_entries,
warnings: all_warnings,
},
}
}
}
@ -526,7 +431,6 @@ fn process_file_in_file_mode(
warnings: &mut Vec<String>,
fe_result: &mut Vec<FileEntry>,
allowed_extensions: &Extensions,
current_folder: &Path,
directories: &Directories,
excluded_items: &ExcludedItems,
minimal_file_size: u64,
@ -536,7 +440,7 @@ fn process_file_in_file_mode(
return;
}
let current_file_name = current_folder.join(entry_data.file_name());
let current_file_name = entry_data.path();
if excluded_items.is_excluded(&current_file_name) {
return;
}
@ -550,7 +454,7 @@ fn process_file_in_file_mode(
}
}
let Some(metadata) = common_get_metadata_dir(entry_data, warnings, current_folder) else {
let Some(metadata) = common_get_metadata_dir(entry_data, warnings, &current_file_name) else {
return;
};
@ -568,51 +472,8 @@ fn process_file_in_file_mode(
}
}
fn process_dir_in_dir_mode(
current_folder: &Path,
entry_data: &DirEntry,
directories: &Directories,
dir_result: &mut Vec<PathBuf>,
warnings: &mut Vec<String>,
excluded_items: &ExcludedItems,
set_as_not_empty_folder_list: &mut Vec<PathBuf>,
folder_entries_list: &mut Vec<(PathBuf, FolderEntry)>,
) {
let next_folder = current_folder.join(entry_data.file_name());
if excluded_items.is_excluded(&next_folder) || directories.is_excluded(&next_folder) {
set_as_not_empty_folder_list.push(current_folder.to_path_buf());
return;
}
#[cfg(target_family = "unix")]
if directories.exclude_other_filesystems() {
match directories.is_on_other_filesystems(&next_folder) {
Ok(true) => return,
Err(e) => warnings.push(e),
_ => (),
}
}
let Some(metadata) = common_get_metadata_dir(entry_data, warnings, current_folder) else {
set_as_not_empty_folder_list.push(current_folder.to_path_buf());
return;
};
dir_result.push(next_folder.clone());
folder_entries_list.push((
next_folder.clone(),
FolderEntry {
path: next_folder,
parent_path: Some(current_folder.to_string_lossy().to_string()),
is_empty: FolderEmptiness::Maybe,
modified_date: get_modified_time(&metadata, warnings, current_folder, true),
},
));
}
fn process_dir_in_file_symlink_mode(
recursive_search: bool,
current_folder: &Path,
entry_data: &DirEntry,
directories: &Directories,
dir_result: &mut Vec<PathBuf>,
@ -623,25 +484,25 @@ fn process_dir_in_file_symlink_mode(
return;
}
let next_folder = current_folder.join(entry_data.file_name());
if directories.is_excluded(&next_folder) {
let dir_path = entry_data.path();
if directories.is_excluded(&dir_path) {
return;
}
if excluded_items.is_excluded(&next_folder) {
if excluded_items.is_excluded(&dir_path) {
return;
}
#[cfg(target_family = "unix")]
if directories.exclude_other_filesystems() {
match directories.is_on_other_filesystems(&next_folder) {
match directories.is_on_other_filesystems(&dir_path) {
Ok(true) => return,
Err(e) => warnings.push(e),
_ => (),
}
}
dir_result.push(next_folder);
dir_result.push(dir_path);
}
fn process_symlink_in_symlink_mode(
@ -649,7 +510,6 @@ fn process_symlink_in_symlink_mode(
warnings: &mut Vec<String>,
fe_result: &mut Vec<FileEntry>,
allowed_extensions: &Extensions,
current_folder: &Path,
directories: &Directories,
excluded_items: &ExcludedItems,
) {
@ -657,21 +517,21 @@ fn process_symlink_in_symlink_mode(
return;
}
let current_file_name = current_folder.join(entry_data.file_name());
let current_file_name = entry_data.path();
if excluded_items.is_excluded(&current_file_name) {
return;
}
#[cfg(target_family = "unix")]
if directories.exclude_other_filesystems() {
match directories.is_on_other_filesystems(current_folder) {
match directories.is_on_other_filesystems(&current_file_name) {
Ok(true) => return,
Err(e) => warnings.push(e),
_ => (),
}
}
let Some(metadata) = common_get_metadata_dir(entry_data, warnings, current_folder) else {
let Some(metadata) = common_get_metadata_dir(entry_data, warnings, &current_file_name) else {
return;
};
@ -826,20 +686,3 @@ pub fn get_lowercase_name(entry_data: &DirEntry, warnings: &mut Vec<String>) ->
.to_lowercase();
Some(name)
}
fn set_as_not_empty_folder(folder_entries: &mut HashMap<String, FolderEntry>, current_folder: &Path) {
let mut d = folder_entries.get_mut(current_folder.to_string_lossy().as_ref()).unwrap();
// Loop to recursively set as non empty this and all his parent folders
loop {
d.is_empty = FolderEmptiness::No;
if d.parent_path.is_some() {
let cf = d.parent_path.clone().unwrap();
d = folder_entries.get_mut(&cf).unwrap();
if d.is_empty == FolderEmptiness::No {
break; // Already set as non empty, so one of child already set it to non empty
}
} else {
break;
}
}
}

View file

@ -204,9 +204,6 @@ impl DuplicateFinder {
true
}
DirTraversalResult::SuccessFolders { .. } => {
unreachable!()
}
DirTraversalResult::Stopped => false,
}
}
@ -280,9 +277,7 @@ impl DuplicateFinder {
true
}
DirTraversalResult::SuccessFolders { .. } => {
unreachable!()
}
DirTraversalResult::Stopped => false,
}
}
@ -356,9 +351,7 @@ impl DuplicateFinder {
true
}
DirTraversalResult::SuccessFolders { .. } => {
unreachable!()
}
DirTraversalResult::Stopped => false,
}
}

View file

@ -77,9 +77,7 @@ impl EmptyFiles {
true
}
DirTraversalResult::SuccessFolders { .. } => {
unreachable!()
}
DirTraversalResult::Stopped => false,
}
}

View file

@ -1,22 +1,45 @@
use std::collections::HashMap;
use std::fs;
use std::fs::DirEntry;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::sync::atomic::Ordering;
use crate::common::{check_if_stop_received, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads};
use crossbeam_channel::{Receiver, Sender};
use fun_time::fun_time;
use log::debug;
use rayon::prelude::*;
use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, FolderEmptiness, FolderEntry, ProgressData, ToolType};
use crate::common_dir_traversal::{common_get_entry_data, common_get_metadata_dir, common_read_dir, get_modified_time, CheckingMethod, ProgressData, ToolType};
use crate::common_directory::Directories;
use crate::common_items::ExcludedItems;
use crate::common_tool::{CommonData, CommonToolData, DeleteMethod};
use crate::common_traits::{DebugPrint, PrintResults};
#[derive(Clone, Debug)]
pub struct FolderEntry {
pub path: PathBuf,
pub(crate) parent_path: Option<String>,
// Usable only when finding
pub(crate) is_empty: FolderEmptiness,
pub modified_date: u64,
}
pub struct EmptyFolder {
common_data: CommonToolData,
information: Info,
empty_folder_list: HashMap<String, FolderEntry>, // Path, FolderEntry
}
/// Enum with values which show if folder is empty.
/// In function "`optimize_folders`" automatically "Maybe" is changed to "Yes", so it is not necessary to put it here
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub(crate) enum FolderEmptiness {
No,
Maybe,
}
#[derive(Default)]
pub struct Info {
pub number_of_empty_folders: usize,
@ -73,36 +96,172 @@ impl EmptyFolder {
#[fun_time(message = "check_for_empty_folders", level = "debug")]
fn check_for_empty_folders(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender<ProgressData>>) -> bool {
let result = DirTraversalBuilder::new()
.root_dirs(self.common_data.directories.included_directories.clone())
.group_by(|_fe| ())
.stop_receiver(stop_receiver)
.progress_sender(progress_sender)
.directories(self.common_data.directories.clone())
.excluded_items(self.common_data.excluded_items.clone())
.collect(Collect::EmptyFolders)
.max_stage(0)
.tool_type(self.common_data.tool_type)
.build()
.run();
let mut folders_to_check: Vec<PathBuf> = self.common_data.directories.included_directories.clone();
match result {
DirTraversalResult::SuccessFiles { .. } => {
unreachable!()
}
DirTraversalResult::SuccessFolders { folder_entries, warnings } => {
for (name, folder_entry) in folder_entries {
if folder_entry.is_empty != FolderEmptiness::No {
self.empty_folder_list.insert(name, folder_entry);
}
}
let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) =
prepare_thread_handler_common(progress_sender, 0, 0, 0, CheckingMethod::None, self.common_data.tool_type);
self.common_data.text_messages.warnings.extend(warnings);
debug!("Found {} empty folders.", self.empty_folder_list.len());
true
}
DirTraversalResult::Stopped => false,
let excluded_items = self.common_data.excluded_items.clone();
let directories = self.common_data.directories.clone();
let mut folder_entries: HashMap<String, FolderEntry> = HashMap::new();
let mut non_empty_folders: Vec<String> = vec![];
for dir in &folders_to_check {
folder_entries.insert(
dir.to_string_lossy().to_string(),
FolderEntry {
path: dir.clone(),
parent_path: None,
is_empty: FolderEmptiness::Maybe,
modified_date: 0,
},
);
}
while !folders_to_check.is_empty() {
if check_if_stop_received(stop_receiver) {
send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle);
return false;
}
let segments: Vec<_> = folders_to_check
.into_par_iter()
.map(|current_folder| {
let mut dir_result = vec![];
let mut warnings = vec![];
let mut set_as_not_empty_folder_list = vec![];
let mut folder_entries_list = vec![];
let Some(read_dir) = common_read_dir(&current_folder, &mut warnings) else {
set_as_not_empty_folder_list.push(current_folder.to_string_lossy().to_string());
return (dir_result, warnings, set_as_not_empty_folder_list, folder_entries_list);
};
let mut counter = 0;
// Check every sub folder/file/link etc.
for entry in read_dir {
let Some(entry_data) = common_get_entry_data(&entry, &mut warnings, &current_folder) else {
continue;
};
let Ok(file_type) = entry_data.file_type() else { continue };
if file_type.is_dir() {
counter += 1;
Self::process_dir_in_dir_mode(
&current_folder,
entry_data,
&directories,
&mut dir_result,
&mut warnings,
&excluded_items,
&mut set_as_not_empty_folder_list,
&mut folder_entries_list,
);
} else {
set_as_not_empty_folder_list.push(current_folder.to_string_lossy().to_string());
}
}
if counter > 0 {
// Increase counter in batch, because usually it may be slow to add multiple times atomic value
atomic_counter.fetch_add(counter, Ordering::Relaxed);
}
(dir_result, warnings, set_as_not_empty_folder_list, folder_entries_list)
})
.collect();
let required_size = segments.iter().map(|(segment, _, _, _)| segment.len()).sum::<usize>();
folders_to_check = Vec::with_capacity(required_size);
// Process collected data
for (segment, warnings, set_as_not_empty_folder_list, fe_list) in segments {
folders_to_check.extend(segment);
self.common_data.text_messages.warnings.extend(warnings);
non_empty_folders.extend(set_as_not_empty_folder_list);
for (path, entry) in fe_list {
folder_entries.insert(path, entry);
}
}
}
// Start to
for current_folder in non_empty_folders.into_iter().rev() {
Self::set_as_not_empty_folder(&mut folder_entries, &current_folder);
}
for (name, folder_entry) in folder_entries {
if folder_entry.is_empty != FolderEmptiness::No {
self.empty_folder_list.insert(name, folder_entry);
}
}
debug!("Found {} empty folders.", self.empty_folder_list.len());
send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle);
true
}
pub(crate) fn set_as_not_empty_folder(folder_entries: &mut HashMap<String, FolderEntry>, current_folder: &str) {
let mut d = folder_entries.get_mut(current_folder).unwrap();
if d.is_empty == FolderEmptiness::No {
return; // Already set as non empty by one of his child
}
// Loop to recursively set as non empty this and all his parent folders
loop {
d.is_empty = FolderEmptiness::No;
if d.parent_path.is_some() {
let cf = d.parent_path.clone().unwrap();
d = folder_entries.get_mut(&cf).unwrap();
if d.is_empty == FolderEmptiness::No {
break; // Already set as non empty, so one of child already set it to non empty
}
} else {
break;
}
}
}
fn process_dir_in_dir_mode(
current_folder: &Path,
entry_data: &DirEntry,
directories: &Directories,
dir_result: &mut Vec<PathBuf>,
warnings: &mut Vec<String>,
excluded_items: &ExcludedItems,
set_as_not_empty_folder_list: &mut Vec<String>,
folder_entries_list: &mut Vec<(String, FolderEntry)>,
) {
let parent_folder_str = current_folder.to_string_lossy().to_string();
let next_folder = entry_data.path();
if excluded_items.is_excluded(&next_folder) || directories.is_excluded(&next_folder) {
set_as_not_empty_folder_list.push(parent_folder_str);
return;
}
#[cfg(target_family = "unix")]
if directories.exclude_other_filesystems() {
match directories.is_on_other_filesystems(&next_folder) {
Ok(true) => return,
Err(e) => warnings.push(e),
_ => (),
}
}
let Some(metadata) = common_get_metadata_dir(entry_data, warnings, &next_folder) else {
set_as_not_empty_folder_list.push(parent_folder_str);
return;
};
dir_result.push(next_folder.clone());
folder_entries_list.push((
next_folder.to_string_lossy().to_string(),
FolderEntry {
path: next_folder,
parent_path: Some(parent_folder_str),
is_empty: FolderEmptiness::Maybe,
modified_date: get_modified_time(&metadata, warnings, current_folder, true),
},
));
}
#[fun_time(message = "delete_files", level = "debug")]

View file

@ -64,7 +64,6 @@ impl InvalidSymlinks {
debug!("Found {} invalid symlinks.", self.information.number_of_invalid_symlinks);
true
}
DirTraversalResult::SuccessFolders { .. } => unreachable!(),
DirTraversalResult::Stopped => false,
}
}

View file

@ -219,9 +219,7 @@ impl SameMusic {
debug!("check_files - Found {} music files.", self.music_to_check.len());
true
}
DirTraversalResult::SuccessFolders { .. } => {
unreachable!()
}
DirTraversalResult::Stopped => false,
}
}

View file

@ -198,7 +198,6 @@ impl SimilarImages {
check_folder_children(
&mut dir_result,
&mut warnings,
&current_folder,
&entry_data,
self.common_data.recursive_search,
&self.common_data.directories,
@ -206,7 +205,7 @@ impl SimilarImages {
);
} else if file_type.is_file() {
atomic_counter.fetch_add(1, Ordering::Relaxed);
self.add_file_entry(&current_folder, &entry_data, &mut fe_result, &mut warnings);
self.add_file_entry(&entry_data, &mut fe_result, &mut warnings);
}
}
(dir_result, warnings, fe_result)
@ -233,12 +232,12 @@ impl SimilarImages {
true
}
fn add_file_entry(&self, current_folder: &Path, entry_data: &DirEntry, fe_result: &mut Vec<(String, FileEntry)>, warnings: &mut Vec<String>) {
fn add_file_entry(&self, entry_data: &DirEntry, fe_result: &mut Vec<(String, FileEntry)>, warnings: &mut Vec<String>) {
if !self.common_data.allowed_extensions.check_if_entry_ends_with_extension(entry_data) {
return;
}
let current_file_name = current_folder.join(entry_data.file_name());
let current_file_name = entry_data.path();
if self.common_data.excluded_items.is_excluded(&current_file_name) {
return;
}
@ -249,16 +248,17 @@ impl SimilarImages {
// Checking files
if (self.common_data.minimal_file_size..=self.common_data.maximal_file_size).contains(&metadata.len()) {
let path_str = current_file_name.to_string_lossy().to_string();
let fe: FileEntry = FileEntry {
path: current_file_name.clone(),
size: metadata.len(),
dimensions: String::new(),
modified_date: get_modified_time(&metadata, warnings, &current_file_name, false),
path: current_file_name,
hash: Vec::new(),
similarity: 0,
};
fe_result.push((current_file_name.to_string_lossy().to_string(), fe));
fe_result.push((path_str, fe));
}
}

View file

@ -174,7 +174,6 @@ impl SimilarVideos {
check_folder_children(
&mut dir_result,
&mut warnings,
&current_folder,
&entry_data,
self.common_data.recursive_search,
&self.common_data.directories,
@ -182,7 +181,7 @@ impl SimilarVideos {
);
} else if file_type.is_file() {
atomic_counter.fetch_add(1, Ordering::Relaxed);
self.add_video_file_entry(&entry_data, &mut fe_result, &mut warnings, &current_folder);
self.add_video_file_entry(&entry_data, &mut fe_result, &mut warnings);
}
}
(dir_result, warnings, fe_result)
@ -207,12 +206,12 @@ impl SimilarVideos {
true
}
fn add_video_file_entry(&self, entry_data: &DirEntry, fe_result: &mut Vec<(String, FileEntry)>, warnings: &mut Vec<String>, current_folder: &Path) {
fn add_video_file_entry(&self, entry_data: &DirEntry, fe_result: &mut Vec<(String, FileEntry)>, warnings: &mut Vec<String>) {
if !self.common_data.allowed_extensions.check_if_entry_ends_with_extension(entry_data) {
return;
}
let current_file_name = current_folder.join(entry_data.file_name());
let current_file_name = entry_data.path();
if self.common_data.excluded_items.is_excluded(&current_file_name) {
return;
}

View file

@ -2,7 +2,7 @@ use std::fs;
use std::fs::DirEntry;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
@ -106,14 +106,13 @@ impl Temporary {
check_folder_children(
&mut dir_result,
&mut warnings,
&current_folder,
&entry_data,
self.common_data.recursive_search,
&self.common_data.directories,
&self.common_data.excluded_items,
);
} else if file_type.is_file() {
if let Some(file_entry) = self.get_file_entry(&atomic_counter, &entry_data, &mut warnings, &current_folder) {
if let Some(file_entry) = self.get_file_entry(&atomic_counter, &entry_data, &mut warnings) {
fe_result.push(file_entry);
}
}
@ -140,7 +139,7 @@ impl Temporary {
true
}
pub fn get_file_entry(&self, atomic_counter: &Arc<AtomicUsize>, entry_data: &DirEntry, warnings: &mut Vec<String>, current_folder: &Path) -> Option<FileEntry> {
pub fn get_file_entry(&self, atomic_counter: &Arc<AtomicUsize>, entry_data: &DirEntry, warnings: &mut Vec<String>) -> Option<FileEntry> {
atomic_counter.fetch_add(1, Ordering::Relaxed);
let file_name_lowercase = get_lowercase_name(entry_data, warnings)?;
@ -148,7 +147,7 @@ impl Temporary {
if !TEMP_EXTENSIONS.iter().any(|f| file_name_lowercase.ends_with(f)) {
return None;
}
let current_file_name = current_folder.join(entry_data.file_name());
let current_file_name = entry_data.path();
if self.common_data.excluded_items.is_excluded(&current_file_name) {
return None;
}

View file

@ -29,13 +29,13 @@ open = "5.0"
image = "0.24"
# To be able to use custom select
regex = "1.9"
regex = "1.10"
# To get image_hasher types
image_hasher = "1.2"
# Move files to trash
trash = "3.0"
trash = "3.1"
# For moving files(why std::fs doesn't have such features?)
fs_extra = "1.3"
@ -43,12 +43,12 @@ fs_extra = "1.3"
# Language
i18n-embed = { version = "0.14", features = ["fluent-system", "desktop-requester"] }
i18n-embed-fl = "0.7"
rust-embed = { version = "8.0", features = ["debug-embed"] }
once_cell = "1.18"
rust-embed = { version = "8.1", features = ["debug-embed"] }
once_cell = "1.19"
log = "0.4.20"
handsome_logger = "0.8"
fun_time = { version = "0.3.1", features = ["log"] }
fun_time = { version = "0.3", features = ["log"] }
czkawka_core = { path = "../czkawka_core", version = "6.1.0", features = [] }
gtk4 = { version = "0.7", default-features = false, features = ["v4_6"] }

View file

@ -1325,13 +1325,13 @@ fn computer_duplicate_finder(
}
}
fn vector_sort_unstable_entry_by_path(vector: &Vec<FileEntry>) -> Vec<FileEntry> {
fn vector_sort_unstable_entry_by_path(vector: &[FileEntry]) -> Vec<FileEntry> {
if vector.len() >= 2 {
let mut vector = vector.clone();
let mut vector = vector.to_owned();
vector.sort_unstable_by(|a, b| split_path_compare(a.path.as_path(), b.path.as_path()));
vector
} else {
vector.clone()
vector.to_owned()
}
}

View file

@ -83,6 +83,8 @@ fn build_ui(application: &Application, arguments: &[OsString]) {
let gui_data: GuiData = GuiData::new_with_application(application);
// Used for getting data from thread
// TODO - deprecation happened without any example, so not sure how new code should look like
#[allow(deprecated)]
let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(Priority::default());
// Futures progress report

View file

@ -257,7 +257,7 @@ impl LoadSaveStruct {
};
return Some((config_file_handler, config_file));
}
if !config_file.exists() || !config_file.is_file() {
if !config_file.is_file() {
if manual_execution {
// Don't show errors when there is no configuration file when starting app
add_text_to_text_view(

View file

@ -40,8 +40,8 @@ rayon = "1.8.0"
# Translations
i18n-embed = { version = "0.14", features = ["fluent-system", "desktop-requester"] }
i18n-embed-fl = "0.7"
rust-embed = { version = "8.0", features = ["debug-embed"] }
once_cell = "1.18"
rust-embed = { version = "8.1", features = ["debug-embed"] }
once_cell = "1.19"
[build-dependencies]
slint-build = "1.3"

View file

@ -3,11 +3,12 @@ use crate::{CurrentTab, GuiState, MainListModel, MainWindow, ProgressToSend};
use chrono::NaiveDateTime;
use crossbeam_channel::{Receiver, Sender};
use czkawka_core::common::{split_path, split_path_compare, DEFAULT_THREAD_SIZE};
use czkawka_core::common_dir_traversal::{FileEntry, FolderEntry, ProgressData};
use czkawka_core::common_dir_traversal::{FileEntry, ProgressData};
use czkawka_core::common_tool::CommonData;
use czkawka_core::common_traits::ResultEntry;
use czkawka_core::empty_files::EmptyFiles;
use czkawka_core::empty_folder::EmptyFolder;
use czkawka_core::empty_folder::FolderEntry;
use czkawka_core::similar_images;
use czkawka_core::similar_images::SimilarImages;
use humansize::{format_size, BINARY};

View file

@ -31,6 +31,8 @@ mod set_initial_gui_info;
mod settings;
use crossbeam_channel::{unbounded, Receiver, Sender};
use slint::VecModel;
use std::rc::Rc;
// use std::rc::Rc;
use crate::connect_delete::connect_delete_button;
@ -60,6 +62,10 @@ fn main() {
// to_remove_debug(&app);
// Slint files may already contains data in models, so clear them before starting - todo,
// check if non zeroed models are useful
zeroing_all_models(&app);
set_initial_gui_infos(&app);
create_default_settings_files();
@ -80,6 +86,12 @@ fn main() {
save_all_settings_to_file(&app);
}
pub fn zeroing_all_models(app: &MainWindow) {
app.set_empty_folder_model(Rc::new(VecModel::default()).into());
app.set_empty_files_model(Rc::new(VecModel::default()).into());
app.set_similar_images_model(Rc::new(VecModel::default()).into());
}
// // TODO remove this after debugging - or leave commented
// pub fn to_remove_debug(app: &MainWindow) {
// app.set_empty_folder_model(to_remove_create_without_header("@@").into());