From 27f73de78c9624865acd26f46cf3a7a1d3700c94 Mon Sep 17 00:00:00 2001 From: Jan Range <30547301+JR-1991@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:30:12 +0200 Subject: [PATCH 1/4] Add rfd and inquire dependencies Added 'rfd' and 'inquire' crates to Cargo.toml and updated Cargo.lock with their dependencies. This enables new functionality that relies on these libraries. --- Cargo.lock | 902 ++++++++++++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 2 + 2 files changed, 857 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30c7578..a0e27bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,6 +112,28 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ashpd" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbdf310d77fd3aaee6ea2093db7011dc2d35d2eb3481e5607f1f8d942ed99df" +dependencies = [ + "async-fs", + "async-net", + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.9.2", + "raw-window-handle", + "serde", + "serde_repr", + "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "zbus", +] + [[package]] name = "assert-json-diff" version = "2.0.2" @@ -122,6 +144,30 @@ dependencies = [ "serde_json", ] +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener 5.3.0", + "event-listener-strategy 0.5.4", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy 0.5.4", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-compression" version = "0.4.15" @@ -135,6 +181,50 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-executor" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix 0.38.44", + "slab", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "async-lock" version = "3.3.0" @@ -142,10 +232,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ "event-listener 4.0.3", - "event-listener-strategy", + "event-listener-strategy 0.4.0", "pin-project-lite", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + [[package]] name = "async-object-pool" version = "0.2.0" @@ -156,6 +257,59 @@ dependencies = [ "event-listener 5.3.0", ] +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener 5.3.0", + "futures-lite", + "rustix 1.0.3", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.44", + "signal-hook-registry", + "slab", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.80" @@ -191,13 +345,19 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -243,9 +403,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" dependencies = [ "serde", ] @@ -259,6 +419,28 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "bon" version = "3.6.3" @@ -331,6 +513,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.39" @@ -440,6 +628,15 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -514,6 +711,33 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags 2.9.4", + "crossterm_winapi", + "derive_more", + "document-features", + "mio", + "parking_lot", + "rustix 1.0.3", + "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 = "crypto-common" version = "0.1.6" @@ -629,6 +853,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "dialoguer" version = "0.12.0" @@ -674,6 +919,18 @@ dependencies = [ "windows-sys 0.61.1", ] +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.4", + "block2", + "libc", + "objc2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -685,12 +942,36 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + [[package]] name = "dotenvy" version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dvcli" version = "0.1.1" @@ -710,14 +991,16 @@ dependencies = [ "httpmock", "indicatif", "infer", + "inquire", "keyring", "lazy_static", "libdbus-sys", "md5", "mime_guess", - "rand 0.9.0-alpha.1", + "rand 0.9.2", "regress", "reqwest", + "rfd", "rpassword", "serde", "serde_json", @@ -766,6 +1049,33 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -825,6 +1135,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener 5.3.0", + "pin-project-lite", +] + [[package]] name = "exitcode" version = "1.1.2" @@ -1013,6 +1333,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1071,12 +1400,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - [[package]] name = "hashbrown" version = "0.15.2" @@ -1094,7 +1417,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.2", + "hashbrown", ] [[package]] @@ -1136,6 +1459,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1476,12 +1805,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown", ] [[package]] @@ -1506,6 +1835,20 @@ dependencies = [ "cfb", ] +[[package]] +name = "inquire" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2628910d0114e9139056161d8644a2026be7b117f8498943f9437748b04c9e0a" +dependencies = [ + "bitflags 2.9.4", + "crossterm", + "dyn-clone", + "fuzzy-matcher", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -1572,6 +1915,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + [[package]] name = "libm" version = "0.2.11" @@ -1584,7 +1937,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.4", "libc", ] @@ -1599,6 +1952,12 @@ dependencies = [ "vcpkg", ] +[[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.3" @@ -1611,6 +1970,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +[[package]] +name = "litrs" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" + [[package]] name = "lock_api" version = "0.4.12" @@ -1649,6 +2014,15 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -1690,6 +2064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -1712,6 +2087,19 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + [[package]] name = "num" version = "0.4.3" @@ -1803,6 +2191,55 @@ dependencies = [ "libm", ] +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.9.4", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.9.4", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.9.4", + "objc2", + "objc2-core-foundation", +] + [[package]] name = "object" version = "0.32.2" @@ -1824,7 +2261,7 @@ version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.4", "cfg-if", "foreign-types", "libc", @@ -1868,6 +2305,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "parking" version = "2.2.0" @@ -1953,6 +2400,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkcs1" version = "0.7.5" @@ -1980,6 +2438,27 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.44", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + [[package]] name = "portable-atomic" version = "1.6.0" @@ -2002,6 +2481,15 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.101" @@ -2011,6 +2499,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.41" @@ -2039,13 +2536,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0-alpha.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31e63ea85be51c423e52ba8f2e68a3efd53eed30203ee029dd09947333693e" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha 0.9.0-alpha.1", - "rand_core 0.9.0-alpha.1", - "zerocopy", + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -2060,12 +2556,12 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.9.0-alpha.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78674ef918c19451dbd250f8201f8619b494f64c9aa6f3adb28fd8a0f1f6da46" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.0-alpha.1", + "rand_core 0.9.3", ] [[package]] @@ -2079,21 +2575,26 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.0-alpha.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc89dffba8377c5ec847d12bb41492bda235dba31a25e8b695cd0fe6589eb8c9" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.2.15", - "zerocopy", + "getrandom 0.3.2", ] +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + [[package]] name = "redox_syscall" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.4", ] [[package]] @@ -2142,7 +2643,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145bb27393fe455dd64d6cbc8d059adfa392590a45eadf079c01b11857e7b010" dependencies = [ - "hashbrown 0.15.2", + "hashbrown", "memchr", ] @@ -2192,6 +2693,30 @@ dependencies = [ "winreg", ] +[[package]] +name = "rfd" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed" +dependencies = [ + "ashpd", + "block2", + "dispatch2", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "pollster", + "raw-window-handle", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.59.0", +] + [[package]] name = "rpassword" version = "7.4.0" @@ -2239,16 +2764,29 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + [[package]] name = "rustix" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.4", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.9.3", "windows-sys 0.59.0", ] @@ -2322,6 +2860,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -2334,7 +2878,7 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.4", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -2347,7 +2891,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.4", "core-foundation 0.10.0", "core-foundation-sys", "libc", @@ -2438,6 +2982,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "serde_tokenstream" version = "0.2.2" @@ -2509,6 +3064,27 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[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.2" @@ -2616,7 +3192,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.2", + "hashbrown", "hashlink", "indexmap", "log", @@ -2682,7 +3258,7 @@ checksum = "0afdd3aa7a629683c2d750c2df343025545087081ab5942593a5288855b1b7a7" dependencies = [ "atoi", "base64", - "bitflags 2.8.0", + "bitflags 2.9.4", "byteorder", "bytes", "crc", @@ -2724,7 +3300,7 @@ checksum = "a0bedbe1bbb5e2615ef347a5e9d8cd7680fb63e77d9dafc0f29be15e53f1ebe6" dependencies = [ "atoi", "base64", - "bitflags 2.8.0", + "bitflags 2.9.4", "byteorder", "crc", "dotenvy", @@ -2783,6 +3359,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stringmetrics" version = "2.2.2" @@ -2896,7 +3478,7 @@ dependencies = [ "fastrand", "getrandom 0.3.2", "once_cell", - "rustix", + "rustix 1.0.3", "windows-sys 0.59.0", ] @@ -2920,6 +3502,15 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -3009,6 +3600,36 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -3128,6 +3749,17 @@ dependencies = [ "typify-impl", ] +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset", + "tempfile", + "winapi", +] + [[package]] name = "unicase" version = "2.7.0" @@ -3164,6 +3796,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.2.1" @@ -3191,8 +3829,15 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf16_iter" version = "1.0.5" @@ -3371,6 +4016,66 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wayland-backend" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" +dependencies = [ + "cc", + "downcast-rs", + "rustix 1.0.3", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" +dependencies = [ + "bitflags 2.9.4", + "rustix 1.0.3", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" +dependencies = [ + "bitflags 2.9.4", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.69" @@ -3604,6 +4309,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.52.0" @@ -3620,7 +4334,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.4", ] [[package]] @@ -3635,6 +4349,16 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "xdg-home" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "yansi" version = "1.0.1" @@ -3666,23 +4390,66 @@ dependencies = [ ] [[package]] -name = "zerocopy" -version = "0.8.0-alpha.6" +name = "zbus" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db678a6ee512bd06adf35c35be471cae2f9c82a5aed2b5d15e03628c98bddd57" +checksum = "cbddd8b6cb25d5d8ec1b23277b45299a98bfb220f1761ca11e186d5c702507f8" dependencies = [ - "zerocopy-derive", + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener 5.3.0", + "futures-core", + "futures-util", + "hex", + "nix", + "ordered-stream", + "serde", + "serde_repr", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.59.0", + "winnow", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", ] [[package]] -name = "zerocopy-derive" -version = "0.8.0-alpha.6" +name = "zbus_macros" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201585ea96d37ee69f2ac769925ca57160cef31acb137c16f38b02b76f4c1e62" +checksum = "dac404d48b4e9cf193c8b49589f3280ceca5ff63519e7e64f55b4cf9c47ce146" dependencies = [ + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.106", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +dependencies = [ + "serde", + "static_assertions", + "winnow", + "zvariant", ] [[package]] @@ -3733,3 +4500,44 @@ dependencies = [ "quote", "syn 2.0.106", ] + +[[package]] +name = "zvariant" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" +dependencies = [ + "endi", + "enumflags2", + "serde", + "url", + "winnow", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.106", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.106", + "winnow", +] diff --git a/Cargo.toml b/Cargo.toml index 77b4d2b..f2c9ca2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,8 @@ bon = "3.6.3" rpassword = "7.3.1" dialoguer = "0.12.0" regress = "0.10.4" +rfd = "0.15.4" +inquire = "0.9.1" [target.'cfg(not(any(target_os = "macos", target_os = "windows")))'.dependencies] libdbus-sys = { version = "0.2.5", features = ["vendored"] } From b2a34718bd9ad249efa6e07d07d53bddba137729 Mon Sep 17 00:00:00 2001 From: Jan Range <30547301+JR-1991@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:30:29 +0200 Subject: [PATCH 2/4] Refactor file upload to use file picker utility Updated dataset and file CLI commands to use the new file_picker utility for selecting upload files, supporting both single and multiple file uploads. Refactored direct upload body creation to work with UploadFile objects and improved error handling for file selection and MIME type inference. --- src/cli/dataset.rs | 47 ++++++++++++++++++++++++++++------------------ src/cli/file.rs | 7 ++++++- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/cli/dataset.rs b/src/cli/dataset.rs index 357890b..b6a915a 100644 --- a/src/cli/dataset.rs +++ b/src/cli/dataset.rs @@ -16,6 +16,7 @@ use clap::Subcommand; use colored_json::Paint; use tokio::runtime::Runtime; +use crate::cli::file_picker::{pick_upload_file, FilePickerOptions}; use crate::client::{print_error, BaseClient}; use crate::data_access::datafile::DataFilePath; use crate::datasetversion::DatasetVersion; @@ -142,7 +143,7 @@ pub enum DatasetSubCommand { id: Identifier, #[arg(help = "Path or URL to the file to upload")] - path: CliUploadFile, + path: Option, #[arg(short, long, help = "Dataverse path to the file to upload")] dv_path: Option, @@ -348,7 +349,11 @@ impl Matcher for DatasetSubCommand { dv_path, } => { let body = Self::prepare_upload_body(body, &dv_path); - let mut path: UploadFile = path.into(); + + let cli_files = path.map(|p| PathBuf::from(p.0)).into_iter().collect(); + let mut path: UploadFile = + pick_upload_file(&FilePickerOptions::as_single(), cli_files) + .expect("Failed to pick file or no file provided"); if let FileSource::RemoteUrl(_) = &path.file { if let Some(dv_path) = &dv_path { @@ -379,7 +384,10 @@ impl Matcher for DatasetSubCommand { parallel, } => { // We are currently using the default body for direct upload. - // TODO: Allow custom bodies for future versions of the CLI + let paths: Vec = + pick_upload_file(&FilePickerOptions::as_multi(), paths) + .expect("Failed to pick files or no files provided"); + let bodies = paths .iter() .map(Self::create_direct_upload_body) @@ -709,24 +717,27 @@ impl DatasetSubCommand { /// /// # Arguments /// - /// * `path` - A reference to the PathBuf containing the file path + /// * `file` - A reference to the UploadFile containing the file path /// /// # Returns /// /// A DirectUploadBody with the filename set - fn create_direct_upload_body(path: &PathBuf) -> Result { - let filename = path - .file_name() - .and_then(|name| name.to_str()) - .map(String::from) - .unwrap_or_default(); - - let mime = infer_mime(path).map_err(|e| format!("Failed to infer mime type. Direct upload only supports files with known mime types. Error: {}", e))?; - - Ok(DirectUploadBody { - file_name: Some(filename), - mime_type: Some(mime), - ..Default::default() - }) + fn create_direct_upload_body(file: &UploadFile) -> Result { + match &file.file { + FileSource::Path(path) => { + let filename = path + .file_name() + .and_then(|f| f.to_str()) + .ok_or_else(|| "Failed to extract filename for direct upload".to_string())?; + let mime = infer_mime(path) + .map_err(|e| format!("Failed to infer mime type. Direct upload only supports files with known mime types. Error: {}", e))?; + Ok(DirectUploadBody { + file_name: Some(filename.to_string()), + mime_type: Some(mime), + ..Default::default() + }) + } + _ => Err("Direct upload only supports local files".to_string()), + } } } diff --git a/src/cli/file.rs b/src/cli/file.rs index b634639..a1ea3e6 100644 --- a/src/cli/file.rs +++ b/src/cli/file.rs @@ -9,8 +9,10 @@ use std::path::PathBuf; use clap::Subcommand; +use crate::cli::file_picker::{pick_upload_file, FilePickerOptions}; use crate::data_access; use crate::data_access::datafile::DataFilePath; +use crate::file::UploadFile; use crate::native_api::file::replace; use crate::prelude::file::metadata; use crate::prelude::{DatasetVersion, Identifier}; @@ -75,9 +77,12 @@ impl Matcher for FileSubCommand { body, force, } => { + let cli_files = vec![path]; + let path: UploadFile = pick_upload_file(&FilePickerOptions::as_single(), cli_files) + .expect("Failed to pick file or no file provided"); let body = prepare_replace_body(&body, &force); let response = - runtime.block_on(replace::replace_file(client, &id, path.clone(), body, None)); + runtime.block_on(replace::replace_file(client, &id, path, body, None)); evaluate_and_print_response(response); } From 5aea719788e5fdd470545564fedb709d1538f86c Mon Sep 17 00:00:00 2001 From: Jan Range <30547301+JR-1991@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:30:35 +0200 Subject: [PATCH 3/4] Add file picker module for CLI file selection Introduces src/cli/file_picker.rs, providing FilePickerOptions, FilePickerResult, and functions for selecting files via GUI or TTY. Also registers the new file_picker module in src/lib.rs. This enables flexible file selection for CLI workflows, supporting both single and multiple file picking. --- src/cli/file_picker.rs | 242 +++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + 2 files changed, 244 insertions(+) create mode 100644 src/cli/file_picker.rs diff --git a/src/cli/file_picker.rs b/src/cli/file_picker.rs new file mode 100644 index 0000000..59f5ee9 --- /dev/null +++ b/src/cli/file_picker.rs @@ -0,0 +1,242 @@ +use std::path::PathBuf; + +use crate::file::UploadFile; + +/// Configuration options for file selection. +/// +/// This struct controls how files are selected, including whether multiple files can be picked +/// and whether to use a GUI dialog or command-line prompt. +#[derive(Debug, Clone)] +pub struct FilePickerOptions { + /// If `true`, allow selecting multiple files. + pub multi: bool, + /// If `true`, force TTY prompt instead of GUI dialog. + pub no_gui: bool, +} + +impl Default for FilePickerOptions { + /// Returns the default configuration for file picking (single file, GUI allowed). + fn default() -> Self { + Self { + multi: false, + no_gui: false, + } + } +} + +impl FilePickerOptions { + /// Creates a new `FilePickerOptions` with default settings (single file, GUI allowed). + pub fn new() -> Self { + Self::default() + } + + /// Creates options for multiple file selection. + pub fn as_multi() -> Self { + Self { + multi: true, + no_gui: false, + } + } + + /// Creates options for single file selection. + pub fn as_single() -> Self { + Self::default() + } + + /// Sets whether to allow multiple file selection. + pub fn multi(mut self, multi: bool) -> Self { + self.multi = multi; + self + } + + /// Sets whether to disable the GUI file picker. + pub fn no_gui(mut self, no_gui: bool) -> Self { + self.no_gui = no_gui; + self + } +} + +/// The result of a file picking operation. +/// +/// This enum represents either a single file or multiple files selected by the user. +pub enum FilePickerResult { + /// A single file was selected. + Single(PathBuf), + /// Multiple files were selected. + Multiple(Vec), +} + +impl From> for FilePickerResult { + /// Converts a vector of `PathBuf` into a `FilePickerResult::Multiple`. + fn from(files: Vec) -> Self { + FilePickerResult::Multiple(files) + } +} + +impl From for FilePickerResult { + /// Converts a single `PathBuf` into a `FilePickerResult::Single`. + fn from(file: PathBuf) -> Self { + FilePickerResult::Single(file) + } +} + +impl Into> for FilePickerResult { + /// Converts a `FilePickerResult` into a vector of `UploadFile`. + fn into(self) -> Vec { + match self { + FilePickerResult::Single(path) => vec![UploadFile::from(path)], + FilePickerResult::Multiple(paths) => paths.into_iter().map(UploadFile::from).collect(), + } + } +} + +impl Into for FilePickerResult { + /// Converts a `FilePickerResult::Single` into an `UploadFile`. + /// + /// # Panics + /// + /// Panics if called on `FilePickerResult::Multiple`. + fn into(self) -> UploadFile { + match self { + FilePickerResult::Single(path) => UploadFile::from(path), + FilePickerResult::Multiple(_) => { + panic!("Multiple files are not supported for this operation."); + } + } + } +} + +/// Picks a file for upload, converting the result to the specified type. +/// +/// This is a convenience wrapper around `pick_files` that handles conversion to the desired type. +/// +/// # Arguments +/// +/// * `options` - The file picker configuration options. +/// * `files` - A vector of pre-selected file paths. +/// +/// # Returns +/// +/// An `Option` containing the converted result, or `None` if no files were selected. +pub fn pick_upload_file(options: &FilePickerOptions, files: Vec) -> Option +where + FilePickerResult: Into, +{ + pick_files(options, files).map(|result| result.into()) +} + +/// Picks files based on the provided options and optional pre-selected files. +/// +/// The selection priority is as follows: +/// 1. If `files` contains paths, use them directly. +/// 2. If GUI is allowed and available, show GUI file picker dialog. +/// 3. Otherwise, use TTY prompt. +/// +/// # Arguments +/// +/// * `options` - The file picker configuration options. +/// * `files` - A vector of pre-selected file paths. +/// +/// # Returns +/// +/// An `Option` containing the selected files, or `None` if no files were selected. +pub fn pick_files(options: &FilePickerOptions, files: Vec) -> Option { + if !files.is_empty() { + return Some(files.into()); + } + + if !options.no_gui && gui_probably_available() { + if let Some(result) = pick_files_gui(options.multi) { + return Some(result); + } + eprintln!("No file selected via GUI; falling back to TTY prompt…"); + } + + Some(pick_file_tty(options.multi).into()) +} + +/// Checks if a GUI is probably available on the current platform. +/// +/// On Linux, this checks for the presence of the `DISPLAY` or `WAYLAND_DISPLAY` environment variables. +/// On macOS and Windows, this always returns `true`. +/// On other platforms, this returns `false`. +fn gui_probably_available() -> bool { + #[cfg(target_os = "linux")] + { + std::env::var_os("DISPLAY").is_some() || std::env::var_os("WAYLAND_DISPLAY").is_some() + } + #[cfg(any(target_os = "macos", target_os = "windows"))] + { + true + } + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] + { + false + } +} + +/// Shows a GUI file picker dialog to the user. +/// +/// If `multi` is `true`, allows selecting multiple files. Otherwise, only a single file can be selected. +/// +/// # Arguments +/// +/// * `multi` - Whether to allow multiple file selection. +/// +/// # Returns +/// +/// An `Option` containing the selected files, or `None` if no files were selected. +fn pick_files_gui(multi: bool) -> Option { + let dlg = rfd::FileDialog::new(); + + if multi { + dlg.pick_files().map(|files| files.into()) + } else { + dlg.pick_file().map(|file| file.into()) + } +} + +/// Prompts the user for file path(s) via TTY (command-line). +/// +/// If `multi` is `true`, prompts for comma-separated file paths. Otherwise, prompts for a single file path +/// and validates that the path exists. +/// +/// # Arguments +/// +/// * `multi` - Whether to allow multiple file selection. +/// +/// # Returns +/// +/// A vector of `PathBuf` containing the selected file paths. +fn pick_file_tty(multi: bool) -> Vec { + use inquire::{validator::Validation, Text}; + + if multi { + let input = Text::new("Enter file paths (comma-separated):") + .prompt() + .unwrap_or_default(); + input + .split(',') + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + .map(PathBuf::from) + .collect() + } else { + let path_str = Text::new("Enter a file path:") + .with_validator(|input: &str| { + if PathBuf::from(input).exists() { + Ok(Validation::Valid) + } else { + Ok(Validation::Invalid("Path does not exist".into())) + } + }) + .prompt() + .unwrap_or_default(); + + if path_str.is_empty() { + vec![] + } else { + vec![PathBuf::from(path_str)] + } + } +} diff --git a/src/lib.rs b/src/lib.rs index e5125d3..2c52914 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -226,6 +226,8 @@ pub mod cli { pub mod dataset; /// File commands pub mod file; + /// File picker functionality + pub mod file_picker; /// Information commands pub mod info; } From c31a544c49360f81f290693351572ced394c2416 Mon Sep 17 00:00:00 2001 From: Jan Range <30547301+JR-1991@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:49:15 +0200 Subject: [PATCH 4/4] Restrict GUI file picker to macOS and Windows Moved the rfd dependency to only build on macOS and Windows, and updated file picker logic to only use the GUI picker on those platforms. On other platforms, file selection now always falls back to TTY prompts. --- Cargo.toml | 4 +++- src/cli/file_picker.rs | 23 ++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f2c9ca2..98c0c39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,9 +57,11 @@ bon = "3.6.3" rpassword = "7.3.1" dialoguer = "0.12.0" regress = "0.10.4" -rfd = "0.15.4" inquire = "0.9.1" +[target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies] +rfd = "0.15.4" + [target.'cfg(not(any(target_os = "macos", target_os = "windows")))'.dependencies] libdbus-sys = { version = "0.2.5", features = ["vendored"] } diff --git a/src/cli/file_picker.rs b/src/cli/file_picker.rs index 59f5ee9..33b72d2 100644 --- a/src/cli/file_picker.rs +++ b/src/cli/file_picker.rs @@ -145,11 +145,14 @@ pub fn pick_files(options: &FilePickerOptions, files: Vec) -> Option) -> Option bool { - #[cfg(target_os = "linux")] - { - std::env::var_os("DISPLAY").is_some() || std::env::var_os("WAYLAND_DISPLAY").is_some() - } #[cfg(any(target_os = "macos", target_os = "windows"))] { true } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] + #[cfg(not(any(target_os = "macos", target_os = "windows")))] { false } @@ -179,6 +177,8 @@ fn gui_probably_available() -> bool { /// /// If `multi` is `true`, allows selecting multiple files. Otherwise, only a single file can be selected. /// +/// This function is only available on macOS and Windows. +/// /// # Arguments /// /// * `multi` - Whether to allow multiple file selection. @@ -186,6 +186,7 @@ fn gui_probably_available() -> bool { /// # Returns /// /// An `Option` containing the selected files, or `None` if no files were selected. +#[cfg(any(target_os = "macos", target_os = "windows"))] fn pick_files_gui(multi: bool) -> Option { let dlg = rfd::FileDialog::new();