diff --git a/Cargo.lock b/Cargo.lock --- a/Cargo.lock +++ b/Cargo.lock @@ -27,6 +27,54 @@ "memchr", ] [[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -54,6 +102,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -75,6 +129,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.48.5", +] + +[[package]] name = "color-eyre" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -102,6 +168,21 @@ "tracing-error", ] [[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "erased-serde" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55d05712b2d8d88102bc9868020c9e5c7a1f5527c452b9b97450a1d006140ba7" +dependencies = [ + "serde", +] + +[[package]] name = "eyre" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -112,6 +193,104 @@ "once_cell", ] [[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -124,18 +303,66 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] +name = "iana-time-zone" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] name = "indenter" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] +name = "inventory" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8573b2b1fb643a372c73b23f4da5f888677feef3305146d68a539250a9bccc7" + +[[package]] name = "itoa" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] +name = "js-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +dependencies = [ + "wasm-bindgen", +] + +[[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -158,6 +385,21 @@ "scopeguard", ] [[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] name = "memchr" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -184,6 +426,15 @@ "windows-sys", ] [[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -194,6 +445,15 @@ "libc", ] [[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] name = "object" version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -234,14 +494,26 @@ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] name = "pin-project-lite" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" @@ -256,11 +528,18 @@ [[package]] name = "ptsd" version = "0.1.0" dependencies = [ + "async-stream", + "async-trait", "color-eyre", + "futures", + "libc", "regex", "serde", "serde_json", "tokio", + "tokio-stream", + "trash", + "typetag", "wildmatch", ] @@ -379,6 +658,15 @@ "libc", ] [[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] name = "smallvec" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -406,6 +694,21 @@ "once_cell", ] [[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] name = "tokio" version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -435,6 +738,17 @@ "syn", ] [[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -476,12 +790,78 @@ "tracing-core", ] [[package]] +name = "trash" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e7b1a28f9550f43ac27987f2144d7798520c6dee6a7eb1dedfe3131e3c257e3" +dependencies = [ + "chrono", + "libc", + "log", + "objc", + "once_cell", + "scopeguard", + "url", + "windows", +] + +[[package]] +name = "typetag" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43148481c7b66502c48f35b8eef38b6ccdc7a9f04bd4cc294226d901ccc9bc7" +dependencies = [ + "erased-serde", + "inventory", + "once_cell", + "serde", + "typetag-impl", +] + +[[package]] +name = "typetag-impl" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291db8a81af4840c10d636e047cac67664e343be44e24dfdbd1492df9a5d3390" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" + +[[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -494,18 +874,105 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] +name = "wasm-bindgen" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" + +[[package]] name = "wildmatch" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "495ec47bf3c1345005f40724f0269362c8556cbc43aed0526ed44cae1d35fceb" [[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -514,26 +981,71 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" @@ -542,16 +1054,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" @@ -560,7 +1108,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,16 @@ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-stream = "0.3.5" +async-trait = "0.1.77" color-eyre = "0.6.2" +futures = "0.3.30" +libc = "0.2.152" regex = "1.10.2" serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" tokio = { version = "1.35.1", default-features = false, features = ["rt-multi-thread", "fs", "io-std", "io-util", "macros", "process", "parking_lot", "mio"] } +tokio-stream = { version = "0.1.14", features = ["fs"] } +trash = "3.2.0" +typetag = "0.2.15" wildmatch = "2.3.0" diff --git a/flake.nix b/flake.nix --- a/flake.nix +++ b/flake.nix @@ -36,9 +36,16 @@ formatter = pkgs.alejandra; devenv.shells.default = { languages.rust = { - enable = true; - channel = "nightly"; + enable = true; }; + + packages = + [] + ++ pkgs.lib.lists.optionals pkgs.stdenv.isDarwin (with pkgs.darwin.apple_sdk; [ + frameworks.Foundation + pkgs.libiconv + pkgs.darwin.libobjc + ]); }; }; }; diff --git a/src/filters.rs b/src/filters.rs new file mode 100644 --- /dev/null +++ b/src/filters.rs @@ -0,0 +1,91 @@ +use std::path::Path; + +use async_trait::async_trait; +use serde::Deserialize; +use tokio::fs; + +use crate::pattern::Pattern; + +#[typetag::deserialize(tag = "type")] +#[async_trait] +pub trait Filter: std::fmt::Debug { + async fn matches(&self, path: &Path) -> bool; +} + +#[derive(Debug, Deserialize)] +pub struct Name(Pattern); + +#[typetag::deserialize(name = "name")] +#[async_trait] +impl Filter for Name { + async fn matches(&self, path: &Path) -> bool { + self.0.matches(path) + } +} + +#[derive(Debug, Deserialize)] +pub struct Size { + size: u64, + #[serde(with = "Ordering")] + ordering: std::cmp::Ordering, +} + +#[derive(Deserialize)] +#[serde(remote = "std::cmp::Ordering")] +enum Ordering { + Less, + Equal, + Greater, +} + +#[typetag::deserialize(name = "size")] +#[async_trait] +impl Filter for Size { + async fn matches(&self, path: &Path) -> bool { + with_metadata(path, |metadata| { + let len = metadata.len(); + + self.size.cmp(&len) == self.ordering + }) + .await + } +} + +#[derive(Debug, Deserialize)] +pub enum FileType { + Dir, + File, + Symlink, +} + +#[typetag::deserialize(name = "file_type")] +#[async_trait] +impl Filter for FileType { + async fn matches(&self, path: &Path) -> bool { + use FileType::*; + + with_metadata(path, |metadata| { + let ft = metadata.file_type(); + + match *self { + Dir => ft.is_dir(), + File => ft.is_file(), + Symlink => ft.is_symlink(), + } + }) + .await + } +} + +async fn with_metadata(path: &Path, fun: F) -> bool +where + F: FnOnce(std::fs::Metadata) -> bool, +{ + fs::metadata(path).await.map(fun).unwrap_or(false) +} + +#[derive(Debug, Deserialize)] +pub enum Magic { + Mime(String), + Bytes(Box<[u8]>), +} diff --git a/src/job.rs b/src/job.rs --- a/src/job.rs +++ b/src/job.rs @@ -1,66 +1,50 @@ use color_eyre::eyre::Result; -use std::fmt; use std::path::{Path, PathBuf}; use tokio::fs; use tokio::process::Command; +use tokio_stream::wrappers::ReadDirStream; -use serde::{de, Deserialize}; -use wildmatch::WildMatch; +use futures::prelude::*; + +use serde::Deserialize; + +use crate::filters::Filter; /// Definition of the job files #[derive(Debug, Deserialize)] pub struct Job { - pattern: Pattern, + filters: Vec>, location: PathBuf, actions: Vec, } impl Job { - pub async fn run(&self) -> Result<()> { + pub async fn run(&self) -> Result + '_> { let loc = normalise_path(&self.location); - let mut dir = fs::read_dir(&loc).await?; + let dir = ReadDirStream::new(fs::read_dir(&loc).await?); - while let Some(entry) = dir.next_entry().await? { - if self.pattern.matches(entry.file_name().as_ref()) { - self.execute_actions(&loc, entry.path().as_ref()).await; + Ok(async_stream::stream! { + for await entry in dir { + let entry = entry.unwrap(); + if self.matches_filters(&entry.path()).await { + for action in &self.actions { + yield (action.clone(), entry.path()) + } + } } - } - - Ok(()) - } - - async fn execute_actions(&self, loc: &Path, path: &Path) { - for action in &self.actions { - action.execute(loc, path).await; - } + }) } -} -/// Patterns that can be matched against files -#[derive(Debug, Deserialize)] -pub enum Pattern { - #[serde(deserialize_with = "deserialize_wildcard")] - Wildcard(WildMatch), - #[serde(deserialize_with = "deserialize_regex")] - Regex(regex::Regex), - Exact(Box), -} - -impl Pattern { - pub fn matches(&self, path: &Path) -> bool { - match *self { - Self::Wildcard(ref pattern) => pattern.matches(path.to_str().unwrap()), - Self::Regex(ref pattern) => pattern.is_match(path.to_str().unwrap()), - Self::Exact(ref pattern) => **pattern == *path, - } + async fn matches_filters(&self, path: &Path) -> bool { + stream::iter(&self.filters).all(|f| f.matches(path)).await } } /// Actions available for file -#[derive(Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize)] #[serde(untagged)] pub enum Action { /// Run given script with 1st argument. It will be ran in parent directory for given file @@ -69,15 +53,17 @@ /// Move given file to new destination Move { move_to: Box }, /// Print message and do nothing Echo { message: String }, + /// Move to trash + Trash, } impl Action { - pub async fn execute(&self, dir: &Path, source: &Path) { - match *self { + pub async fn execute(self, source: PathBuf) { + match self { Action::Script { ref script } => { Command::new(script.as_ref()) - .arg(source) - .current_dir(dir) + .arg(&source) + .current_dir(source.parent().unwrap()) .spawn() .expect("Couldnt spawn process") .wait() @@ -85,10 +71,12 @@ .await .expect("Child exited abnormally"); } - Action::Move { move_to: ref dest_dir } => { + Action::Move { + move_to: ref dest_dir, + } => { let dest = normalise_path(dest_dir).join(source.file_name().unwrap()); - if let Err(err) = std::fs::rename(source, &dest) { - if err.kind() == std::io::ErrorKind::CrossesDevices { + if let Err(err) = fs::rename(&source, &dest).await { + if err.raw_os_error() == Some(libc::EXDEV) { panic!("X dev"); } else { panic!("Cannot move {source:?} -> {dest:?}: {err:?}"); @@ -97,6 +85,8 @@ } } Action::Echo { ref message } => println!("{source:?} - {message}"), + + Action::Trash => trash::delete(source).unwrap(), } } } @@ -107,57 +97,3 @@ Ok(prefix) => std::env::home_dir().unwrap().join(prefix), Err(_) => path.to_owned(), } } - -struct RegexVisitor; - -impl<'de> de::Visitor<'de> for RegexVisitor { - type Value = regex::Regex; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "expected regex string") - } - - fn visit_str(self, s: &str) -> Result - where - E: de::Error, - { - match regex::Regex::new(s) { - Ok(regex) => Ok(regex), - Err(regex::Error::Syntax(ref desc)) => { - Err(E::invalid_value(de::Unexpected::Str(s), &desc.as_str())) - } - Err(_) => unreachable!(), - } - } -} - -fn deserialize_regex<'de, D>(des: D) -> Result -where - D: serde::Deserializer<'de>, -{ - des.deserialize_str(RegexVisitor) -} - -struct WildcardVisitor; - -impl<'de> de::Visitor<'de> for WildcardVisitor { - type Value = WildMatch; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "expected regex string") - } - - fn visit_str(self, s: &str) -> Result - where - E: de::Error, - { - Ok(WildMatch::new(s)) - } -} - -fn deserialize_wildcard<'de, D>(des: D) -> Result -where - D: serde::Deserializer<'de>, -{ - des.deserialize_str(WildcardVisitor) -} diff --git a/src/main.rs b/src/main.rs --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,34 @@ -#![feature(io_error_more)] - use color_eyre::eyre::Result; +use tokio_stream::iter; +use futures::StreamExt; +mod filters; mod job; +mod pattern; -const data: &str = r#" -{ - "pattern": {"Wildcard": "*.dmg"}, - "location": "~/Downloads", - "actions": [ - {"message": "move to ~/Documents/Gitara/"} - ] -}"#; +const DATA: &str = r#" +[ + { + "filters": [ + {"type": "name", "Wildcard": "*.dmg"} + ], + "location": "~/Downloads", + "actions": [ + {"message": "move to ~/Documents/Gitara/"} + ] + } +]"#; #[tokio::main] async fn main() -> Result<()> { - println!("{data}"); - let j: job::Job = serde_json::from_str(data).unwrap(); + let jobs: Vec = serde_json::from_str(DATA).unwrap(); - j.run().await?; - - println!("{j:?}"); + iter(&jobs) + .then(|job| job.run()) + .map(|result| result.unwrap()) + .flatten() + .for_each_concurrent(None, |(action, path)| action.execute(path)) + .await; Ok(()) } diff --git a/src/pattern.rs b/src/pattern.rs new file mode 100644 --- /dev/null +++ b/src/pattern.rs @@ -0,0 +1,79 @@ +use std::fmt; +use std::path::Path; + +use serde::{de, Deserialize}; +use wildmatch::WildMatch; + +/// Patterns that can be matched against files +#[derive(Debug, Deserialize)] +pub enum Pattern { + #[serde(deserialize_with = "deserialize_wildcard")] + Wildcard(WildMatch), + #[serde(deserialize_with = "deserialize_regex")] + Regex(regex::Regex), + Exact(Box), +} + +impl Pattern { + pub fn matches(&self, path: &Path) -> bool { + match *self { + Self::Wildcard(ref pattern) => pattern.matches(path.to_str().unwrap()), + Self::Regex(ref pattern) => pattern.is_match(path.to_str().unwrap()), + Self::Exact(ref pattern) => **pattern == *path, + } + } +} + +struct RegexVisitor; + +impl<'de> de::Visitor<'de> for RegexVisitor { + type Value = regex::Regex; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "expected regex string") + } + + fn visit_str(self, s: &str) -> Result + where + E: de::Error, + { + match regex::Regex::new(s) { + Ok(regex) => Ok(regex), + Err(regex::Error::Syntax(ref desc)) => { + Err(E::invalid_value(de::Unexpected::Str(s), &desc.as_str())) + } + Err(_) => unreachable!(), + } + } +} + +fn deserialize_regex<'de, D>(des: D) -> Result +where + D: serde::Deserializer<'de>, +{ + des.deserialize_str(RegexVisitor) +} + +struct WildcardVisitor; + +impl<'de> de::Visitor<'de> for WildcardVisitor { + type Value = WildMatch; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "expected regex string") + } + + fn visit_str(self, s: &str) -> Result + where + E: de::Error, + { + Ok(WildMatch::new(s)) + } +} + +fn deserialize_wildcard<'de, D>(des: D) -> Result +where + D: serde::Deserializer<'de>, +{ + des.deserialize_str(WildcardVisitor) +}