From 3c79e812ebf2f7b7bbfa3b91576e4dea6404f327 Mon Sep 17 00:00:00 2001 From: veeso Date: Sat, 6 Sep 2025 16:40:01 +0200 Subject: [PATCH 01/14] build: 0.19 deps --- .github/workflows/build-artifacts.yml | 2 +- Cargo.lock | 964 +++++++++++++------------- Cargo.toml | 19 +- README.md | 2 +- docs/de/README.md | 2 +- docs/es/README.md | 2 +- docs/fr/README.md | 2 +- docs/it/README.md | 2 +- docs/pt-BR/README.md | 2 +- docs/zh-CN/README.md | 2 +- install.sh | 2 +- site/html/get-started.html | 4 +- site/html/home.html | 2 +- site/lang/en.json | 4 +- site/lang/es.json | 4 +- site/lang/fr.json | 4 +- site/lang/it.json | 4 +- site/lang/zh-CN.json | 4 +- src/filetransfer/remotefs_builder.rs | 12 +- 19 files changed, 522 insertions(+), 517 deletions(-) diff --git a/.github/workflows/build-artifacts.yml b/.github/workflows/build-artifacts.yml index 1dd2a50..fcc49a3 100644 --- a/.github/workflows/build-artifacts.yml +++ b/.github/workflows/build-artifacts.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: env: - TERMSCP_VERSION: "0.18.0" + TERMSCP_VERSION: "0.19.0" jobs: build-binaries: diff --git a/Cargo.lock b/Cargo.lock index aaa76c4..6ebfc98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,15 +60,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" dependencies = [ "derive_arbitrary", ] @@ -119,15 +119,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-config" -version = "1.6.3" +version = "1.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a18fd934af6ae7ca52410d4548b98eb895aab0f1ea417d168d85db1434a141" +checksum = "8bc1b40fb26027769f16960d2f4a6bc20c4bb755d403e552c8c1a73af433c246" dependencies = [ "aws-credential-types", "aws-runtime", @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.3" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687bc16bc431a8533fe0097c7f0182874767f920989d7260950172ae8e3c4465" +checksum = "d025db5d9f52cbc413b167136afb3d8aeea708c0d8884783cf6253be5e22f6f2" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.13.1" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" +checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" dependencies = [ "aws-lc-sys", "zeroize", @@ -177,9 +177,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" +checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" dependencies = [ "bindgen", "cc", @@ -190,9 +190,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.7" +version = "1.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c4063282c69991e57faab9e5cb21ae557e59f5b0fb285c196335243df8dc25c" +checksum = "c034a1bc1d70e16e7f4e4caf7e9f7693e4c9c24cd91cf17c2a0b21abaebc7c8b" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -215,9 +215,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.91.0" +version = "1.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10c7d58f9c99e7d33e5a9b288ec84db24de046add7ba4c1e98baf6b3a5b37fde" +checksum = "38c488cd6abb0ec9811c401894191932e941c5f91dc226043edacd0afa1634bc" dependencies = [ "aws-credential-types", "aws-runtime", @@ -249,9 +249,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.72.0" +version = "1.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13118ad30741222f67b1a18e5071385863914da05124652b38e172d6d3d9ce31" +checksum = "643cd43af212d2a1c4dedff6f044d7e1961e5d9e7cfe773d70f31d9842413886" dependencies = [ "aws-credential-types", "aws-runtime", @@ -271,9 +271,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.73.0" +version = "1.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f879a8572b4683a8f84f781695bebf2f25cf11a81a2693c31fc0e0215c2c1726" +checksum = "20ec4a95bd48e0db7a424356a161f8d87bd6a4f0af37204775f0da03d9e39fc3" dependencies = [ "aws-credential-types", "aws-runtime", @@ -293,9 +293,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.73.0" +version = "1.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1e9c3c24e36183e2f698235ed38dcfbbdff1d09b9232dc866c4be3011e0b47e" +checksum = "410309ad0df4606bc721aff0d89c3407682845453247213a0ccc5ff8801ee107" dependencies = [ "aws-credential-types", "aws-runtime", @@ -316,9 +316,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.3.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3734aecf9ff79aa401a6ca099d076535ab465ff76b46440cf567c8e70b65dc13" +checksum = "084c34162187d39e3740cb635acd73c4e3a551a36146ad6fe8883c929c9f876c" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", @@ -355,9 +355,9 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.63.3" +version = "0.63.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f77a921dbd2c78ebe70726799787c1d110a2245dd65e39b20923dfdfb2deee" +checksum = "56d2df0314b8e307995a3b86d44565dfe9de41f876901a7d71886c756a25979f" dependencies = [ "aws-smithy-http", "aws-smithy-types", @@ -375,9 +375,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.8" +version = "0.60.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c45d3dddac16c5c59d553ece225a88870cf81b7b813c9cc17b78cf4685eac7a" +checksum = "182b03393e8c677347fb5705a04a9392695d47d20ef0a2f8cfe28c8e6b9b9778" dependencies = [ "aws-smithy-types", "bytes", @@ -386,9 +386,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.62.1" +version = "0.62.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99335bec6cdc50a346fda1437f9fefe33abf8c99060739a546a16457f2862ca9" +checksum = "7c4dacf2d38996cf729f55e7a762b30918229917eca115de45dfa8dfb97796c9" dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", @@ -407,38 +407,39 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "073d330f94bdf1f47bb3e0f5d45dda1e372a54a553c39ab6e9646902c8c81594" +checksum = "147e8eea63a40315d704b97bf9bc9b8c1402ae94f89d5ad6f7550d963309da1b" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", - "h2 0.3.26", - "h2 0.4.10", + "h2 0.3.27", + "h2 0.4.12", "http 0.2.12", "http 1.3.1", "http-body 0.4.6", "hyper 0.14.32", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-rustls 0.24.2", "hyper-rustls 0.27.7", "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.27", + "rustls 0.23.31", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", + "tokio-rustls 0.26.2", "tower 0.5.2", "tracing", ] [[package]] name = "aws-smithy-json" -version = "0.61.3" +version = "0.61.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92144e45819cae7dc62af23eac5a038a58aa544432d2102609654376a900bd07" +checksum = "eaa31b350998e703e9826b2104dd6f63be0508666e1aba88137af060e8944047" dependencies = [ "aws-smithy-types", ] @@ -464,9 +465,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.8.3" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14302f06d1d5b7d333fd819943075b13d27c7700b414f574c3c35859bfb55d5e" +checksum = "d3946acbe1ead1301ba6862e712c7903ca9bb230bdf1fbd1b5ac54158ef2ab1f" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -488,9 +489,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e5d9e3a80a18afa109391fb5ad09c3daf887b516c6fd805a157c6ea7994a57" +checksum = "07f5e0fc8a6b3f2303f331b94504bbf754d85488f402d6f1dd7a6080f99afe56" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -505,9 +506,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40076bd09fadbc12d5e026ae080d0930defa606856186e31d83ccc6a255eeaf3" +checksum = "d498595448e43de7f4296b7b7a18a8a02c61ec9349128c80a368f7c3b4ab11a8" dependencies = [ "base64-simd", "bytes", @@ -531,18 +532,18 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.9" +version = "0.60.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" +checksum = "3db87b96cb1b16c024980f133968d52882ca0daaee3a086c6decc500f6c99728" dependencies = [ "xmlparser", ] [[package]] name = "aws-types" -version = "1.3.7" +version = "1.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a322fec39e4df22777ed3ad8ea868ac2f94cd15e1a55f6ee8d8d6305057689a" +checksum = "b069d19bf01e46298eaedd7c6f283fe565a59263e53eebec945f3e6398f42390" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -607,7 +608,7 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools 0.12.1", @@ -632,9 +633,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "block-buffer" @@ -665,9 +666,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.18.1" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byteorder" @@ -708,9 +709,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.10" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" +checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" dependencies = [ "serde", ] @@ -735,7 +736,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -746,9 +747,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "castaway" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" dependencies = [ "rustversion", ] @@ -764,10 +765,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.26" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -784,9 +786,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "cfg_aliases" @@ -806,7 +808,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -951,23 +953,22 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc-fast" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68fcb2be5386ffb77e30bf10820934cb89a628bcb976e7cc632dcd88c059ebea" +checksum = "6bf62af4cc77d8fe1c22dde4e721d87f2f54056139d8c412e1366b740305f56f" dependencies = [ - "cc", "crc", "digest", "libc", - "rand 0.9.1", + "rand 0.9.2", "regex", ] [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -1003,7 +1004,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "crossterm_winapi", "mio", "parking_lot", @@ -1019,13 +1020,13 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "crossterm_winapi", "derive_more", "document-features", "mio", "parking_lot", - "rustix 1.0.7", + "rustix 1.0.8", "signal-hook", "signal-hook-mio", "winapi", @@ -1142,27 +1143,24 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dbus" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +checksum = "190b6255e8ab55a7b568df5a883e9497edc3e4821c06396612048b430e5ad1e9" dependencies = [ "libc", "libdbus-sys", - "winapi", + "windows-sys 0.59.0", ] [[package]] name = "dbus-secret-service" -version = "4.0.3" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42a16374481d92aed73ae45b1f120207d8e71d24fb89f357fadbd8f946fd84b" +checksum = "708b509edf7889e53d7efb0ffadd994cc6c2345ccb62f55cfd6b0682165e4fa6" dependencies = [ "dbus", - "futures-util", - "num", - "once_cell", "openssl", - "rand 0.8.5", + "zeroize", ] [[package]] @@ -1193,18 +1191,18 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ "powerfmt", ] [[package]] name = "derive_arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", @@ -1307,7 +1305,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -1316,7 +1314,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "objc2", ] @@ -1370,9 +1368,9 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", @@ -1442,12 +1440,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1474,16 +1472,22 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "flate2" version = "1.1.2" @@ -1523,9 +1527,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -1595,9 +1599,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand", "futures-core", @@ -1680,7 +1684,7 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi 0.14.4+wasi-0.2.4", "wasm-bindgen", ] @@ -1696,7 +1700,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "libc", "libgit2-sys", "log", @@ -1707,9 +1711,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "group" @@ -1724,9 +1728,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -1743,9 +1747,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -1762,9 +1766,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", @@ -1833,7 +1837,7 @@ checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" dependencies = [ "cfg-if", "libc", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -1914,14 +1918,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -1930,19 +1934,21 @@ dependencies = [ [[package]] name = "hyper" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", - "h2 0.4.10", + "futures-core", + "h2 0.4.12", "http 1.3.1", "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -1958,7 +1964,7 @@ dependencies = [ "futures-util", "headers", "http 1.3.1", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-rustls 0.27.7", "hyper-util", "pin-project-lite", @@ -1991,10 +1997,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ "http 1.3.1", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-util", "log", - "rustls 0.23.27", + "rustls 0.23.31", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", @@ -2009,7 +2015,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.6.0", + "hyper 1.7.0", "hyper-util", "pin-project-lite", "tokio", @@ -2031,9 +2037,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ "base64 0.22.1", "bytes", @@ -2042,12 +2048,12 @@ dependencies = [ "futures-util", "http 1.3.1", "http-body 1.0.1", - "hyper 1.6.0", + "hyper 1.7.0", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.0", "tokio", "tower-service", "tracing", @@ -2171,9 +2177,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -2192,9 +2198,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", "hashbrown", @@ -2225,7 +2231,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "inotify-sys", "libc", ] @@ -2251,9 +2257,9 @@ dependencies = [ [[package]] name = "instability" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d" +checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a" dependencies = [ "darling", "indoc", @@ -2262,6 +2268,17 @@ dependencies = [ "syn", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -2323,9 +2340,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ "getrandom 0.3.3", "libc", @@ -2333,9 +2350,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" dependencies = [ "once_cell", "wasm-bindgen", @@ -2371,17 +2388,18 @@ dependencies = [ [[package]] name = "keyring" -version = "3.6.2" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1961983669d57bdfe6c0f3ef8e4c229b5ef751afcc7d87e4271d2f71f6ccfa8b" +checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" dependencies = [ "byteorder", "dbus-secret-service", "log", "openssl", "security-framework 2.11.1", - "security-framework 3.2.0", - "windows-sys 0.59.0", + "security-framework 3.3.0", + "windows-sys 0.60.2", + "zeroize", ] [[package]] @@ -2430,7 +2448,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-http-proxy", "hyper-rustls 0.27.7", "hyper-timeout", @@ -2440,7 +2458,7 @@ dependencies = [ "kube-core", "pem", "rand 0.8.5", - "rustls 0.23.27", + "rustls 0.23.31", "rustls-pemfile 2.2.0", "secrecy", "serde", @@ -2507,15 +2525,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libdbus-sys" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +checksum = "5cbe856efeb50e4681f010e9aaa2bf0a644e10139e54cde10fc83a307c23bd9f" dependencies = [ "cc", "pkg-config", @@ -2523,9 +2541,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.18.1+1.9.0" +version = "0.18.2+1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1dcb20f84ffcdd825c7a311ae347cce604a6f084a767dec4a4929829645290e" +checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" dependencies = [ "cc", "libc", @@ -2542,16 +2560,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-targets 0.53.3", ] [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "libc", "redox_syscall", ] @@ -2602,9 +2620,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "litrs" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" [[package]] name = "lock_api" @@ -2618,9 +2636,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "lru" @@ -2639,9 +2657,9 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "mac-notification-sys" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b95dfb34071d1592b45622bf93e315e3a72d414b6782aca9a015c12bec367ef" +checksum = "119c8490084af61b44c9eda9d626475847a186737c0378c85e32d77c33a01cd4" dependencies = [ "cc", "objc2", @@ -2677,9 +2695,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "mime" @@ -2749,12 +2767,11 @@ checksum = "995defdca0a589acfdd1bd2e8e3b896b4d4f7675a31fd14c32611440c7f608e6" [[package]] name = "notify" -version = "8.0.0" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" +checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.9.1", - "filetime", + "bitflags 2.9.4", "fsevent-sys", "inotify", "kqueue", @@ -2763,7 +2780,7 @@ dependencies = [ "mio", "notify-types", "walkdir", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2815,39 +2832,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -2863,28 +2847,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -2911,9 +2873,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "objc2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" dependencies = [ "objc2-encode", ] @@ -2924,7 +2886,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "dispatch2", "objc2", ] @@ -2941,7 +2903,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "block2", "libc", "objc2", @@ -2980,7 +2942,7 @@ version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cfg-if", "foreign-types", "libc", @@ -3008,9 +2970,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.5.0+3.5.0" +version = "300.5.2+3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ce546f549326b0e6052b649198487d91320875da901e7bd11a06d1ee3f9c2f" +checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" dependencies = [ "cc", ] @@ -3095,12 +3057,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "path-slash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "498a099351efa4becc6a19c72aa9270598e8fd274ca47052e37455241c88b696" - [[package]] name = "path-slash" version = "0.2.1" @@ -3124,7 +3080,7 @@ dependencies = [ "libc", "log", "pavao-sys", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] @@ -3162,26 +3118,26 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", - "thiserror 2.0.12", + "thiserror 2.0.16", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" dependencies = [ "pest", "pest_generator", @@ -3189,9 +3145,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" dependencies = [ "pest", "pest_meta", @@ -3202,11 +3158,10 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" dependencies = [ - "once_cell", "pest", "sha2", ] @@ -3277,9 +3232,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -3311,9 +3266,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.33" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", "syn", @@ -3321,9 +3276,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -3348,9 +3303,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", @@ -3358,9 +3313,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.1.1", - "rustls 0.23.27", - "socket2", - "thiserror 2.0.12", + "rustls 0.23.31", + "socket2 0.6.0", + "thiserror 2.0.16", "tokio", "tracing", "web-time", @@ -3368,20 +3323,20 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.12" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", "getrandom 0.3.3", "lru-slab", - "rand 0.9.1", + "rand 0.9.2", "ring", "rustc-hash 2.1.1", - "rustls 0.23.27", + "rustls 0.23.31", "rustls-pki-types", "slab", - "thiserror 2.0.12", + "thiserror 2.0.16", "tinyvec", "tracing", "web-time", @@ -3389,16 +3344,16 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.6.0", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3412,9 +3367,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -3429,9 +3384,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -3481,7 +3436,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cassowary", "compact_str", "crossterm 0.28.1", @@ -3498,9 +3453,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -3508,9 +3463,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -3518,29 +3473,29 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", ] [[package]] name = "redox_users" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", @@ -3550,9 +3505,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -3561,15 +3516,15 @@ dependencies = [ [[package]] name = "regex-lite" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" +checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30" [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "remotefs" @@ -3592,20 +3547,20 @@ dependencies = [ "aws-credential-types", "aws-sdk-s3", "log", - "path-slash 0.2.1", + "path-slash", "remotefs", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", ] [[package]] name = "remotefs-ftp" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd5ed3e1a54684a0254980535eb4276dce92f16762f260f713ca9c3d574d9f0e" +checksum = "b1c84ed1367170d6f589f09998b648e7d9bc09d93091130293be8ff09b7a8329" dependencies = [ "log", - "path-slash 0.1.5", + "path-slash", "remotefs", "suppaftp", ] @@ -3622,7 +3577,7 @@ dependencies = [ "kube", "lazy-regex", "log", - "path-slash 0.2.1", + "path-slash", "remotefs", "tar", "tempfile", @@ -3647,14 +3602,14 @@ dependencies = [ [[package]] name = "remotefs-ssh" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0835109bdc3eeeb4b77f40b6146e0442155372cd9eb741a49e7479e97ea5c746" +checksum = "d29de4702886ae0e4433904d4f6f9b2ed2961d31d76a7e7bef58305097238eb6" dependencies = [ "chrono", "lazy-regex", "log", - "path-slash 0.2.1", + "path-slash", "remotefs", "ssh2", "ssh2-config", @@ -3692,7 +3647,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.3.26", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.32", @@ -3723,20 +3678,20 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.20" +version = "0.12.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", "futures-core", "futures-util", - "h2 0.4.10", + "h2 0.4.12", "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.6.0", + "hyper 1.7.0", "hyper-rustls 0.27.7", "hyper-util", "js-sys", @@ -3744,7 +3699,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.27", + "rustls 0.23.31", "rustls-pki-types", "serde", "serde_json", @@ -3816,9 +3771,9 @@ checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2" [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -3847,7 +3802,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.4.15", @@ -3856,15 +3811,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3881,16 +3836,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.3", + "rustls-webpki 0.103.4", "subtle", "zeroize", ] @@ -3929,7 +3884,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.2.0", + "security-framework 3.3.0", ] [[package]] @@ -3972,9 +3927,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "aws-lc-rs", "ring", @@ -3984,9 +3939,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rustydav" @@ -4014,9 +3969,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" dependencies = [ "sdd", ] @@ -4048,9 +4003,9 @@ dependencies = [ [[package]] name = "sdd" -version = "3.0.8" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" [[package]] name = "sec1" @@ -4082,7 +4037,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -4091,11 +4046,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -4131,12 +4086,12 @@ checksum = "d832c086ece0dacc29fb2947bb4219b8f6e12fe9e40b7108f9e57c4224e47b5c" dependencies = [ "either", "flate2", - "hyper 1.6.0", + "hyper 1.7.0", "indicatif", "log", "quick-xml 0.37.5", "regex", - "reqwest 0.12.20", + "reqwest 0.12.23", "self-replace", "semver", "serde_json", @@ -4188,9 +4143,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr", @@ -4200,9 +4155,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" dependencies = [ "serde", ] @@ -4308,9 +4263,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] @@ -4354,12 +4309,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -4383,6 +4335,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "spki" version = "0.6.0" @@ -4409,7 +4371,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f84d13b3b8a0d4e91a2629911e951db1bb8671512f5c09d7d4ba34500ba68c8" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "libc", "libssh2-sys", "parking_lot", @@ -4417,17 +4379,17 @@ dependencies = [ [[package]] name = "ssh2-config" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c8904276fd411f602a6d7e447cccb6f669068badf71359bc4564a5144a866b" +checksum = "68555eda3e0678ceb573e60be349cc7a2df7332dcc6a56791af404a361392186" dependencies = [ "anyhow", - "bitflags 2.9.1", + "bitflags 2.9.4", "dirs", "git2", "glob", "log", - "thiserror 2.0.12", + "thiserror 2.0.16", "wildmatch", ] @@ -4479,23 +4441,23 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "suppaftp" -version = "6.3.0" +version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d869e942cc5f349ad91645925a9e6b570f62c4c170ad1c7b92b867bd16bd54" +checksum = "1d3453e9f37ec7f6b5c18e1fbb1aa9900ba6a02fb392bfd2bb4e3f78f893eee1" dependencies = [ "chrono", "futures-lite", "lazy-regex", "log", "native-tls", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "syn" -version = "2.0.102" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -4580,22 +4542,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" dependencies = [ "quick-xml 0.37.5", - "thiserror 2.0.12", - "windows 0.61.1", + "thiserror 2.0.16", + "windows 0.61.3", "windows-version", ] [[package]] name = "tempfile" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix 1.0.7", - "windows-sys 0.59.0", + "rustix 1.0.8", + "windows-sys 0.60.2", ] [[package]] @@ -4609,10 +4571,10 @@ dependencies = [ [[package]] name = "termscp" -version = "0.18.0" +version = "0.19.0" dependencies = [ "argh", - "bitflags 2.9.1", + "bitflags 2.9.4", "bytesize", "cfg_aliases", "chrono", @@ -4631,7 +4593,7 @@ dependencies = [ "nucleo", "open", "pretty_assertions", - "rand 0.9.1", + "rand 0.9.2", "regex", "remotefs", "remotefs-aws-s3", @@ -4647,7 +4609,7 @@ dependencies = [ "simplelog", "ssh2-config", "tempfile", - "thiserror 2.0.12", + "thiserror 2.0.16", "tokio", "toml", "tui-realm-stdlib", @@ -4683,11 +4645,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.16", ] [[package]] @@ -4703,9 +4665,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -4723,12 +4685,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", @@ -4740,15 +4701,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -4766,9 +4727,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -4781,19 +4742,21 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.1" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "socket2", + "slab", + "socket2 0.6.0", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4833,7 +4796,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.27", + "rustls 0.23.31", "tokio", ] @@ -4851,9 +4814,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -4864,44 +4827,42 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "toml_write", + "toml_parser", + "toml_writer", "winnow", ] [[package]] -name = "toml_write" -version = "0.1.2" +name = "toml_datetime" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_parser" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" [[package]] name = "tower" @@ -4942,7 +4903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "base64 0.21.7", - "bitflags 2.9.1", + "bitflags 2.9.4", "bytes", "http 1.3.1", "http-body 1.0.1", @@ -4960,7 +4921,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "bytes", "futures-util", "http 1.3.1", @@ -4998,9 +4959,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", @@ -5045,15 +5006,15 @@ dependencies = [ [[package]] name = "tuirealm" -version = "3.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29607ee819f733f15c6bbad6aa760ed3d52b345588130003399bd792bfc6b0a8" +checksum = "7af0e5ae72e143be385952fe1bb76cc1fd5c517ba4f3a44f5f66e71e2e9d93e9" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "crossterm 0.29.0", "lazy-regex", "ratatui", - "thiserror 2.0.12", + "thiserror 2.0.16", "tuirealm_derive", ] @@ -5153,13 +5114,14 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -5188,9 +5150,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "js-sys", "wasm-bindgen", @@ -5333,11 +5295,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -5348,21 +5310,22 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", "log", @@ -5374,9 +5337,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" dependencies = [ "cfg-if", "js-sys", @@ -5387,9 +5350,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5397,9 +5360,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", @@ -5410,18 +5373,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" dependencies = [ "js-sys", "wasm-bindgen", @@ -5439,9 +5402,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ "rustls-pki-types", ] @@ -5460,11 +5423,11 @@ dependencies = [ [[package]] name = "whoami" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall", + "libredox", "wasite", "web-sys", ] @@ -5493,11 +5456,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -5518,14 +5481,14 @@ dependencies = [ [[package]] name = "windows" -version = "0.61.1" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", "windows-core 0.61.2", "windows-future", - "windows-link", + "windows-link 0.1.3", "windows-numerics", ] @@ -5558,7 +5521,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement 0.60.0", "windows-interface 0.59.1", - "windows-link", + "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings", ] @@ -5570,7 +5533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core 0.61.2", - "windows-link", + "windows-link 0.1.3", "windows-threading", ] @@ -5620,9 +5583,15 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" [[package]] name = "windows-numerics" @@ -5631,7 +5600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ "windows-core 0.61.2", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -5649,7 +5618,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -5658,7 +5627,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -5688,6 +5657,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -5721,10 +5708,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -5741,16 +5729,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] name = "windows-version" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" +checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb" dependencies = [ - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -5893,12 +5881,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" -dependencies = [ - "memchr", -] +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" [[package]] name = "winreg" @@ -5911,13 +5896,10 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" [[package]] name = "writeable" @@ -5927,12 +5909,12 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "xattr" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" +checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" dependencies = [ "libc", - "rustix 1.0.7", + "rustix 1.0.8", ] [[package]] @@ -5973,18 +5955,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", @@ -6017,6 +5999,20 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "zerotrie" @@ -6031,9 +6027,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -6064,7 +6060,7 @@ dependencies = [ "flate2", "indexmap", "memchr", - "thiserror 2.0.12", + "thiserror 2.0.16", "time", "zopfli", ] @@ -6077,7 +6073,7 @@ checksum = "dba6063ff82cdbd9a765add16d369abe81e520f836054e997c2db217ceca40c0" dependencies = [ "base64 0.22.1", "ed25519-dalek", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e5fc639..15da9c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,8 @@ license = "MIT" name = "termscp" readme = "README.md" repository = "https://github.com/veeso/termscp" -version = "0.18.0" -rust-version = "1.85.1" +version = "0.19.0" +rust-version = "1.87.0" [package.metadata.rpm] package = "termscp" @@ -71,11 +71,11 @@ self_update = { version = "^0.42", default-features = false, features = [ ] } serde = { version = "^1", features = ["derive"] } simplelog = "^0.12" -ssh2-config = "^0.5" +ssh2-config = "^0.6" tempfile = "3" thiserror = "2" tokio = { version = "1.44", features = ["rt"] } -toml = "^0.8" +toml = "^0.9" tui-realm-stdlib = "3" tuirealm = "3" tui-term = "0.2" @@ -88,13 +88,16 @@ wildmatch = "^2" remotefs-smb = { version = "^0.3", optional = true } [target."cfg(target_family = \"unix\")".dependencies] -remotefs-ftp = { version = "^0.2", features = ["vendored", "native-tls"] } -remotefs-ssh = { version = "^0.6", features = ["ssh2-vendored"] } +remotefs-ftp = { version = "^0.3", features = [ + "native-tls-vendored", + "native-tls", +] } +remotefs-ssh = { version = "^0.7", features = ["libssh2-vendored"] } uzers = "0.12" [target."cfg(target_family = \"windows\")".dependencies] -remotefs-ftp = { version = "^0.2", features = ["native-tls"] } -remotefs-ssh = { version = "^0.6" } +remotefs-ftp = { version = "^0.3", features = ["native-tls"] } +remotefs-ssh = { version = "^0.7" } [dev-dependencies] pretty_assertions = "^1" diff --git a/README.md b/README.md index 8299a19..b497625 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@

Developed by @veeso

-

Current version: 0.18.0 10/06/2025

+

Current version: 0.19.0 10/06/2025

Entwickelt von @veeso

-

Aktuelle Version: 0.18.0 10/06/2025

+

Aktuelle Version: 0.19.0 10/06/2025

Desarrollado por @veeso

-

Versión actual: 0.18.0 10/06/2025

+

Versión actual: 0.19.0 10/06/2025

Développé par @veeso

-

Version actuelle: 0.18.0 10/06/2025

+

Version actuelle: 0.19.0 10/06/2025

Sviluppato da @veeso

-

Versione corrente: 0.18.0 10/06/2025

+

Versione corrente: 0.19.0 10/06/2025

Desenvolvido por @veeso

-

Versão atual: 0.18.0 10/06/2025

+

Versão atual: 0.19.0 10/06/2025

@veeso 开发

-

当前版本: 0.18.0 10/06/2025

+

当前版本: 0.19.0 10/06/2025

Consider that Chocolatey moderation can take up to a few weeks since last release, so if the latest version is not available yet, you can install it downloading the ZIP file from - Github and then, from the ZIP directory, install it via

@@ -74,7 +74,7 @@ On Debian based distros, you can install termscp using the Deb package via:

-
wget -O termscp.deb https://github.com/veeso/termscp/releases/latest/download/termscp_0.18.0_amd64.deb
+          
wget -O termscp.deb https://github.com/veeso/termscp/releases/latest/download/termscp_0.19.0_amd64.deb
 sudo dpkg -i termscp.deb

diff --git a/site/html/home.html b/site/html/home.html index 90ec757..e01f928 100644 --- a/site/html/home.html +++ b/site/html/home.html @@ -12,7 +12,7 @@

- termscp 0.18.0 is NOW out! Download it from  + termscp 0.19.0 is NOW out! Download it from  here!

diff --git a/site/lang/en.json b/site/lang/en.json index d02566f..6661ec5 100644 --- a/site/lang/en.json +++ b/site/lang/en.json @@ -12,7 +12,7 @@ "intro": { "caption": "A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/WebDAV", "getStarted": "Get started →", - "versionAlert": "termscp 0.18.0 is NOW out! Download it from", + "versionAlert": "termscp 0.19.0 is NOW out! Download it from", "here": "here", "features": { "handy": { @@ -112,4 +112,4 @@ "then": "Once started, you will be prompted whether to install or not the update. Confirm the installation and ta-dah, the new version of termscp should now be available on your machine" } } -} \ No newline at end of file +} diff --git a/site/lang/es.json b/site/lang/es.json index 48154b3..ea6c605 100644 --- a/site/lang/es.json +++ b/site/lang/es.json @@ -12,7 +12,7 @@ "intro": { "caption": "Un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/Kube/S3/WebDAV", "getStarted": "Para iniciar →", - "versionAlert": "termscp 0.18.0 ya está disponible! Descárgalo desde", + "versionAlert": "termscp 0.19.0 ya está disponible! Descárgalo desde", "here": "aquì", "features": { "handy": { @@ -112,4 +112,4 @@ "then": "Una vez iniciado, se le preguntará si desea instalar o no la actualización. Confirme la instalación y ta-dah, la nueva versión de termscp ahora debería estar disponible en su máquina" } } -} \ No newline at end of file +} diff --git a/site/lang/fr.json b/site/lang/fr.json index a6a9462..79e2dae 100644 --- a/site/lang/fr.json +++ b/site/lang/fr.json @@ -12,7 +12,7 @@ "intro": { "caption": "Un file transfer et navigateur de terminal riche en fonctionnalités avec support pour SCP/SFTP/FTP/Kube/S3/WebDAV", "getStarted": "Pour commencer →", - "versionAlert": "termscp 0.18.0 est maintenant sorti! Télécharge-le depuis", + "versionAlert": "termscp 0.19.0 est maintenant sorti! Télécharge-le depuis", "here": "ici", "features": { "handy": { @@ -112,4 +112,4 @@ "then": "Une fois démarré, vous serez invité à installer ou non la mise à jour. Confirmez l'installation et ta-dah, la nouvelle version de termscp devrait maintenant être disponible sur votre machine" } } -} \ No newline at end of file +} diff --git a/site/lang/it.json b/site/lang/it.json index f444677..ec66c83 100644 --- a/site/lang/it.json +++ b/site/lang/it.json @@ -12,7 +12,7 @@ "intro": { "caption": "Un file transfer ed explorer ricco di funzionalità con supporto per SFTP/SCP/FTP/S3", "getStarted": "Installa termscp →", - "versionAlert": "termscp 0.18.0 è ORA disponbile! Scaricalo da", + "versionAlert": "termscp 0.19.0 è ORA disponbile! Scaricalo da", "here": "qui", "features": { "handy": { @@ -112,4 +112,4 @@ "then": "Una volta lanciato, se c'è un aggiornamento disponibile ti chiederà se procedere. Conferma e a questo punto dovrebbe installarlo. Se tutto è andato a buon fine, riavviando termscp dovrebbe essere l'ultima versione." } } -} \ No newline at end of file +} diff --git a/site/lang/zh-CN.json b/site/lang/zh-CN.json index 15efff5..0d38421 100644 --- a/site/lang/zh-CN.json +++ b/site/lang/zh-CN.json @@ -12,7 +12,7 @@ "intro": { "caption": "功能丰富的终端 UI 文件传输和浏览器,支持 SCP/SFTP/FTP/Kube/S3/WebDAV", "getStarted": "开始 →", - "versionAlert": "termscp 0.18.0 现已发布! 从下载", + "versionAlert": "termscp 0.19.0 现已发布! 从下载", "here": "这里", "features": { "handy": { @@ -112,4 +112,4 @@ "then": "启动后,系统将提示您是否安装更新。 确认安装和 ta-dah,新版本的termscp 现在应该可以在你的机器上使用了" } } -} \ No newline at end of file +} diff --git a/src/filetransfer/remotefs_builder.rs b/src/filetransfer/remotefs_builder.rs index 53cf17c..3d9edd0 100644 --- a/src/filetransfer/remotefs_builder.rs +++ b/src/filetransfer/remotefs_builder.rs @@ -13,7 +13,7 @@ use remotefs_kube::KubeMultiPodFs as KubeFs; use remotefs_smb::SmbOptions; #[cfg(smb)] use remotefs_smb::{SmbCredentials, SmbFs}; -use remotefs_ssh::{ScpFs, SftpFs, SshAgentIdentity, SshConfigParseRule, SshOpts}; +use remotefs_ssh::{LibSsh2Session, ScpFs, SftpFs, SshAgentIdentity, SshConfigParseRule, SshOpts}; use remotefs_webdav::WebDAVFs; #[cfg(not(smb))] @@ -138,12 +138,18 @@ impl RemoteFsBuilder { } /// Build scp client - fn scp_client(params: GenericProtocolParams, config_client: &ConfigClient) -> ScpFs { + fn scp_client( + params: GenericProtocolParams, + config_client: &ConfigClient, + ) -> ScpFs { Self::build_ssh_opts(params, config_client).into() } /// Build sftp client - fn sftp_client(params: GenericProtocolParams, config_client: &ConfigClient) -> SftpFs { + fn sftp_client( + params: GenericProtocolParams, + config_client: &ConfigClient, + ) -> SftpFs { Self::build_ssh_opts(params, config_client).into() } From 86660a0cc9e8fc44b82320efc70ec3b5d458a23e Mon Sep 17 00:00:00 2001 From: veeso Date: Sat, 20 Sep 2025 18:07:26 +0200 Subject: [PATCH 02/14] fix: SMB support for MacOS with vendored build of libsmbclient. closes #334 --- .github/workflows/build-artifacts.yml | 39 ++++++++++++++++++++++++++- .github/workflows/macos.yml | 7 +++++ CHANGELOG.md | 8 ++++++ Cargo.toml | 4 +-- build.rs | 4 +-- 5 files changed, 56 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-artifacts.yml b/.github/workflows/build-artifacts.yml index fcc49a3..f1146f1 100644 --- a/.github/workflows/build-artifacts.yml +++ b/.github/workflows/build-artifacts.yml @@ -29,8 +29,45 @@ jobs: with: toolchain: stable targets: ${{ matrix.platform.target }} + - name: Install dependencies + run: | + brew update + brew install \ + bison \ + cpanminus \ + cups \ + flex \ + gettext \ + gmp \ + gnutls \ + icu4c \ + jansson \ + libarchive \ + libbsd \ + libunistring \ + libgit2 \ + libtirpc \ + openldap \ + pkg-config \ + zlib + brew link --force bison + brew link --force cups + brew link --force flex + brew link --force gettext + brew link --force gmp + brew link --force gnutls + brew link --force icu4c + brew link --force jansson + brew link --force libarchive + brew link --force libbsd + brew link --force libgit2 + brew link --force libtirpc + brew link --force libunistring + brew link --force openldap + brew link --force zlib + cpanm Parse::Yapp::Driver - name: Build release - run: cargo build --release --target ${{ matrix.platform.target }} + run: cargo build --release --features smb-vendored --target ${{ matrix.platform.target }} - name: Prepare artifact files run: | mkdir -p .artifact diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 7ca11b4..3922f76 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -22,6 +22,13 @@ jobs: with: toolchain: stable components: rustfmt, clippy + - name: Install dependencies + run: | + brew update + brew install \ + pkg-config \ + samba + brew link --force samba - name: Build run: cargo build - name: Run tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 74119a7..014616f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog - [Changelog](#changelog) + - [0.19.0](#0190) - [0.18.0](#0180) - [0.17.0](#0170) - [0.16.1](#0161) @@ -41,6 +42,13 @@ --- +## 0.19.0 + +Released on 20/09/2025 + +- [Issue 356](https://github.com/veeso/termscp/issues/356): Fixed SSH auth issue not trying with the password if any RSA key was found. +- [Issue 334](https://github.com/veeso/termscp/issues/334): SMB support for MacOS with vendored build of libsmbclient. + ## 0.18.0 Released on 10/06/2025 diff --git a/Cargo.toml b/Cargo.toml index 15da9c8..2930fa5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ regex = "^1" remotefs = "^0.3" remotefs-aws-s3 = "0.4" remotefs-kube = "0.4" +remotefs-smb = { version = "^0.3", optional = true } remotefs-webdav = "^0.2" rpassword = "^7" self_update = { version = "^0.42", default-features = false, features = [ @@ -84,9 +85,6 @@ version-compare = "^0.2" whoami = "^1.6" wildmatch = "^2" -[target."cfg(not(target_os = \"macos\"))".dependencies] -remotefs-smb = { version = "^0.3", optional = true } - [target."cfg(target_family = \"unix\")".dependencies] remotefs-ftp = { version = "^0.3", features = [ "native-tls-vendored", diff --git a/build.rs b/build.rs index d6b0acc..d05b0b3 100644 --- a/build.rs +++ b/build.rs @@ -10,8 +10,8 @@ fn main() -> Result<(), Box> { posix: { target_family = "unix" }, win: { target_family = "windows" }, // exclusive features - smb: { all(feature = "smb", not( macos )) }, - smb_unix: { all(unix, feature = "smb", not(macos)) }, + smb: { feature = "smb" }, + smb_unix: { all(unix, feature = "smb") }, smb_windows: { all(windows, feature = "smb") } } From 205d2813ad0407a23999ea8f212c6d7ef25a7ad3 Mon Sep 17 00:00:00 2001 From: veeso Date: Sat, 20 Sep 2025 18:13:20 +0200 Subject: [PATCH 03/14] perf: Migrated to libssh.org on Linux and MacOS for better ssh agent support. closes #337 --- CHANGELOG.md | 1 + Cargo.lock | 26 ++++++++++++++++++++++++++ Cargo.toml | 5 ++++- src/filetransfer/remotefs_builder.rs | 10 +++++++--- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 014616f..a7ab1ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Released on 20/09/2025 - [Issue 356](https://github.com/veeso/termscp/issues/356): Fixed SSH auth issue not trying with the password if any RSA key was found. - [Issue 334](https://github.com/veeso/termscp/issues/334): SMB support for MacOS with vendored build of libsmbclient. +- [Issue 337](https://github.com/veeso/termscp/issues/337): Migrated to libssh.org on Linux and MacOS for better ssh agent support. ## 0.18.0 diff --git a/Cargo.lock b/Cargo.lock index 6ebfc98..0d06111 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2574,6 +2574,31 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "libssh-rs" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3066e110d6bb95a5addbd9c2ee595efdaeecaddd4793f3803dfee2968a74c685" +dependencies = [ + "bitflags 1.3.2", + "libc", + "libssh-rs-sys", + "openssl-sys", + "thiserror 1.0.69", +] + +[[package]] +name = "libssh-rs-sys" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d528ea9ac190fa364ff12193da82222dfc645e7ab28666ae91493bd288a1a0" +dependencies = [ + "cc", + "libz-sys", + "openssl-sys", + "pkg-config", +] + [[package]] name = "libssh2-sys" version = "0.3.1" @@ -3608,6 +3633,7 @@ checksum = "d29de4702886ae0e4433904d4f6f9b2ed2961d31d76a7e7bef58305097238eb6" dependencies = [ "chrono", "lazy-regex", + "libssh-rs", "log", "path-slash", "remotefs", diff --git a/Cargo.toml b/Cargo.toml index 2930fa5..e66b940 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,7 +90,10 @@ remotefs-ftp = { version = "^0.3", features = [ "native-tls-vendored", "native-tls", ] } -remotefs-ssh = { version = "^0.7", features = ["libssh2-vendored"] } +remotefs-ssh = { version = "^0.7", default-features = false, features = [ + "find", + "libssh-vendored", +] } uzers = "0.12" [target."cfg(target_family = \"windows\")".dependencies] diff --git a/src/filetransfer/remotefs_builder.rs b/src/filetransfer/remotefs_builder.rs index 3d9edd0..b52fb7c 100644 --- a/src/filetransfer/remotefs_builder.rs +++ b/src/filetransfer/remotefs_builder.rs @@ -13,7 +13,11 @@ use remotefs_kube::KubeMultiPodFs as KubeFs; use remotefs_smb::SmbOptions; #[cfg(smb)] use remotefs_smb::{SmbCredentials, SmbFs}; -use remotefs_ssh::{LibSsh2Session, ScpFs, SftpFs, SshAgentIdentity, SshConfigParseRule, SshOpts}; +#[cfg(windows)] +use remotefs_ssh::LibSsh2Session as SshSession; +#[cfg(unix)] +use remotefs_ssh::LibSshSession as SshSession; +use remotefs_ssh::{ScpFs, SftpFs, SshAgentIdentity, SshConfigParseRule, SshOpts}; use remotefs_webdav::WebDAVFs; #[cfg(not(smb))] @@ -141,7 +145,7 @@ impl RemoteFsBuilder { fn scp_client( params: GenericProtocolParams, config_client: &ConfigClient, - ) -> ScpFs { + ) -> ScpFs { Self::build_ssh_opts(params, config_client).into() } @@ -149,7 +153,7 @@ impl RemoteFsBuilder { fn sftp_client( params: GenericProtocolParams, config_client: &ConfigClient, - ) -> SftpFs { + ) -> SftpFs { Self::build_ssh_opts(params, config_client).into() } From 05c8613279e6ca63b483df10ea4ffcf208228936 Mon Sep 17 00:00:00 2001 From: Christian Visintin Date: Thu, 2 Oct 2025 20:58:26 +0200 Subject: [PATCH 04/14] fix: Report a message while calculating total size of files to transfer. (#362) * fix: Report a message while calculating total size of files to transfer. Currently, in case of huge transfers the app may look frozen while calculating the transfer size. We should at least report to the user we are actually doing something. closes #361 * ci: windows runner --- .github/workflows/windows.yml | 2 +- CHANGELOG.md | 1 + src/ui/activities/filetransfer/session.rs | 21 +++++++++++++++++---- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 1f4235c..cc45cc1 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -15,7 +15,7 @@ env: jobs: build: - runs-on: windows-2019 + runs-on: windows-latest steps: - uses: actions/checkout@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index a7ab1ce..d0f40c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ Released on 20/09/2025 - [Issue 356](https://github.com/veeso/termscp/issues/356): Fixed SSH auth issue not trying with the password if any RSA key was found. - [Issue 334](https://github.com/veeso/termscp/issues/334): SMB support for MacOS with vendored build of libsmbclient. - [Issue 337](https://github.com/veeso/termscp/issues/337): Migrated to libssh.org on Linux and MacOS for better ssh agent support. +- [Issue 361](https://github.com/veeso/termscp/issues/361): Report a message while calculating total size of files to transfer. ## 0.18.0 diff --git a/src/ui/activities/filetransfer/session.rs b/src/ui/activities/filetransfer/session.rs index f2e34e0..d58ac8d 100644 --- a/src/ui/activities/filetransfer/session.rs +++ b/src/ui/activities/filetransfer/session.rs @@ -1260,7 +1260,10 @@ impl FileTransferActivity { /// Get total size of transfer for host_bridgehost fn get_total_transfer_size_host(&mut self, entry: &File) -> usize { - if entry.is_dir() { + // mount message to tell we are calculating size + self.mount_blocking_wait("Calculating transfer size…"); + + let sz = if entry.is_dir() { // List dir match self.host_bridge.list_dir(entry.path()) { Ok(files) => files @@ -1281,12 +1284,18 @@ impl FileTransferActivity { } } else { entry.metadata.size as usize - } + }; + self.umount_wait(); + + sz } /// Get total size of transfer for remote host fn get_total_transfer_size_remote(&mut self, entry: &File) -> usize { - if entry.is_dir() { + // mount message to tell we are calculating size + self.mount_blocking_wait("Calculating transfer size…"); + + let sz = if entry.is_dir() { // List directory match self.client.list_dir(entry.path()) { Ok(files) => files @@ -1307,7 +1316,11 @@ impl FileTransferActivity { } } else { entry.metadata.size as usize - } + }; + + self.umount_wait(); + + sz } // file changed From 4bebec369f1dd705f23680414914a523e8a0fd0a Mon Sep 17 00:00:00 2001 From: Christian Visintin Date: Thu, 2 Oct 2025 21:27:51 +0200 Subject: [PATCH 05/14] fix: Issues with update checks (#363) Removed error popup message if failed to check for updates. Prevent long timeouts when checking for updates if the network is down or the DNS is not working. closes #354 --- CHANGELOG.md | 3 +++ src/system/auto_update.rs | 31 +++++++++++++++++++++++++++++++ src/ui/activities/auth/misc.rs | 5 +---- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0f40c9..d2ca7c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,9 @@ Released on 20/09/2025 - [Issue 334](https://github.com/veeso/termscp/issues/334): SMB support for MacOS with vendored build of libsmbclient. - [Issue 337](https://github.com/veeso/termscp/issues/337): Migrated to libssh.org on Linux and MacOS for better ssh agent support. - [Issue 361](https://github.com/veeso/termscp/issues/361): Report a message while calculating total size of files to transfer. +- [Issue 354](https://github.com/veeso/termscp/issues/354): + - Removed error popup message if failed to check for updates. + - Prevent long timeouts when checking for updates if the network is down or the DNS is not working. ## 0.18.0 diff --git a/src/system/auto_update.rs b/src/system/auto_update.rs index f66e9ff..a0b618e 100644 --- a/src/system/auto_update.rs +++ b/src/system/auto_update.rs @@ -2,6 +2,8 @@ //! //! Automatic update module. This module is used to upgrade the current version of termscp to the latest available on Github +use std::net::ToSocketAddrs as _; + use self_update::backends::github::Update as GithubUpdater; pub use self_update::errors::Error as UpdateError; use self_update::update::Release as UpdRelease; @@ -67,6 +69,9 @@ impl Update { /// otherwise if no version is available, return None /// In case of error returns Error with the error description pub fn is_new_version_available() -> Result, UpdateError> { + // check if api.github.com is reachable before doing anything + Self::check_github_api_reachable()?; + info!("Checking whether a new version is available..."); GithubUpdater::configure() // Set default options @@ -83,6 +88,27 @@ impl Update { .map(Self::check_version) } + /// Check if api.github.com is reachable + /// This is useful to avoid long timeouts when the network is down + /// or the DNS is not working + fn check_github_api_reachable() -> Result<(), UpdateError> { + let Some(socket_addr) = ("api.github.com", 443) + .to_socket_addrs() + .ok() + .and_then(|mut i| i.next()) + else { + error!("Could not resolve api.github.com"); + return Err(UpdateError::Network( + "Could not resolve api.github.com".into(), + )); + }; + + // just try to open a connection to api.github.com with a timeout of 5 seconds with tcp + std::net::TcpStream::connect_timeout(&socket_addr, std::time::Duration::from_secs(5)) + .map(|_| ()) + .map_err(|e| UpdateError::Network(format!("Could not reach api.github.com: {e}"))) + } + /// In case received version is newer than current one, version as Some is returned; otherwise None fn check_version(r: Release) -> Option { debug!("got version from GitHub: {}", r.version); @@ -212,4 +238,9 @@ mod test { assert!(!Update::is_new_version_higher("0.9.9", "0.10.1")); assert!(!Update::is_new_version_higher("0.10.9", "0.11.0")); } + + #[test] + fn test_should_check_whether_github_api_is_reachable() { + assert!(Update::check_github_api_reachable().is_ok()); + } } diff --git a/src/ui/activities/auth/misc.rs b/src/ui/activities/auth/misc.rs index 7de6194..e011d7e 100644 --- a/src/ui/activities/auth/misc.rs +++ b/src/ui/activities/auth/misc.rs @@ -223,10 +223,7 @@ impl AuthActivity { } Err(err) => { // Report error - error!("Failed to get latest version: {}", err); - self.mount_error( - format!("Could not check for new updates: {err}").as_str(), - ); + error!("Failed to get latest version: {err}",); } } } else { From f4156a505901bb31a4442ffc9240b35c7612d665 Mon Sep 17 00:00:00 2001 From: Christian Visintin Date: Sat, 8 Nov 2025 15:32:52 +0100 Subject: [PATCH 06/14] feat: Import bookmarks from ssh config with a CLI command (#364) * feat: Import bookmarks from ssh config with a CLI command Use import-ssh-hosts to import all the possible hosts by the configured ssh config or the default one on your machine closes #331 --- CHANGELOG.md | 1 + Cargo.lock | 591 ++++++++---------- Cargo.toml | 5 +- docs/de/man.md | 24 +- docs/es/man.md | 20 + docs/fr/man.md | 21 +- docs/it/man.md | 21 +- docs/man.md | 7 + docs/pt-BR/man.md | 7 + docs/zh-CN/man.md | 19 + src/activity_manager.rs | 30 +- src/cli.rs | 26 +- src/explorer/builder.rs | 8 +- src/filetransfer/remotefs_builder.rs | 8 +- src/main.rs | 27 +- src/support.rs | 38 +- src/support/import_ssh_hosts.rs | 326 ++++++++++ src/system/config_client.rs | 17 +- src/system/sshkey_storage.rs | 14 +- src/ui/activities/auth/bookmarks.rs | 36 +- src/ui/activities/auth/update.rs | 14 +- src/ui/activities/auth/view.rs | 48 +- .../filetransfer/components/popups/goto.rs | 4 +- src/ui/activities/filetransfer/mod.rs | 8 +- src/ui/activities/setup/actions.rs | 29 +- src/ui/activities/setup/config.rs | 13 +- src/ui/activities/setup/view/ssh_keys.rs | 2 +- 27 files changed, 883 insertions(+), 481 deletions(-) create mode 100644 src/support/import_ssh_hosts.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index d2ca7c7..d8c7f87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Released on 20/09/2025 +- [Issue 331](https://github.com/veeso/termscp/issues/331): Added new `import-ssh-hosts` CLI subcommand to import all the hosts from the ssh config as bookmarks. - [Issue 356](https://github.com/veeso/termscp/issues/356): Fixed SSH auth issue not trying with the password if any RSA key was found. - [Issue 334](https://github.com/veeso/termscp/issues/334): SMB support for MacOS with vendored build of libsmbclient. - [Issue 337](https://github.com/veeso/termscp/issues/337): Migrated to libssh.org on Linux and MacOS for better ssh agent support. diff --git a/Cargo.lock b/Cargo.lock index 0d06111..c8e2e4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -43,12 +34,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[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" @@ -60,9 +45,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" @@ -167,9 +152,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.13.3" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d" dependencies = [ "aws-lc-sys", "zeroize", @@ -177,15 +162,16 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.30.0" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +checksum = "a2b715a6010afb9e457ca2b7c9d2b9c344baa8baed7b38dc476034c171b32575" dependencies = [ "bindgen", "cc", "cmake", "dunce", "fs_extra", + "libloading", ] [[package]] @@ -215,9 +201,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.104.0" +version = "1.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c488cd6abb0ec9811c401894191932e941c5f91dc226043edacd0afa1634bc" +checksum = "2c230530df49ed3f2b7b4d9c8613b72a04cdac6452eede16d587fc62addfabac" dependencies = [ "aws-credential-types", "aws-runtime", @@ -249,9 +235,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.83.0" +version = "1.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cd43af212d2a1c4dedff6f044d7e1961e5d9e7cfe773d70f31d9842413886" +checksum = "357a841807f6b52cb26123878b3326921e2a25faca412fabdd32bd35b7edd5d3" dependencies = [ "aws-credential-types", "aws-runtime", @@ -271,9 +257,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.84.0" +version = "1.86.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ec4a95bd48e0db7a424356a161f8d87bd6a4f0af37204775f0da03d9e39fc3" +checksum = "9d1cc7fb324aa12eb4404210e6381195c5b5e9d52c2682384f295f38716dd3c7" dependencies = [ "aws-credential-types", "aws-runtime", @@ -293,9 +279,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.85.0" +version = "1.86.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410309ad0df4606bc721aff0d89c3407682845453247213a0ccc5ff8801ee107" +checksum = "e7d835f123f307cafffca7b9027c14979f1d403b417d8541d67cf252e8a21e35" dependencies = [ "aws-credential-types", "aws-runtime", @@ -407,9 +393,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147e8eea63a40315d704b97bf9bc9b8c1402ae94f89d5ad6f7550d963309da1b" +checksum = "734b4282fbb7372923ac339cc2222530f8180d9d4745e582de19a18cee409fd8" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -426,11 +412,11 @@ dependencies = [ "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower 0.5.2", "tracing", ] @@ -465,9 +451,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3946acbe1ead1301ba6862e712c7903ca9bb230bdf1fbd1b5ac54158ef2ab1f" +checksum = "4fa63ad37685ceb7762fa4d73d06f1d5493feb88e3f27259b9ed277f4c01b185" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -553,21 +539,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base16ct" version = "0.1.1" @@ -604,25 +575,22 @@ checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bindgen" -version = "0.69.5" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ "bitflags 2.9.4", "cexpr", "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", + "itertools", "log", "prettyplease", "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash", "shlex", "syn", - "which", ] [[package]] @@ -694,26 +662,26 @@ dependencies = [ [[package]] name = "bytesize" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3c8f83209414aacf0eeae3cf730b18d6981697fba62f200fcfb92b9f082acba" +checksum = "f5c434ae3cf0089ca203e9019ebe529c47ff45cefe8af7c85ecb734ef541822f" [[package]] name = "bytestring" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" dependencies = [ "bytes", ] [[package]] name = "camino" -version = "1.1.12" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -736,7 +704,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -765,9 +733,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.36" +version = "1.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" dependencies = [ "find-msvc-tools", "jobserver", @@ -798,17 +766,16 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link 0.1.3", + "windows-link 0.2.0", ] [[package]] @@ -1026,7 +993,7 @@ dependencies = [ "document-features", "mio", "parking_lot", - "rustix 1.0.8", + "rustix 1.1.2", "signal-hook", "signal-hook-mio", "winapi", @@ -1191,9 +1158,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", ] @@ -1305,7 +1272,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.0", + "windows-sys 0.60.2", ] [[package]] @@ -1440,12 +1407,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -1484,9 +1451,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "flate2" @@ -1684,16 +1651,10 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi 0.14.4+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "git2" version = "0.20.2" @@ -1970,7 +1931,7 @@ dependencies = [ "pin-project-lite", "rustls-native-certs 0.7.3", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower-service", ] @@ -2000,11 +1961,11 @@ dependencies = [ "hyper 1.7.0", "hyper-util", "log", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower-service", "webpki-roots", ] @@ -2037,9 +1998,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64 0.22.1", "bytes", @@ -2053,7 +2014,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -2061,9 +2022,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2071,7 +2032,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.2", + "windows-core 0.57.0", ] [[package]] @@ -2198,9 +2159,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", @@ -2268,17 +2229,6 @@ dependencies = [ "syn", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -2314,15 +2264,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -2350,9 +2291,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.78" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -2397,7 +2338,7 @@ dependencies = [ "log", "openssl", "security-framework 2.11.1", - "security-framework 3.3.0", + "security-framework 3.5.1", "windows-sys 0.60.2", "zeroize", ] @@ -2458,7 +2399,7 @@ dependencies = [ "kube-core", "pem", "rand 0.8.5", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-pemfile 2.2.0", "secrecy", "serde", @@ -2490,9 +2431,9 @@ dependencies = [ [[package]] name = "lazy-regex" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60c7310b93682b36b98fa7ea4de998d3463ccbebd94d935d6b48ba5b6ffa7126" +checksum = "191898e17ddee19e60bccb3945aa02339e81edd4a8c50e21fd4d48cdecda7b29" dependencies = [ "lazy-regex-proc_macros", "once_cell", @@ -2501,9 +2442,9 @@ dependencies = [ [[package]] name = "lazy-regex-proc_macros" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ba01db5ef81e17eb10a5e0f2109d1b3a3e29bac3070fdbd7d156bf7dbd206a1" +checksum = "c35dc8b0da83d1a9507e12122c80dea71a9c7c613014347392483a83ea593e04" dependencies = [ "proc-macro2", "quote", @@ -2517,17 +2458,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" -version = "0.2.175" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libdbus-sys" @@ -2560,14 +2495,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-targets 0.48.5", ] [[package]] name = "libredox" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags 2.9.4", "libc", @@ -2633,9 +2568,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -2720,9 +2655,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -2935,15 +2870,6 @@ dependencies = [ "objc2-core-foundation", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -2995,9 +2921,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.5.2+3.5.2" +version = "300.5.3+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" +checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" dependencies = [ "cc", ] @@ -3096,16 +3022,16 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "pavao" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5b84c6ab7b745d233668e868f67dac1f40a8329c0f9d41ac50addf36adb883" +checksum = "f7c62e3a544910e4a9bbb56218bad91593b79a27c676e54a36097200d10d2d6e" dependencies = [ "cfg_aliases", "lazy_static", "libc", "log", "pavao-sys", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3121,9 +3047,9 @@ dependencies = [ [[package]] name = "pavao-sys" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd4336fa254e9df9f752adc3e2b70f01b4eacfb32f34433bafda3a898056737" +checksum = "a3e72a8efe4193b073995a99981a288cfef121027d12c420c647c2f19d4103d4" dependencies = [ "cc", "libc", @@ -3149,20 +3075,20 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" dependencies = [ "memchr", - "thiserror 2.0.16", + "thiserror 2.0.17", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663" dependencies = [ "pest", "pest_generator", @@ -3170,9 +3096,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" +checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f" dependencies = [ "pest", "pest_meta", @@ -3183,9 +3109,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" +checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420" dependencies = [ "pest", "sha2", @@ -3337,10 +3263,10 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.1", - "rustls 0.23.31", - "socket2 0.6.0", - "thiserror 2.0.16", + "rustc-hash", + "rustls 0.23.32", + "socket2 0.5.10", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -3357,11 +3283,11 @@ dependencies = [ "lru-slab", "rand 0.9.2", "ring", - "rustc-hash 2.1.1", - "rustls 0.23.31", + "rustc-hash", + "rustls 0.23.32", "rustls-pki-types", "slab", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -3376,16 +3302,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.0", + "socket2 0.5.10", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -3467,7 +3393,7 @@ dependencies = [ "crossterm 0.28.1", "indoc", "instability", - "itertools 0.13.0", + "itertools", "lru", "paste", "strum", @@ -3513,14 +3439,14 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -3530,9 +3456,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -3574,7 +3500,7 @@ dependencies = [ "log", "path-slash", "remotefs", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", ] @@ -3725,14 +3651,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.2", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower 0.5.2", "tower-http 0.6.6", "tower-service", @@ -3795,18 +3721,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2" -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -3832,20 +3746,20 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags 2.9.4", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", + "linux-raw-sys 0.11.0", + "windows-sys 0.52.0", ] [[package]] @@ -3862,16 +3776,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki 0.103.7", "subtle", "zeroize", ] @@ -3910,7 +3824,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.3.0", + "security-framework 3.5.1", ] [[package]] @@ -3953,9 +3867,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "aws-lc-rs", "ring", @@ -4004,11 +3918,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -4072,9 +3986,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.3.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ "bitflags 2.9.4", "core-foundation 0.10.1", @@ -4085,9 +3999,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -4130,19 +4044,21 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" dependencies = [ "serde", + "serde_core", ] [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -4157,10 +4073,19 @@ dependencies = [ ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -4169,23 +4094,24 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_spanned" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -4260,6 +4186,15 @@ dependencies = [ "digest", ] +[[package]] +name = "shellexpand" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1fdf65dd6331831494dd616b30351c38e96e45921a27745cf98490458b90bb" +dependencies = [ + "dirs", +] + [[package]] name = "shlex" version = "1.3.0" @@ -4405,9 +4340,9 @@ dependencies = [ [[package]] name = "ssh2-config" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68555eda3e0678ceb573e60be349cc7a2df7332dcc6a56791af404a361392186" +checksum = "bc7aae258493fa8ea06796b133b9076f3002c46cd1a4085ddd6df7236fee7034" dependencies = [ "anyhow", "bitflags 2.9.4", @@ -4415,7 +4350,7 @@ dependencies = [ "git2", "glob", "log", - "thiserror 2.0.16", + "thiserror 2.0.17", "wildmatch", ] @@ -4467,16 +4402,16 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "suppaftp" -version = "7.0.3" +version = "7.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3453e9f37ec7f6b5c18e1fbb1aa9900ba6a02fb392bfd2bb4e3f78f893eee1" +checksum = "ba8928c89e226be233f0eb1594e9bd023f72a948dc06581c0d908387f57de1de" dependencies = [ "chrono", "futures-lite", "lazy-regex", "log", "native-tls", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4568,22 +4503,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" dependencies = [ "quick-xml 0.37.5", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows 0.61.3", "windows-version", ] [[package]] name = "tempfile" -version = "3.21.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix 1.0.8", - "windows-sys 0.60.2", + "rustix 1.1.2", + "windows-sys 0.52.0", ] [[package]] @@ -4632,10 +4567,11 @@ dependencies = [ "self_update", "serde", "serial_test", + "shellexpand", "simplelog", "ssh2-config", "tempfile", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "toml", "tui-realm-stdlib", @@ -4671,11 +4607,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -4691,9 +4627,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -4711,11 +4647,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.43" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", + "itoa", "libc", "num-conv", "num_threads", @@ -4768,28 +4705,25 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "slab", "socket2 0.6.0", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -4818,11 +4752,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.31", + "rustls 0.23.32", "tokio", ] @@ -4853,12 +4787,12 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "indexmap", - "serde", + "serde_core", "serde_spanned", "toml_datetime", "toml_parser", @@ -4868,27 +4802,27 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "tower" @@ -5040,7 +4974,7 @@ dependencies = [ "crossterm 0.29.0", "lazy-regex", "ratatui", - "thiserror 2.0.16", + "thiserror 2.0.17", "tuirealm_derive", ] @@ -5075,9 +5009,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -5087,9 +5021,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-linebreak" @@ -5109,7 +5043,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ - "itertools 0.13.0", + "itertools", "unicode-segmentation", "unicode-width 0.1.14", ] @@ -5245,9 +5179,9 @@ dependencies = [ [[package]] name = "version-compare" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" @@ -5321,9 +5255,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.4+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] @@ -5336,9 +5279,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", @@ -5349,9 +5292,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", @@ -5363,9 +5306,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.51" +version = "0.4.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" dependencies = [ "cfg-if", "js-sys", @@ -5376,9 +5319,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5386,9 +5329,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", @@ -5399,18 +5342,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.78" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" dependencies = [ "js-sys", "wasm-bindgen", @@ -5460,9 +5403,9 @@ dependencies = [ [[package]] name = "wildmatch" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ce1ab1f8c62655ebe1350f589c61e505cf94d385bc6a12899442d9081e71fd" +checksum = "2d654e41fe05169e03e27b97e0c23716535da037c1652a31fd99c6b2fad84059" [[package]] name = "winapi" @@ -5482,11 +5425,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.48.0", ] [[package]] @@ -5545,8 +5488,8 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement 0.60.1", + "windows-interface 0.59.2", "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings", @@ -5576,9 +5519,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" dependencies = [ "proc-macro2", "quote", @@ -5598,9 +5541,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" dependencies = [ "proc-macro2", "quote", @@ -5689,14 +5632,14 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.4", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" dependencies = [ "windows-link 0.2.0", ] @@ -5734,11 +5677,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" dependencies = [ - "windows-link 0.1.3", + "windows-link 0.2.0", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -5760,9 +5703,9 @@ dependencies = [ [[package]] name = "windows-version" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb" +checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e" dependencies = [ "windows-link 0.2.0", ] @@ -5923,9 +5866,9 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" @@ -5935,12 +5878,12 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "xattr" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "rustix 1.0.8", + "rustix 1.1.2", ] [[package]] @@ -5981,18 +5924,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", @@ -6022,9 +5965,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] @@ -6086,7 +6029,7 @@ dependencies = [ "flate2", "indexmap", "memchr", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "zopfli", ] @@ -6099,7 +6042,7 @@ checksum = "dba6063ff82cdbd9a765add16d369abe81e520f836054e997c2db217ceca40c0" dependencies = [ "base64 0.22.1", "ed25519-dalek", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e66b940..c4f56d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ name = "termscp" readme = "README.md" repository = "https://github.com/veeso/termscp" version = "0.19.0" -rust-version = "1.87.0" +rust-version = "1.88.0" [package.metadata.rpm] package = "termscp" @@ -71,11 +71,12 @@ self_update = { version = "^0.42", default-features = false, features = [ "compression-zip-deflate", ] } serde = { version = "^1", features = ["derive"] } +shellexpand = "3" simplelog = "^0.12" ssh2-config = "^0.6" tempfile = "3" thiserror = "2" -tokio = { version = "1.44", features = ["rt"] } +tokio = { version = "1", features = ["rt"] } toml = "^0.9" tui-realm-stdlib = "3" tuirealm = "3" diff --git a/docs/de/man.md b/docs/de/man.md index 63f96f3..be25040 100644 --- a/docs/de/man.md +++ b/docs/de/man.md @@ -10,6 +10,10 @@ - [Unterbefehle](#unterbefehle) - [Ein Thema importieren](#ein-thema-importieren) - [Neueste Version installieren](#neueste-version-installieren) + - [Unterbefehle](#unterbefehle-1) + - [Ein Theme importieren](#ein-theme-importieren) + - [Neueste Version installieren](#neueste-version-installieren-1) + - [SSH-Hosts importieren](#ssh-hosts-importieren) - [S3-Verbindungsparameter](#s3-verbindungsparameter) - [S3-Anmeldeinformationen 🦊](#s3-anmeldeinformationen-) - [Dateiexplorer 📂](#dateiexplorer-) @@ -29,9 +33,9 @@ - [AWS S3 Adressargument](#aws-s3-adressargument-1) - [SMB Adressargument](#smb-adressargument-1) - [Wie das Passwort bereitgestellt werden kann 🔐](#wie-das-passwort-bereitgestellt-werden-kann--1) - - [Unterbefehle](#unterbefehle-1) + - [Unterbefehle](#unterbefehle-2) - [Ein Thema importieren](#ein-thema-importieren-1) - - [Neueste Version installieren](#neueste-version-installieren-1) + - [Neueste Version installieren](#neueste-version-installieren-2) - [S3-Verbindungsparameter](#s3-verbindungsparameter-1) - [S3-Anmeldeinformationen 🦊](#s3-anmeldeinformationen--1) - [Dateiexplorer 📂](#dateiexplorer--1) @@ -173,6 +177,22 @@ Führen Sie termscp als `termscp theme ` aus Führen Sie termscp als `termscp update` aus +### Unterbefehle + +#### Ein Theme importieren + +Führen Sie termscp mit `termscp theme ` aus. + +#### Neueste Version installieren + +Führen Sie termscp mit `termscp update` aus. + +#### SSH-Hosts importieren + +Führen Sie termscp mit `termscp import-ssh-hosts [ssh-config-datei]` aus. + +Importieren Sie alle Hosts aus der angegebenen SSH-Konfigurationsdatei (wenn keine angegeben ist, wird `~/.ssh/config` verwendet) als Lesezeichen in termscp. Identitätsdateien werden ebenfalls als SSH-Schlüssel in termscp importiert. + --- ## S3-Verbindungsparameter diff --git a/docs/es/man.md b/docs/es/man.md index 4f9bd08..8ce718e 100644 --- a/docs/es/man.md +++ b/docs/es/man.md @@ -8,6 +8,10 @@ - [Argumento de dirección de WebDAV](#argumento-de-dirección-de-webdav) - [Argumento dirección por SMB](#argumento-dirección-por-smb) - [Cómo se puede proporcionar la contraseña 🔐](#cómo-se-puede-proporcionar-la-contraseña-) + - [Subcomandos](#subcomandos) + - [Importar un tema](#importar-un-tema) + - [Instalar la versión más reciente](#instalar-la-versión-más-reciente) + - [Importar hosts SSH](#importar-hosts-ssh) - [S3 parámetros de conexión](#s3-parámetros-de-conexión) - [Credenciales de S3 🦊](#credenciales-de-s3-) - [Explorador de archivos 📂](#explorador-de-archivos-) @@ -153,6 +157,22 @@ La contraseña se puede proporcionar básicamente a través de 3 formas cuando s - Con `sshpass`: puede proporcionar la contraseña a través de `sshpass`, p. ej. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - Se te pedirá que ingreses: si no utilizas ninguno de los métodos anteriores, se te pedirá la contraseña, como ocurre con las herramientas más clásicas como `scp`, `ssh`, etc. +### Subcomandos + +#### Importar un tema + +Ejecute termscp como `termscp theme ` + +#### Instalar la versión más reciente + +Ejecute termscp como `termscp update` + +#### Importar hosts SSH + +Ejecute termscp como `termscp import-ssh-hosts [archivo-config-ssh]` + +Importa todos los hosts del archivo de configuración SSH especificado (si no se proporciona, se usará `~/.ssh/config`) como marcadores en termscp. Los archivos de identidad también se importarán como claves SSH en termscp. + --- ## S3 parámetros de conexión diff --git a/docs/fr/man.md b/docs/fr/man.md index 30f5444..d3c177a 100644 --- a/docs/fr/man.md +++ b/docs/fr/man.md @@ -8,6 +8,10 @@ - [Argument d'adresse WebDAV](#argument-dadresse-webdav) - [Argument d'adresse SMB](#argument-dadresse-smb) - [Comment le mot de passe peut être fourni 🔐](#comment-le-mot-de-passe-peut-être-fourni-) + - [Sous-commandes](#sous-commandes) + - [Importer un thème](#importer-un-thème) + - [Installer la dernière version](#installer-la-dernière-version) + - [Importer des hôtes SSH](#importer-des-hôtes-ssh) - [S3 paramètres de connexion](#s3-paramètres-de-connexion) - [Identifiants S3 🦊](#identifiants-s3-) - [Explorateur de fichiers 📂](#explorateur-de-fichiers-) @@ -142,7 +146,6 @@ syntaxe **Other systems**: smb://[username@][:port]/[/path/.../] ``` - #### Comment le mot de passe peut être fourni 🔐 Vous avez probablement remarqué que, lorsque vous fournissez l'adresse comme argument, il n'y a aucun moyen de fournir le mot de passe. @@ -152,6 +155,22 @@ Le mot de passe peut être fourni de 3 manières lorsque l'argument d'adresse es - Avec `sshpass`: vous pouvez fournir un mot de passe via `sshpass`, par ex. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - Il vous sera demandé : si vous n'utilisez aucune des méthodes précédentes, le mot de passe vous sera demandé, comme c'est le cas avec les outils plus classiques tels que `scp`, `ssh`, etc. +### Sous-commandes + +#### Importer un thème + +Exécutez termscp avec `termscp theme ` + +#### Installer la dernière version + +Exécutez termscp avec `termscp update` + +#### Importer des hôtes SSH + +Exécutez termscp avec `termscp import-ssh-hosts [fichier-config-ssh]` + +Importez tous les hôtes du fichier de configuration SSH spécifié (si non fourni, `~/.ssh/config` sera utilisé) comme favoris dans termscp. Les fichiers d'identité seront également importés comme clés SSH dans termscp. + --- ## S3 paramètres de connexion diff --git a/docs/it/man.md b/docs/it/man.md index 7d4effa..d583026 100644 --- a/docs/it/man.md +++ b/docs/it/man.md @@ -8,6 +8,10 @@ - [Argomento indirizzo per WebDAV](#argomento-indirizzo-per-webdav) - [Indirizzo SMB](#indirizzo-smb) - [Come fornire la password 🔐](#come-fornire-la-password-) + - [Sottocomandi](#sottocomandi) + - [Importare un tema](#importare-un-tema) + - [Installare l’ultima versione](#installare-lultima-versione) + - [Importare host SSH](#importare-host-ssh) - [Parametri di connessione S3](#parametri-di-connessione-s3) - [Credenziali S3 🦊](#credenziali-s3-) - [File explorer 📂](#file-explorer-) @@ -140,7 +144,6 @@ SMB ha una sintassi differente rispetto agli altri protocolli e cambia in base a smb://[username@][:port]/[/path/.../] ``` - #### Come fornire la password 🔐 Quando si usa l'argomento indirizzo non è possibile fornire la password direttamente nell'argomento, esistono però altri metodi per farlo: @@ -149,6 +152,22 @@ Quando si usa l'argomento indirizzo non è possibile fornire la password diretta - Tramite `sshpass`: puoi fornire la password tramite l'applicazione GNU/Linux sshpass `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - Forniscila quando richiesta: se non la fornisci tramite nessun metodo precedente, alla connessione ti verrà richiesto di fornirla in un prompt che la oscurerà (come avviene con sudo tipo). +### Sottocomandi + +#### Importare un tema + +Esegui termscp come `termscp theme ` + +#### Installare l’ultima versione + +Esegui termscp come `termscp update` + +#### Importare host SSH + +Esegui termscp come `termscp import-ssh-hosts [file-config-ssh]` + +Importa tutti gli host dal file di configurazione SSH specificato (se non fornito, verrà usato `~/.ssh/config`) come segnalibri in termscp. I file di identità verranno importati come chiavi SSH in termscp. + --- ## Parametri di connessione S3 diff --git a/docs/man.md b/docs/man.md index 15db697..178ddae 100644 --- a/docs/man.md +++ b/docs/man.md @@ -11,6 +11,7 @@ - [Subcommands](#subcommands) - [Import a theme](#import-a-theme) - [Install latest version](#install-latest-version) + - [Import ssh hosts](#import-ssh-hosts) - [S3 connection parameters](#s3-connection-parameters) - [S3 credentials 🦊](#s3-credentials-) - [File explorer 📂](#file-explorer-) @@ -166,6 +167,12 @@ Run termscp as `termscp theme ` Run termscp as `termscp update` +#### Import ssh hosts + +Run termscp as `termscp import-ssh-hosts [ssh-config-file]` + +Import all the hosts from the specified ssh config file (if not provided, `~/.ssh/config` will be used) as bookmarks in termscp. Identity files will be imported as ssh keys in termscp too. + --- ## S3 connection parameters diff --git a/docs/pt-BR/man.md b/docs/pt-BR/man.md index 7d29a09..2fa2d34 100644 --- a/docs/pt-BR/man.md +++ b/docs/pt-BR/man.md @@ -11,6 +11,7 @@ - [Subcomandos](#subcomandos) - [Importar um Tema](#importar-um-tema) - [Instalar a Última Versão](#instalar-a-última-versão) + - [Importar hosts SSH](#importar-hosts-ssh) - [Parâmetros de Conexão do S3](#parâmetros-de-conexão-do-s3) - [Credenciais do S3 🦊](#credenciais-do-s3-) - [Explorador de Arquivos 📂](#explorador-de-arquivos-) @@ -164,6 +165,12 @@ Execute o termscp como `termscp theme ` Execute o termscp como `termscp update` +#### Importar hosts SSH + +Execute o termscp como `termscp import-ssh-hosts [arquivo-config-ssh]` + +Importe todos os hosts do arquivo de configuração SSH especificado (se não for fornecido, `~/.ssh/config` será usado) como favoritos no termscp. Os arquivos de identidade também serão importados como chaves SSH no termscp. + --- ## Parâmetros de Conexão do S3 diff --git a/docs/zh-CN/man.md b/docs/zh-CN/man.md index 7e46c63..a04fc62 100644 --- a/docs/zh-CN/man.md +++ b/docs/zh-CN/man.md @@ -8,6 +8,10 @@ - [WebDAV 地址参数](#webdav-地址参数) - [SMB 地址参数](#smb-地址参数) - [如何输入密码](#如何输入密码) + - [子命令](#子命令) + - [导入主题](#导入主题) + - [安装最新版本](#安装最新版本) + - [导入 SSH 主机](#导入-ssh-主机) - [S3 连接参数](#s3-连接参数) - [Aws S3 凭证](#aws-s3-凭证) - [文件浏览](#文件浏览) @@ -149,6 +153,21 @@ smb://[username@][:port]/[/path/.../] - 通过 `sshpass`: 你可以通过 `sshpass` 传入密码, 例如: `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - 提示输入密码:如果你不使用前面的任何方法,你会被提示输入密码,就像 `scp`、`ssh` 等比较经典的工具上一样。 +### 子命令 + +#### 导入主题 + +以 termscp theme 的方式运行 termscp。 + +#### 安装最新版本 + +以 termscp update 的方式运行 termscp。 + +#### 导入 SSH 主机 + +以 `termscp import-ssh-hosts [ssh-config-file]` 的方式运行 termscp。 +从指定的 SSH 配置文件中导入所有主机(如果未提供,则使用 `~/.ssh/config`)作为 termscp 中的书签。身份文件也会作为 SSH 密钥导入到 termscp 中。 + --- ## S3 连接参数 diff --git a/src/activity_manager.rs b/src/activity_manager.rs index faf617c..38ed111 100644 --- a/src/activity_manager.rs +++ b/src/activity_manager.rs @@ -448,35 +448,7 @@ impl ActivityManager { // -- misc fn init_bookmarks_client(keyring: bool) -> Result, String> { - // Get config dir - match environment::init_config_dir() { - Ok(path) => { - // If some configure client, otherwise do nothing; don't bother users telling them that bookmarks are not supported on their system. - if let Some(config_dir_path) = path { - let bookmarks_file: PathBuf = - environment::get_bookmarks_paths(config_dir_path.as_path()); - // Initialize client - BookmarksClient::new( - bookmarks_file.as_path(), - config_dir_path.as_path(), - 16, - keyring, - ) - .map(Option::Some) - .map_err(|e| { - format!( - "Could not initialize bookmarks (at \"{}\", \"{}\"): {}", - bookmarks_file.display(), - config_dir_path.display(), - e - ) - }) - } else { - Ok(None) - } - } - Err(err) => Err(err), - } + crate::support::bookmarks_client(keyring) } /// Initialize configuration client diff --git a/src/cli.rs b/src/cli.rs index 840a18b..e497f89 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -15,6 +15,9 @@ use crate::system::logging::LogLevel; pub enum Task { Activity(NextActivity), + /// Import ssh hosts from the specified ssh config file, or from the default location + /// and save them as bookmarks. + ImportSshHosts(Option), ImportTheme(PathBuf), InstallUpdate, Version, @@ -72,7 +75,8 @@ pub struct Args { #[argh(subcommand)] pub enum ArgsSubcommands { Config(ConfigArgs), - LoadTheme(LoadThemeArgs), + ImportSshHosts(ImportSshHostsArgs), + ImportTheme(ImportThemeArgs), Update(UpdateArgs), } @@ -86,10 +90,20 @@ pub struct ConfigArgs {} #[argh(subcommand, name = "update")] pub struct UpdateArgs {} +#[derive(FromArgs)] +/// import ssh hosts from the specified ssh config file, or from the default location +/// and save them as bookmarks. +#[argh(subcommand, name = "import-ssh-hosts")] +pub struct ImportSshHostsArgs { + #[argh(positional)] + /// optional ssh config file; if not specified, the default location will be used + pub ssh_config: Option, +} + #[derive(FromArgs)] /// import the specified theme #[argh(subcommand, name = "theme")] -pub struct LoadThemeArgs { +pub struct ImportThemeArgs { #[argh(positional)] /// theme file pub theme: PathBuf, @@ -118,6 +132,14 @@ impl RunOpts { } } + pub fn import_ssh_hosts(ssh_config: Option, keyring: bool) -> Self { + Self { + task: Task::ImportSshHosts(ssh_config), + keyring, + ..Default::default() + } + } + pub fn import_theme(theme: PathBuf) -> Self { Self { task: Task::ImportTheme(theme), diff --git a/src/explorer/builder.rs b/src/explorer/builder.rs index d571d80..59a3e89 100644 --- a/src/explorer/builder.rs +++ b/src/explorer/builder.rs @@ -65,10 +65,10 @@ impl FileExplorerBuilder { /// Set formatter for FileExplorer pub fn with_formatter(&mut self, fmt_str: Option<&str>) -> &mut FileExplorerBuilder { - if let Some(e) = self.explorer.as_mut() { - if let Some(fmt_str) = fmt_str { - e.fmt = Formatter::new(fmt_str); - } + if let Some(e) = self.explorer.as_mut() + && let Some(fmt_str) = fmt_str + { + e.fmt = Formatter::new(fmt_str); } self } diff --git a/src/filetransfer/remotefs_builder.rs b/src/filetransfer/remotefs_builder.rs index b52fb7c..5c58fbc 100644 --- a/src/filetransfer/remotefs_builder.rs +++ b/src/filetransfer/remotefs_builder.rs @@ -245,10 +245,10 @@ impl RemoteFsBuilder { } // For SSH protocols, only set password if explicitly provided and non-empty. // This allows the SSH library to prioritize key-based and agent authentication. - if let Some(password) = params.password { - if !password.is_empty() { - opts = opts.password(password); - } + if let Some(password) = params.password + && !password.is_empty() + { + opts = opts.password(password); } if let Some(config_path) = config_client.get_ssh_config() { opts = opts.config_file( diff --git a/src/main.rs b/src/main.rs index 77c08f8..1bff2ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,7 @@ extern crate log; extern crate magic_crypt; use std::env; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::time::Duration; use self::activity_manager::{ActivityManager, NextActivity}; @@ -72,7 +72,10 @@ fn main() -> MainResult<()> { fn parse_args(args: Args) -> Result { let run_opts = match args.nested { Some(ArgsSubcommands::Update(_)) => RunOpts::update(), - Some(ArgsSubcommands::LoadTheme(args)) => RunOpts::import_theme(args.theme), + Some(ArgsSubcommands::ImportSshHosts(subargs)) => { + RunOpts::import_ssh_hosts(subargs.ssh_config, !args.wno_keyring) + } + Some(ArgsSubcommands::ImportTheme(args)) => RunOpts::import_theme(args.theme), Some(ArgsSubcommands::Config(_)) => RunOpts::config(), None => { let mut run_opts: RunOpts = RunOpts::default(); @@ -111,10 +114,10 @@ fn parse_args(args: Args) -> Result { }; // Local directory - if let Some(localdir) = run_opts.remote.local_dir.as_deref() { - if let Err(err) = env::set_current_dir(localdir) { - return Err(format!("Bad working directory argument: {err}")); - } + if let Some(localdir) = run_opts.remote.local_dir.as_deref() + && let Err(err) = env::set_current_dir(localdir) + { + return Err(format!("Bad working directory argument: {err}")); } run_opts @@ -127,6 +130,7 @@ fn parse_args(args: Args) -> Result { /// Run task and return rc fn run(run_opts: RunOpts) -> MainResult<()> { match run_opts.task { + Task::ImportSshHosts(ssh_config) => run_import_ssh_hosts(ssh_config, run_opts.keyring), Task::ImportTheme(theme) => run_import_theme(&theme), Task::InstallUpdate => run_install_update(), Task::Activity(activity) => { @@ -145,6 +149,17 @@ fn print_version() -> MainResult<()> { Ok(()) } +fn run_import_ssh_hosts(ssh_config_path: Option, keyring: bool) -> MainResult<()> { + support::import_ssh_hosts(ssh_config_path, keyring) + .map(|_| { + println!("SSH hosts have been successfully imported!"); + }) + .map_err(|err| { + eprintln!("{err}"); + err.into() + }) +} + fn run_import_theme(theme: &Path) -> MainResult<()> { match support::import_theme(theme) { Ok(_) => { diff --git a/src/support.rs b/src/support.rs index 64a0561..7e083ef 100644 --- a/src/support.rs +++ b/src/support.rs @@ -2,11 +2,14 @@ //! //! this module exposes some extra run modes for termscp, meant to be used for "support", such as installing themes -// mod +mod import_ssh_hosts; + use std::fs; use std::path::{Path, PathBuf}; +pub use self::import_ssh_hosts::import_ssh_hosts; use crate::system::auto_update::{Update, UpdateStatus}; +use crate::system::bookmarks_client::BookmarksClient; use crate::system::config_client::ConfigClient; use crate::system::environment; use crate::system::notifications::Notification; @@ -83,3 +86,36 @@ fn get_config_client() -> Option { } } } + +/// Init [`BookmarksClient`]. +pub fn bookmarks_client(keyring: bool) -> Result, String> { + // Get config dir + match environment::init_config_dir() { + Ok(path) => { + // If some configure client, otherwise do nothing; don't bother users telling them that bookmarks are not supported on their system. + if let Some(config_dir_path) = path { + let bookmarks_file: PathBuf = + environment::get_bookmarks_paths(config_dir_path.as_path()); + // Initialize client + BookmarksClient::new( + bookmarks_file.as_path(), + config_dir_path.as_path(), + 16, + keyring, + ) + .map(Option::Some) + .map_err(|e| { + format!( + "Could not initialize bookmarks (at \"{}\", \"{}\"): {}", + bookmarks_file.display(), + config_dir_path.display(), + e + ) + }) + } else { + Ok(None) + } + } + Err(err) => Err(err), + } +} diff --git a/src/support/import_ssh_hosts.rs b/src/support/import_ssh_hosts.rs new file mode 100644 index 0000000..9e8ae9b --- /dev/null +++ b/src/support/import_ssh_hosts.rs @@ -0,0 +1,326 @@ +use std::fs::File; +use std::io::BufReader; +use std::path::PathBuf; + +use ssh2_config::{Host, HostClause, ParseRule, SshConfig}; + +use crate::filetransfer::params::GenericProtocolParams; +use crate::filetransfer::{FileTransferParams, FileTransferProtocol, ProtocolParams}; + +/// Parameters required to add an ssh key for a host. +struct SshKeyParams { + host: String, + ssh_key: String, + username: String, +} + +/// Import ssh hosts from the specified ssh config file, or from the default location +/// and save them as bookmarks. +pub fn import_ssh_hosts(ssh_config: Option, keyring: bool) -> Result<(), String> { + // get config client + let mut cfg_client = super::get_config_client() + .ok_or_else(|| String::from("Could not import ssh hosts: could not load configuration"))?; + + // resolve ssh_config + let ssh_config = ssh_config.or_else(|| cfg_client.get_ssh_config().map(PathBuf::from)); + + // load bookmarks client + let mut bookmarks_client = super::bookmarks_client(keyring)? + .ok_or_else(|| String::from("Could not import ssh hosts: could not load bookmarks"))?; + + // load ssh config + let ssh_config = match ssh_config { + Some(p) => { + debug!("Importing ssh hosts from file: {}", p.display()); + let mut reader = BufReader::new( + File::open(&p) + .map_err(|e| format!("Could not open ssh config file {}: {e}", p.display()))?, + ); + SshConfig::default().parse(&mut reader, ParseRule::ALLOW_UNKNOWN_FIELDS) + } + None => { + debug!("Importing ssh hosts from default location"); + SshConfig::parse_default_file(ParseRule::ALLOW_UNKNOWN_FIELDS) + } + } + .map_err(|e| format!("Could not parse ssh config file: {e}"))?; + + // iter hosts and add bookmarks + ssh_config + .get_hosts() + .iter() + .flat_map(host_to_params) + .for_each(|(name, params, identity_file_params)| { + debug!("Adding bookmark for host: {name} with params: {params:?}"); + bookmarks_client.add_bookmark(name, params, false); + + // add ssh key if any + if let Some(identity_file_params) = identity_file_params { + debug!( + "Host {host} has identity file, will add ssh key for it", + host = identity_file_params.host + ); + if let Err(err) = cfg_client.add_ssh_key( + &identity_file_params.host, + &identity_file_params.username, + &identity_file_params.ssh_key, + ) { + error!( + "Could not add ssh key for host {host}: {err}", + host = identity_file_params.host + ); + } + } + }); + + // save bookmarks + if let Err(err) = bookmarks_client.write_bookmarks() { + return Err(format!( + "Could not save imported ssh hosts as bookmarks: {err}" + )); + } + + println!("Imported ssh hosts"); + + Ok(()) +} + +/// Tries to derive [`FileTransferParams`] from the specified ssh host. +fn host_to_params( + host: &Host, +) -> impl Iterator)> { + host.pattern + .iter() + .filter_map(|pattern| host_pattern_to_params(host, pattern)) +} + +/// Tries to derive [`FileTransferParams`] from the specified ssh host and pattern. +/// +/// If `IdentityFile` is specified in the host parameters, it will be included in the returned tuple. +fn host_pattern_to_params( + host: &Host, + pattern: &HostClause, +) -> Option<(String, FileTransferParams, Option)> { + debug!("Processing host with pattern: {pattern:?}",); + if pattern.negated || pattern.pattern.contains('*') || pattern.pattern.contains('?') { + debug!("Skipping host with pattern: {pattern}",); + return None; + } + + let address = host + .params + .host_name + .as_deref() + .unwrap_or(pattern.pattern.as_str()) + .to_string(); + debug!("Resolved address for pattern {pattern}: {address}"); + let port = host.params.port.unwrap_or(22); + debug!("Resolved port for pattern {pattern}: {port}"); + let username = host.params.user.clone(); + debug!("Resolved username for pattern {pattern}: {username:?}"); + + let identity_file_params = resolve_identity_file_path(host, pattern, &address); + + Some(( + pattern.to_string(), + FileTransferParams::new( + FileTransferProtocol::Sftp, + ProtocolParams::Generic( + GenericProtocolParams::default() + .address(address) + .port(port) + .username(username), + ), + ), + identity_file_params, + )) +} + +fn resolve_identity_file_path( + host: &Host, + pattern: &HostClause, + resolved_address: &str, +) -> Option { + let (Some(username), Some(identity_file)) = ( + host.params.user.as_ref(), + host.params.identity_file.as_ref().and_then(|v| v.first()), + ) else { + debug!( + "No identity file specified for host {host}, skipping ssh key import", + host = pattern.pattern + ); + return None; + }; + + // expand tilde + let identity_filepath = shellexpand::tilde(&identity_file.display().to_string()).to_string(); + debug!("Resolved identity file for pattern {pattern}: {identity_filepath}",); + let Ok(mut ssh_file) = File::open(identity_file) else { + error!( + "Could not open identity file {identity_filepath} for host {host}", + host = pattern.pattern + ); + return None; + }; + let mut ssh_key = String::new(); + use std::io::Read as _; + if let Err(err) = ssh_file.read_to_string(&mut ssh_key) { + error!( + "Could not read identity file {identity_filepath} for host {host}: {err}", + host = pattern.pattern + ); + return None; + } + + Some(SshKeyParams { + host: resolved_address.to_string(), + username: username.clone(), + ssh_key, + }) +} + +#[cfg(test)] +mod tests { + + use pretty_assertions::assert_eq; + use tempfile::NamedTempFile; + + use super::*; + use crate::system::bookmarks_client::BookmarksClient; + + #[test] + fn test_should_import_ssh_hosts() { + let ssh_test_config = ssh_test_config(); + + // import ssh hosts + let result = import_ssh_hosts(Some(ssh_test_config.config.path().to_path_buf()), false); + assert!(result.is_ok()); + + // verify imported hosts + let config_client = super::super::get_config_client() + .ok_or_else(|| String::from("Could not import ssh hosts: could not load configuration")) + .expect("failed to load config client"); + + // load bookmarks client + let bookmarks_client = super::super::bookmarks_client(false) + .expect("failed to load bookmarks client") + .expect("bookmarks client is none"); + + // verify bookmarks + check_bookmark(&bookmarks_client, "test1", "test1.example.com", 2200, None); + check_bookmark( + &bookmarks_client, + "test2", + "test2.example.com", + 22, + Some("test2user"), + ); + check_bookmark( + &bookmarks_client, + "test3", + "test3.example.com", + 2222, + Some("test3user"), + ); + + // verify ssh keys + let (host, username, _key) = config_client + .get_ssh_key("test3user@test3.example.com") + .expect("ssh key is missing for test3user@test3.example.com"); + + assert_eq!(host, "test3.example.com"); + assert_eq!(username, "test3user"); + } + + fn check_bookmark( + bookmarks_client: &BookmarksClient, + name: &str, + expected_address: &str, + expected_port: u16, + expected_username: Option<&str>, + ) { + // verify bookmarks + let bookmark = bookmarks_client + .get_bookmark(name) + .expect("failed to get bookmark"); + let params1 = bookmark + .params + .generic_params() + .expect("should have generic params"); + assert_eq!(params1.address, expected_address); + assert_eq!(params1.port, expected_port); + assert_eq!(params1.username.as_deref(), expected_username); + assert!(params1.password.is_none()); + } + + struct SshTestConfig { + config: NamedTempFile, + #[allow(dead_code)] + identity_file: NamedTempFile, + } + + fn ssh_test_config() -> SshTestConfig { + use std::io::Write as _; + let mut identity_file = NamedTempFile::new().expect("failed to create tempfile"); + writeln!( + identity_file, + r"-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEAxKyYUMRCNPlb4ZV1VMofrzApu2l3wgP4Ot9wBvHsw/+RMpcHIbQK +9iQqAVp8Z+M1fJyPXTKjoJtIzuCLF6Sjo0KI7/tFTh+yPnA5QYNLZOIRZb8skumL4gwHww +5Z942FDPuUDQ30C2mZR9lr3Cd5pA8S1ZSPTAV9QQHkpgoS8cAL8QC6dp3CJjUC8wzvXh3I +oN3bTKxCpM10KMEVuWO3lM4Nvr71auB9gzo1sFJ3bwebCZIRH01FROyA/GXRiaOtJFG/9N +nWWI/iG5AJzArKpLZNHIP+FxV/NoRH0WBXm9Wq5MrBYrD1NQzm+kInpS/2sXk3m1aZWqLm +HF2NKRXSbQAAA8iI+KSniPikpwAAAAdzc2gtcnNhAAABAQDErJhQxEI0+VvhlXVUyh+vMC +m7aXfCA/g633AG8ezD/5EylwchtAr2JCoBWnxn4zV8nI9dMqOgm0jO4IsXpKOjQojv+0VO +H7I+cDlBg0tk4hFlvyyS6YviDAfDDln3jYUM+5QNDfQLaZlH2WvcJ3mkDxLVlI9MBX1BAe +SmChLxwAvxALp2ncImNQLzDO9eHcig3dtMrEKkzXQowRW5Y7eUzg2+vvVq4H2DOjWwUndv +B5sJkhEfTUVE7ID8ZdGJo60kUb/02dZYj+IbkAnMCsqktk0cg/4XFX82hEfRYFeb1arkys +FisPU1DOb6QielL/axeTebVplaouYcXY0pFdJtAAAAAwEAAQAAAP8u3PFuTVV5SfGazwIm +MgNaux82iOsAT/HWFWecQAkqqrruUw5f+YajH/riV61NE9aq2qNOkcJrgpTWtqpt980GGd +SHWlgpRWQzfIooEiDk6Pk8RVFZsEykkDlJQSIu2onZjhi5A5ojHgZoGGabDsztSqoyOjPq +6WPvGYRiDAR3leBMyp1WufBCJqAsC4L8CjPJSmnZhc5a0zXkC9Syz74Fa08tdM7bGhtvP1 +GmzuYxkgxHH2IFeoumUSBHRiTZayGuRUDel6jgEiUMxenaDKXe7FpYzMm9tQZA10Mm4LhK +5rP9nd2/KRTFRnfZMnKvtIRC9vtlSLBe14qw+4ZCl60AAACAf1kghlO3+HIWplOmk/lCL0 +w75Zz+RdvueL9UuoyNN1QrUEY420LsixgWSeRPby+Rb/hW+XSAZJQHowQ8acFJhU85So7f +4O4wcDuE4f6hpsW9tTfkCEUdLCQJ7EKLCrod6jIV7hvI6rvXiVucRpeAzdOaq4uzj2cwDd +tOdYVsnmQAAACBAOVxBsvO/Sr3rZUbNtA6KewZh/09HNGoKNaCeiD7vaSn2UJbbPRByF/o +Oo5zv8ee8r3882NnmG808XfSn7pPZAzbbTmOaJt0fmyZhivCghSNzV6njW3o0PdnC0fGZQ +ruVXgkd7RJFbsIiD4dDcF4VCjwWHfTK21EOgJUA5pN6TNvAAAAgQDbcJWRx8Uyhkj2+srb +3n2Rt6CR7kEl9cw17ItFjMn+pO81/5U2aGw0iLlX7E06TAMQC+dyW/WaxQRey8RRdtbJ1e +TNKCN34QCWkyuYRHGhcNc0quEDayPw5QWGXlP4BzjfRUcPxY9cCXLe5wDLYsX33HwOAc59 +RorU9FCmS/654wAAABFyb290QDhjNTBmZDRjMzQ1YQECAw== +-----END OPENSSH PRIVATE KEY-----" + ) + .expect("failed to write identity file"); + + let mut file = NamedTempFile::new().expect("failed to create tempfile"); + + // let's declare a couple of hosts + writeln!( + file, + r#" +Host test1 + HostName test1.example.com + Port 2200 + +Host test2 + HostName test2.example.com + User test2user + +Host test3 + HostName test3.example.com + User test3user + Port 2222 + IdentityFile {identity_path} +"#, + identity_path = identity_file.path().display() + ) + .expect("failed to write ssh config"); + + SshTestConfig { + config: file, + identity_file, + } + } +} diff --git a/src/system/config_client.rs b/src/system/config_client.rs index e7b9aa1..90fe0aa 100644 --- a/src/system/config_client.rs +++ b/src/system/config_client.rs @@ -300,19 +300,18 @@ impl ConfigClient { /// Get ssh key from host. /// None is returned if key doesn't exist - /// `std::io::Error` is returned in case it was not possible to read the key file - pub fn get_ssh_key(&self, mkey: &str) -> std::io::Result> { + pub fn get_ssh_key(&self, mkey: &str) -> Option { if self.degraded { - return Ok(None); + return None; } // Check if Key exists match self.config.remote.ssh_keys.get(mkey) { - None => Ok(None), + None => None, Some(key_path) => { // Get host and username let (host, username): (String, String) = Self::get_ssh_tokens(mkey); // Return key - Ok(Some((host, username, PathBuf::from(key_path)))) + Some((host, username, PathBuf::from(key_path))) } } } @@ -451,7 +450,7 @@ mod tests { // I/O assert!(client.add_ssh_key("Omar", "omar", "omar").is_err()); assert!(client.del_ssh_key("omar", "omar").is_err()); - assert!(client.get_ssh_key("omar").ok().unwrap().is_none()); + assert!(client.get_ssh_key("omar").is_none()); assert!(client.write_config().is_err()); assert!(client.read_config().is_err()); } @@ -493,7 +492,7 @@ mod tests { let mut expected_key_path: PathBuf = key_path; expected_key_path.push("pi@192.168.1.31.key"); assert_eq!( - client.get_ssh_key("pi@192.168.1.31").unwrap().unwrap(), + client.get_ssh_key("pi@192.168.1.31").unwrap(), ( String::from("192.168.1.31"), String::from("pi"), @@ -684,7 +683,7 @@ mod tests { ); // Iterate keys for key in client.iter_ssh_keys() { - let host: SshHost = client.get_ssh_key(key).ok().unwrap().unwrap(); + let host: SshHost = client.get_ssh_key(key).unwrap(); assert_eq!(host.0, String::from("192.168.1.31")); assert_eq!(host.1, String::from("pi")); let mut expected_key_path: PathBuf = key_path.clone(); @@ -699,7 +698,7 @@ mod tests { assert_eq!(key, rsa_key); } // Unexisting key - assert!(client.get_ssh_key("test").ok().unwrap().is_none()); + assert!(client.get_ssh_key("test").is_none()); // Delete key assert!(client.del_ssh_key("192.168.1.31", "pi").is_ok()); } diff --git a/src/system/sshkey_storage.rs b/src/system/sshkey_storage.rs index 259357a..2101b73 100644 --- a/src/system/sshkey_storage.rs +++ b/src/system/sshkey_storage.rs @@ -103,17 +103,11 @@ impl From<&ConfigClient> for SshKeyStorage { // Iterate over keys in storage for key in cfg_client.iter_ssh_keys() { match cfg_client.get_ssh_key(key) { - Ok(host) => match host { - Some((addr, username, rsa_key_path)) => { - let key_name: String = Self::make_mapkey(&addr, &username); - hosts.insert(key_name, rsa_key_path); - } - None => continue, - }, - Err(err) => { - error!("Failed to get SSH key for {}: {}", key, err); - continue; + Some((addr, username, rsa_key_path)) => { + let key_name: String = Self::make_mapkey(&addr, &username); + hosts.insert(key_name, rsa_key_path); } + None => continue, } info!("Got SSH key for {}", key); } diff --git a/src/ui/activities/auth/bookmarks.rs b/src/ui/activities/auth/bookmarks.rs index 3e70e62..06f9e7f 100644 --- a/src/ui/activities/auth/bookmarks.rs +++ b/src/ui/activities/auth/bookmarks.rs @@ -30,13 +30,13 @@ impl AuthActivity { pub(super) fn load_bookmark(&mut self, form_tab: FormTab, idx: usize) { if let Some(bookmarks_cli) = self.bookmarks_client() { // Iterate over bookmarks - if let Some(key) = self.bookmarks_list.get(idx) { - if let Some(bookmark) = bookmarks_cli.get_bookmark(key) { - // Load parameters into components - match form_tab { - FormTab::Remote => self.load_remote_bookmark_into_gui(bookmark), - FormTab::HostBridge => self.load_host_bridge_bookmark_into_gui(bookmark), - } + if let Some(key) = self.bookmarks_list.get(idx) + && let Some(bookmark) = bookmarks_cli.get_bookmark(key) + { + // Load parameters into components + match form_tab { + FormTab::Remote => self.load_remote_bookmark_into_gui(bookmark), + FormTab::HostBridge => self.load_host_bridge_bookmark_into_gui(bookmark), } } } @@ -99,13 +99,13 @@ impl AuthActivity { pub(super) fn load_recent(&mut self, form_tab: FormTab, idx: usize) { if let Some(client) = self.bookmarks_client() { // Iterate over bookmarks - if let Some(key) = self.recents_list.get(idx) { - if let Some(bookmark) = client.get_recent(key) { - // Load parameters - match form_tab { - FormTab::Remote => self.load_remote_bookmark_into_gui(bookmark), - FormTab::HostBridge => self.load_host_bridge_bookmark_into_gui(bookmark), - } + if let Some(key) = self.recents_list.get(idx) + && let Some(bookmark) = client.get_recent(key) + { + // Load parameters + match form_tab { + FormTab::Remote => self.load_remote_bookmark_into_gui(bookmark), + FormTab::HostBridge => self.load_host_bridge_bookmark_into_gui(bookmark), } } } @@ -129,10 +129,10 @@ impl AuthActivity { /// Write bookmarks to file fn write_bookmarks(&mut self) { - if let Some(bookmarks_cli) = self.bookmarks_client() { - if let Err(err) = bookmarks_cli.write_bookmarks() { - self.mount_error(format!("Could not write bookmarks: {err}").as_str()); - } + if let Some(bookmarks_cli) = self.bookmarks_client() + && let Err(err) = bookmarks_cli.write_bookmarks() + { + self.mount_error(format!("Could not write bookmarks: {err}").as_str()); } } diff --git a/src/ui/activities/auth/update.rs b/src/ui/activities/auth/update.rs index 539cbf9..5e4b69e 100644 --- a/src/ui/activities/auth/update.rs +++ b/src/ui/activities/auth/update.rs @@ -126,13 +126,13 @@ impl AuthActivity { self.host_bridge_protocol = protocol; // Update port let port: u16 = self.get_input_port(FormTab::HostBridge); - if let HostBridgeProtocol::Remote(remote_protocol) = protocol { - if Self::is_port_standard(port) { - self.mount_port( - FormTab::HostBridge, - Self::get_default_port_for_protocol(remote_protocol), - ); - } + if let HostBridgeProtocol::Remote(remote_protocol) = protocol + && Self::is_port_standard(port) + { + self.mount_port( + FormTab::HostBridge, + Self::get_default_port_for_protocol(remote_protocol), + ); } } FormMsg::RemoteProtocolChanged(protocol) => { diff --git a/src/ui/activities/auth/view.rs b/src/ui/activities/auth/view.rs index 70e2ffd..0916724 100644 --- a/src/ui/activities/auth/view.rs +++ b/src/ui/activities/auth/view.rs @@ -687,30 +687,30 @@ impl AuthActivity { /// mount release notes text area pub(super) fn mount_release_notes(&mut self) { - if let Some(ctx) = self.context.as_ref() { - if let Some(release_notes) = ctx.store().get_string(super::STORE_KEY_RELEASE_NOTES) { - // make spans - let info_color = self.theme().misc_info_dialog; - assert!( - self.app - .remount( - Id::NewVersionChangelog, - Box::new(components::ReleaseNotes::new(release_notes, info_color)), - vec![] - ) - .is_ok() - ); - assert!( - self.app - .remount( - Id::InstallUpdatePopup, - Box::new(components::InstallUpdatePopup::new(info_color)), - vec![] - ) - .is_ok() - ); - assert!(self.app.active(&Id::InstallUpdatePopup).is_ok()); - } + if let Some(ctx) = self.context.as_ref() + && let Some(release_notes) = ctx.store().get_string(super::STORE_KEY_RELEASE_NOTES) + { + // make spans + let info_color = self.theme().misc_info_dialog; + assert!( + self.app + .remount( + Id::NewVersionChangelog, + Box::new(components::ReleaseNotes::new(release_notes, info_color)), + vec![] + ) + .is_ok() + ); + assert!( + self.app + .remount( + Id::InstallUpdatePopup, + Box::new(components::InstallUpdatePopup::new(info_color)), + vec![] + ) + .is_ok() + ); + assert!(self.app.active(&Id::InstallUpdatePopup).is_ok()); } } diff --git a/src/ui/activities/filetransfer/components/popups/goto.rs b/src/ui/activities/filetransfer/components/popups/goto.rs index d7447d1..4797ed5 100644 --- a/src/ui/activities/filetransfer/components/popups/goto.rs +++ b/src/ui/activities/filetransfer/components/popups/goto.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use tui_realm_stdlib::Input; use tuirealm::command::{Cmd, CmdResult, Direction, Position}; @@ -158,7 +158,7 @@ impl OwnStates { .unwrap_or_else(|| PathBuf::from("/")); // if path is `.`, then return None - if parent == PathBuf::from(".") { + if parent == Path::new(".") { return Suggestion::None; } diff --git a/src/ui/activities/filetransfer/mod.rs b/src/ui/activities/filetransfer/mod.rs index 3d515ed..5416411 100644 --- a/src/ui/activities/filetransfer/mod.rs +++ b/src/ui/activities/filetransfer/mod.rs @@ -506,10 +506,10 @@ impl Activity for FileTransferActivity { /// This function must be called once before terminating the activity. fn on_destroy(&mut self) -> Option { // Destroy cache - if let Some(cache) = self.cache.take() { - if let Err(err) = cache.close() { - error!("Failed to delete cache: {}", err); - } + if let Some(cache) = self.cache.take() + && let Err(err) = cache.close() + { + error!("Failed to delete cache: {}", err); } // Disable raw mode if let Err(err) = self.context_mut().terminal().disable_raw_mode() { diff --git a/src/ui/activities/setup/actions.rs b/src/ui/activities/setup/actions.rs index 115ead6..dd27e6a 100644 --- a/src/ui/activities/setup/actions.rs +++ b/src/ui/activities/setup/actions.rs @@ -99,27 +99,14 @@ impl SetupActivity { Ok(State::One(StateValue::Usize(idx))) => Some(idx), _ => None, }; - if let Some(idx) = idx { - let key: Option = self.config().iter_ssh_keys().nth(idx).cloned(); - if let Some(key) = key { - match self.config().get_ssh_key(&key) { - Ok(opt) => { - if let Some((host, username, _)) = opt { - if let Err(err) = self.delete_ssh_key(host.as_str(), username.as_str()) - { - // Report error - self.mount_error(err.as_str()); - } - } - } - Err(err) => { - // Report error - self.mount_error( - format!("Could not get ssh key \"{key}\": {err}").as_str(), - ); - } - } - } + // get ssh key and delete it + if let Some(Err(err)) = idx + .and_then(|i| self.config().iter_ssh_keys().nth(i).cloned()) + .and_then(|key| self.config().get_ssh_key(&key)) + .map(|(host, username, _)| self.delete_ssh_key(host.as_str(), username.as_str())) + { + // Report error + self.mount_error(err.as_str()); } } diff --git a/src/ui/activities/setup/config.rs b/src/ui/activities/setup/config.rs index ae49445..d26e086 100644 --- a/src/ui/activities/setup/config.rs +++ b/src/ui/activities/setup/config.rs @@ -77,16 +77,11 @@ impl SetupActivity { Some(key) => { // Get key path match ctx.config().get_ssh_key(key) { - Ok(ssh_key) => match ssh_key { - None => Ok(()), - Some((_, _, key_path)) => { - match edit::edit_file(key_path.as_path()) { - Ok(_) => Ok(()), - Err(err) => Err(format!("Could not edit ssh key: {err}")), - } - } + None => Ok(()), + Some((_, _, key_path)) => match edit::edit_file(key_path.as_path()) { + Ok(_) => Ok(()), + Err(err) => Err(format!("Could not edit ssh key: {err}")), }, - Err(err) => Err(format!("Could not read ssh key: {err}")), } } None => Ok(()), diff --git a/src/ui/activities/setup/view/ssh_keys.rs b/src/ui/activities/setup/view/ssh_keys.rs index 7dba30f..56933e1 100644 --- a/src/ui/activities/setup/view/ssh_keys.rs +++ b/src/ui/activities/setup/view/ssh_keys.rs @@ -126,7 +126,7 @@ impl SetupActivity { .config() .iter_ssh_keys() .map(|x| { - let (addr, username, _) = self.config().get_ssh_key(x).ok().unwrap().unwrap(); + let (addr, username, _) = self.config().get_ssh_key(x).unwrap(); format!("{username} at {addr}") }) .collect(); From 085ab721f9999d610b97748a12fe2ad05b9aa5ae Mon Sep 17 00:00:00 2001 From: veeso Date: Sun, 9 Nov 2025 17:38:50 +0100 Subject: [PATCH 07/14] build: remotefs-ssh 0.7.1 This version fixes compatibility with hosts which don't use bash/sh as the default shell. closes #365 --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8e2e4a..adf87f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1272,7 +1272,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -2032,7 +2032,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.57.0", + "windows-core 0.61.2", ] [[package]] @@ -3553,9 +3553,9 @@ dependencies = [ [[package]] name = "remotefs-ssh" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29de4702886ae0e4433904d4f6f9b2ed2961d31d76a7e7bef58305097238eb6" +checksum = "5ca8b65fbd60801ac03973a41196b030fb04d1ce1af33d3c58c5bad94d46eb27" dependencies = [ "chrono", "lazy-regex", From 75943f2b93acb76fb2e3f1c40a5b53f8bb405564 Mon Sep 17 00:00:00 2001 From: Christian Visintin Date: Sun, 9 Nov 2025 19:00:17 +0100 Subject: [PATCH 08/14] feat: Changed file overwrite behaviour (#366) Now the user can choose for each file whether to overwrite, skip or overwrite all/skip all. closes #335 --- CHANGELOG.md | 8 +- .../activities/filetransfer/actions/find.rs | 56 ++--- .../activities/filetransfer/actions/save.rs | 217 +++++++++++++----- .../activities/filetransfer/components/mod.rs | 5 +- .../filetransfer/components/popups.rs | 111 ++------- src/ui/activities/filetransfer/mod.rs | 11 +- src/ui/activities/filetransfer/update.rs | 10 - src/ui/activities/filetransfer/view.rs | 56 +---- 8 files changed, 218 insertions(+), 256 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8c7f87..17af7c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,13 +47,15 @@ Released on 20/09/2025 - [Issue 331](https://github.com/veeso/termscp/issues/331): Added new `import-ssh-hosts` CLI subcommand to import all the hosts from the ssh config as bookmarks. +- [Issue 335](https://github.com/veeso/termscp/issues/335): Changed file overwrite behaviour + - Now the user can choose for each file whether to overwrite, skip or overwrite all/skip all. +- [Issue 354](https://github.com/veeso/termscp/issues/354): + - Removed error popup message if failed to check for updates. + - Prevent long timeouts when checking for updates if the network is down or the DNS is not working. - [Issue 356](https://github.com/veeso/termscp/issues/356): Fixed SSH auth issue not trying with the password if any RSA key was found. - [Issue 334](https://github.com/veeso/termscp/issues/334): SMB support for MacOS with vendored build of libsmbclient. - [Issue 337](https://github.com/veeso/termscp/issues/337): Migrated to libssh.org on Linux and MacOS for better ssh agent support. - [Issue 361](https://github.com/veeso/termscp/issues/361): Report a message while calculating total size of files to transfer. -- [Issue 354](https://github.com/veeso/termscp/issues/354): - - Removed error popup message if failed to check for updates. - - Prevent long timeouts when checking for updates if the network is down or the DNS is not working. ## 0.18.0 diff --git a/src/ui/activities/filetransfer/actions/find.rs b/src/ui/activities/filetransfer/actions/find.rs index a8f3c9f..9ccff01 100644 --- a/src/ui/activities/filetransfer/actions/find.rs +++ b/src/ui/activities/filetransfer/actions/find.rs @@ -99,24 +99,16 @@ impl FileTransferActivity { // Iter files match self.browser.tab() { FileExplorerTab::FindHostBridge | FileExplorerTab::HostBridge => { - if self.config().get_prompt_on_file_replace() { - // Check which file would be replaced - let existing_files: Vec<&File> = entries - .iter() - .filter(|(x, dest_path)| { - self.remote_file_exists( - Self::file_to_check_many(x, dest_path.as_path()).as_path(), - ) - }) - .map(|(x, _)| x) - .collect(); - // Check whether to replace files - if !existing_files.is_empty() - && !self.should_replace_files(existing_files) - { - return; - } - } + let super::save::TransferFilesWithOverwritesResult::FilesToTransfer( + entries, + ) = self.get_files_to_transfer_with_overwrites( + entries, + super::save::CheckFileExists::Remote, + ) + else { + debug!("User cancelled file transfer due to overwrites"); + return; + }; if let Err(err) = self.filetransfer_send( TransferPayload::TransferQueue(entries), dest_path.as_path(), @@ -131,24 +123,16 @@ impl FileTransferActivity { } } FileExplorerTab::FindRemote | FileExplorerTab::Remote => { - if self.config().get_prompt_on_file_replace() { - // Check which file would be replaced - let existing_files: Vec<&File> = entries - .iter() - .filter(|(x, dest_path)| { - self.host_bridge_file_exists( - Self::file_to_check_many(x, dest_path.as_path()).as_path(), - ) - }) - .map(|(x, _)| x) - .collect(); - // Check whether to replace files - if !existing_files.is_empty() - && !self.should_replace_files(existing_files) - { - return; - } - } + let super::save::TransferFilesWithOverwritesResult::FilesToTransfer( + entries, + ) = self.get_files_to_transfer_with_overwrites( + entries, + super::save::CheckFileExists::HostBridge, + ) + else { + debug!("User cancelled file transfer due to overwrites"); + return; + }; if let Err(err) = self.filetransfer_recv( TransferPayload::TransferQueue(entries), dest_path.as_path(), diff --git a/src/ui/activities/filetransfer/actions/save.rs b/src/ui/activities/filetransfer/actions/save.rs index fe2cf65..d6c477e 100644 --- a/src/ui/activities/filetransfer/actions/save.rs +++ b/src/ui/activities/filetransfer/actions/save.rs @@ -10,6 +10,37 @@ use super::{ TransferPayload, }; +enum GetFileToReplaceResult { + Replace(Vec<(File, PathBuf)>), + Cancel, +} + +/// Result of getting files to transfer with overwrites. +/// +/// - FilesToTransfer: files to transfer. +/// - Cancel: user cancelled the operation. +pub(crate) enum TransferFilesWithOverwritesResult { + FilesToTransfer(Vec<(File, PathBuf)>), + Cancel, +} + +/// Decides whether to check file existence on host bridge or remote side. +pub(crate) enum CheckFileExists { + HostBridge, + Remote, +} + +/// Options for all files replacement. +/// +/// - ReplaceAll: user wants to replace all files. +/// - SkipAll: user wants to skip all files. +/// - Unset: no option set yet. +enum AllOpts { + ReplaceAll, + SkipAll, + Unset, +} + impl FileTransferActivity { pub(crate) fn action_local_saveas(&mut self, input: String) { self.local_send_file(TransferOpts::default().save_as(Some(input))); @@ -60,22 +91,12 @@ impl FileTransferActivity { dest_path.push(save_as); } // Iter files - if self.config().get_prompt_on_file_replace() { - // Check which file would be replaced - let existing_files: Vec<&File> = entries - .iter() - .filter(|(x, dest_path)| { - self.remote_file_exists( - Self::file_to_check_many(x, dest_path.as_path()).as_path(), - ) - }) - .map(|(x, _)| x) - .collect(); - // Check whether to replace files - if !existing_files.is_empty() && !self.should_replace_files(existing_files) { - return; - } - } + let TransferFilesWithOverwritesResult::FilesToTransfer(entries) = + self.get_files_to_transfer_with_overwrites(entries, CheckFileExists::Remote) + else { + debug!("User cancelled file transfer due to overwrites"); + return; + }; if let Err(err) = self.filetransfer_send( TransferPayload::TransferQueue(entries), dest_path.as_path(), @@ -128,23 +149,13 @@ impl FileTransferActivity { if let Some(save_as) = opts.save_as { dest_path.push(save_as); } - // Iter files - if self.config().get_prompt_on_file_replace() { - // Check which file would be replaced - let existing_files: Vec<&File> = entries - .iter() - .filter(|(x, dest_path)| { - self.host_bridge_file_exists( - Self::file_to_check_many(x, dest_path.as_path()).as_path(), - ) - }) - .map(|(x, _)| x) - .collect(); - // Check whether to replace files - if !existing_files.is_empty() && !self.should_replace_files(existing_files) { - return; - } - } + let TransferFilesWithOverwritesResult::FilesToTransfer(entries) = self + .get_files_to_transfer_with_overwrites(entries, CheckFileExists::HostBridge) + else { + debug!("User cancelled file transfer due to overwrites"); + return; + }; + if let Err(err) = self.filetransfer_recv( TransferPayload::TransferQueue(entries), dest_path.as_path(), @@ -172,11 +183,17 @@ impl FileTransferActivity { self.mount_radio_replace(&file_name); // Wait for answer trace!("Asking user whether he wants to replace file {}", file_name); - if self.wait_for_pending_msg(&[ - Msg::PendingAction(PendingActionMsg::CloseReplacePopups), - Msg::PendingAction(PendingActionMsg::TransferPendingFile), - ]) == Msg::PendingAction(PendingActionMsg::TransferPendingFile) - { + if matches!( + self.wait_for_pending_msg(&[ + Msg::PendingAction(PendingActionMsg::ReplaceCancel), + Msg::PendingAction(PendingActionMsg::ReplaceOverwrite), + Msg::PendingAction(PendingActionMsg::ReplaceSkip), + Msg::PendingAction(PendingActionMsg::ReplaceSkipAll), + Msg::PendingAction(PendingActionMsg::ReplaceOverwriteAll), + ]), + Msg::PendingAction(PendingActionMsg::ReplaceOverwrite) + | Msg::PendingAction(PendingActionMsg::ReplaceOverwriteAll) + ) { trace!("User wants to replace file"); self.umount_radio_replace(); true @@ -187,28 +204,76 @@ impl FileTransferActivity { } } - /// Set pending transfer for many files into storage and mount radio - pub(crate) fn should_replace_files(&mut self, files: Vec<&File>) -> bool { - let file_names: Vec = files.iter().map(|x| x.name()).collect(); - self.mount_radio_replace_many(file_names.as_slice()); - // Wait for answer - trace!( - "Asking user whether he wants to replace files {:?}", - file_names - ); - if self.wait_for_pending_msg(&[ - Msg::PendingAction(PendingActionMsg::CloseReplacePopups), - Msg::PendingAction(PendingActionMsg::TransferPendingFile), - ]) == Msg::PendingAction(PendingActionMsg::TransferPendingFile) - { - trace!("User wants to replace files"); + /// Get files to replace + fn get_files_to_replace(&mut self, files: Vec<(File, PathBuf)>) -> GetFileToReplaceResult { + // keep only files the user want to replace + let mut files_to_replace = vec![]; + let mut all_opts = AllOpts::Unset; + for (file, p) in files { + // Check for all opts + match all_opts { + AllOpts::ReplaceAll => { + trace!( + "User wants to replace all files, including file {}", + file.name() + ); + files_to_replace.push((file, p)); + continue; + } + AllOpts::SkipAll => { + trace!( + "User wants to skip all files, including file {}", + file.name() + ); + continue; + } + AllOpts::Unset => {} + } + + let file_name = file.name(); + self.mount_radio_replace(&file_name); + + // Wait for answer + match self.wait_for_pending_msg(&[ + Msg::PendingAction(PendingActionMsg::ReplaceCancel), + Msg::PendingAction(PendingActionMsg::ReplaceOverwrite), + Msg::PendingAction(PendingActionMsg::ReplaceSkip), + Msg::PendingAction(PendingActionMsg::ReplaceSkipAll), + Msg::PendingAction(PendingActionMsg::ReplaceOverwriteAll), + ]) { + Msg::PendingAction(PendingActionMsg::ReplaceCancel) => { + trace!("The user cancelled the replace operation"); + self.umount_radio_replace(); + return GetFileToReplaceResult::Cancel; + } + Msg::PendingAction(PendingActionMsg::ReplaceOverwrite) => { + trace!("User wants to replace file {}", file_name); + files_to_replace.push((file, p)); + } + Msg::PendingAction(PendingActionMsg::ReplaceOverwriteAll) => { + trace!( + "User wants to replace all files from now on, including file {}", + file_name + ); + files_to_replace.push((file, p)); + all_opts = AllOpts::ReplaceAll; + } + Msg::PendingAction(PendingActionMsg::ReplaceSkip) => { + trace!("The user skipped file {}", file_name); + } + Msg::PendingAction(PendingActionMsg::ReplaceSkipAll) => { + trace!( + "The user skipped all files from now on, including file {}", + file_name + ); + all_opts = AllOpts::SkipAll; + } + _ => {} + } self.umount_radio_replace(); - true - } else { - trace!("The user doesn't want replace file"); - self.umount_radio_replace(); - false } + + GetFileToReplaceResult::Replace(files_to_replace) } /// Get file to check for path @@ -224,4 +289,40 @@ impl FileTransferActivity { p.push(e.name()); p } + + /// Get the files to transfer with overwrites. + /// + /// Existing and unexisting files are splitted, and only existing files are prompted for replacement. + pub(crate) fn get_files_to_transfer_with_overwrites( + &mut self, + files: Vec<(File, PathBuf)>, + file_exists: CheckFileExists, + ) -> TransferFilesWithOverwritesResult { + if !self.config().get_prompt_on_file_replace() { + return TransferFilesWithOverwritesResult::FilesToTransfer(files); + } + + // unzip between existing and non-existing files + let (existing_files, new_files): (Vec<_>, Vec<_>) = + files.into_iter().partition(|(x, dest_path)| { + let p = Self::file_to_check_many(x, dest_path); + match file_exists { + CheckFileExists::Remote => self.remote_file_exists(p.as_path()), + CheckFileExists::HostBridge => self.host_bridge_file_exists(p.as_path()), + } + }); + + // filter only files to replace + let existing_files = match self.get_files_to_replace(existing_files) { + GetFileToReplaceResult::Replace(files) => files, + GetFileToReplaceResult::Cancel => { + return TransferFilesWithOverwritesResult::Cancel; + } + }; + + // merge back + TransferFilesWithOverwritesResult::FilesToTransfer( + existing_files.into_iter().chain(new_files).collect(), + ) + } } diff --git a/src/ui/activities/filetransfer/components/mod.rs b/src/ui/activities/filetransfer/components/mod.rs index d47a477..4f20a1e 100644 --- a/src/ui/activities/filetransfer/components/mod.rs +++ b/src/ui/activities/filetransfer/components/mod.rs @@ -21,9 +21,8 @@ pub use popups::{ ATTR_FILES, ChmodPopup, CopyPopup, DeletePopup, DisconnectPopup, ErrorPopup, FatalPopup, FileInfoPopup, FilterPopup, GotoPopup, KeybindingsPopup, MkdirPopup, NewfilePopup, OpenWithPopup, ProgressBarFull, ProgressBarPartial, QuitPopup, RenamePopup, ReplacePopup, - ReplacingFilesListPopup, SaveAsPopup, SortingPopup, StatusBarLocal, StatusBarRemote, - SymlinkPopup, SyncBrowsingMkdirPopup, WaitPopup, WalkdirWaitPopup, WatchedPathsList, - WatcherPopup, + SaveAsPopup, SortingPopup, StatusBarLocal, StatusBarRemote, SymlinkPopup, + SyncBrowsingMkdirPopup, WaitPopup, WalkdirWaitPopup, WatchedPathsList, WatcherPopup, }; pub use transfer::{ExplorerFind, ExplorerFuzzy, ExplorerLocal, ExplorerRemote}; diff --git a/src/ui/activities/filetransfer/components/popups.rs b/src/ui/activities/filetransfer/components/popups.rs index 3b6b656..efd6a61 100644 --- a/src/ui/activities/filetransfer/components/popups.rs +++ b/src/ui/activities/filetransfer/components/popups.rs @@ -1196,7 +1196,7 @@ impl ReplacePopup { .modifiers(BorderType::Rounded), ) .foreground(color) - .choices(["Yes", "No"]) + .choices(["Replace", "Skip", "Replace All", "Skip All", "Cancel"]) .title(text, Alignment::Center), } } @@ -1205,9 +1205,6 @@ impl ReplacePopup { impl Component for ReplacePopup { fn on(&mut self, ev: Event) -> Option { match ev { - Event::Keyboard(KeyEvent { code: Key::Tab, .. }) => { - Some(Msg::Ui(UiMsg::ReplacePopupTabbed)) - } Event::Keyboard(KeyEvent { code: Key::Left, .. }) => { @@ -1221,102 +1218,36 @@ impl Component for ReplacePopup { Some(Msg::None) } Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => { - Some(Msg::PendingAction(PendingActionMsg::CloseReplacePopups)) + Some(Msg::PendingAction(PendingActionMsg::ReplaceCancel)) } Event::Keyboard(KeyEvent { code: Key::Char('y'), modifiers: KeyModifiers::NONE, - }) => Some(Msg::PendingAction(PendingActionMsg::TransferPendingFile)), + }) => Some(Msg::PendingAction(PendingActionMsg::ReplaceOverwrite)), Event::Keyboard(KeyEvent { code: Key::Char('n'), modifiers: KeyModifiers::NONE, - }) => Some(Msg::PendingAction(PendingActionMsg::CloseReplacePopups)), + }) => Some(Msg::PendingAction(PendingActionMsg::ReplaceSkip)), Event::Keyboard(KeyEvent { code: Key::Enter, .. - }) => { - if matches!( - self.perform(Cmd::Submit), - CmdResult::Submit(State::One(StateValue::Usize(0))) - ) { - Some(Msg::PendingAction(PendingActionMsg::TransferPendingFile)) - } else { - Some(Msg::PendingAction(PendingActionMsg::CloseReplacePopups)) + }) => match self.perform(Cmd::Submit) { + CmdResult::Submit(State::One(StateValue::Usize(0))) => { + Some(Msg::PendingAction(PendingActionMsg::ReplaceOverwrite)) } - } - _ => None, - } - } -} - -#[derive(MockComponent)] -pub struct ReplacingFilesListPopup { - component: List, -} - -impl ReplacingFilesListPopup { - pub fn new(files: &[String], color: Color) -> Self { - Self { - component: List::default() - .borders( - Borders::default() - .color(color) - .modifiers(BorderType::Rounded), - ) - .scroll(true) - .step(4) - .highlighted_color(color) - .highlighted_str("➤ ") - .title( - "The following files are going to be replaced", - Alignment::Center, - ) - .rows(files.iter().map(|x| vec![TextSpan::from(x)]).collect()), - } - } -} - -impl Component for ReplacingFilesListPopup { - fn on(&mut self, ev: Event) -> Option { - match ev { - Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => { - Some(Msg::PendingAction(PendingActionMsg::CloseReplacePopups)) - } - Event::Keyboard(KeyEvent { code: Key::Tab, .. }) => { - Some(Msg::Ui(UiMsg::ReplacePopupTabbed)) - } - Event::Keyboard(KeyEvent { - code: Key::Down, .. - }) => { - self.perform(Cmd::Move(Direction::Down)); - Some(Msg::None) - } - Event::Keyboard(KeyEvent { code: Key::Up, .. }) => { - self.perform(Cmd::Move(Direction::Up)); - Some(Msg::None) - } - Event::Keyboard(KeyEvent { - code: Key::PageDown, - .. - }) => { - self.perform(Cmd::Scroll(Direction::Down)); - Some(Msg::None) - } - Event::Keyboard(KeyEvent { - code: Key::PageUp, .. - }) => { - self.perform(Cmd::Scroll(Direction::Up)); - Some(Msg::None) - } - Event::Keyboard(KeyEvent { - code: Key::Home, .. - }) => { - self.perform(Cmd::GoTo(Position::Begin)); - Some(Msg::None) - } - Event::Keyboard(KeyEvent { code: Key::End, .. }) => { - self.perform(Cmd::GoTo(Position::End)); - Some(Msg::None) - } + CmdResult::Submit(State::One(StateValue::Usize(1))) => { + Some(Msg::PendingAction(PendingActionMsg::ReplaceSkip)) + } + CmdResult::Submit(State::One(StateValue::Usize(2))) => { + Some(Msg::PendingAction(PendingActionMsg::ReplaceOverwriteAll)) + } + CmdResult::Submit(State::One(StateValue::Usize(3))) => { + Some(Msg::PendingAction(PendingActionMsg::ReplaceSkipAll)) + } + CmdResult::Submit(State::One(StateValue::Usize(4))) => { + Some(Msg::PendingAction(PendingActionMsg::ReplaceCancel)) + } + _ => Some(Msg::None), + }, _ => None, } } diff --git a/src/ui/activities/filetransfer/mod.rs b/src/ui/activities/filetransfer/mod.rs index 5416411..a3ba76d 100644 --- a/src/ui/activities/filetransfer/mod.rs +++ b/src/ui/activities/filetransfer/mod.rs @@ -72,7 +72,6 @@ enum Id { QuitPopup, RenamePopup, ReplacePopup, - ReplacingFilesListPopup, SaveAsPopup, SortingPopup, StatusBarHostBridge, @@ -98,10 +97,14 @@ enum Msg { #[derive(Debug, PartialEq)] enum PendingActionMsg { - CloseReplacePopups, CloseSyncBrowsingMkdirPopup, MakePendingDirectory, - TransferPendingFile, + /// Replace file popup + ReplaceCancel, + ReplaceOverwrite, + ReplaceOverwriteAll, + ReplaceSkip, + ReplaceSkipAll, } #[derive(Debug, PartialEq)] @@ -171,8 +174,8 @@ enum UiMsg { MarkAll, /// Clear all marks MarkClear, + Quit, - ReplacePopupTabbed, ShowChmodPopup, ShowCopyPopup, ShowDeletePopup, diff --git a/src/ui/activities/filetransfer/update.rs b/src/ui/activities/filetransfer/update.rs index 418e780..99f897f 100644 --- a/src/ui/activities/filetransfer/update.rs +++ b/src/ui/activities/filetransfer/update.rs @@ -5,7 +5,6 @@ // locals // externals use remotefs::fs::File; -use tuirealm::props::{AttrValue, Attribute}; use tuirealm::{State, StateValue, Update}; use super::actions::SelectedFile; @@ -504,15 +503,6 @@ impl FileTransferActivity { self.disconnect_and_quit(); self.umount_quit(); } - UiMsg::ReplacePopupTabbed => { - if let Ok(Some(AttrValue::Flag(true))) = - self.app.query(&Id::ReplacePopup, Attribute::Focus) - { - assert!(self.app.active(&Id::ReplacingFilesListPopup).is_ok()); - } else { - assert!(self.app.active(&Id::ReplacePopup).is_ok()); - } - } UiMsg::ShowChmodPopup => { let selected_file = match self.browser.tab() { #[cfg(posix)] diff --git a/src/ui/activities/filetransfer/view.rs b/src/ui/activities/filetransfer/view.rs index 721ee00..0842285 100644 --- a/src/ui/activities/filetransfer/view.rs +++ b/src/ui/activities/filetransfer/view.rs @@ -269,29 +269,10 @@ impl FileTransferActivity { // make popup self.app.view(&Id::DeletePopup, f, popup); } else if self.app.mounted(&Id::ReplacePopup) { - // NOTE: handle extended / normal modes - if self.is_radio_replace_extended() { - let popup = Popup(Size::Percentage(50), Size::Percentage(50)).draw_in(f.area()); - f.render_widget(Clear, popup); - let popup_chunks = Layout::default() - .direction(Direction::Vertical) - .constraints( - [ - Constraint::Percentage(85), // List - Constraint::Percentage(15), // Radio - ] - .as_ref(), - ) - .split(popup); - self.app - .view(&Id::ReplacingFilesListPopup, f, popup_chunks[0]); - self.app.view(&Id::ReplacePopup, f, popup_chunks[1]); - } else { - let popup = Popup(Size::Percentage(50), Size::Unit(3)).draw_in(f.area()); - f.render_widget(Clear, popup); - // make popup - self.app.view(&Id::ReplacePopup, f, popup); - } + let popup = Popup(Size::Percentage(50), Size::Unit(3)).draw_in(f.area()); + f.render_widget(Clear, popup); + // make popup + self.app.view(&Id::ReplacePopup, f, popup); } else if self.app.mounted(&Id::DisconnectPopup) { let popup = Popup(Size::Percentage(30), Size::Unit(3)).draw_in(f.area()); f.render_widget(Clear, popup); @@ -944,37 +925,8 @@ impl FileTransferActivity { assert!(self.app.active(&Id::ReplacePopup).is_ok()); } - pub(super) fn mount_radio_replace_many(&mut self, files: &[String]) { - let warn_color = self.theme().misc_warn_dialog; - assert!( - self.app - .remount( - Id::ReplacingFilesListPopup, - Box::new(components::ReplacingFilesListPopup::new(files, warn_color)), - vec![], - ) - .is_ok() - ); - assert!( - self.app - .remount( - Id::ReplacePopup, - Box::new(components::ReplacePopup::new(None, warn_color)), - vec![], - ) - .is_ok() - ); - assert!(self.app.active(&Id::ReplacePopup).is_ok()); - } - - /// Returns whether radio replace is in "extended" mode (for many files) - pub(super) fn is_radio_replace_extended(&self) -> bool { - self.app.mounted(&Id::ReplacingFilesListPopup) - } - pub(super) fn umount_radio_replace(&mut self) { let _ = self.app.umount(&Id::ReplacePopup); - let _ = self.app.umount(&Id::ReplacingFilesListPopup); // NOTE: replace anyway } pub(super) fn mount_file_info(&mut self, file: &File) { From a0b357cf8c2ccd9c938d952225caecee1f2c982f Mon Sep 17 00:00:00 2001 From: Christian Visintin Date: Sun, 9 Nov 2025 21:14:42 +0100 Subject: [PATCH 09/14] feat: Added `` keybinding to get the total size of selected paths. (#367) * feat: Added `` keybinding to get the total size of selected paths. closes #297 --- CHANGELOG.md | 1 + docs/de/man.md | 1 + docs/es/man.md | 21 +++-- docs/fr/man.md | 21 +++-- docs/it/man.md | 19 ++-- docs/man.md | 1 + docs/pt-BR/man.md | 1 + docs/zh-CN/man.md | 19 ++-- .../filetransfer/actions/file_size.rs | 94 +++++++++++++++++++ src/ui/activities/filetransfer/actions/mod.rs | 1 + .../filetransfer/components/popups.rs | 5 + .../filetransfer/components/transfer/mod.rs | 16 ++++ src/ui/activities/filetransfer/mod.rs | 1 + src/ui/activities/filetransfer/update.rs | 3 + 14 files changed, 166 insertions(+), 38 deletions(-) create mode 100644 src/ui/activities/filetransfer/actions/file_size.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 17af7c0..c7d8209 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Released on 20/09/2025 +- [Issue 297](https://github.com/veeso/termscp/issues/297): Added `` keybinding to get the total size of selected paths. - [Issue 331](https://github.com/veeso/termscp/issues/331): Added new `import-ssh-hosts` CLI subcommand to import all the hosts from the ssh config as bookmarks. - [Issue 335](https://github.com/veeso/termscp/issues/335): Changed file overwrite behaviour - Now the user can choose for each file whether to overwrite, skip or overwrite all/skip all. diff --git a/docs/de/man.md b/docs/de/man.md index be25040..9a38028 100644 --- a/docs/de/man.md +++ b/docs/de/man.md @@ -316,6 +316,7 @@ Diese Panels sind im Wesentlichen 3 (ja, tatsächlich drei): | | Alle Dateien auswählen | | | | Alle Dateien abwählen | | | | Dateiübertragungsvorgang abbrechen | | +| `` | Gesamte Größe des ausgewählten Pfads abrufen | Size | | | Alle synchronisierten Pfade anzeigen | Track | ### Mit mehreren Dateien arbeiten 🥷 diff --git a/docs/es/man.md b/docs/es/man.md index 8ce718e..43904cf 100644 --- a/docs/es/man.md +++ b/docs/es/man.md @@ -251,25 +251,25 @@ Para cambiar de panel, debe escribir `` para mover el panel del explorador | `` | Cambiar entre la pestaña de registro y el explorador | | | `` | Alternar archivos ocultos | All | | `` | Ordenar archivos por | Bubblesort? | -| `` | Copiar archivo / directorio | Copy | -| `` | Hacer directorio | Directory | -| `` | Eliminar archivo | Erase | +| `` | Copiar archivo / directorio | Copy | +| `` | Hacer directorio | Directory | +| `` | Eliminar archivo | Erase | | `` | Búsqueda de archivos | Find | | `` | Ir a la ruta proporcionada | Go to | -| `` | Mostrar ayuda | Help | +| `` | Mostrar ayuda | Help | | `` | Mostrar información sobre el archivo | Info | | `` | Crear un enlace simbólico que apunte a la entrada seleccionada actualmente | symlinK | | `` | Recargar contenido del directorio / Borrar selección | List | | `` | Seleccione un archivo | Mark | | `` | Crear un nuevo archivo con el nombre proporcionado | New | -| `` | Editar archivo | Open | +| `` | Editar archivo | Open | | `

` | Ouvre le panel de journals | Panel | -| `` | Quitter termscp | Quit | -| `` | Renommer le fichier | Rename | -| `` | Enregistrer le fichier sous... | Save | +| `` | Quitter termscp | Quit | +| `` | Renommer le fichier | Rename | +| `` | Enregistrer le fichier sous... | Save | | `` | Synchroniser les modifications apportées au chemin sélectionné | Track | | `` | Aller dans le répertoire parent | Upper | -| `` | Ouvrir le fichier avec le programme défaut pour le type de fichier | View | +| `` | Ouvrir le fichier avec le programme défaut pour le type de fichier | View | | `` | Ouvrir le fichier avec le programme spécifié | With | | `` | Exécuter une commande | eXecute | | `` | Basculer la navigation synchronisée | sYnc | @@ -276,9 +276,10 @@ Pour changer de panneau, vous devez taper `` pour déplacer le panneau de | `` | Sélectionner tous les fichiers | | | `` | Desélectionner tous les fichiers | | | `` | Abandonner le processus de transfert de fichiers | | +| `` | Obtenir la taille totale du chemin sélectionné | Size | | `` | Afficher tous les chemins synchronisés | Track | -### Travailler sur plusieurs fichiers 🥷 +### Travailler sur plusieurs fichiers 🥷 Vous pouvez choisir de travailler sur plusieurs fichiers avec ces simples commandes : diff --git a/docs/it/man.md b/docs/it/man.md index d583026..770974a 100644 --- a/docs/it/man.md +++ b/docs/it/man.md @@ -245,25 +245,25 @@ Per cambiare pannello ti puoi muovere con le frecce, `` per andare sul pan | `` | Cambia tra explorer e pannello di log | | | `` | Mostra/nascondi file nascosti | All | | `` | Ordina file per | Bubblesort? | -| `` | Copia file/directory | Copy | -| `` | Crea directory | Directory | -| `` | Elimina file | Erase | +| `` | Copia file/directory | Copy | +| `` | Crea directory | Directory | +| `` | Elimina file | Erase | | `` | Cerca file (wild match supportato) | Find | | `` | Vai al percorso indicato | Go to | -| `` | Mostra help | Help | +| `` | Mostra help | Help | | `` | Mostra informazioni per il file selezionato | Info | | `` | Crea un link simbolico che punta al file selezionato | symlinK | | `` | Ricarica posizione corrente / pulisci selezione file | List | | `` | Seleziona file | Mark | | `` | Crea nuovo file con il nome fornito | New | -| `` | Modifica file; Vedi text editor | Open | +| `` | Modifica file; Vedi text editor | Open | | `

` | Apri pannello log | Panel | -| `` | Termina termscp | Quit | -| `` | Rinomina file | Rename | -| `` | Salva file con nome | Save | +| `` | Termina termscp | Quit | +| `` | Rinomina file | Rename | +| `` | Salva file con nome | Save | | `` | Sincronizza il percorso locale con l'host remoto | Track | | `` | Vai alla directory padre | Upper | -| `` | Apri il file con il programma definito dal sistema | View | +| `` | Apri il file con il programma definito dal sistema | View | | `` | Apri il file con il programma specificato | With | | `` | Esegui comando shell | eXecute | | `` | Abilita/disabilita Sync-Browsing | sYnc | @@ -272,6 +272,7 @@ Per cambiare pannello ti puoi muovere con le frecce, `` per andare sul pan | `` | Seleziona tutti i file | | | `` | Deseleziona tutti i file | | | `` | Annulla trasferimento file | | +| `` | Ottieni la dimensione totale del percorso selezionato | Size | | `` | Visualizza tutti i percorsi sincronizzati | Track | ### Lavora con più file 🥷 diff --git a/docs/man.md b/docs/man.md index 178ddae..9a29fc8 100644 --- a/docs/man.md +++ b/docs/man.md @@ -278,6 +278,7 @@ In order to change panel you need to type `` to move the remote explorer p | `` | Select all files | | | `` | Deselect all files | | | `` | Abort file transfer process | | +| `` | Get total size of the selected path | Size | | `` | Show all synchronized paths | Track | ### Work on multiple files 🥷 diff --git a/docs/pt-BR/man.md b/docs/pt-BR/man.md index 2fa2d34..c688c3e 100644 --- a/docs/pt-BR/man.md +++ b/docs/pt-BR/man.md @@ -278,6 +278,7 @@ Para trocar de painel, você precisa pressionar `` para mover para o paine | `` | Selecionar todos os arquivos | | | `` | Deselecionar todos os arquivos | | | `` | Abortir processo de transferência de arquivo | | +| `` | Obter o tamanho total do caminho selecionado | | Size | | `` | Mostrar todos os caminhos sincronizados | Track | ### Trabalhar com múltiplos arquivos 🥷 diff --git a/docs/zh-CN/man.md b/docs/zh-CN/man.md index a04fc62..e2b21ba 100644 --- a/docs/zh-CN/man.md +++ b/docs/zh-CN/man.md @@ -245,25 +245,25 @@ termscp中的文件资源管理器是指你与远程建立连接后可以看到 | `` | 在日志面板和管理器面板之间切换 | | | `` | 是否显示隐藏文件 | All | | `` | 按..排序 | Bubblesort? | -| `` | 复制文件(夹) | Copy | -| `` | 创建文件夹 | Directory | -| `` | 删除文件 | Erase | +| `` | 复制文件(夹) | Copy | +| `` | 创建文件夹 | Directory | +| `` | 删除文件 | Erase | | `` | 文件搜索 (支持通配符) | Find | | `` | 跳转到指定路径 | Go to | -| `` | 显示帮助 | Help | +| `` | 显示帮助 | Help | | `` | 显示选中文件(夹)信息 | Info | | `` | 创建指向当前选定条目的符号链接 | symlinK | | `` | 刷新当前目录列表 / 清除选中状态 | List | | `` | 选中文件 | Mark | | `` | 使用键入的名称新建文件 | New | -| `` | 编辑文件;参考文本编辑器文档 | Open | +| `` | 编辑文件;参考文本编辑器文档 | Open | | `

` | 打开日志面板 | Panel | -| `` | 退出termscp | Quit | -| `` | 重命名文件 | Rename | -| `` | 另存为... | Save | +| `` | 退出termscp | Quit | +| `` | 重命名文件 | Rename | +| `` | 另存为... | Save | | `` | 显示所有同步路径 | Track | | `` | 进入上层目录 | Upper | -| `` | 使用默认方式打开文件 | View | +| `` | 使用默认方式打开文件 | View | | `` | 使用指定程序打开文件 | With | | `` | 运行命令 | eXecute | | `` | 是否开启同步浏览 | sYnc | @@ -272,6 +272,7 @@ termscp中的文件资源管理器是指你与远程建立连接后可以看到 | `` | 选中所有文件 | | | `` | 取消选择所有文件 | | | `` | 终止文件传输 | | +| `` | 获取所选路径的总大小 | Size | | `` | 显示所有同步路径 | Track | ### 操作多个文件 🥷 diff --git a/src/ui/activities/filetransfer/actions/file_size.rs b/src/ui/activities/filetransfer/actions/file_size.rs new file mode 100644 index 0000000..fb0251e --- /dev/null +++ b/src/ui/activities/filetransfer/actions/file_size.rs @@ -0,0 +1,94 @@ +use remotefs::File; + +use super::{FileTransferActivity, LogLevel}; +use crate::ui::activities::filetransfer::lib::browser::FileExplorerTab; + +#[derive(Debug, Copy, Clone)] +enum Host { + HostBridge, + Remote, +} + +impl FileTransferActivity { + pub(crate) fn action_get_file_size(&mut self) { + // Get selected file + self.mount_blocking_wait("Getting total path size..."); + + let total_size = match self.browser.tab() { + FileExplorerTab::HostBridge => { + let files = self.get_local_selected_entries().get_files(); + self.get_files_size(files, Host::HostBridge) + } + FileExplorerTab::Remote => { + let files = self.get_remote_selected_entries().get_files(); + self.get_files_size(files, Host::Remote) + } + FileExplorerTab::FindHostBridge => { + let files = self.get_found_selected_entries().get_files(); + self.get_files_size(files, Host::HostBridge) + } + FileExplorerTab::FindRemote => { + let files = self.get_found_selected_entries().get_files(); + self.get_files_size(files, Host::Remote) + } + }; + + self.umount_wait(); + self.mount_info(format!( + "Total file size: {size}", + size = bytesize::ByteSize::b(total_size) + )); + } + + fn get_files_size(&mut self, files: Vec, host: Host) -> u64 { + files.into_iter().map(|f| self.get_file_size(f, host)).sum() + } + + fn get_file_size(&mut self, file: File, host: Host) -> u64 { + if let Some(symlink) = &file.metadata().symlink { + // stat + let stat_res = match host { + Host::HostBridge => self.host_bridge.stat(symlink).map_err(|e| e.to_string()), + Host::Remote => self.client.stat(symlink).map_err(|e| e.to_string()), + }; + match stat_res { + Ok(stat) => stat.metadata().size, + Err(err_msg) => { + self.log( + LogLevel::Error, + format!( + "Failed to stat symlink target {path}: {err_msg}", + path = symlink.display(), + ), + ); + 0 + } + } + } else if file.is_dir() { + // list and sum + let list_res = match host { + Host::HostBridge => self + .host_bridge + .list_dir(&file.path) + .map_err(|e| e.to_string()), + Host::Remote => self.client.list_dir(&file.path).map_err(|e| e.to_string()), + }; + + match list_res { + Ok(list) => list.into_iter().map(|f| self.get_file_size(f, host)).sum(), + Err(err_msg) => { + self.log( + LogLevel::Error, + format!( + "Failed to list directory {path}: {err_msg}", + path = file.path.display(), + ), + ); + 0 + } + } + } else { + file.metadata().size + } + } +} diff --git a/src/ui/activities/filetransfer/actions/mod.rs b/src/ui/activities/filetransfer/actions/mod.rs index ee89bc6..600a0b0 100644 --- a/src/ui/activities/filetransfer/actions/mod.rs +++ b/src/ui/activities/filetransfer/actions/mod.rs @@ -23,6 +23,7 @@ pub(crate) mod copy; pub(crate) mod delete; pub(crate) mod edit; pub(crate) mod exec; +pub(crate) mod file_size; pub(crate) mod filter; pub(crate) mod find; pub(crate) mod mark; diff --git a/src/ui/activities/filetransfer/components/popups.rs b/src/ui/activities/filetransfer/components/popups.rs index efd6a61..2c5469a 100644 --- a/src/ui/activities/filetransfer/components/popups.rs +++ b/src/ui/activities/filetransfer/components/popups.rs @@ -644,6 +644,11 @@ impl KeybindingsPopup { .add_col(TextSpan::new("").bold().fg(key_color)) .add_col(TextSpan::from(" Interrupt file transfer")) .add_row() + .add_col(TextSpan::new("").bold().fg(key_color)) + .add_col(TextSpan::from( + " Get total path size of selected files", + )) + .add_row() .add_col(TextSpan::new("").bold().fg(key_color)) .add_col(TextSpan::from(" Show watched paths")) .build(), diff --git a/src/ui/activities/filetransfer/components/transfer/mod.rs b/src/ui/activities/filetransfer/components/transfer/mod.rs index 9ef347a..29eb61a 100644 --- a/src/ui/activities/filetransfer/components/transfer/mod.rs +++ b/src/ui/activities/filetransfer/components/transfer/mod.rs @@ -192,6 +192,10 @@ impl ExplorerFuzzy { code: Key::Char('i'), modifiers: KeyModifiers::NONE, }) => Some(Msg::Ui(UiMsg::ShowFileInfoPopup)), + Event::Keyboard(KeyEvent { + code: Key::Char('s'), + modifiers: KeyModifiers::CONTROL, + }) => Some(Msg::Transfer(TransferMsg::GetFileSize)), Event::Keyboard(KeyEvent { code: Key::Char('s') | Key::Function(2), modifiers: KeyModifiers::NONE, @@ -338,6 +342,10 @@ impl Component for ExplorerFind { code: Key::Char('i'), modifiers: KeyModifiers::NONE, }) => Some(Msg::Ui(UiMsg::ShowFileInfoPopup)), + Event::Keyboard(KeyEvent { + code: Key::Char('s'), + modifiers: KeyModifiers::CONTROL, + }) => Some(Msg::Transfer(TransferMsg::GetFileSize)), Event::Keyboard(KeyEvent { code: Key::Char('s') | Key::Function(2), modifiers: KeyModifiers::NONE, @@ -528,6 +536,10 @@ impl Component for ExplorerLocal { code: Key::Char('r') | Key::Function(6), modifiers: KeyModifiers::NONE, }) => Some(Msg::Ui(UiMsg::ShowRenamePopup)), + Event::Keyboard(KeyEvent { + code: Key::Char('s'), + modifiers: KeyModifiers::CONTROL, + }) => Some(Msg::Transfer(TransferMsg::GetFileSize)), Event::Keyboard(KeyEvent { code: Key::Char('s') | Key::Function(2), modifiers: KeyModifiers::NONE, @@ -742,6 +754,10 @@ impl Component for ExplorerRemote { code: Key::Char('r') | Key::Function(6), modifiers: KeyModifiers::NONE, }) => Some(Msg::Ui(UiMsg::ShowRenamePopup)), + Event::Keyboard(KeyEvent { + code: Key::Char('s'), + modifiers: KeyModifiers::CONTROL, + }) => Some(Msg::Transfer(TransferMsg::GetFileSize)), Event::Keyboard(KeyEvent { code: Key::Char('s') | Key::Function(2), modifiers: KeyModifiers::NONE, diff --git a/src/ui/activities/filetransfer/mod.rs b/src/ui/activities/filetransfer/mod.rs index a3ba76d..d0b43e7 100644 --- a/src/ui/activities/filetransfer/mod.rs +++ b/src/ui/activities/filetransfer/mod.rs @@ -117,6 +117,7 @@ enum TransferMsg { DeleteFile, EnterDirectory, ExecuteCmd(String), + GetFileSize, GoTo(String), GoToParentDirectory, GoToPreviousDirectory, diff --git a/src/ui/activities/filetransfer/update.rs b/src/ui/activities/filetransfer/update.rs index 99f897f..bce542c 100644 --- a/src/ui/activities/filetransfer/update.rs +++ b/src/ui/activities/filetransfer/update.rs @@ -152,6 +152,9 @@ impl FileTransferActivity { _ => panic!("Found tab doesn't support EXEC"), }; } + TransferMsg::GetFileSize => { + self.action_get_file_size(); + } TransferMsg::GoTo(dir) => { match self.browser.tab() { FileExplorerTab::HostBridge => self.action_change_local_dir(dir), From 47d23673e61af3881f4704c83cc5305bd2f813b1 Mon Sep 17 00:00:00 2001 From: Christian Visintin Date: Mon, 10 Nov 2025 16:43:25 +0100 Subject: [PATCH 10/14] ci: Build artifacts for Windows x86_64 and Ubuntu x86_64 (#368) --- .github/workflows/build-artifacts.yml | 75 ++++++++++++++++++++++++--- Cargo.lock | 14 ++--- 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-artifacts.yml b/.github/workflows/build-artifacts.yml index f1146f1..7f90743 100644 --- a/.github/workflows/build-artifacts.yml +++ b/.github/workflows/build-artifacts.yml @@ -14,13 +14,23 @@ jobs: platform: - release_for: MacOS-x86_64 os: macos-latest + platform: macos target: x86_64-apple-darwin - script: macos.sh - - release_for: MacOS-M1 + - release_for: MacOS-aarch64 os: macos-latest + platform: macos target: aarch64-apple-darwin - script: macos.sh + + - release_for: Linux-x86_64 + os: ubuntu-latest + platform: linux + target: x86_64-unknown-linux-gnu + + - release_for: Windows-x86_64 + os: windows-latest + platform: windows + target: x86_64-pc-windows-msvc runs-on: ${{ matrix.platform.os }} steps: @@ -29,7 +39,42 @@ jobs: with: toolchain: stable targets: ${{ matrix.platform.target }} - - name: Install dependencies + + - name: Install dependencies (Linux) + if: matrix.platform.platform == 'linux' + run: | + sudo apt-get update + sudo apt-get install -y \ + make \ + libgit2-dev \ + build-essential \ + pkg-config \ + libbsd-dev \ + libcap-dev \ + libcups2-dev \ + libgnutls28-dev \ + libicu-dev \ + libjansson-dev \ + libkeyutils-dev \ + libldap2-dev \ + zlib1g-dev \ + libpam0g-dev \ + libacl1-dev \ + libarchive-dev \ + flex \ + bison \ + libntirpc-dev \ + libtracker-sparql-3.0-dev \ + libglib2.0-dev \ + libdbus-1-dev \ + libsasl2-dev \ + libunistring-dev \ + libdbus-1-dev \ + cpanminus; + sudo cpanm Parse::Yapp::Driver + + - name: Install dependencies (MacOS) + if: matrix.platform.platform == 'macos' run: | brew update brew install \ @@ -66,18 +111,34 @@ jobs: brew link --force openldap brew link --force zlib cpanm Parse::Yapp::Driver - - name: Build release + - name: Build release (MacOS Intel) + if: matrix.platform.target == 'x86_64-apple-darwin' + run: cargo build --release --no-default-features --features keyring --target ${{ matrix.platform.target }} + + - name: Build release (others) + if: matrix.platform.target != 'x86_64-apple-darwin' run: cargo build --release --features smb-vendored --target ${{ matrix.platform.target }} - - name: Prepare artifact files + - name: Prepare artifact files (Posix) + if: matrix.platform.platform != 'windows' run: | mkdir -p .artifact mv target/${{ matrix.platform.target }}/release/termscp .artifact/termscp tar -czf .artifact/termscp-v${{ env.TERMSCP_VERSION }}-${{ matrix.platform.target }}.tar.gz -C .artifact termscp ls -l .artifact/ - - name: "Upload artifact" + - name: Upload artifact (Posix) + if: matrix.platform.platform != 'windows' uses: actions/upload-artifact@v4 with: if-no-files-found: error retention-days: 1 name: termscp-${{ matrix.platform.target }} path: .artifact/termscp-v${{ env.TERMSCP_VERSION }}-${{ matrix.platform.target }}.tar.gz + + - name: Upload artifact (Windows) + if: matrix.platform.platform == 'windows' + uses: actions/upload-artifact@v4 + with: + if-no-files-found: error + retention-days: 1 + name: termscp-${{ matrix.platform.target }} + path: target/${{ matrix.platform.target }}/release/termscp.exe diff --git a/Cargo.lock b/Cargo.lock index adf87f4..7038a61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1272,7 +1272,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3022,9 +3022,9 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "pavao" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c62e3a544910e4a9bbb56218bad91593b79a27c676e54a36097200d10d2d6e" +checksum = "f716d52d838ee3062b42302f328d6a3ecfb0006b651707886fa890e8951c7cf7" dependencies = [ "cfg_aliases", "lazy_static", @@ -3036,9 +3036,9 @@ dependencies = [ [[package]] name = "pavao-src" -version = "4.22.0" +version = "4.22.0-3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29b20a487b78fd44d081eb16717d062f78cae52888a7affeed1e7da3be1b9247" +checksum = "18364b5a8ff85f60fcca22e0d21a60f50ab4b9152d51f7358f3b42bbace88aab" dependencies = [ "cc", "git2", @@ -3047,9 +3047,9 @@ dependencies = [ [[package]] name = "pavao-sys" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e72a8efe4193b073995a99981a288cfef121027d12c420c647c2f19d4103d4" +checksum = "51792a86ac195a0e5b7a942f5b62e8f9494a260a5febe31673c5e7bb72ade55f" dependencies = [ "cc", "libc", From 2cb600083e62ad84b7ca512bd4287eb8995102a6 Mon Sep 17 00:00:00 2001 From: veeso Date: Mon, 10 Nov 2025 16:44:24 +0100 Subject: [PATCH 11/14] docs: Release date --- CHANGELOG.md | 2 +- README.md | 2 +- docs/de/README.md | 2 +- docs/es/README.md | 2 +- docs/fr/README.md | 2 +- docs/it/README.md | 2 +- docs/pt-BR/README.md | 2 +- docs/zh-CN/README.md | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7d8209..b5249c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,7 +60,7 @@ Released on 20/09/2025 ## 0.18.0 -Released on 10/06/2025 +Released on 11/11/2025 - 🐚 An **Embedded shell for termscp**: - [Issue 340](https://github.com/veeso/termscp/issues/340): Replaced the `Exec` popup with a **fully functional terminal emulator** embedded thanks to [A-Kenji's tui-term](https://github.com/a-kenji/tui-term). diff --git a/README.md b/README.md index b497625..44ac93c 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@

Developed by @veeso

-

Current version: 0.19.0 10/06/2025

+

Current version: 0.19.0 11/11/2025

Entwickelt von @veeso

-

Aktuelle Version: 0.19.0 10/06/2025

+

Aktuelle Version: 0.19.0 11/11/2025

Desarrollado por @veeso

-

Versión actual: 0.19.0 10/06/2025

+

Versión actual: 0.19.0 11/11/2025

Développé par @veeso

-

Version actuelle: 0.19.0 10/06/2025

+

Version actuelle: 0.19.0 11/11/2025

Sviluppato da @veeso

-

Versione corrente: 0.19.0 10/06/2025

+

Versione corrente: 0.19.0 11/11/2025

Desenvolvido por @veeso

-

Versão atual: 0.19.0 10/06/2025

+

Versão atual: 0.19.0 11/11/2025

@veeso 开发

-

当前版本: 0.19.0 10/06/2025

+

当前版本: 0.19.0 11/11/2025

Date: Mon, 10 Nov 2025 17:06:44 +0100 Subject: [PATCH 12/14] ci: Debian --- .github/workflows/build-artifacts.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/build-artifacts.yml b/.github/workflows/build-artifacts.yml index 7f90743..050496e 100644 --- a/.github/workflows/build-artifacts.yml +++ b/.github/workflows/build-artifacts.yml @@ -26,6 +26,7 @@ jobs: os: ubuntu-latest platform: linux target: x86_64-unknown-linux-gnu + debian_suffix: amd64 - release_for: Windows-x86_64 os: windows-latest @@ -118,6 +119,13 @@ jobs: - name: Build release (others) if: matrix.platform.target != 'x86_64-apple-darwin' run: cargo build --release --features smb-vendored --target ${{ matrix.platform.target }} + + - name: Build deb + if: matrix.platform.platform == 'linux' + run: | + cargo install cargo-deb + cargo deb --target ${{ matrix.platform.target }} --features smb-vendored + - name: Prepare artifact files (Posix) if: matrix.platform.platform != 'windows' run: | @@ -142,3 +150,12 @@ jobs: retention-days: 1 name: termscp-${{ matrix.platform.target }} path: target/${{ matrix.platform.target }}/release/termscp.exe + + - name: Upload artifact (Deb) + if: matrix.platform.platform == 'linux' + uses: actions/upload-artifact@v4 + with: + if-no-files-found: error + retention-days: 1 + name: termscp-${{ matrix.platform.target }}-deb + path: target/${{ matrix.platform.target }}/debian/termscp_${{ env.TERMSCP_VERSION }}_${{ matrix.platform.debian_suffix }}.deb From befc32198a5fc9be7c525717ac218c2772bd1ca0 Mon Sep 17 00:00:00 2001 From: veeso Date: Mon, 10 Nov 2025 17:25:29 +0100 Subject: [PATCH 13/14] ci: debian fix --- .github/workflows/build-artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-artifacts.yml b/.github/workflows/build-artifacts.yml index 050496e..9faf518 100644 --- a/.github/workflows/build-artifacts.yml +++ b/.github/workflows/build-artifacts.yml @@ -158,4 +158,4 @@ jobs: if-no-files-found: error retention-days: 1 name: termscp-${{ matrix.platform.target }}-deb - path: target/${{ matrix.platform.target }}/debian/termscp_${{ env.TERMSCP_VERSION }}_${{ matrix.platform.debian_suffix }}.deb + path: target/debian/termscp_${{ env.TERMSCP_VERSION }}-1_${{ matrix.platform.debian_suffix }}.deb From e9b54a227b57bd19b53159fca525d9b107a40063 Mon Sep 17 00:00:00 2001 From: veeso Date: Tue, 11 Nov 2025 09:42:21 +0100 Subject: [PATCH 14/14] chore: CHANGELOG date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5249c2..dda8da0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,7 @@ ## 0.19.0 -Released on 20/09/2025 +Released on 11/11/2025 - [Issue 297](https://github.com/veeso/termscp/issues/297): Added `` keybinding to get the total size of selected paths. - [Issue 331](https://github.com/veeso/termscp/issues/331): Added new `import-ssh-hosts` CLI subcommand to import all the hosts from the ssh config as bookmarks.

` | Open log panel | Panel | -| `` | Salir de termscp | Quit | -| `` | Renombrar archivo | Rename | -| `` | Guardar archivo como... | Save | +| `` | Salir de termscp | Quit | +| `` | Renombrar archivo | Rename | +| `` | Guardar archivo como... | Save | | `` | Sincronizar los cambios en la ruta seleccionada con el control remoto | Track | | `` | Ir al directorio principal | Upper | -| `` | Abrir archivo con el programa predeterminado | View | +| `` | Abrir archivo con el programa predeterminado | View | | `` | Abrir archivo con el programa proporcionado | With | | `` | Ejecutar un comando | eXecute | | `` | Alternar navegación sincronizada | sYnc | @@ -278,9 +278,10 @@ Para cambiar de panel, debe escribir `` para mover el panel del explorador | `` | Seleccionar todos los archivos | | | `` | Deseleccionar todos los archivos | | | `` | Abortar el proceso de transferencia de archivos | | +| `` | Obtener el tamaño total de la ruta seleccionada | Size | | `` | Mostrar todas las rutas sincronizadas | Track | -### Trabajar con múltiples archivos 🥷 +### Trabajar con múltiples archivos 🥷 Puedes optar por trabajar con varios archivos, usando estos controles: diff --git a/docs/fr/man.md b/docs/fr/man.md index d3c177a..37fc5e0 100644 --- a/docs/fr/man.md +++ b/docs/fr/man.md @@ -249,25 +249,25 @@ Pour changer de panneau, vous devez taper `` pour déplacer le panneau de | `` | Basculer entre l'onglet journal et l'explorateur | | | `` | Basculer les fichiers cachés | All | | `` | Trier les fichiers par | Bubblesort? | -| `` | Copier le fichier/répertoire | Copy | -| `` | Créer un dossier | Directory | -| `` | Supprimer le fichier (Identique à `DEL`) | Erase | +| `` | Copier le fichier/répertoire | Copy | +| `` | Créer un dossier | Directory | +| `` | Supprimer le fichier (Identique à `DEL`) | Erase | | `` | Rechercher des fichiers | Find | | `` | Aller au chemin fourni | Go to | -| `` | Afficher l'aide | Help | +| `` | Afficher l'aide | Help | | `` | Afficher les informations sur le fichier ou le dossier sélectionné | Info | | `` | Créer un lien symbolique pointant vers l'entrée actuellement sélectionnée | symlinK | | `` | Recharger le contenu du répertoire actuel / Effacer la sélection | List | | `` | Sélectionner un fichier | Mark | | `` | Créer un nouveau fichier avec le nom fourni | New | -| `` | Modifier le fichier | Open | +| `` | Modifier le fichier | Open | | `