mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afba6c32c5 | ||
|
|
31f5bd095b | ||
|
|
e1add0ed28 | ||
|
|
79bc6a684b | ||
|
|
bae4db8e27 | ||
|
|
4cbba3f3cb | ||
|
|
e9fbb7f317 | ||
|
|
044f2436f8 | ||
|
|
b7369162d2 | ||
|
|
a13663e5e9 | ||
|
|
79dd9e2303 | ||
|
|
b4fa50a666 | ||
|
|
5a67fc7b0e | ||
|
|
9dab34e7ee | ||
|
|
c5eeae74b7 | ||
|
|
9009002b6e | ||
|
|
9bf23b3f6b | ||
|
|
3ec94c17bc | ||
|
|
ed8ba628e5 | ||
|
|
7c638473d6 | ||
|
|
d37140ead6 | ||
|
|
fdb0d97a61 |
2
.github/workflows/coverage.yml
vendored
2
.github/workflows/coverage.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: sudo apt update && sudo apt install -y libdbus-1-dev libssh2-1-dev libssl-dev
|
||||
run: sudo apt update && sudo apt install -y libdbus-1-dev libsmbclient-dev libsmbclient
|
||||
- name: Setup nightly toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
8
.github/workflows/install.yml
vendored
8
.github/workflows/install.yml
vendored
@@ -1,6 +1,10 @@
|
||||
name: Install.sh
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -15,5 +19,5 @@ jobs:
|
||||
run: sudo apt update && sudo apt install -y curl wget
|
||||
- name: Install termscp from script
|
||||
run: |
|
||||
./install.sh -v=0.11.1 -f
|
||||
./install.sh -v=0.12.0 -f
|
||||
which termscp || exit 1
|
||||
|
||||
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: sudo apt update && sudo apt install -y libdbus-1-dev
|
||||
run: sudo apt update && sudo apt install -y libdbus-1-dev libsmbclient-dev
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
1
.github/workflows/macos.yml
vendored
1
.github/workflows/macos.yml
vendored
@@ -8,7 +8,6 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
|
||||
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,6 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
- [Changelog](#changelog)
|
||||
- [0.12.0](#0120)
|
||||
- [0.11.3](#0113)
|
||||
- [0.11.2](#0112)
|
||||
- [0.11.1](#0111)
|
||||
- [0.11.0](#0110)
|
||||
@@ -29,6 +31,26 @@
|
||||
|
||||
---
|
||||
|
||||
## 0.12.0
|
||||
|
||||
Released on 16/05/2023
|
||||
|
||||
- **Change file permissions**: you can now change file permissions easily with the permissions popup pressing `Z` in the explorer.
|
||||
- [Issue 172](https://github.com/veeso/termscp/issues/172)
|
||||
- **SMB protocol**: Support for SMB protocol has been added thanks to the [remotefs-smb](https://github.com/veeso/remotefs-rs-smb) library and the [pavao](https://github.com/veeso/pavao) project. You may notice that the interface is quiet different between Windows and Linux/MacOs/BSD due to the fact that SMB is natively supported on Windows systems.
|
||||
- [Issue 182](https://github.com/veeso/termscp/issues/182)
|
||||
- [Issue 153](https://github.com/veeso/termscp/issues/153): show a loading message when loading directory's content
|
||||
- [Issue 176](https://github.com/veeso/termscp/issues/176): debug log is now written to CACHE_DIR
|
||||
- [Issue 173](https://github.com/veeso/termscp/issues/173): allow unknown fields in ssh2 configuration file
|
||||
- [Issue 175](https://github.com/veeso/termscp/issues/175): don't prompt for password if a ssh key is set for that host
|
||||
- Fixed an issue that didn't use the `User` specified in ssh2-config
|
||||
|
||||
## 0.11.3
|
||||
|
||||
Released on 19/04/2023
|
||||
|
||||
- [Issue 166](https://github.com/veeso/termscp/issues/166): fixed SCP relative paths on Windows
|
||||
|
||||
## 0.11.2
|
||||
|
||||
Released on 18/04/2023
|
||||
|
||||
397
Cargo.lock
generated
397
Cargo.lock
generated
@@ -39,9 +39,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.20"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||
checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -57,9 +57,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.70"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
|
||||
[[package]]
|
||||
name = "argh"
|
||||
@@ -173,7 +173,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -190,7 +190,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -267,9 +267,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.1.0"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3"
|
||||
checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813"
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
@@ -329,9 +329,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
version = "3.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||
checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
@@ -375,6 +375,12 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.24"
|
||||
@@ -399,16 +405,6 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.2.0"
|
||||
@@ -458,9 +454,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181"
|
||||
checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -547,50 +543,6 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.4.0"
|
||||
@@ -680,11 +632,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.0"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dece029acd3353e3a58ac2e3eb3c8d6c35827a892edc6cc4138ef9c33df46ecd"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.0",
|
||||
"dirs-sys 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -710,13 +662,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04414300db88f70d74c5ff54e50f9e1d1737d9a5b90f53fcf2e95ca2a9ab554b"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.45.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -788,7 +741,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -841,9 +794,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.25"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
||||
checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@@ -985,7 +938,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1041,9 +994,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.18"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21"
|
||||
checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -1232,12 +1185,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1268,7 +1220,7 @@ checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729"
|
||||
dependencies = [
|
||||
"console",
|
||||
"number_prefix",
|
||||
"portable-atomic",
|
||||
"portable-atomic 0.3.20",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
@@ -1354,9 +1306,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.61"
|
||||
version = "0.3.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
|
||||
checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@@ -1422,9 +1374,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.141"
|
||||
version = "0.2.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
|
||||
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
|
||||
[[package]]
|
||||
name = "libdbus-sys"
|
||||
@@ -1451,9 +1403,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.8"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
|
||||
checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -1461,15 +1413,6 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-keyutils"
|
||||
version = "0.2.3"
|
||||
@@ -1482,9 +1425,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.1"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
|
||||
checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -1515,7 +1458,7 @@ dependencies = [
|
||||
"dirs-next",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1601,9 +1544,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
@@ -1879,9 +1822,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "4.0.2"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "873240a4a404d44c8cd1bf394359245d466a5695771fea15a79cafbc5e5cf4d7"
|
||||
checksum = "d16814a067484415fda653868c9be0ac5f2abd2ef5d951082a5f2fe1b3662944"
|
||||
dependencies = [
|
||||
"is-wsl",
|
||||
"pathdiff",
|
||||
@@ -1889,9 +1832,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.50"
|
||||
version = "0.10.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1"
|
||||
checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -1910,7 +1853,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1921,18 +1864,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-src"
|
||||
version = "111.25.2+1.1.1t"
|
||||
version = "111.25.3+1.1.1t"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320708a054ad9b3bf314688b5db87cf4d6683d64cfc835e2337924ae62bf4431"
|
||||
checksum = "924757a6a226bf60da5f7dd0311a34d2b52283dd82ddeb103208ddc66362f80c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.85"
|
||||
version = "0.9.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0"
|
||||
checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -1941,6 +1884,12 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-multimap"
|
||||
version = "0.3.1"
|
||||
@@ -2042,6 +1991,20 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
|
||||
|
||||
[[package]]
|
||||
name = "pavao"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bcafb8d680c0b6750c095fbd3c9263fc0b3c315e6055cd1867db038641c1757"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"pkg-config",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
@@ -2062,15 +2025,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.26"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.7.0"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4be1c66a6add46bff50935c313dae30a5030cf8385c5206e8a95e9e9def974aa"
|
||||
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags 1.3.2",
|
||||
@@ -2084,9 +2047,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "0.3.19"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b"
|
||||
checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e"
|
||||
dependencies = [
|
||||
"portable-atomic 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc59d1bcc64fc5d021d67521f818db868368028108d37f0e98d74e33f68297b5"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
@@ -2118,9 +2090,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.56"
|
||||
version = "1.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||
checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -2136,9 +2108,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.26"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||
checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -2204,9 +2176,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.3"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
|
||||
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -2215,9 +2187,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
|
||||
|
||||
[[package]]
|
||||
name = "remotefs"
|
||||
@@ -2260,10 +2232,24 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remotefs-ssh"
|
||||
version = "0.1.5"
|
||||
name = "remotefs-smb"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dc949a6747835d440afadec5a51842d063047c355fbe1960adc322108587d94"
|
||||
checksum = "27c4fb523b04b6bcd5dae95a33cbaee73cf7d6607862039b6d2bff310db6ed9f"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
"log",
|
||||
"pavao",
|
||||
"remotefs",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remotefs-ssh"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b9bebc0c117c79679d55bd3bbe857ecc2f398eed678b593a9440138a1e6c05b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
@@ -2278,9 +2264,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.16"
|
||||
version = "0.11.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254"
|
||||
checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"bytes",
|
||||
@@ -2392,9 +2378,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.11"
|
||||
version = "0.37.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
|
||||
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"errno",
|
||||
@@ -2455,12 +2441,6 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.0"
|
||||
@@ -2492,9 +2472,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.8.2"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
|
||||
checksum = "ca2855b3715770894e67cbfa3df957790aa0c9edc3bf06efa1a84d77fa0839d1"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation",
|
||||
@@ -2505,9 +2485,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
|
||||
checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@@ -2543,9 +2523,9 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.160"
|
||||
version = "1.0.163"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
|
||||
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@@ -2564,13 +2544,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.160"
|
||||
version = "1.0.163"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
|
||||
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2592,7 +2572,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2638,7 +2618,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2714,7 +2694,7 @@ checksum = "acee08041c5de3d5048c8b3f6f13fafb3026b24ba43c6a695a0c76179b844369"
|
||||
dependencies = [
|
||||
"log",
|
||||
"termcolor",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2768,11 +2748,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ssh2-config"
|
||||
version = "0.1.6"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65a664be1af7787264859a2a9272596fac07f0aeea6de56ca96f75aa82932a0f"
|
||||
checksum = "e31d9bb8e97972d6541ccf32ed51294e4e16feeef06a0e77a6272d041f0f5bc7"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
"bitflags 2.2.1",
|
||||
"dirs 5.0.1",
|
||||
"thiserror",
|
||||
"wildmatch",
|
||||
]
|
||||
@@ -2836,9 +2817,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.15"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
|
||||
checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2891,14 +2872,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "termscp"
|
||||
version = "0.11.2"
|
||||
version = "0.12.0"
|
||||
dependencies = [
|
||||
"argh",
|
||||
"bitflags 2.1.0",
|
||||
"bitflags 2.2.1",
|
||||
"bytesize",
|
||||
"cfg_aliases",
|
||||
"chrono",
|
||||
"content_inspector",
|
||||
"dirs 5.0.0",
|
||||
"dirs 5.0.1",
|
||||
"edit",
|
||||
"filetime",
|
||||
"hostname",
|
||||
@@ -2915,6 +2897,7 @@ dependencies = [
|
||||
"remotefs",
|
||||
"remotefs-aws-s3",
|
||||
"remotefs-ftp",
|
||||
"remotefs-smb",
|
||||
"remotefs-ssh",
|
||||
"rpassword",
|
||||
"self_update",
|
||||
@@ -2962,7 +2945,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2989,9 +2972,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.20"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||
checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"libc",
|
||||
@@ -3003,15 +2986,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||
checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.8"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
|
||||
checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
@@ -3033,9 +3016,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.27.0"
|
||||
version = "1.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001"
|
||||
checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
@@ -3044,7 +3027,7 @@ dependencies = [
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"windows-sys 0.45.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3060,9 +3043,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.12"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313"
|
||||
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
@@ -3071,9 +3054,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.7"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2"
|
||||
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -3137,20 +3120,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.23"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||
checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.30"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
@@ -3360,9 +3343,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
@@ -3370,24 +3353,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||
checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.16",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.34"
|
||||
version = "0.4.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
|
||||
checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
@@ -3397,9 +3380,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||
checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -3407,28 +3390,28 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.16",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.61"
|
||||
version = "0.3.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
|
||||
checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -3724,9 +3707,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.1"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
|
||||
checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -3771,9 +3754,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.4"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||
checksum = "1690519550bfa95525229b9ca2350c63043a4857b3b0013811b2ccf4a2420b01"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
@@ -3836,9 +3819,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zbus_names"
|
||||
version = "2.5.0"
|
||||
version = "2.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f34f314916bd89bdb9934154627fab152f4f28acdda03e7c4c68181b214fe7e3"
|
||||
checksum = "82441e6033be0a741157a72951a3e4957d519698f3a824439cc131c5ba77ac2a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"static_assertions",
|
||||
@@ -3847,22 +3830,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.4"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef"
|
||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"flate2",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "3.12.0"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46fe4914a985446d6fd287019b5fceccce38303d71407d9e6e711d44954a05d8"
|
||||
checksum = "5cb36cd95352132911c9c99fdcc1635de5c2c139bd34cbcf6dfb8350ee8ff6a7"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"enumflags2",
|
||||
@@ -3874,9 +3857,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_derive"
|
||||
version = "3.12.0"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34c20260af4b28b3275d6676c7e2a6be0d4332e8e0aba4616d34007fd84e462a"
|
||||
checksum = "9b34951e1ac64f3a1443fe7181256b9ed6a811a1631917566c3d5ca718d8cf33"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
|
||||
21
Cargo.toml
21
Cargo.toml
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
authors = ["Christian Visintin <christian.visintin1997@gmail.com>"]
|
||||
authors = ["Christian Visintin <christian.visintin@veeso.dev>"]
|
||||
categories = ["command-line-utilities"]
|
||||
description = "termscp is a feature rich terminal file transfer and explorer with support for SCP/SFTP/FTP/S3"
|
||||
edition = "2021"
|
||||
@@ -10,7 +10,7 @@ license = "MIT"
|
||||
name = "termscp"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/veeso/termscp"
|
||||
version = "0.11.2"
|
||||
version = "0.12.0"
|
||||
|
||||
[package.metadata.rpm]
|
||||
package = "termscp"
|
||||
@@ -22,8 +22,8 @@ buildflags = ["--release"]
|
||||
termscp = { path = "/usr/bin/termscp" }
|
||||
|
||||
[package.metadata.deb]
|
||||
maintainer = "Christian Visintin <christian.visintin1997@gmail.com>"
|
||||
copyright = "2022, Christian Visintin <christian.visintin1997@gmail.com>"
|
||||
maintainer = "Christian Visintin <christian.visintin@veeso.dev>"
|
||||
copyright = "2022, Christian Visintin <christian.visintin@veeso.dev>"
|
||||
extended-description-file = "docs/misc/README.deb.txt"
|
||||
|
||||
[[bin]]
|
||||
@@ -55,7 +55,7 @@ rpassword = "^7.0"
|
||||
self_update = { version = "^0.36", default-features = false, features = [ "rustls", "archive-tar", "archive-zip", "compression-flate2", "compression-zip-deflate" ] }
|
||||
serde = { version = "^1", features = [ "derive" ] }
|
||||
simplelog = "^0.12"
|
||||
ssh2-config = "^0.1.6"
|
||||
ssh2-config = "^0.2"
|
||||
tempfile = "^3.4"
|
||||
thiserror = "^1"
|
||||
toml = "^0.7"
|
||||
@@ -70,20 +70,27 @@ wildmatch = "^2.1"
|
||||
pretty_assertions = "^1.3"
|
||||
serial_test = "^2.0"
|
||||
|
||||
[build-dependencies]
|
||||
cfg_aliases = "0.1"
|
||||
|
||||
[features]
|
||||
default = [ "with-keyring" ]
|
||||
github-actions = [ ]
|
||||
with-keyring = [ "keyring" ]
|
||||
|
||||
[target."cfg(not(target_os = \"macos\"))"]
|
||||
[target."cfg(not(target_os = \"macos\"))".dependencies]
|
||||
remotefs-smb = "^0.2"
|
||||
|
||||
[target."cfg(target_family = \"windows\")"]
|
||||
[target."cfg(target_family = \"windows\")".dependencies]
|
||||
remotefs-ftp = { version = "^0.1.2", features = [ "native-tls" ] }
|
||||
remotefs-ssh = "^0.1.5"
|
||||
remotefs-ssh = "^0.2"
|
||||
|
||||
[target."cfg(target_family = \"unix\")"]
|
||||
[target."cfg(target_family = \"unix\")".dependencies]
|
||||
remotefs-ftp = { version = "^0.1.2", features = [ "vendored", "native-tls" ] }
|
||||
remotefs-ssh = { version = "^0.1.5", features = [ "ssh2-vendored" ] }
|
||||
remotefs-ssh = { version = "^0.2", features = [ "ssh2-vendored" ] }
|
||||
users = "0.11.0"
|
||||
|
||||
[profile.dev]
|
||||
|
||||
18
README.md
18
README.md
@@ -6,11 +6,11 @@
|
||||
|
||||
<p align="center">~ A feature rich terminal file transfer ~</p>
|
||||
<p align="center">
|
||||
<a href="https://veeso.github.io/termscp/" target="_blank">Website</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/" target="_blank">Website</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Installation</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#get-started" target="_blank">Installation</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">User manual</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#user-manual" target="_blank">User manual</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -62,8 +62,8 @@
|
||||
/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">Developed by <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Current version: 0.11.2 (18/04/2023)</p>
|
||||
<p align="center">Developed by <a href="https://termscp.veeso.dev/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Current version: 0.12.0 (16/05/2023)</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/MIT"
|
||||
@@ -132,6 +132,7 @@ Termscp is a feature rich terminal file transfer and explorer, with support for
|
||||
- **SCP**
|
||||
- **FTP** and **FTPS**
|
||||
- **S3**
|
||||
- **SMB**
|
||||
- 🖥 Explore and operate on the remote and on the local machine file system with a handy UI
|
||||
- Create, remove, rename, search, view and edit files
|
||||
- ⭐ Connect to your favourite hosts through built-in bookmarks and recent connections
|
||||
@@ -178,7 +179,7 @@ NetBSD users can install termscp from the official repositories.
|
||||
pkgin install termscp
|
||||
```
|
||||
|
||||
For more information or other platforms, please visit [veeso.github.io](https://veeso.github.io/termscp/#get-started) to view all installation methods.
|
||||
For more information or other platforms, please visit [termscp.veeso.dev](https://termscp.veeso.dev/termscp/#get-started) to view all installation methods.
|
||||
|
||||
⚠️ If you're looking on how to update termscp just run termscp from CLI with: `(sudo) termscp --update` ⚠️
|
||||
|
||||
@@ -187,9 +188,11 @@ For more information or other platforms, please visit [veeso.github.io](https://
|
||||
- **Linux** users:
|
||||
- libdbus-1
|
||||
- pkg-config
|
||||
- libsmbclient
|
||||
- **FreeBSD** or, **NetBSD** users:
|
||||
- dbus
|
||||
- pkgconf
|
||||
- libsmbclient
|
||||
|
||||
### Optional Requirements ✔️
|
||||
|
||||
@@ -223,7 +226,7 @@ You can make a donation with one of these platforms:
|
||||
|
||||
## User manual 📚
|
||||
|
||||
The user manual can be found on the [termscp's website](https://veeso.github.io/termscp/#user-manual) or on [Github](docs/man.md).
|
||||
The user manual can be found on the [termscp's website](https://termscp.veeso.dev/termscp/#user-manual) or on [Github](docs/man.md).
|
||||
|
||||
---
|
||||
|
||||
@@ -261,6 +264,7 @@ termscp is powered by these awesome projects:
|
||||
- [edit](https://github.com/milkey-mouse/edit)
|
||||
- [keyring-rs](https://github.com/hwchen/keyring-rs)
|
||||
- [open-rs](https://github.com/Byron/open-rs)
|
||||
- [pavao](https://github.com/veeso/pavao)
|
||||
- [remotefs](https://github.com/veeso/remotefs-rs)
|
||||
- [rpassword](https://github.com/conradkleinespel/rpassword)
|
||||
- [self_update](https://github.com/jaemk/self_update)
|
||||
|
||||
15
build.rs
Normal file
15
build.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use cfg_aliases::cfg_aliases;
|
||||
|
||||
fn main() {
|
||||
// Setup cfg aliases
|
||||
cfg_aliases! {
|
||||
// Platforms
|
||||
macos: { target_os = "macos" },
|
||||
linux: { target_os = "linux" },
|
||||
unix: { target_family = "unix" },
|
||||
windows: { target_family = "windows" },
|
||||
// exclusive features
|
||||
smb: { not( macos ) },
|
||||
smb_unix: { all(unix, not(macos)) }
|
||||
}
|
||||
}
|
||||
1
dist/build/aarch64_centos7/Dockerfile
vendored
1
dist/build/aarch64_centos7/Dockerfile
vendored
@@ -9,6 +9,7 @@ RUN yum -y install \
|
||||
gcc \
|
||||
make \
|
||||
dbus-devel \
|
||||
libsmbclient-devel \
|
||||
bash \
|
||||
rpm-build
|
||||
# Install rust
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:stretch
|
||||
FROM debian:buster
|
||||
|
||||
WORKDIR /usr/src/
|
||||
# Install dependencies
|
||||
@@ -8,6 +8,8 @@ RUN apt update && apt install -y \
|
||||
pkg-config \
|
||||
libdbus-1-dev \
|
||||
build-essential \
|
||||
libsmbclient-dev \
|
||||
libsmbclient \
|
||||
bash \
|
||||
curl
|
||||
|
||||
2
dist/build/freebsd.sh
vendored
2
dist/build/freebsd.sh
vendored
@@ -39,7 +39,7 @@ echo -e "desc: <<EOD\n\
|
||||
A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3\n\
|
||||
EOD\n\
|
||||
arch: \"amd64\"\n\
|
||||
www: \"https://veeso.github.io/termscp/\"\n\
|
||||
www: \"https://termscp.veeso.dev/termscp/\"\n\
|
||||
maintainer: \"christian.visintin1997@gmail.com\"\n\
|
||||
prefix: \"/usr/local/bin\"\n\
|
||||
deps: {\n\
|
||||
|
||||
14
dist/build/linux-aarch64.sh
vendored
14
dist/build/linux-aarch64.sh
vendored
@@ -23,6 +23,8 @@ fi
|
||||
ARM64_DEB_NAME="termscp-arm64_deb"
|
||||
ARM64_RPM_NAME="termscp-arm64_rpm"
|
||||
|
||||
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
|
||||
set -e # Don't fail
|
||||
|
||||
# Create pkgs directory
|
||||
@@ -31,19 +33,20 @@ PKGS_DIR=$(pwd)/pkgs
|
||||
cd -
|
||||
mkdir -p ${PKGS_DIR}/
|
||||
# Build aarch64_deb
|
||||
cd aarch64_debian9/
|
||||
cd aarch64_debian10/
|
||||
docker buildx build --platform linux/arm64 $CACHE --build-arg branch=${BRANCH} --tag $ARM64_DEB_NAME .
|
||||
cd -
|
||||
mkdir -p ${PKGS_DIR}/deb/
|
||||
mkdir -p ${PKGS_DIR}/aarch64-unknown-linux-gnu/
|
||||
docker run --name "$ARM64_DEB_NAME" -d "$ARM64_DEB_NAME" || docker start "$ARM64_DEB_NAME"
|
||||
docker exec -it "$ARM64_DEB_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH && cargo build --release && cargo deb"
|
||||
docker cp ${CONTAINER_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}_arm64.deb ${PKGS_DIR}/deb/
|
||||
docker cp ${CONTAINER_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/aarch64-unknown-linux-gnu/
|
||||
docker cp ${ARM64_DEB_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}_arm64.deb ${PKGS_DIR}/deb/
|
||||
docker cp ${ARM64_DEB_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/aarch64-unknown-linux-gnu/
|
||||
docker stop "$ARM64_DEB_NAME"
|
||||
# Make tar.gz
|
||||
cd ${PKGS_DIR}/aarch64-unknown-linux-gnu/
|
||||
tar cvzf termscp-v${VERSION}-aarch64-unknown-linux-gnu.tar.gz termscp
|
||||
echo "Sha256 (homebrew aarch64): $(sha256sum termscp-v${VERSION}-aarch64-unknown-linux-gnu.tar.gz)"
|
||||
rm termscp
|
||||
cd -
|
||||
# Build aarch64_centos7
|
||||
@@ -52,7 +55,8 @@ docker buildx build --platform linux/arm64 $CACHE --build-arg branch=${BRANCH} -
|
||||
cd -
|
||||
mkdir -p ${PKGS_DIR}/rpm/
|
||||
docker run --name "$ARM64_RPM_NAME" -d "$ARM64_RPM_NAME" || docker start "$ARM64_RPM_NAME"
|
||||
docker exec -it "$ARM64_RPM_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH && cargo rpm init && cargo rpm build"
|
||||
docker cp ${CONTAINER_NAME}:/usr/src/termscp/target/release/rpmbuild/RPMS/aarch64/termscp-${VERSION}-1.el7.aarch64.rpm ${PKGS_DIR}/rpm/termscp-${VERSION}-1.aarch64.rpm
|
||||
docker exec -it "$ARM64_RPM_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH; cargo rpm init; cargo rpm build"
|
||||
docker cp ${ARM64_RPM_NAME}:/usr/src/termscp/target/release/rpmbuild/RPMS/aarch64/termscp-${VERSION}-1.el7.aarch64.rpm ${PKGS_DIR}/rpm/termscp-${VERSION}-1.aarch64.rpm
|
||||
docker stop "$ARM64_RPM_NAME"
|
||||
|
||||
exit $?
|
||||
|
||||
5
dist/build/linux-x86_64.sh
vendored
5
dist/build/linux-x86_64.sh
vendored
@@ -31,7 +31,7 @@ PKGS_DIR=$(pwd)/pkgs
|
||||
cd -
|
||||
mkdir -p ${PKGS_DIR}/
|
||||
# Build x86_64_deb
|
||||
cd x86_64_debian9/
|
||||
cd x86_64_debian10/
|
||||
docker build $CACHE --build-arg branch=${BRANCH} --tag "$X86_64_DEB_NAME" .
|
||||
cd -
|
||||
mkdir -p ${PKGS_DIR}/deb/
|
||||
@@ -44,6 +44,7 @@ docker stop "$X86_64_DEB_NAME"
|
||||
# Make tar.gz
|
||||
cd ${PKGS_DIR}/x86_64-unknown-linux-gnu/
|
||||
tar cvzf termscp-v${VERSION}-x86_64-unknown-linux-gnu.tar.gz termscp
|
||||
echo "Sha256 x86_64 (homebrew): $(sha256sum termscp-v${VERSION}-x86_64-unknown-linux-gnu.tar.gz)"
|
||||
rm termscp
|
||||
cd -
|
||||
# Build x86_64_centos7
|
||||
@@ -52,7 +53,7 @@ docker build $CACHE --build-arg branch=${BRANCH} --tag "$X86_64_RPM_NAME" .
|
||||
cd -
|
||||
mkdir -p ${PKGS_DIR}/rpm/
|
||||
docker run --name "$X86_64_RPM_NAME" -d "$X86_64_RPM_NAME" || docker start "$X86_64_RPM_NAME"
|
||||
docker exec -it "$X86_64_RPM_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH && cargo rpm init && cargo rpm build"
|
||||
docker exec -it "$X86_64_RPM_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH; cargo rpm init; cargo rpm build"
|
||||
docker cp ${X86_64_RPM_NAME}:/usr/src/termscp/target/release/rpmbuild/RPMS/x86_64/termscp-${VERSION}-1.el7.x86_64.rpm ${PKGS_DIR}/rpm/termscp-${VERSION}-1.x86_64.rpm
|
||||
docker stop "$X86_64_RPM_NAME"
|
||||
|
||||
|
||||
61
dist/build/macos.sh
vendored
61
dist/build/macos.sh
vendored
@@ -18,11 +18,52 @@ make_pkg() {
|
||||
echo "$HASH"
|
||||
}
|
||||
|
||||
detect_platform() {
|
||||
local platform
|
||||
platform="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
case "${platform}" in
|
||||
linux) platform="linux" ;;
|
||||
darwin) platform="macos" ;;
|
||||
freebsd) platform="freebsd" ;;
|
||||
esac
|
||||
|
||||
printf '%s' "${platform}"
|
||||
}
|
||||
|
||||
detect_arch() {
|
||||
local arch
|
||||
arch="$(uname -m | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
case "${arch}" in
|
||||
amd64) arch="x86_64" ;;
|
||||
armv*) arch="arm" ;;
|
||||
arm64) arch="aarch64" ;;
|
||||
esac
|
||||
|
||||
# `uname -m` in some cases mis-reports 32-bit OS as 64-bit, so double check
|
||||
if [ "${arch}" = "x86_64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then
|
||||
arch="i686"
|
||||
elif [ "${arch}" = "aarch64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then
|
||||
arch="arm"
|
||||
fi
|
||||
|
||||
printf '%s' "${arch}"
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: macos.sh <version>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PLATFORM="$(detect_platform)"
|
||||
ARCH="$(detect_arch)"
|
||||
|
||||
if [ "$PLATFORM" != "macos" ]; then
|
||||
echo "macos build is only available on MacOs systems"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION=$1
|
||||
export BUILD_ROOT
|
||||
BUILD_ROOT="$(pwd)/../../"
|
||||
@@ -38,16 +79,28 @@ if [ ! -f Cargo.toml ]; then
|
||||
fi
|
||||
|
||||
# Build release (x86_64)
|
||||
cargo build --release
|
||||
X86_TARGET=""
|
||||
X86_TARGET_DIR=""
|
||||
if [ "$ARCH" == "aarch64" ]; then
|
||||
X86_TARGET="--target x86_64-apple-darwin"
|
||||
X86_TARGET_DIR="target/x86_64-apple-darwin/release/"
|
||||
fi
|
||||
cargo build --release $X86_TARGET
|
||||
# Make pkg
|
||||
X86_64_HASH=$(make_pkg "x86_64" "$VERSION")
|
||||
X86_64_HASH=$(make_pkg "x86_64" "$VERSION" $X86_TARGET_DIR)
|
||||
RET_X86_64=$?
|
||||
|
||||
ARM64_TARGET=""
|
||||
ARM64_TARGET_DIR=""
|
||||
if [ "$ARCH" == "aarch64" ]; then
|
||||
ARM64_TARGET="--target aarch64-apple-darwin"
|
||||
ARM64_TARGET_DIR="target/aarch64-apple-darwin/release/"
|
||||
fi
|
||||
cd "$BUILD_ROOT"
|
||||
# Build ARM64 pkg
|
||||
cargo build --release --target aarch64-apple-darwin
|
||||
cargo build --release $ARM64_TARGET
|
||||
# Make pkg
|
||||
ARM64_HASH=$(make_pkg "arm64" "$VERSION" "target/aarch64-apple-darwin/release/")
|
||||
ARM64_HASH=$(make_pkg "arm64" "$VERSION" $ARM64_TARGET_DIR)
|
||||
RET_ARM64=$?
|
||||
|
||||
echo "x86_64 hash: $X86_64_HASH"
|
||||
|
||||
1
dist/build/x86_64_centos7/Dockerfile
vendored
1
dist/build/x86_64_centos7/Dockerfile
vendored
@@ -9,6 +9,7 @@ RUN yum -y install \
|
||||
gcc \
|
||||
make \
|
||||
dbus-devel \
|
||||
libsmbclient-devel \
|
||||
bash \
|
||||
rpm-build
|
||||
# Install rust
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:stretch
|
||||
FROM debian:buster
|
||||
|
||||
WORKDIR /usr/src/
|
||||
# Install dependencies
|
||||
@@ -8,6 +8,8 @@ RUN apt update && apt install -y \
|
||||
pkg-config \
|
||||
libdbus-1-dev \
|
||||
build-essential \
|
||||
libsmbclient-dev \
|
||||
libsmbclient \
|
||||
bash \
|
||||
curl
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
<p align="center">~ Eine funktionsreiche Terminal-Dateiübertragung ~</p>
|
||||
<p align="center">
|
||||
<a href="https://veeso.github.io/termscp/" target="_blank">Webseite</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/" target="_blank">Webseite</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Installation</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#get-started" target="_blank">Installation</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">Benutzerhandbuch</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#user-manual" target="_blank">Benutzerhandbuch</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -62,8 +62,8 @@
|
||||
/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">Entwickelt von <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Aktuelle Version: 0.11.2 (18/04/2023)</p>
|
||||
<p align="center">Entwickelt von <a href="https://termscp.veeso.dev/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Aktuelle Version: 0.12.0 (16/05/2023)</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/MIT"
|
||||
@@ -137,6 +137,7 @@ Termscp ist ein funktionsreicher Terminal-Dateitransfer und Explorer mit Unterst
|
||||
- **SCP**
|
||||
- **FTP** und **FTPS**
|
||||
- **S3**
|
||||
- **SMB**
|
||||
- 🖥 Erkunden und bedienen Sie das Dateisystem der Fernbedienung und des lokalen Computers mit einer praktischen Benutzeroberfläche
|
||||
- Erstellen, Entfernen, Umbenennen, Suchen, Anzeigen und Bearbeiten von Dateien
|
||||
- ⭐ Verbinden Sie sich über integrierte Lesezeichen und aktuelle Verbindungen mit Ihren Lieblingshosts
|
||||
@@ -175,7 +176,7 @@ Wenn Sie ein Windows-Benutzer sind, können Sie termscp mit [Chocolatey](https:/
|
||||
choco install termscp
|
||||
```
|
||||
|
||||
Für weitere Informationen oder andere Plattformen besuchen Sie bitte [veeso.github.io](https://veeso.github.io/termscp/#get-started), um alle Installationsmethoden anzuzeigen.
|
||||
Für weitere Informationen oder andere Plattformen besuchen Sie bitte [termscp.veeso.dev](https://termscp.veeso.dev/termscp/#get-started), um alle Installationsmethoden anzuzeigen.
|
||||
|
||||
⚠️ Wenn Sie wissen möchten, wie Sie termscp aktualisieren können, führen Sie einfach termscp über die CLI aus mit: `(sudo) termscp --update` ⚠️
|
||||
|
||||
@@ -185,10 +186,12 @@ Für weitere Informationen oder andere Plattformen besuchen Sie bitte [veeso.git
|
||||
- libssh
|
||||
- libdbus-1
|
||||
- pkg-config
|
||||
- libsmbclient
|
||||
- **FreeBSD** Benutzer:
|
||||
- libssh
|
||||
- dbus
|
||||
- pkgconf
|
||||
- libsmbclient
|
||||
|
||||
### Optionale Softwareanforderungen ✔️
|
||||
|
||||
@@ -221,7 +224,7 @@ Sie können mit einer dieser Plattformen spenden:
|
||||
|
||||
## User manual 📚
|
||||
|
||||
Das Benutzerhandbuch finden Sie auf der [termscp-Website](https://veeso.github.io/termscp/#user-manual) oder auf [Github](man.md).
|
||||
Das Benutzerhandbuch finden Sie auf der [termscp-Website](https://termscp.veeso.dev/termscp/#user-manual) oder auf [Github](man.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
- [Usage ❓](#usage-)
|
||||
- [Address argument 🌎](#address-argument-)
|
||||
- [AWS S3 address argument](#aws-s3-address-argument)
|
||||
- [SMB address argument](#smb-address-argument)
|
||||
- [How Password can be provided 🔐](#how-password-can-be-provided-)
|
||||
- [S3 connection parameters](#s3-connection-parameters)
|
||||
- [S3 credentials 🦊](#s3-credentials-)
|
||||
@@ -105,6 +106,22 @@ e.g.
|
||||
s3://buckethead@eu-central-1:default:/assets
|
||||
```
|
||||
|
||||
#### SMB address argument
|
||||
|
||||
SMB has a different syntax for CLI address argument, which is different whether you're on Windows or other systems:
|
||||
|
||||
**Windows** syntax:
|
||||
|
||||
```txt
|
||||
\\[username@]<server-name>\<share>[\path\...]
|
||||
```
|
||||
|
||||
**Other systems** syntax:
|
||||
|
||||
```txt
|
||||
smb://[username@]<server-name>[:port]/<share>[/path/.../]
|
||||
```
|
||||
|
||||
#### How Password can be provided 🔐
|
||||
|
||||
You have probably noticed, that, when providing the address as argument, there's no way to provide the password.
|
||||
@@ -214,6 +231,7 @@ In order to change panel you need to type `<LEFT>` to move the remote explorer p
|
||||
| `<W>` | Open file with provided program | With |
|
||||
| `<X>` | Execute a command | eXecute |
|
||||
| `<Y>` | Toggle synchronized browsing | sYnc |
|
||||
| `<Z>` | Change file mode | |
|
||||
| `<CTRL+A>` | Select all files | |
|
||||
| `<CTRL+C>` | Abort file transfer process | |
|
||||
| `<CTRL+T>` | Show all synchronized paths | Track |
|
||||
@@ -340,7 +358,7 @@ These parameters can be changed:
|
||||
- **Local File formatter syntax**: syntax to display file info for each file in the local explorer. See [File explorer format](#file-explorer-format)
|
||||
- **Enable notifications?**: If set to `Yes`, notifications will be displayed.
|
||||
- **Notifications: minimum transfer size**: if transfer size is greater or equal than the specified value, notifications for transfer will be displayed. The accepted values are in format `{UNSIGNED} B/KB/MB/GB/TB/PB`
|
||||
- **SSH configuration path**: Set SSH configuration file to use when connecting to a SCP/SFTP server. If unset (empty) no file will be used. You can specify a path starting with `~` to indicate the home path (e.g. `~/.ssh/config`)
|
||||
- **SSH configuration path**: Set SSH configuration file to use when connecting to a SCP/SFTP server. If unset (empty) no file will be used. You can specify a path starting with `~` to indicate the home path (e.g. `~/.ssh/config`). The parameters supported by termscp are specified [HERE](https://github.com/veeso/ssh2-config#exposed-attributes).
|
||||
|
||||
### SSH Key Storage 🔐
|
||||
|
||||
@@ -482,9 +500,9 @@ Just a reminder: **you can edit only textual file**; binary files are not suppor
|
||||
|
||||
termscp writes a log file for each session, which is written at
|
||||
|
||||
- `$HOME/.config/termscp/termscp.log` on Linux/BSD
|
||||
- `$HOME/Library/Application Support/termscp/termscp.log` on MacOs
|
||||
- `FOLDERID_RoamingAppData\termscp\termscp.log` on Windows
|
||||
- `$HOME/.cache/termscp/termscp.log` on Linux/BSD
|
||||
- `$HOME/Library/Caches/termscp/termscp.log` on MacOs
|
||||
- `FOLDERID_LocalAppData\termscp\termscp.log` on Windows
|
||||
|
||||
the log won't be rotated, but will just be truncated after each launch of termscp, so if you want to report an issue and you want to attach your log file, keep in mind to save the log file in a safe place before using termscp again.
|
||||
The logging by default reports in *INFO* level, so it is not very verbose.
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
<p align="center">~ Una transferencia de archivos de terminal rica en funciones ~</p>
|
||||
<p align="center">
|
||||
<a href="https://veeso.github.io/termscp/" target="_blank">Sitio Web</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/" target="_blank">Sitio Web</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Instalación</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#get-started" target="_blank">Instalación</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">Manual de usuario</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#user-manual" target="_blank">Manual de usuario</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -62,8 +62,8 @@
|
||||
/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">Desarrollado por <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Versión actual: 0.11.2 (18/04/2023)</p>
|
||||
<p align="center">Desarrollado por <a href="https://termscp.veeso.dev/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Versión actual: 0.12.0 (16/05/2023)</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/MIT"
|
||||
@@ -137,6 +137,7 @@ Termscp es un explorador y transferencia de archivos de terminal rico en funcion
|
||||
- **SCP**
|
||||
- **FTP** y **FTPS**
|
||||
- **S3**
|
||||
- **SMB**
|
||||
- 🖥 Explore y opere en el sistema de archivos de la máquina local y remota con una interfaz de usuario práctica
|
||||
- Cree, elimine, cambie el nombre, busque, vea y edite archivos
|
||||
- ⭐ Conéctese a sus hosts favoritos y conexiones recientes
|
||||
@@ -175,20 +176,20 @@ mientras que si eres un usuario de Windows, puedes instalar termscp con [Chocola
|
||||
choco install termscp
|
||||
```
|
||||
|
||||
Para obtener más información u otras plataformas, visite [veeso.github.io](https://veeso.github.io/termscp/#get-started) para ver todos los métodos de instalación.
|
||||
Para obtener más información u otras plataformas, visite [termscp.veeso.dev](https://termscp.veeso.dev/termscp/#get-started) para ver todos los métodos de instalación.
|
||||
|
||||
⚠️ Si estás buscando cómo actualizar termscp, simplemente ejecute termscp desde CLI con:: `(sudo) termscp --update` ⚠️
|
||||
|
||||
### Requisitos ❗
|
||||
|
||||
- Usuarios **Linux**:
|
||||
- libssh
|
||||
- **Linux** users:
|
||||
- libdbus-1
|
||||
- pkg-config
|
||||
- Usuarios **FreeBSD**:
|
||||
- libssh
|
||||
- libsmbclient
|
||||
- **FreeBSD** or, **NetBSD** users:
|
||||
- dbus
|
||||
- pkgconf
|
||||
- libsmbclient
|
||||
|
||||
### Requisitos opcionales ✔️
|
||||
|
||||
@@ -221,7 +222,7 @@ Puedes hacer una donación con una de estas plataformas:
|
||||
|
||||
## Manual de usuario y documentación 📚
|
||||
|
||||
El manual del usuario se puede encontrar en el [sitio web de termscp](https://veeso.github.io/termscp/#user-manual) o en [Github](man.md).
|
||||
El manual del usuario se puede encontrar en el [sitio web de termscp](https://termscp.veeso.dev/termscp/#user-manual) o en [Github](man.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
- [Uso ❓](#uso-)
|
||||
- [Argumento dirección 🌎](#argumento-dirección-)
|
||||
- [Argumento dirección por AWS S3](#argumento-dirección-por-aws-s3)
|
||||
- [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-)
|
||||
- [S3 parámetros de conexión](#s3-parámetros-de-conexión)
|
||||
- [Credenciales de S3 🦊](#credenciales-de-s3-)
|
||||
@@ -105,6 +106,22 @@ por ejemplo
|
||||
s3://buckethead@eu-central-1:default:/assets
|
||||
```
|
||||
|
||||
#### Argumento dirección por SMB
|
||||
|
||||
SMB tiene una sintaxis diferente para el argumento de la dirección CLI, que es diferente si está en Windows u otros sistemas:
|
||||
|
||||
**Windows** sintaxis:
|
||||
|
||||
```txt
|
||||
\\[username@]<server-name>\<share>[\path\...]
|
||||
```
|
||||
|
||||
**Other systems** sintaxis:
|
||||
|
||||
```txt
|
||||
smb://[username@]<server-name>[:port]/<share>[/path/.../]
|
||||
```
|
||||
|
||||
#### Cómo se puede proporcionar la contraseña 🔐
|
||||
|
||||
Probablemente haya notado que, al proporcionar la dirección como argumento, no hay forma de proporcionar la contraseña.
|
||||
@@ -214,6 +231,7 @@ Para cambiar de panel, debe escribir `<LEFT>` para mover el panel del explorador
|
||||
| `<W>` | Abrir archivo con el programa proporcionado | With |
|
||||
| `<X>` | Ejecutar un comando | eXecute |
|
||||
| `<Y>` | Alternar navegación sincronizada | sYnc |
|
||||
| `<Z>` | Cambiar ppermisos de archivo | |
|
||||
| `<CTRL+A>` | Seleccionar todos los archivos | |
|
||||
| `<CTRL+C>` | Abortar el proceso de transferencia de archivos | |
|
||||
| `<CTRL+T>` | Mostrar todas las rutas sincronizadas | Track |
|
||||
@@ -339,7 +357,7 @@ Estos parámetros se pueden cambiar:
|
||||
- **Local File formatter syntax**: sintaxis para mostrar información de archivo para cada archivo en el explorador local. Consulte [Formato del explorador de archivos](#formato-del-explorador-de-archivos).
|
||||
- **Enable notifications?**: Si se establece en "Sí", se mostrarán las notificaciones.
|
||||
- **Notifications: minimum transfer size**: si el tamaño de la transferencia es mayor o igual que el valor especificado, se mostrarán notificaciones de transferencia. Los valores aceptados están en formato `{UNSIGNED} B/KB/MB/GB/TB/PB`
|
||||
- **SSH configuration path**: Configure el archivo de configuración SSH para usar al conectarse a un servidor SCP / SFTP. Si no se configura (está vacío), no se utilizará ningún archivo. Puede especificar una ruta que comience con `~` para indicar la ruta de inicio (por ejemplo, `~/.ssh/config`)
|
||||
- **SSH configuration path**: Configure el archivo de configuración SSH para usar al conectarse a un servidor SCP / SFTP. Si no se configura (está vacío), no se utilizará ningún archivo. Puede especificar una ruta que comience con `~` para indicar la ruta de inicio (por ejemplo, `~/.ssh/config`). Se especifican los parámetros soportados [AQUI](https://github.com/veeso/ssh2-config#exposed-attributes).
|
||||
|
||||
### SSH Key Storage 🔐
|
||||
|
||||
@@ -481,9 +499,9 @@ En caso de que el archivo esté ubicado en un host remoto, el archivo se descarg
|
||||
|
||||
termscp escribe un archivo de registro para cada sesión, que se escribe en
|
||||
|
||||
- `$HOME/.config/termscp/termscp.log` en Linux/BSD
|
||||
- `$HOME/Library/Application Support/termscp/termscp.log` en MacOs
|
||||
- `FOLDERID_RoamingAppData\termscp\termscp.log` en Windows
|
||||
- `$HOME/.cache/termscp/termscp.log` en Linux/BSD
|
||||
- `$HOME/Library/Caches/termscp/termscp.log` en MacOs
|
||||
- `FOLDERID_LocalAppData\termscp\termscp.log` en Windows
|
||||
|
||||
el registro no se rotará, sino que se truncará después de cada lanzamiento de termscp, por lo que si desea informar un problema y desea adjuntar su archivo de registro, recuerde guardar el archivo de registro en un lugar seguro antes de usar termscp de nuevo.
|
||||
El registro por defecto informa en el nivel *INFO*, por lo que no es muy detallado.
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
<p align="center">~ Un file transfer de terminal riche en fonctionnalités ~</p>
|
||||
<p align="center">
|
||||
<a href="https://veeso.github.io/termscp/" target="_blank">Site internet</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/" target="_blank">Site internet</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Installation</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#get-started" target="_blank">Installation</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">Manuel de l'Utilisateur</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#user-manual" target="_blank">Manuel de l'Utilisateur</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -62,8 +62,8 @@
|
||||
/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">Développé par <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Version actuelle: 0.11.2 (18/04/2023)</p>
|
||||
<p align="center">Développé par <a href="https://termscp.veeso.dev/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Version actuelle: 0.12.0 (16/05/2023)</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/MIT"
|
||||
@@ -137,6 +137,7 @@ Termscp est un file transfer et explorateur de fichiers de terminal riche en fon
|
||||
- **SCP**
|
||||
- **FTP** et **FTPS**
|
||||
- **S3**
|
||||
- **SMB**
|
||||
- 🖥 Explorer et opérer sur le système de fichiers distant et local avec une interface utilisateur pratique.
|
||||
- Créer, supprimer, renommer, rechercher, afficher et modifier des fichiers
|
||||
- ⭐ Connectez-vous à vos hôtes préférés via des signets et des connexions récentes.
|
||||
@@ -175,20 +176,20 @@ tandis que si tu es un utilisateur Windows, tu peux installer termscp avec [Choc
|
||||
choco install termscp
|
||||
```
|
||||
|
||||
Pour plus d'informations sur les autres méthodes d'installation, veuillez visiter [veeso.github.io](https://veeso.github.io/termscp/#get-started).
|
||||
Pour plus d'informations sur les autres méthodes d'installation, veuillez visiter [termscp.veeso.dev](https://termscp.veeso.dev/termscp/#get-started).
|
||||
|
||||
⚠️ Si tu cherche comme de mettre à jour termscp, tu dois exécuter cette commande dans le terminal: `(sudo) termscp --update` ⚠️
|
||||
|
||||
### Requis ❗
|
||||
|
||||
- utilisateurs **Linux**:
|
||||
- libssh
|
||||
- **Linux** users:
|
||||
- libdbus-1
|
||||
- pkg-config
|
||||
- utilisateurs **FreeBSD**:
|
||||
- libssh
|
||||
- libsmbclient
|
||||
- **FreeBSD** or, **NetBSD** users:
|
||||
- dbus
|
||||
- pkgconf
|
||||
- libsmbclient
|
||||
|
||||
### Requis facultatives ✔️
|
||||
|
||||
@@ -221,7 +222,7 @@ Tu peux faire un don avec l'une de ces plateformes:
|
||||
|
||||
## Manuel d'utilisateur et Documentation 📚
|
||||
|
||||
Le manuel d'utilisateur peut être trouvé sur le [site de termscp](https://veeso.github.io/termscp/#user-manual) ou sur [Github](man.md).
|
||||
Le manuel d'utilisateur peut être trouvé sur le [site de termscp](https://termscp.veeso.dev/termscp/#user-manual) ou sur [Github](man.md).
|
||||
|
||||
La documentation peut être trouvé sur Rust Docs <https://docs.rs/termscp>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
- [Usage ❓](#usage-)
|
||||
- [Argument d'adresse 🌎](#argument-dadresse-)
|
||||
- [Argument d'adresse AWS S3](#argument-dadresse-aws-s3)
|
||||
- [Argument d'adresse SMB](#argument-dadresse-smb)
|
||||
- [Comment le mot de passe peut être fourni 🔐](#comment-le-mot-de-passe-peut-être-fourni-)
|
||||
- [S3 paramètres de connexion](#s3-paramètres-de-connexion)
|
||||
- [Identifiants S3 🦊](#identifiants-s3-)
|
||||
@@ -103,6 +104,23 @@ e.g.
|
||||
s3://buckethead@eu-central-1:default:/assets
|
||||
```
|
||||
|
||||
#### Argument d'adresse SMB
|
||||
|
||||
SMB a une syntaxe différente pour l'argument d'adresse CLI, qui est différente que vous soyez sur Windows ou sur d'autres systèmes :
|
||||
|
||||
syntaxe **Windows**:
|
||||
|
||||
```txt
|
||||
\\[username@]<server-name>\<share>[\path\...]
|
||||
```
|
||||
|
||||
syntaxe **Other systems**:
|
||||
|
||||
```txt
|
||||
smb://[username@]<server-name>[:port]/<share>[/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.
|
||||
@@ -212,6 +230,7 @@ Pour changer de panneau, vous devez taper `<LEFT>` pour déplacer le panneau de
|
||||
| `<W>` | Ouvrir le fichier avec le programme spécifié | With |
|
||||
| `<X>` | Exécuter une commande | eXecute |
|
||||
| `<Y>` | Basculer la navigation synchronisée | sYnc |
|
||||
| `<Z>` | Changer permissions de fichier | |
|
||||
| `<CTRL+A>` | Sélectionner tous les fichiers | |
|
||||
| `<CTRL+C>` | Abandonner le processus de transfert de fichiers | |
|
||||
| `<CTRL+T>` | Afficher tous les chemins synchronisés | Track |
|
||||
@@ -337,7 +356,7 @@ Ces paramètres peuvent être modifiés :
|
||||
- **Local File formatter syntax**: syntaxe pour afficher les informations de fichier pour chaque fichier dans l'explorateur local. Voir [File explorer format](#format-de-lexplorateur-de-fichiers)
|
||||
- **Enable notifications?**: S'il est défini sur `Yes`, les notifications seront affichées.
|
||||
- **Notifications: minimum transfer size**: si la taille du transfert est supérieure ou égale à la valeur spécifiée, les notifications de transfert seront affichées. Les valeurs acceptées sont au format `{UNSIGNED} B/KB/MB/GB/TB/PB`
|
||||
- **SSH configuration path** : définissez le fichier de configuration SSH à utiliser lors de la connexion à un serveur SCP/SFTP. S'il n'est pas défini (vide), aucun fichier ne sera utilisé. Vous pouvez spécifier un chemin commençant par `~` pour indiquer le chemin d'accueil (par exemple `~/.ssh/config`)
|
||||
- **SSH configuration path** : définissez le fichier de configuration SSH à utiliser lors de la connexion à un serveur SCP/SFTP. S'il n'est pas défini (vide), aucun fichier ne sera utilisé. Vous pouvez spécifier un chemin commençant par `~` pour indiquer le chemin d'accueil (par exemple `~/.ssh/config`). Les paramétrages disponibles pour la configuration sont listées [ICI](https://github.com/veeso/ssh2-config#exposed-attributes).
|
||||
|
||||
### SSH Key Storage 🔐
|
||||
|
||||
@@ -479,9 +498,9 @@ Si le fichier se trouve sur l'hôte distant, le fichier sera d'abord télécharg
|
||||
|
||||
termscp écrit un fichier journal pour chaque session, qui est écrit à
|
||||
|
||||
- `$HOME/.config/termscp/termscp.log` sous Linux/BSD
|
||||
- `$HOME/Library/Application Support/termscp/termscp.log` sous MacOs
|
||||
- `FOLDERID_RoamingAppData\termscp\termscp.log` sous Windows
|
||||
- `$HOME/.cache/termscp/termscp.log` sous Linux/BSD
|
||||
- `$HOME/Library/Caches/termscp/termscp.log` sous MacOs
|
||||
- `FOLDERID_LocalAppData\termscp\termscp.log` sous Windows
|
||||
|
||||
le journal ne sera pas tourné, mais sera simplement tronqué après chaque lancement de termscp, donc si vous souhaitez signaler un problème et que vous souhaitez joindre votre fichier journal, n'oubliez pas de sauvegarder le fichier journal dans un endroit sûr avant de l'utiliser termescp à nouveau.
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
<p align="center">~ Un file transfer ricco di funzionalità ~</p>
|
||||
<p align="center">
|
||||
<a href="https://veeso.github.io/termscp/" target="_blank">Sito</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/" target="_blank">Sito</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Installazione</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#get-started" target="_blank">Installazione</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">Manuale utente</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#user-manual" target="_blank">Manuale utente</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -62,8 +62,8 @@
|
||||
/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">Sviluppato da <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Versione corrente: 0.11.2 (18/04/2023)</p>
|
||||
<p align="center">Sviluppato da <a href="https://termscp.veeso.dev/" target="_blank">@veeso</a></p>
|
||||
<p align="center">Versione corrente: 0.12.0 (16/05/2023)</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/MIT"
|
||||
@@ -137,6 +137,7 @@ Termscp è un file transfer ed explorer ricco di funzionalità, con supporto a S
|
||||
- **SCP**
|
||||
- **FTP** and **FTPS**
|
||||
- **S3**
|
||||
- **SMB**
|
||||
- 🖥 Esplora e opera sia sul file system locale che su quello remoto con una UI di facile utilizzo.
|
||||
- Crea, rimuove, rinomina, cerca, visualizza e modifica file
|
||||
- ⭐ Connettiti ai tuoi host preferiti tramite la funzionalità integrata dei segnalibri e delle connessioni recenti.
|
||||
@@ -175,20 +176,20 @@ mentre se sei un utente Windows, puoi installare termscp con [Chocolatey](https:
|
||||
choco install termscp
|
||||
```
|
||||
|
||||
Per ulteriori informazioni sui metodi di installazione su altre piattaforme, visita [veeso.github.io](https://veeso.github.io/termscp/#get-started).
|
||||
Per ulteriori informazioni sui metodi di installazione su altre piattaforme, visita [termscp.veeso.dev](https://termscp.veeso.dev/termscp/#get-started).
|
||||
|
||||
⚠️ Se stavi cercando come aggiornare la tua versione di termscp, puoi semplicemente lanciare termscp con questi argomenti: `(sudo) termscp --update` ⚠️
|
||||
|
||||
### Requisiti ❗
|
||||
|
||||
- Utenti **Linux**:
|
||||
- libssh
|
||||
- **Linux** users:
|
||||
- libdbus-1
|
||||
- pkg-config
|
||||
- Utenti **FreeBSD**:
|
||||
- libssh
|
||||
- libsmbclient
|
||||
- **FreeBSD** or, **NetBSD** users:
|
||||
- dbus
|
||||
- pkgconf
|
||||
- libsmbclient
|
||||
|
||||
### Requisiti opzionali ✔️
|
||||
|
||||
@@ -221,7 +222,7 @@ Puoi fare una donazione tramite una di queste piattaforme:
|
||||
|
||||
## Manuale utente 📚
|
||||
|
||||
Il manuale utente lo puoi trovare sul [sito di termscp](https://veeso.github.io/termscp/#user-manual) o su [Github](man.md).
|
||||
Il manuale utente lo puoi trovare sul [sito di termscp](https://termscp.veeso.dev/termscp/#user-manual) o su [Github](man.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
- [Argomenti da linea di comando ❓](#argomenti-da-linea-di-comando-)
|
||||
- [Argomento indirizzo 🌎](#argomento-indirizzo-)
|
||||
- [Argomento indirizzo per AWS S3](#argomento-indirizzo-per-aws-s3)
|
||||
- [Indirizzo SMB](#indirizzo-smb)
|
||||
- [Come fornire la password 🔐](#come-fornire-la-password-)
|
||||
- [Parametri di connessione S3](#parametri-di-connessione-s3)
|
||||
- [Credenziali S3 🦊](#credenziali-s3-)
|
||||
@@ -101,6 +102,23 @@ e.g.
|
||||
s3://buckethead@eu-central-1:default:/assets
|
||||
```
|
||||
|
||||
#### Indirizzo SMB
|
||||
|
||||
SMB ha una sintassi differente rispetto agli altri protocolli e cambia in base al sistema operativo:
|
||||
|
||||
**Windows**:
|
||||
|
||||
```txt
|
||||
\\[username@]<server-name>\<share>[\path\...]
|
||||
```
|
||||
|
||||
**Altri sistemi**:
|
||||
|
||||
```txt
|
||||
smb://[username@]<server-name>[:port]/<share>[/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:
|
||||
@@ -208,6 +226,7 @@ Per cambiare pannello ti puoi muovere con le frecce, `<LEFT>` per andare sul pan
|
||||
| `<W>` | Apri il file con il programma specificato | With |
|
||||
| `<X>` | Esegui comando shell | eXecute |
|
||||
| `<Y>` | Abilita/disabilita Sync-Browsing | sYnc |
|
||||
| `<Z>` | Modifica permessi file | |
|
||||
| `<CTRL+A>` | Seleziona tutti i file | |
|
||||
| `<CTRL+C>` | Annulla trasferimento file | |
|
||||
| `<CTRL+T>` | Visualizza tutti i percorsi sincronizzati | Track |
|
||||
@@ -335,7 +354,7 @@ Questi parametri possono essere impostati:
|
||||
- **Local File formatter syntax**: La formattazione da usare per formattare i file sull'explorer locale. Vedi [File explorer format](#file-explorer-format)
|
||||
- **Enable notifications?**: Se impostato a `yes`, le notifiche desktop saranno abilitate.
|
||||
- **Notifications: minimum transfer size**: se la dimensione di un trasferimento supera o è uguale al valore impostato, al termine del trasferimento riceverai una notifica desktop (se queste sono abilitate). Il formato del valore dev'essere `{UNSIGNED} B/KB/MB/GB/TB/PB`
|
||||
- **SSH configuration path**: Imposta il percorso del file di configurazione per SSH, per quando ci si connette ad un server SFTP/SCP. Se lasciato vuoto, nessun file verrà usato. Il percorso può anche iniziare con `~` per indicare il percorso della home dell'utente attuale (e.s. `~/.ssh/config`).
|
||||
- **SSH configuration path**: Imposta il percorso del file di configurazione per SSH, per quando ci si connette ad un server SFTP/SCP. Se lasciato vuoto, nessun file verrà usato. Il percorso può anche iniziare con `~` per indicare il percorso della home dell'utente attuale (e.s. `~/.ssh/config`). I parametri supportati dalla configurazioni sono descritti [QUI](https://github.com/veeso/ssh2-config#exposed-attributes).
|
||||
|
||||
### SSH Key Storage 🔐
|
||||
|
||||
@@ -478,9 +497,9 @@ Nel caso il file si trovi su host remoto, il file verrà prima scaricato tempora
|
||||
|
||||
termscp scrive un file di log per ogni sessione, nel percorso seguente:
|
||||
|
||||
- `$HOME/.config/termscp/termscp.log` su Linux/BSD
|
||||
- `$HOME/Library/Application Support/termscp/termscp.log` su MacOs
|
||||
- `FOLDERID_RoamingAppData\termscp\termscp.log` su Windows
|
||||
- `$HOME/.cache/termscp/termscp.log` su Linux/BSD
|
||||
- `$HOME/Library/Caches/termscp/termscp.log` su MacOs
|
||||
- `FOLDERID_LocalAppData\termscp\termscp.log` su Windows
|
||||
|
||||
Il log non viene ruotato, ma viene troncato ad ogni lancio di termscp, quindi se devi riportare un issue, non avviare termscp fino a che non avrai salvato il file di log.
|
||||
I log sono di default riportati a livello *INFO*, quindi non sono particolarmente parlanti.
|
||||
|
||||
26
docs/man.md
26
docs/man.md
@@ -4,6 +4,7 @@
|
||||
- [Usage ❓](#usage-)
|
||||
- [Address argument 🌎](#address-argument-)
|
||||
- [AWS S3 address argument](#aws-s3-address-argument)
|
||||
- [SMB address argument](#smb-address-argument)
|
||||
- [How Password can be provided 🔐](#how-password-can-be-provided-)
|
||||
- [S3 connection parameters](#s3-connection-parameters)
|
||||
- [S3 credentials 🦊](#s3-credentials-)
|
||||
@@ -103,6 +104,22 @@ e.g.
|
||||
s3://buckethead@eu-central-1:default:/assets
|
||||
```
|
||||
|
||||
#### SMB address argument
|
||||
|
||||
SMB has a different syntax for CLI address argument, which is different whether you're on Windows or other systems:
|
||||
|
||||
**Windows** syntax:
|
||||
|
||||
```txt
|
||||
\\[username@]<server-name>\<share>[\path\...]
|
||||
```
|
||||
|
||||
**Other systems** syntax:
|
||||
|
||||
```txt
|
||||
smb://[username@]<server-name>[:port]/<share>[/path/.../]
|
||||
```
|
||||
|
||||
#### How Password can be provided 🔐
|
||||
|
||||
You have probably noticed, that, when providing the address as argument, there's no way to provide the password.
|
||||
@@ -212,6 +229,7 @@ In order to change panel you need to type `<LEFT>` to move the remote explorer p
|
||||
| `<W>` | Open file with provided program | With |
|
||||
| `<X>` | Execute a command | eXecute |
|
||||
| `<Y>` | Toggle synchronized browsing | sYnc |
|
||||
| `<Z>` | Change file mode | |
|
||||
| `<CTRL+A>` | Select all files | |
|
||||
| `<CTRL+C>` | Abort file transfer process | |
|
||||
| `<CTRL+T>` | Show all synchronized paths | Track |
|
||||
@@ -338,7 +356,7 @@ These parameters can be changed:
|
||||
- **Local File formatter syntax**: syntax to display file info for each file in the local explorer. See [File explorer format](#file-explorer-format)
|
||||
- **Enable notifications?**: If set to `Yes`, notifications will be displayed.
|
||||
- **Notifications: minimum transfer size**: if transfer size is greater or equal than the specified value, notifications for transfer will be displayed. The accepted values are in format `{UNSIGNED} B/KB/MB/GB/TB/PB`
|
||||
- **SSH configuration path**: Set SSH configuration file to use when connecting to a SCP/SFTP server. If unset (empty) no file will be used. You can specify a path starting with `~` to indicate the home path (e.g. `~/.ssh/config`)
|
||||
- **SSH configuration path**: Set SSH configuration file to use when connecting to a SCP/SFTP server. If unset (empty) no file will be used. You can specify a path starting with `~` to indicate the home path (e.g. `~/.ssh/config`). The parameters supported by termscp are specified [HERE](https://github.com/veeso/ssh2-config#exposed-attributes).
|
||||
|
||||
### SSH Key Storage 🔐
|
||||
|
||||
@@ -480,9 +498,9 @@ In case the file is located on remote host, the file will be first downloaded in
|
||||
|
||||
termscp writes a log file for each session, which is written at
|
||||
|
||||
- `$HOME/.config/termscp/termscp.log` on Linux/BSD
|
||||
- `$HOME/Library/Application Support/termscp/termscp.log` on MacOs
|
||||
- `FOLDERID_RoamingAppData\termscp\termscp.log` on Windows
|
||||
- `$HOME/.cache/termscp/termscp.log` on Linux/BSD
|
||||
- `$HOME/Library/Caches/termscp/termscp.log` on MacOs
|
||||
- `FOLDERID_LocalAppData\termscp\termscp.log` on Windows
|
||||
|
||||
the log won't be rotated, but will just be truncated after each launch of termscp, so if you want to report an issue and you want to attach your log file, keep in mind to save the log file in a safe place before using termscp again.
|
||||
The logging by default reports in *INFO* level, so it is not very verbose.
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
<p align="center">~ 功能丰富的终端文件传输工具 ~</p>
|
||||
<p align="center">
|
||||
<a href="https://veeso.github.io/termscp/" target="_blank">网站</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/" target="_blank">网站</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">安装</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#get-started" target="_blank">安装</a>
|
||||
·
|
||||
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">用户手册</a>
|
||||
<a href="https://termscp.veeso.dev/termscp/#user-manual" target="_blank">用户手册</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -62,8 +62,8 @@
|
||||
/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">由 <a href="https://veeso.github.io/" target="_blank">@veeso</a> 开发</p>
|
||||
<p align="center">当前版本: 0.11.2 (18/04/2023)</p>
|
||||
<p align="center">由 <a href="https://termscp.veeso.dev/" target="_blank">@veeso</a> 开发</p>
|
||||
<p align="center">当前版本: 0.12.0 (16/05/2023)</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/MIT"
|
||||
@@ -139,6 +139,7 @@ termscp 是一个功能丰富的终端文件浏览和传输工具,支持 SCP/S
|
||||
- **SCP**
|
||||
- **FTP** and **FTPS**
|
||||
- **S3**
|
||||
- **SMB**
|
||||
- 🖥 使用便捷的 UI 在远程和本地文件系统上浏览和操作
|
||||
- 创建、删除、重命名、搜索、查看和编辑文件
|
||||
- ⭐ 通过“内置书签”和“最近连接”快速连接到您的主机
|
||||
@@ -178,7 +179,7 @@ curl -sSLf http://get-termscp.veeso.dev | sh
|
||||
choco install termscp
|
||||
```
|
||||
|
||||
如需更多信息或其他的平台支持,请访问 [veeso.github.io](https://veeso.github.io/termscp/#get-started) 查看所有安装方法。
|
||||
如需更多信息或其他的平台支持,请访问 [termscp.veeso.dev](https://termscp.veeso.dev/termscp/#get-started) 查看所有安装方法。
|
||||
|
||||
⚠️ 如果您正在寻找如何更新 termscp 只需从 CLI 运行 termscp : `(sudo) termscp --update` ⚠️
|
||||
|
||||
@@ -188,10 +189,12 @@ choco install termscp
|
||||
- libssh
|
||||
- libdbus-1
|
||||
- pkg-config
|
||||
- libsmbclient
|
||||
- **FreeBSD** 用户:
|
||||
- libssh
|
||||
- dbus
|
||||
- pkgconf
|
||||
- libsmbclient
|
||||
|
||||
### 可选项 ✔️
|
||||
|
||||
@@ -225,7 +228,7 @@ choco install termscp
|
||||
|
||||
## 用户手册和文档 📚
|
||||
|
||||
用户手册可以在[termscp的网站](https://veeso.github.io/termscp/#user-manual)或者在[Github](man.md)上找到。
|
||||
用户手册可以在[termscp的网站](https://termscp.veeso.dev/termscp/#user-manual)或者在[Github](man.md)上找到。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
- [用法](#用法)
|
||||
- [地址参数](#地址参数)
|
||||
- [AWS S3 地址参数](#aws-s3-地址参数)
|
||||
- [SMB 地址参数](#smb-地址参数)
|
||||
- [如何输入密码](#如何输入密码)
|
||||
- [S3 连接参数](#s3-连接参数)
|
||||
- [Aws S3 凭证](#aws-s3-凭证)
|
||||
@@ -102,6 +103,22 @@ s3://<bucket-name>@<region>[:profile][:/wrkdir]
|
||||
s3://buckethead@eu-central-1:default:/assets
|
||||
```
|
||||
|
||||
#### SMB 地址参数
|
||||
|
||||
SMB 对 CLI 地址参数有不同的语法,无论您是在 Windows 还是其他系统上,这都是不同的:
|
||||
|
||||
**Windows** 句法:
|
||||
|
||||
```txt
|
||||
\\[username@]<server-name>\<share>[\path\...]
|
||||
```
|
||||
|
||||
**其他系统** 句法:
|
||||
|
||||
```txt
|
||||
smb://[username@]<server-name>[:port]/<share>[/path/.../]
|
||||
```
|
||||
|
||||
#### 如何输入密码
|
||||
|
||||
你可能已经注意到,url参数中没有办法直接附加密码,你可以通过以下三种方式提供密码:
|
||||
@@ -209,6 +226,7 @@ termscp中的文件资源管理器是指你与远程建立连接后可以看到
|
||||
| `<W>` | 使用指定程序打开文件 | With |
|
||||
| `<X>` | 运行命令 | eXecute |
|
||||
| `<Y>` | 是否开启同步浏览 | sYnc |
|
||||
| `<Z>` | 更改文件权限 | |
|
||||
| `<CTRL+A>` | 选中所有文件 | |
|
||||
| `<CTRL+C>` | 终止文件传输 | |
|
||||
| `<CTRL+T>` | 显示所有同步路径 | Track |
|
||||
@@ -330,7 +348,7 @@ termscp和书签一样,只需要保证这些路径是可访问的:
|
||||
- **Local File formatter syntax**:在本地资源管理器中显示每个文件的文件信息的语法。参见[资源管理器格式](#资源管理器格式)
|
||||
- **Enable notifications?**: 如果设置为 `Yes`,则会显示通知。
|
||||
- **Notifications: minimum transfer size**: 如果传输大小大于或等于指定值,将显示传输通知。 接受的值格式为 `{UNSIGNED} B/KB/MB/GB/TB/PB`
|
||||
- **SSH Configuration path**:设置连接到 SCP/SFTP 服务器时使用的 SSH 配置文件。 如果未设置(空),则不会使用任何文件。 你可以指定一个以 `~` 开头的路径来表示主路径(例如 `~/.ssh/config`)
|
||||
- **SSH Configuration path**:设置连接到 SCP/SFTP 服务器时使用的 SSH 配置文件。 如果未设置(空),则不会使用任何文件。 你可以指定一个以 `~` 开头的路径来表示主路径(例如 `~/.ssh/config`). 指定了 termscp 支持的参数 [HERE](https://github.com/veeso/ssh2-config#exposed-attributes).
|
||||
|
||||
### SSH Key Storage
|
||||
|
||||
@@ -472,9 +490,9 @@ Termscp有很多功能,你可能已经注意到了,其中之一就是可以
|
||||
|
||||
termscp会为每个会话创建一个日志文件,该文件在
|
||||
|
||||
- `$HOME/.config/termscp/termscp.log` -- Linux/BSD
|
||||
- `$HOME/Library/Application Support/termscp/termscp.log` -- MacOs
|
||||
- `FOLDERID_RoamingAppData\termscp\termscp.log` -- Windows
|
||||
- `$HOME/.cache/termscp/termscp.log` -- Linux/BSD
|
||||
- `$HOME/Library/Caches/termscp/termscp.log` -- MacOs
|
||||
- `FOLDERID_LocalAppData\termscp\termscp.log` -- Windows
|
||||
|
||||
日志不会被轮换,但只会在每次启动 termcp 后被截断,因此如果您想报告问题并希望附加您的日志文件,请记住在使用前将日志文件保存在安全的地方 再次termscp。
|
||||
默认情况下,日志记录在 *INFO* 级别报告,因此它不是很详细。
|
||||
|
||||
46
install.sh
46
install.sh
@@ -8,7 +8,7 @@
|
||||
# -f, -y, --force, --yes
|
||||
# Skip the confirmation prompt during installation
|
||||
|
||||
TERMSCP_VERSION="0.11.1"
|
||||
TERMSCP_VERSION="0.12.0"
|
||||
GITHUB_URL="https://github.com/veeso/termscp/releases/download/v${TERMSCP_VERSION}"
|
||||
DEB_URL_AMD64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_amd64.deb"
|
||||
DEB_URL_AARCH64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_arm64.deb"
|
||||
@@ -209,6 +209,18 @@ install_on_arch_linux() {
|
||||
$pkg -S termscp
|
||||
}
|
||||
|
||||
install_with_brew() {
|
||||
info "Installing termscp with brew"
|
||||
if has termscp; then
|
||||
info "Upgrading ${GREEN}termscp${NO_COLOR}…"
|
||||
# The OR is used since someone could have installed via cargo previously
|
||||
brew update && brew upgrade termscp || brew install veeso/termscp/termscp
|
||||
else
|
||||
info "Installing ${GREEN}termscp${NO_COLOR}…"
|
||||
brew install veeso/termscp/termscp
|
||||
fi
|
||||
}
|
||||
|
||||
install_on_linux() {
|
||||
local msg
|
||||
local sudo
|
||||
@@ -271,6 +283,8 @@ install_on_linux() {
|
||||
info "$msg"
|
||||
$sudo rpm -U "${archive}"
|
||||
rm -f ${archive}
|
||||
elif has brew; then
|
||||
install_with_brew
|
||||
else
|
||||
try_with_cargo "No suitable installation method found for your Linux distribution; if you're running on Arch linux, please install an AUR package manager (such as yay). Currently only Arch, Debian based and Red Hat based distros are supported" "linux"
|
||||
fi
|
||||
@@ -278,23 +292,7 @@ install_on_linux() {
|
||||
|
||||
install_on_macos() {
|
||||
if has brew; then
|
||||
# get homebrew formula name
|
||||
if [ "${ARCH}" == "x86_64" ]; then
|
||||
FORMULA="termscp"
|
||||
elif [ "$ARCH" == "aarch64" ]; then
|
||||
FORMULA="termscp-m1"
|
||||
else
|
||||
error "unsupported arch: $ARCH"
|
||||
exit 1
|
||||
fi
|
||||
if has termscp; then
|
||||
info "Upgrading ${GREEN}termscp${NO_COLOR}…"
|
||||
# The OR is used since someone could have installed via cargo previously
|
||||
brew update && brew upgrade ${FORMULA} || brew install veeso/termscp/${FORMULA}
|
||||
else
|
||||
info "Installing ${GREEN}termscp${NO_COLOR}…"
|
||||
brew install veeso/termscp/${FORMULA}
|
||||
fi
|
||||
install_with_brew
|
||||
else
|
||||
try_with_cargo "brew is missing on your system; please install it from <https://brew.sh/>" "macos"
|
||||
fi
|
||||
@@ -306,14 +304,14 @@ install_bsd_cargo_deps() {
|
||||
set -e
|
||||
confirm "${YELLOW}libssh, gcc${NO_COLOR} are required to install ${GREEN}termscp${NO_COLOR}; would you like to proceed?"
|
||||
sudo="$(elevate_priv_ex /usr/local/bin)"
|
||||
$sudo pkg install -y curl wget libssh gcc dbus pkgconf
|
||||
$sudo pkg install -y curl wget libssh gcc dbus pkgconf libsmbclient
|
||||
info "Dependencies installed successfully"
|
||||
}
|
||||
|
||||
install_linux_cargo_deps() {
|
||||
local debian_deps="gcc pkg-config libdbus-1-dev"
|
||||
local rpm_deps="gcc openssl pkgconfig libdbus-devel openssl-devel"
|
||||
local arch_deps="gcc openssl pkg-config dbus"
|
||||
local debian_deps="gcc pkg-config libdbus-1-dev libsmbclient-dev"
|
||||
local rpm_deps="gcc openssl pkgconfig libdbus-devel openssl-devel libsmbclient-devel"
|
||||
local arch_deps="gcc openssl pkg-config dbus smbclient"
|
||||
local deps_cmd=""
|
||||
# Get pkg manager
|
||||
if has apt; then
|
||||
@@ -478,8 +476,8 @@ case $PLATFORM in
|
||||
esac
|
||||
|
||||
completed "Congratulations! Termscp has successfully been installed on your system!"
|
||||
info "If you're a new user, you might be interested in reading the user manual <https://veeso.github.io/termscp/#user-manual>"
|
||||
info "While if you've just updated your termscp version, you can find the changelog at this link <https://veeso.github.io/termscp/#changelog>"
|
||||
info "If you're a new user, you might be interested in reading the user manual <https://termscp.veeso.dev/termscp/#user-manual>"
|
||||
info "While if you've just updated your termscp version, you can find the changelog at this link <https://termscp.veeso.dev/termscp/#changelog>"
|
||||
info "Remember that if you encounter any issue, you can report them on Github <https://github.com/veeso/termscp/issues/new>"
|
||||
info "Feel free to open an issue also if you have an idea which could improve the project"
|
||||
info "If you want to support the project, please, consider a little donation <https://ko-fi.com/veeso>"
|
||||
|
||||
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
group_imports = "StdExternalCrate"
|
||||
imports_granularity = "Module"
|
||||
@@ -119,15 +119,33 @@ footer .contacts a i {
|
||||
}
|
||||
|
||||
footer .contacts li a:hover i {
|
||||
color: dodgerblue !important;
|
||||
color: #202020 !important;
|
||||
}
|
||||
|
||||
footer p.copyright {
|
||||
.footer--vat {
|
||||
color: #404040;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer--address {
|
||||
color: #505050;
|
||||
font-size: 0.8em;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer--copyright {
|
||||
color: #606060;
|
||||
font-size: 0.7em;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer--link {
|
||||
color: #606060;
|
||||
}
|
||||
|
||||
.alert {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.25rem;
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
<head>
|
||||
<link rel="stylesheet" href="css/get-started.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section id="start" class="container start">
|
||||
<h1 translate="getStarted.title">Get started</h1>
|
||||
<section>
|
||||
<h2>
|
||||
<i class="fa fa-rocket"></i> <span
|
||||
translate="getStarted.quickSetup"
|
||||
>Quick setup</span
|
||||
>
|
||||
<i class="fa fa-rocket"></i> <span translate="getStarted.quickSetup">Quick setup</span>
|
||||
</h2>
|
||||
<div class="installation">
|
||||
<div class="alert alert-primary">
|
||||
<p>
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span translate="getStarted.suggested"
|
||||
>We strongly suggest this method to install termscp</span
|
||||
>
|
||||
<span translate="getStarted.suggested">We strongly suggest this method to install termscp</span>
|
||||
</p>
|
||||
</div>
|
||||
<p translate="getStarted.posixUsers">
|
||||
@@ -29,125 +25,99 @@
|
||||
</section>
|
||||
<section>
|
||||
<h2>
|
||||
<i class="devicon-windows8-plain"></i> <span
|
||||
translate="getStarted.windows.title"
|
||||
>Windows users</span
|
||||
>
|
||||
<i class="devicon-windows8-plain"></i> <span translate="getStarted.windows.title">Windows users</span>
|
||||
</h2>
|
||||
<div class="installation">
|
||||
<p>
|
||||
<span translate="getStarted.windows.intro"
|
||||
>You can install termscp on Windows via</span
|
||||
>
|
||||
<a
|
||||
href="https://community.chocolatey.org/packages/termscp"
|
||||
target="_blank"
|
||||
>Chocolatey</a
|
||||
>
|
||||
<span translate="getStarted.windows.intro">You can install termscp on Windows via</span>
|
||||
<a href="https://community.chocolatey.org/packages/termscp" target="_blank">Chocolatey</a>
|
||||
</p>
|
||||
<pre><span class="function">choco</span> install <span class="string">termscp</span></pre>
|
||||
<p>
|
||||
<span translate="getStarted.windows.moderation"
|
||||
>Consider that Chocolatey moderation can take up to a few weeks
|
||||
<span translate="getStarted.windows.moderation">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</span
|
||||
>
|
||||
<a
|
||||
href="https://github.com/veeso/termscp/releases/latest/download/termscp.0.11.2.nupkg"
|
||||
target="_blank"
|
||||
>Github</a
|
||||
>
|
||||
<span translate="getStarted.windows.then"
|
||||
>and then, from the ZIP directory, install it via</span
|
||||
>
|
||||
you can install it downloading the ZIP file from</span>
|
||||
<a href="https://github.com/veeso/termscp/releases/latest/download/termscp.0.12.0.nupkg"
|
||||
target="_blank">Github</a>
|
||||
<span translate="getStarted.windows.then">and then, from the ZIP directory, install it via</span>
|
||||
</p>
|
||||
<pre><span class="function">choco</span> install <span class="string">termscp</span> -s .</pre>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h2>
|
||||
<i class="devicon-linux-plain"></i> <span
|
||||
translate="getStarted.linuxUsers"
|
||||
>Linux users</span
|
||||
>
|
||||
<i class="devicon-linux-plain"></i> <span translate="getStarted.linuxUsers">Linux users</span>
|
||||
</h2>
|
||||
<div class="sub-system">
|
||||
<div class="alert alert-warning">
|
||||
<p>
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span translate="getStarted.notConfident"
|
||||
>Opt for these methods instead if you don't feel confident using
|
||||
the shell script</span
|
||||
>
|
||||
<span translate="getStarted.notConfident">Opt for these methods instead if you don't feel confident using
|
||||
the shell script</span>
|
||||
</p>
|
||||
</div>
|
||||
<h3>
|
||||
<i class="devicon-linux-plain"></i> <span
|
||||
translate="getStarted.arch.title"
|
||||
>Arch derived users</span
|
||||
>
|
||||
<i class="devicon-linux-plain"></i> <span translate="getStarted.arch.title">Arch derived users</span>
|
||||
</h3>
|
||||
<div class="installation">
|
||||
<p>
|
||||
<span translate="getStarted.arch.intro"
|
||||
>On Arch Linux based distros, you can install termscp using an AUR
|
||||
package manager such as</span
|
||||
>
|
||||
<span translate="getStarted.arch.intro">On Arch Linux based distros, you can install termscp using an AUR
|
||||
package manager such as</span>
|
||||
<a href="https://github.com/Jguer/yay" target="_blank">yay</a>
|
||||
<span translate="getStarted.arch.then">then run:</span>
|
||||
</p>
|
||||
<pre><span class="function">yay</span> -S <span class="string">termscp</span></pre>
|
||||
</div>
|
||||
<h3>
|
||||
<i class="devicon-debian-plain"></i> <span
|
||||
translate="getStarted.debian.title"
|
||||
>Debian derived users</span
|
||||
>
|
||||
<i class="devicon-debian-plain"></i> <span translate="getStarted.debian.title">Debian derived
|
||||
users</span>
|
||||
</h3>
|
||||
<div class="installation">
|
||||
<p translate="getStarted.debian.body">
|
||||
On Debian based distros, you can install termscp using the Deb
|
||||
package via:
|
||||
</p>
|
||||
<pre><span class="function">wget</span> -O termscp.deb <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp_0.11.2_amd64.deb</span>
|
||||
<pre><span class="function">wget</span> -O termscp.deb <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp_0.12.0_amd64.deb</span>
|
||||
sudo <span class="function">dpkg</span> -i <span class="string">termscp.deb</span></pre>
|
||||
</div>
|
||||
<h3>
|
||||
<i class="devicon-redhat-plain"></i> <span
|
||||
translate="getStarted.redhat.title"
|
||||
>Redhat derived users</span
|
||||
>
|
||||
<i class="devicon-redhat-plain"></i> <span translate="getStarted.redhat.title">Redhat derived
|
||||
users</span>
|
||||
</h3>
|
||||
<div class="installation">
|
||||
<p translate="getStarted.redhat.body">
|
||||
On RedHat based distros, you can install termscp using the RPM
|
||||
package via:
|
||||
</p>
|
||||
<pre><span class="function">wget</span> -O termscp.rpm <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp-0.11.2-1.x86_64.rpm</span>
|
||||
<pre><span class="function">wget</span> -O termscp.rpm <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp-0.12.0-1.x86_64.rpm</span>
|
||||
sudo <span class="function">rpm</span> -U <span class="string">termscp.rpm</span></pre>
|
||||
</div>
|
||||
<h3>
|
||||
<span>Brew</span>
|
||||
</h3>
|
||||
<div class="installation">
|
||||
<p>
|
||||
<span translate="getStarted.macos.install">Install termscp via</span>
|
||||
<a href="https://brew.sh/" target="_blank">Brew</a>
|
||||
</p>
|
||||
<pre><span class="function">brew</span> install <span class="string">veeso/termscp/termscp</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h2>
|
||||
<i class="devicon-apple-plain"></i> <span
|
||||
translate="getStarted.macos.title"
|
||||
>MacOS users</span
|
||||
>
|
||||
<i class="devicon-apple-plain"></i> <span translate="getStarted.macos.title">MacOS users</span>
|
||||
</h2>
|
||||
<div class="installation">
|
||||
<div class="alert alert-warning">
|
||||
<p>
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span translate="getStarted.notConfident"
|
||||
>Opt for this method instead if you don't feel confident using the
|
||||
shell script</span
|
||||
>
|
||||
<span translate="getStarted.notConfident">Opt for this method instead if you don't feel confident using the
|
||||
shell script</span>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
<span translate="getStarted.macos.install">Install termscp via</span
|
||||
>
|
||||
<span translate="getStarted.macos.install">Install termscp via</span>
|
||||
<a href="https://brew.sh/" target="_blank">Brew</a>
|
||||
</p>
|
||||
<pre><span class="function">brew</span> install <span class="string">veeso/termscp/termscp</span></pre>
|
||||
@@ -155,33 +125,22 @@ sudo <span class="function">rpm</span> -U <span class="string">termscp.rpm</span
|
||||
</section>
|
||||
<section>
|
||||
<h2>
|
||||
<i class="devicon-rust-plain"></i> <span
|
||||
translate="getStarted.cargo.title"
|
||||
>Install with Cargo</span
|
||||
>
|
||||
<i class="devicon-rust-plain"></i> <span translate="getStarted.cargo.title">Install with Cargo</span>
|
||||
</h2>
|
||||
<div class="installation">
|
||||
<div class="alert alert-warning">
|
||||
<p>
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span translate="getStarted.noBinary"
|
||||
>Opt for this method instead if binaries for your platform are not
|
||||
available</span
|
||||
>
|
||||
<span translate="getStarted.noBinary">Opt for this method instead if binaries for your platform are not
|
||||
available</span>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
<span translate="getStarted.cargo.body"
|
||||
>If a package is not available for your system, you can opt to
|
||||
install termscp via</span
|
||||
>
|
||||
<a href="https://www.rust-lang.org/tools/install" target="_blank"
|
||||
>Cargo</a
|
||||
>.
|
||||
<span translate="getStarted.cargo.requirements"
|
||||
>To install termscp via Cargo, these requirements must be
|
||||
satisfied:</span
|
||||
>
|
||||
<span translate="getStarted.cargo.body">If a package is not available for your system, you can opt to
|
||||
install termscp via</span>
|
||||
<a href="https://www.rust-lang.org/tools/install" target="_blank">Cargo</a>.
|
||||
<span translate="getStarted.cargo.requirements">To install termscp via Cargo, these requirements must be
|
||||
satisfied:</span>
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
@@ -212,4 +171,4 @@ sudo <span class="function">rpm</span> -U <span class="string">termscp.rpm</span
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</body>
|
||||
@@ -15,7 +15,7 @@
|
||||
<div class="alert alert-center alert-success">
|
||||
<p>
|
||||
<span translate="intro.versionAlert"
|
||||
>termscp 0.11.2 is NOW out! Download it from</span
|
||||
>termscp 0.12.0 is NOW out! Download it from</span
|
||||
>
|
||||
<a href="#get-started" translate="intro.here">here!</a>
|
||||
</p>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
Termscp is an application that is still in its early stage of
|
||||
development, the first version has been released in december in 2020
|
||||
and practically there's only one
|
||||
<a href="https://veeso.github.io/" target="_blank">guy</a> working on
|
||||
<a href="https://termscp.veeso.dev/" target="_blank">guy</a> working on
|
||||
it and there's still a lot of work to do in order to improve it and
|
||||
make it fast and reliable. Along to this, you should also consider
|
||||
that since it's an application which works with network protocols and
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en_US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>
|
||||
termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3
|
||||
</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="minimum-scale=1, initial-scale=1, width=device-width"
|
||||
property="og:description"
|
||||
content="termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/S3. It is Linux, MacOS, FreeBSD, NetBSD and Windows compatible"
|
||||
/>
|
||||
<meta
|
||||
name="description"
|
||||
content="termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/S3. It is Linux, MacOS, FreeBSD, NetBSD and Windows compatible"
|
||||
/>
|
||||
<meta
|
||||
property="og:title"
|
||||
content="termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/S3"
|
||||
/>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="robots" content="index, follow" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://termscp.veeso.dev/assets/images/og_preview.jpg"
|
||||
@@ -14,9 +27,9 @@
|
||||
<meta property="og:image:width" content="1024" />
|
||||
<meta property="og:image:height" content="820" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="termscp" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://termscp.veeso.dev" />
|
||||
<meta property="og:title" content="termscp" />
|
||||
<meta property="og:description" content="terminal UI file transfer" />
|
||||
<!-- Pure.css -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
@@ -62,7 +75,6 @@
|
||||
sizes="16x16"
|
||||
href="assets/images/favicon-16x16.png"
|
||||
/>
|
||||
<title>termscp: terminal UI file transfer</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="layout">
|
||||
@@ -79,7 +91,9 @@
|
||||
<img class="avatar" alt="logo" src="assets/images/termscp.webp" />
|
||||
</div>
|
||||
<h1>termscp</h1>
|
||||
<p translate="menu.desc">A feature rich terminal UI file transfer</p>
|
||||
<p translate="menu.desc">
|
||||
A feature rich terminal UI file transfer
|
||||
</p>
|
||||
<a href="https://github.com/veeso/termscp/stargazers/">
|
||||
<img
|
||||
src="https://img.shields.io/github/stars/veeso/termscp.svg?style=social&label=Star&maxAge=2592000"
|
||||
@@ -88,19 +102,38 @@
|
||||
</div>
|
||||
<ul class="pure-menu-list">
|
||||
<li class="pure-menu-item pure-menu-selected">
|
||||
<a href="#intro" class="pure-menu-link" translate="menu.intro">Intro</a>
|
||||
<a href="#intro" class="pure-menu-link" translate="menu.intro"
|
||||
>Intro</a
|
||||
>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
<a href="#get-started" class="pure-menu-link" translate="menu.getStarted">Get started</a>
|
||||
<a
|
||||
href="#get-started"
|
||||
class="pure-menu-link"
|
||||
translate="menu.getStarted"
|
||||
>Get started</a
|
||||
>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
<a href="#updates" class="pure-menu-link" translate="menu.updates">Install updates</a>
|
||||
<a href="#updates" class="pure-menu-link" translate="menu.updates"
|
||||
>Install updates</a
|
||||
>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
<a href="#user-manual" class="pure-menu-link" translate="menu.manual">User manual</a>
|
||||
<a
|
||||
href="#user-manual"
|
||||
class="pure-menu-link"
|
||||
translate="menu.manual"
|
||||
>User manual</a
|
||||
>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
<a href="#changelog" class="pure-menu-link" translate="menu.changelog">Release history</a>
|
||||
<a
|
||||
href="#changelog"
|
||||
class="pure-menu-link"
|
||||
translate="menu.changelog"
|
||||
>Release history</a
|
||||
>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
<a
|
||||
@@ -115,7 +148,9 @@
|
||||
href="https://veeso.dev/"
|
||||
class="pure-menu-link"
|
||||
target="_blank"
|
||||
><span translate="menu.author">About the author</span> <i class="fas fa-external-link-alt"></i
|
||||
><span translate="menu.author">About the author</span> <i
|
||||
class="fas fa-external-link-alt"
|
||||
></i
|
||||
></a>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
@@ -123,7 +158,9 @@
|
||||
href="https://ko-fi.com/veeso"
|
||||
class="pure-menu-link"
|
||||
target="_blank"
|
||||
><span translate="menu.support">Support me</span> <i class="fas fa-external-link-alt"></i
|
||||
><span translate="menu.support">Support me</span> <i
|
||||
class="fas fa-external-link-alt"
|
||||
></i
|
||||
></a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -184,10 +221,24 @@
|
||||
></a>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- vat number -->
|
||||
<p class="footer--vat">
|
||||
<span>P.IVA IT03104140300 </span>
|
||||
</p>
|
||||
<p class="footer--address">
|
||||
<span>Via Antonio Marangoni 33, 33100, Udine (UD)</span>
|
||||
</p>
|
||||
<!-- Copyright -->
|
||||
<p class="copyright">
|
||||
<span>Christian Visintin © All Rights Reserved | </span
|
||||
><span resolve-copyright></span>
|
||||
<p class="footer--copyright">
|
||||
<span>Christian Visintin © </span><span resolve-copyright></span>
|
||||
<span> | </span>
|
||||
<a class="footer--link" href="https://veeso.dev/en/privacy" target="_blank"
|
||||
>Privacy policy</a
|
||||
>
|
||||
<span> | </span>
|
||||
<a class="footer--link" href="https://veeso.dev/en/cookie-policy" target="_blank"
|
||||
>Cookie policy</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -208,13 +259,13 @@
|
||||
<script src="js/events.js"></script>
|
||||
<script src="js/resolvers.js"></script>
|
||||
<!-- ko-fi -->
|
||||
<script src='https://storage.ko-fi.com/cdn/scripts/overlay-widget.js'></script>
|
||||
<script src="https://storage.ko-fi.com/cdn/scripts/overlay-widget.js"></script>
|
||||
<script>
|
||||
kofiWidgetOverlay.draw('veeso', {
|
||||
'type': 'floating-chat',
|
||||
'floating-chat.donateButton.text': 'Support me',
|
||||
'floating-chat.donateButton.background-color': '#323842',
|
||||
'floating-chat.donateButton.text-color': '#fff'
|
||||
kofiWidgetOverlay.draw("veeso", {
|
||||
type: "floating-chat",
|
||||
"floating-chat.donateButton.text": "Support me",
|
||||
"floating-chat.donateButton.background-color": "#323842",
|
||||
"floating-chat.donateButton.text-color": "#fff",
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"intro": {
|
||||
"caption": "A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3",
|
||||
"getStarted": "Get started →",
|
||||
"versionAlert": "termscp 0.11.2 is NOW out! Download it from",
|
||||
"versionAlert": "termscp 0.12.0 is NOW out! Download it from",
|
||||
"here": "here",
|
||||
"features": {
|
||||
"handy": {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"intro": {
|
||||
"caption": "Un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/S3",
|
||||
"getStarted": "Para iniciar →",
|
||||
"versionAlert": "termscp 0.11.2 ya está disponible! Descárgalo desde",
|
||||
"versionAlert": "termscp 0.12.0 ya está disponible! Descárgalo desde",
|
||||
"here": "aquì",
|
||||
"features": {
|
||||
"handy": {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"intro": {
|
||||
"caption": "Un file transfer et navigateur de terminal riche en fonctionnalités avec support pour SCP/SFTP/FTP/S3",
|
||||
"getStarted": "Pour commencer →",
|
||||
"versionAlert": "termscp 0.11.2 est maintenant sorti! Télécharge-le depuis",
|
||||
"versionAlert": "termscp 0.12.0 est maintenant sorti! Télécharge-le depuis",
|
||||
"here": "ici",
|
||||
"features": {
|
||||
"handy": {
|
||||
|
||||
@@ -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.11.2 è ORA disponbile! Scaricalo da",
|
||||
"versionAlert": "termscp 0.12.0 è ORA disponbile! Scaricalo da",
|
||||
"here": "qui",
|
||||
"features": {
|
||||
"handy": {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"intro": {
|
||||
"caption": "功能丰富的终端 UI 文件传输和浏览器,支持 SCP/SFTP/FTP/S3",
|
||||
"getStarted": "开始 →",
|
||||
"versionAlert": "termscp 0.11.2 现已发布! 从下载",
|
||||
"versionAlert": "termscp 0.12.0 现已发布! 从下载",
|
||||
"here": "这里",
|
||||
"features": {
|
||||
"handy": {
|
||||
|
||||
@@ -3,26 +3,26 @@
|
||||
//! `activity_manager` is the module which provides run methods and handling for activities
|
||||
|
||||
// Deps
|
||||
use crate::filetransfer::FileTransferParams;
|
||||
use crate::host::{HostError, Localhost};
|
||||
use crate::system::bookmarks_client::BookmarksClient;
|
||||
use crate::system::config_client::ConfigClient;
|
||||
use crate::system::environment;
|
||||
use crate::system::theme_provider::ThemeProvider;
|
||||
use crate::ui::activities::{
|
||||
auth::AuthActivity, filetransfer::FileTransferActivity, setup::SetupActivity, Activity,
|
||||
ExitReason,
|
||||
};
|
||||
use crate::ui::context::Context;
|
||||
use crate::utils::fmt;
|
||||
use crate::utils::tty;
|
||||
|
||||
// Namespaces
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
/// ### NextActivity
|
||||
///
|
||||
use remotefs_ssh::SshKeyStorage as SshKeyStorageTrait;
|
||||
|
||||
use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
|
||||
use crate::host::{HostError, Localhost};
|
||||
use crate::system::bookmarks_client::BookmarksClient;
|
||||
use crate::system::config_client::ConfigClient;
|
||||
use crate::system::environment;
|
||||
use crate::system::sshkey_storage::SshKeyStorage;
|
||||
use crate::system::theme_provider::ThemeProvider;
|
||||
use crate::ui::activities::auth::AuthActivity;
|
||||
use crate::ui::activities::filetransfer::FileTransferActivity;
|
||||
use crate::ui::activities::setup::SetupActivity;
|
||||
use crate::ui::activities::{Activity, ExitReason};
|
||||
use crate::ui::context::Context;
|
||||
use crate::utils::{fmt, tty};
|
||||
|
||||
/// NextActivity identifies the next identity to run once the current has ended
|
||||
pub enum NextActivity {
|
||||
Authentication,
|
||||
@@ -30,8 +30,6 @@ pub enum NextActivity {
|
||||
SetupActivity,
|
||||
}
|
||||
|
||||
/// ### ActivityManager
|
||||
///
|
||||
/// The activity manager takes care of running activities and handling them until the application has ended
|
||||
pub struct ActivityManager {
|
||||
context: Option<Context>,
|
||||
@@ -76,18 +74,37 @@ impl ActivityManager {
|
||||
if params.password_missing() {
|
||||
if let Some(password) = password {
|
||||
params.set_default_secret(password.to_string());
|
||||
} else {
|
||||
match tty::read_secret_from_tty("Password: ") {
|
||||
Err(err) => return Err(format!("Could not read password: {err}")),
|
||||
Ok(Some(secret)) => {
|
||||
debug!(
|
||||
"Read password from tty: {}",
|
||||
fmt::shadow_password(secret.as_str())
|
||||
);
|
||||
params.set_default_secret(secret);
|
||||
}
|
||||
Ok(None) => {}
|
||||
} else if matches!(
|
||||
params.protocol,
|
||||
FileTransferProtocol::Scp | FileTransferProtocol::Sftp,
|
||||
) && params.params.generic_params().is_some()
|
||||
{
|
||||
// * if protocol is SCP or SFTP check whether a SSH key is registered for this remote, in case not ask password
|
||||
let storage = SshKeyStorage::from(self.context.as_ref().unwrap().config());
|
||||
let generic_params = params.params.generic_params().unwrap();
|
||||
if storage
|
||||
.resolve(
|
||||
&generic_params.address,
|
||||
&generic_params
|
||||
.username
|
||||
.clone()
|
||||
.unwrap_or(whoami::username()),
|
||||
)
|
||||
.is_none()
|
||||
{
|
||||
debug!(
|
||||
"storage could not find any suitable key for {}... prompting for password",
|
||||
generic_params.address
|
||||
);
|
||||
self.prompt_password(&mut params)?;
|
||||
} else {
|
||||
debug!(
|
||||
"a key is already set for {}; password is not required",
|
||||
generic_params.address
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.prompt_password(&mut params)?;
|
||||
}
|
||||
}
|
||||
// Put params into the context
|
||||
@@ -95,6 +112,22 @@ impl ActivityManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prompt user for password to set into params.
|
||||
fn prompt_password(&self, params: &mut FileTransferParams) -> Result<(), String> {
|
||||
match tty::read_secret_from_tty("Password: ") {
|
||||
Err(err) => Err(format!("Could not read password: {err}")),
|
||||
Ok(Some(secret)) => {
|
||||
debug!(
|
||||
"Read password from tty: {}",
|
||||
fmt::shadow_password(secret.as_str())
|
||||
);
|
||||
params.set_default_secret(secret);
|
||||
Ok(())
|
||||
}
|
||||
Ok(None) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve provided bookmark name and set it as file transfer params.
|
||||
/// Returns error if bookmark is not found
|
||||
pub fn resolve_bookmark_name(
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
//!
|
||||
//! defines the types for main.rs types
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
use argh::FromArgs;
|
||||
|
||||
use crate::activity_manager::NextActivity;
|
||||
use crate::filetransfer::FileTransferParams;
|
||||
use crate::system::logging::LogLevel;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
pub enum Task {
|
||||
Activity(NextActivity),
|
||||
ImportTheme(PathBuf),
|
||||
@@ -28,6 +28,8 @@ Address syntax can be:
|
||||
|
||||
- `protocol://user@address:port:wrkdir` for protocols such as Sftp, Scp, Ftp
|
||||
- `s3://bucket-name@region:profile:/wrkdir` for Aws S3 protocol
|
||||
- `\\\\<server>[:port]\\<share>[\\path]` for SMB (on Windows)
|
||||
- `smb://[user@]<server>[:port]</share>[/path]` for SMB (on other systems)
|
||||
|
||||
Please, report issues to <https://github.com/veeso/termscp>
|
||||
Please, consider supporting the author <https://ko-fi.com/veeso>")]
|
||||
|
||||
@@ -2,14 +2,18 @@
|
||||
//!
|
||||
//! `bookmarks` is the module which provides data types and de/serializer for bookmarks
|
||||
|
||||
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams};
|
||||
use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
|
||||
|
||||
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::de::Error as DeError;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::filetransfer::params::{
|
||||
AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams as TransferSmbParams,
|
||||
};
|
||||
use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
|
||||
|
||||
/// UserHosts contains all the hosts saved by the user in the data storage
|
||||
/// It contains both `Bookmark`
|
||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||
@@ -38,6 +42,8 @@ pub struct Bookmark {
|
||||
pub directory: Option<PathBuf>,
|
||||
/// S3 params; optional. When used other fields are empty for sure
|
||||
pub s3: Option<S3Params>,
|
||||
/// SMB params; optional. Extra params required for SMB protocol
|
||||
pub smb: Option<SmbParams>,
|
||||
}
|
||||
|
||||
/// Connection parameters for Aws s3 protocol
|
||||
@@ -53,6 +59,13 @@ pub struct S3Params {
|
||||
pub new_path_style: Option<bool>,
|
||||
}
|
||||
|
||||
/// Extra Connection parameters for SMB protocol
|
||||
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
|
||||
pub struct SmbParams {
|
||||
pub share: String,
|
||||
pub workgroup: Option<String>,
|
||||
}
|
||||
|
||||
// -- impls
|
||||
|
||||
impl From<FileTransferParams> for Bookmark {
|
||||
@@ -69,6 +82,7 @@ impl From<FileTransferParams> for Bookmark {
|
||||
password: params.password,
|
||||
directory,
|
||||
s3: None,
|
||||
smb: None,
|
||||
},
|
||||
ProtocolParams::AwsS3(params) => Self {
|
||||
protocol,
|
||||
@@ -78,6 +92,20 @@ impl From<FileTransferParams> for Bookmark {
|
||||
password: None,
|
||||
directory,
|
||||
s3: Some(S3Params::from(params)),
|
||||
smb: None,
|
||||
},
|
||||
ProtocolParams::Smb(params) => Self {
|
||||
smb: Some(SmbParams::from(params.clone())),
|
||||
protocol,
|
||||
address: Some(params.address),
|
||||
#[cfg(unix)]
|
||||
port: Some(params.port),
|
||||
#[cfg(windows)]
|
||||
port: None,
|
||||
username: params.username,
|
||||
password: params.password,
|
||||
directory,
|
||||
s3: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -102,6 +130,30 @@ impl From<Bookmark> for FileTransferParams {
|
||||
.password(bookmark.password);
|
||||
Self::new(bookmark.protocol, ProtocolParams::Generic(params))
|
||||
}
|
||||
#[cfg(unix)]
|
||||
FileTransferProtocol::Smb => {
|
||||
let params = TransferSmbParams::new(
|
||||
bookmark.address.unwrap_or_default(),
|
||||
bookmark.smb.clone().map(|x| x.share).unwrap_or_default(),
|
||||
)
|
||||
.port(bookmark.port.unwrap_or(445))
|
||||
.username(bookmark.username)
|
||||
.password(bookmark.password)
|
||||
.workgroup(bookmark.smb.and_then(|x| x.workgroup));
|
||||
|
||||
Self::new(bookmark.protocol, ProtocolParams::Smb(params))
|
||||
}
|
||||
#[cfg(windows)]
|
||||
FileTransferProtocol::Smb => {
|
||||
let params = TransferSmbParams::new(
|
||||
bookmark.address.unwrap_or_default(),
|
||||
bookmark.smb.clone().map(|x| x.share).unwrap_or_default(),
|
||||
)
|
||||
.username(bookmark.username)
|
||||
.password(bookmark.password);
|
||||
|
||||
Self::new(bookmark.protocol, ProtocolParams::Smb(params))
|
||||
}
|
||||
}
|
||||
.entry_directory(bookmark.directory) // Set entry directory
|
||||
}
|
||||
@@ -131,6 +183,26 @@ impl From<S3Params> for AwsS3Params {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl From<TransferSmbParams> for SmbParams {
|
||||
fn from(params: TransferSmbParams) -> Self {
|
||||
Self {
|
||||
share: params.share,
|
||||
workgroup: params.workgroup,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl From<TransferSmbParams> for SmbParams {
|
||||
fn from(params: TransferSmbParams) -> Self {
|
||||
Self {
|
||||
share: params.share,
|
||||
workgroup: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_protocol<'de, D>(deserializer: D) -> Result<FileTransferProtocol, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
@@ -155,9 +227,10 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_bookmarks_default() {
|
||||
let bookmarks: UserHosts = UserHosts::default();
|
||||
@@ -175,6 +248,7 @@ mod tests {
|
||||
password: Some(String::from("password")),
|
||||
directory: Some(PathBuf::from("/tmp")),
|
||||
s3: None,
|
||||
smb: None,
|
||||
};
|
||||
let recent: Bookmark = Bookmark {
|
||||
address: Some(String::from("192.168.1.2")),
|
||||
@@ -184,6 +258,7 @@ mod tests {
|
||||
password: Some(String::from("password")),
|
||||
directory: Some(PathBuf::from("/home")),
|
||||
s3: None,
|
||||
smb: None,
|
||||
};
|
||||
let mut bookmarks: HashMap<String, Bookmark> = HashMap::with_capacity(1);
|
||||
bookmarks.insert(String::from("test"), bookmark);
|
||||
@@ -272,6 +347,7 @@ mod tests {
|
||||
password: Some(String::from("password")),
|
||||
directory: Some(PathBuf::from("/tmp")),
|
||||
s3: None,
|
||||
smb: None,
|
||||
};
|
||||
let params = FileTransferParams::from(bookmark);
|
||||
assert_eq!(params.protocol, FileTransferProtocol::Sftp);
|
||||
@@ -304,6 +380,7 @@ mod tests {
|
||||
secret_access_key: Some(String::from("pluto")),
|
||||
new_path_style: Some(true),
|
||||
}),
|
||||
smb: None,
|
||||
};
|
||||
let params = FileTransferParams::from(bookmark);
|
||||
assert_eq!(params.protocol, FileTransferProtocol::AwsS3);
|
||||
@@ -320,4 +397,64 @@ mod tests {
|
||||
assert_eq!(gparams.secret_access_key.as_deref().unwrap(), "pluto");
|
||||
assert_eq!(gparams.new_path_style, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn should_get_ftparams_from_smb_bookmark() {
|
||||
let bookmark: Bookmark = Bookmark {
|
||||
protocol: FileTransferProtocol::Smb,
|
||||
address: Some("localhost".to_string()),
|
||||
port: Some(445),
|
||||
username: Some("foo".to_string()),
|
||||
password: Some("bar".to_string()),
|
||||
directory: Some(PathBuf::from("/tmp")),
|
||||
s3: None,
|
||||
smb: Some(SmbParams {
|
||||
share: "test".to_string(),
|
||||
workgroup: Some("testone".to_string()),
|
||||
}),
|
||||
};
|
||||
|
||||
let params = FileTransferParams::from(bookmark);
|
||||
assert_eq!(params.protocol, FileTransferProtocol::Smb);
|
||||
assert_eq!(
|
||||
params.entry_directory.as_deref().unwrap(),
|
||||
std::path::Path::new("/tmp")
|
||||
);
|
||||
let smb_params = params.params.smb_params().unwrap();
|
||||
assert_eq!(smb_params.address.as_str(), "localhost");
|
||||
assert_eq!(smb_params.port, 445);
|
||||
assert_eq!(smb_params.share.as_str(), "test");
|
||||
assert_eq!(smb_params.password.as_deref().unwrap(), "bar");
|
||||
assert_eq!(smb_params.username.as_deref().unwrap(), "foo");
|
||||
assert_eq!(smb_params.workgroup.as_deref().unwrap(), "testone");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn should_get_ftparams_from_smb_bookmark() {
|
||||
let bookmark: Bookmark = Bookmark {
|
||||
protocol: FileTransferProtocol::Smb,
|
||||
address: Some("localhost".to_string()),
|
||||
port: Some(445),
|
||||
username: None,
|
||||
password: None,
|
||||
directory: Some(PathBuf::from("/tmp")),
|
||||
s3: None,
|
||||
smb: Some(SmbParams {
|
||||
share: "test".to_string(),
|
||||
workgroup: None,
|
||||
}),
|
||||
};
|
||||
|
||||
let params = FileTransferParams::from(bookmark);
|
||||
assert_eq!(params.protocol, FileTransferProtocol::Smb);
|
||||
assert_eq!(
|
||||
params.entry_directory.as_deref().unwrap(),
|
||||
std::path::Path::new("/tmp")
|
||||
);
|
||||
let smb_params = params.params.smb_params().unwrap();
|
||||
assert_eq!(smb_params.address.as_str(), "localhost");
|
||||
assert_eq!(smb_params.share.as_str(), "test");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
//! `config` is the module which provides access to termscp configuration
|
||||
|
||||
// Locals
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
// Ext
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
|
||||
pub const DEFAULT_NOTIFICATION_TRANSFER_THRESHOLD: u64 = 536870912; // 512MB
|
||||
|
||||
@@ -91,9 +92,10 @@ impl Default for UserInterfaceConfig {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_config_mod_new() {
|
||||
let mut keys: HashMap<String, PathBuf> = HashMap::with_capacity(1);
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
//!
|
||||
//! `serialization` provides serialization and deserialization for configurations
|
||||
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Contains the error for serializer/deserializer
|
||||
@@ -49,8 +51,6 @@ impl std::fmt::Display for SerializerError {
|
||||
}
|
||||
}
|
||||
|
||||
/// ### serialize
|
||||
///
|
||||
/// Serialize `UserHosts` into TOML and write content to writable
|
||||
pub fn serialize<S>(serializable: &S, mut writable: Box<dyn Write>) -> Result<(), SerializerError>
|
||||
where
|
||||
@@ -77,8 +77,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// ### deserialize
|
||||
///
|
||||
/// Read data from readable and deserialize its content as TOML
|
||||
pub fn deserialize<S>(mut readable: Box<dyn Read>) -> Result<S, SerializerError>
|
||||
where
|
||||
@@ -109,20 +107,20 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Seek;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::config::bookmarks::{Bookmark, S3Params, UserHosts};
|
||||
use pretty_assertions::assert_eq;
|
||||
use tuirealm::tui::style::Color;
|
||||
|
||||
use super::*;
|
||||
use crate::config::bookmarks::{Bookmark, S3Params, SmbParams, UserHosts};
|
||||
use crate::config::params::UserConfig;
|
||||
use crate::config::themes::Theme;
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
use crate::utils::test_helpers::create_file_ioers;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Seek;
|
||||
use std::path::PathBuf;
|
||||
use tuirealm::tui::style::Color;
|
||||
|
||||
#[test]
|
||||
fn test_config_serialization_errors() {
|
||||
let error: SerializerError = SerializerError::new(SerializerErrorKind::Syntax);
|
||||
@@ -368,7 +366,7 @@ mod tests {
|
||||
assert_eq!(host.username.as_deref().unwrap(), "root");
|
||||
assert_eq!(host.password, None);
|
||||
// Verify bookmarks
|
||||
assert_eq!(hosts.bookmarks.len(), 4);
|
||||
assert_eq!(hosts.bookmarks.len(), 5);
|
||||
let host: &Bookmark = hosts.bookmarks.get("raspberrypi2").unwrap();
|
||||
assert_eq!(host.address.as_deref().unwrap(), "192.168.1.31");
|
||||
assert_eq!(host.port.unwrap(), 22);
|
||||
@@ -406,6 +404,20 @@ mod tests {
|
||||
assert_eq!(s3.access_key.as_deref().unwrap(), "pippo");
|
||||
assert_eq!(s3.secret_access_key.as_deref().unwrap(), "pluto");
|
||||
assert_eq!(s3.new_path_style.unwrap(), true);
|
||||
|
||||
// smb
|
||||
let host = hosts.bookmarks.get("smb").unwrap();
|
||||
assert_eq!(host.address.as_deref().unwrap(), "localhost");
|
||||
assert_eq!(host.port.unwrap(), 445);
|
||||
#[cfg(unix)]
|
||||
assert_eq!(host.username.as_deref().unwrap(), "test");
|
||||
#[cfg(unix)]
|
||||
assert_eq!(host.password.as_deref().unwrap(), "test");
|
||||
|
||||
let smb = host.smb.as_ref().unwrap();
|
||||
assert_eq!(smb.share.as_str(), "temp");
|
||||
#[cfg(unix)]
|
||||
assert_eq!(smb.workgroup.as_deref().unwrap(), "test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -431,6 +443,7 @@ mod tests {
|
||||
password: None,
|
||||
directory: None,
|
||||
s3: None,
|
||||
smb: None,
|
||||
},
|
||||
);
|
||||
bookmarks.insert(
|
||||
@@ -443,6 +456,7 @@ mod tests {
|
||||
password: Some(String::from("password")),
|
||||
directory: Some(PathBuf::from("/tmp")),
|
||||
s3: None,
|
||||
smb: None,
|
||||
},
|
||||
);
|
||||
bookmarks.insert(
|
||||
@@ -463,6 +477,24 @@ mod tests {
|
||||
secret_access_key: None,
|
||||
new_path_style: None,
|
||||
}),
|
||||
smb: None,
|
||||
},
|
||||
);
|
||||
let smb_params: Option<SmbParams> = Some(SmbParams {
|
||||
share: "test".to_string(),
|
||||
workgroup: None,
|
||||
});
|
||||
bookmarks.insert(
|
||||
String::from("smb"),
|
||||
Bookmark {
|
||||
address: Some("localhost".to_string()),
|
||||
port: Some(445),
|
||||
protocol: FileTransferProtocol::Smb,
|
||||
username: None,
|
||||
password: None,
|
||||
directory: None,
|
||||
s3: None,
|
||||
smb: smb_params,
|
||||
},
|
||||
);
|
||||
let mut recents: HashMap<String, Bookmark> = HashMap::with_capacity(1);
|
||||
@@ -476,6 +508,7 @@ mod tests {
|
||||
password: Some(String::from("aaa")),
|
||||
directory: Some(PathBuf::from("/tmp")),
|
||||
s3: None,
|
||||
smb: None,
|
||||
},
|
||||
);
|
||||
let tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap();
|
||||
@@ -529,6 +562,17 @@ mod tests {
|
||||
secret_access_key = "pluto"
|
||||
new_path_style = true
|
||||
|
||||
[bookmarks.smb]
|
||||
protocol = "SMB"
|
||||
address = "localhost"
|
||||
port = 445
|
||||
username = "test"
|
||||
password = "test"
|
||||
|
||||
[bookmarks.smb.smb]
|
||||
share = "temp"
|
||||
workgroup = "test"
|
||||
|
||||
[recents]
|
||||
ISO20201215T094000Z = { address = "172.16.104.10", port = 22, protocol = "SCP", username = "root" }
|
||||
"#;
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
//! `themes` is the module which provides the themes configurations and the serializers
|
||||
|
||||
// locals
|
||||
use crate::utils::fmt::fmt_color;
|
||||
use crate::utils::parser::parse_color;
|
||||
// ext
|
||||
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::de::Error as DeError;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use tuirealm::tui::style::Color;
|
||||
|
||||
/// ### Theme
|
||||
///
|
||||
use crate::utils::fmt::fmt_color;
|
||||
use crate::utils::parser::parse_color;
|
||||
|
||||
/// Theme contains all the colors lookup table for termscp
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct Theme {
|
||||
@@ -213,10 +213,10 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_config_themes_default() {
|
||||
let theme: Theme = Theme::default();
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
//! `builder` is the module which provides a builder for FileExplorer
|
||||
|
||||
// Locals
|
||||
use super::formatter::Formatter;
|
||||
use super::{ExplorerOpts, FileExplorer, FileSorting, GroupDirs};
|
||||
// Ext
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use super::formatter::Formatter;
|
||||
use super::{ExplorerOpts, FileExplorer, FileSorting, GroupDirs};
|
||||
|
||||
/// Struct used to create a `FileExplorer`
|
||||
pub struct FileExplorerBuilder {
|
||||
explorer: Option<FileExplorer>,
|
||||
@@ -76,10 +77,10 @@ impl FileExplorerBuilder {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_fs_explorer_builder_new_default() {
|
||||
let explorer: FileExplorer = FileExplorerBuilder::new().build();
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
//! `formatter` is the module which provides formatting utilities for `FileExplorer`
|
||||
|
||||
// Locals
|
||||
use crate::utils::fmt::{fmt_path_elide, fmt_pex, fmt_time};
|
||||
use crate::utils::path::diff_paths;
|
||||
use crate::utils::string::secure_substring;
|
||||
use std::path::PathBuf;
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
// Ext
|
||||
use bytesize::ByteSize;
|
||||
use lazy_regex::{Lazy, Regex};
|
||||
use remotefs::File;
|
||||
use std::path::PathBuf;
|
||||
use std::time::UNIX_EPOCH;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
use users::{get_group_by_gid, get_user_by_uid};
|
||||
|
||||
use crate::utils::fmt::{fmt_path_elide, fmt_pex, fmt_time};
|
||||
use crate::utils::path::diff_paths;
|
||||
use crate::utils::string::secure_substring;
|
||||
// Types
|
||||
// FmtCallback: Formatter, fsentry: &File, cur_str, prefix, length, extra
|
||||
type FmtCallback = fn(&Formatter, &File, &str, &str, Option<&usize>, Option<&String>) -> String;
|
||||
@@ -209,7 +211,7 @@ impl Formatter {
|
||||
_fmt_extra: Option<&String>,
|
||||
) -> String {
|
||||
// Get username
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
let group: String = match fsentry.metadata().gid {
|
||||
Some(gid) => match get_group_by_gid(gid) {
|
||||
Some(user) => user.name().to_string_lossy().to_string(),
|
||||
@@ -217,7 +219,7 @@ impl Formatter {
|
||||
},
|
||||
None => 0.to_string(),
|
||||
};
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
let group: String = match fsentry.metadata().gid {
|
||||
Some(gid) => gid.to_string(),
|
||||
None => 0.to_string(),
|
||||
@@ -418,7 +420,7 @@ impl Formatter {
|
||||
_fmt_extra: Option<&String>,
|
||||
) -> String {
|
||||
// Get username
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
let username: String = match fsentry.metadata().uid {
|
||||
Some(uid) => match get_user_by_uid(uid) {
|
||||
Some(user) => user.name().to_string_lossy().to_string(),
|
||||
@@ -426,7 +428,7 @@ impl Formatter {
|
||||
},
|
||||
None => 0.to_string(),
|
||||
};
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
let username: String = match fsentry.metadata().uid {
|
||||
Some(uid) => uid.to_string(),
|
||||
None => 0.to_string(),
|
||||
@@ -521,12 +523,13 @@ impl Formatter {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use remotefs::fs::{File, FileType, Metadata, UnixPex};
|
||||
use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_fs_explorer_formatter_callchain() {
|
||||
@@ -589,7 +592,7 @@ mod tests {
|
||||
mode: Some(UnixPex::from(0o644)),
|
||||
},
|
||||
};
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -597,7 +600,7 @@ mod tests {
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -620,7 +623,7 @@ mod tests {
|
||||
mode: Some(UnixPex::from(0o644)),
|
||||
},
|
||||
};
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -628,7 +631,7 @@ mod tests {
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -651,7 +654,7 @@ mod tests {
|
||||
mode: None,
|
||||
},
|
||||
};
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -659,7 +662,7 @@ mod tests {
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -682,7 +685,7 @@ mod tests {
|
||||
mode: None,
|
||||
},
|
||||
};
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -690,7 +693,7 @@ mod tests {
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -720,7 +723,7 @@ mod tests {
|
||||
mode: Some(UnixPex::from(0o755)),
|
||||
},
|
||||
};
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -728,7 +731,7 @@ mod tests {
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -751,7 +754,7 @@ mod tests {
|
||||
mode: None,
|
||||
},
|
||||
};
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -759,7 +762,7 @@ mod tests {
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
assert_eq!(
|
||||
formatter.fmt(&entry),
|
||||
format!(
|
||||
@@ -861,7 +864,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn should_fmt_path() {
|
||||
let t: SystemTime = SystemTime::now();
|
||||
let entry = File {
|
||||
@@ -893,7 +896,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn should_fmt_utf8_path() {
|
||||
let t: SystemTime = SystemTime::now();
|
||||
let entry = File {
|
||||
|
||||
@@ -6,15 +6,16 @@
|
||||
pub(crate) mod builder;
|
||||
mod formatter;
|
||||
// Locals
|
||||
use formatter::Formatter;
|
||||
// Ext
|
||||
use remotefs::fs::File;
|
||||
use std::cmp::Reverse;
|
||||
use std::collections::VecDeque;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
|
||||
use formatter::Formatter;
|
||||
// Ext
|
||||
use remotefs::fs::File;
|
||||
|
||||
bitflags! {
|
||||
/// ExplorerOpts are bit options which provides different behaviours to `FileExplorer`
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
@@ -289,13 +290,14 @@ impl FromStr for GroupDirs {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::utils::fmt::fmt_time;
|
||||
use std::thread::sleep;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use remotefs::fs::{File, FileType, Metadata, UnixPex};
|
||||
use std::thread::sleep;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use super::*;
|
||||
use crate::utils::fmt::fmt_time;
|
||||
|
||||
#[test]
|
||||
fn test_fs_explorer_new() {
|
||||
@@ -511,7 +513,7 @@ mod tests {
|
||||
mode: Some(UnixPex::from(0o644)),
|
||||
},
|
||||
};
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
assert_eq!(
|
||||
explorer.fmt_file(&entry),
|
||||
format!(
|
||||
@@ -519,7 +521,7 @@ mod tests {
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
assert_eq!(
|
||||
explorer.fmt_file(&entry),
|
||||
format!(
|
||||
|
||||
@@ -2,16 +2,25 @@
|
||||
//!
|
||||
//! Remotefs client builder
|
||||
|
||||
use super::params::{AwsS3Params, GenericProtocolParams};
|
||||
use super::{FileTransferProtocol, ProtocolParams};
|
||||
use crate::system::config_client::ConfigClient;
|
||||
use crate::system::sshkey_storage::SshKeyStorage;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use remotefs::RemoteFs;
|
||||
use remotefs_aws_s3::AwsS3Fs;
|
||||
use remotefs_ftp::FtpFs;
|
||||
use remotefs_ssh::{ScpFs, SftpFs, SshOpts};
|
||||
use std::path::PathBuf;
|
||||
#[cfg(smb_unix)]
|
||||
use remotefs_smb::SmbOptions;
|
||||
#[cfg(smb)]
|
||||
use remotefs_smb::{SmbCredentials, SmbFs};
|
||||
use remotefs_ssh::{ScpFs, SftpFs, SshConfigParseRule, SshOpts};
|
||||
|
||||
#[cfg(not(smb))]
|
||||
use super::params::{AwsS3Params, GenericProtocolParams};
|
||||
#[cfg(smb)]
|
||||
use super::params::{AwsS3Params, GenericProtocolParams, SmbParams};
|
||||
use super::{FileTransferProtocol, ProtocolParams};
|
||||
use crate::system::config_client::ConfigClient;
|
||||
use crate::system::sshkey_storage::SshKeyStorage;
|
||||
use crate::utils::ssh as ssh_utils;
|
||||
|
||||
/// Remotefs builder
|
||||
pub struct Builder;
|
||||
@@ -38,6 +47,10 @@ impl Builder {
|
||||
(FileTransferProtocol::Sftp, ProtocolParams::Generic(params)) => {
|
||||
Box::new(Self::sftp_client(params, config_client))
|
||||
}
|
||||
#[cfg(smb)]
|
||||
(FileTransferProtocol::Smb, ProtocolParams::Smb(params)) => {
|
||||
Box::new(Self::smb_client(params))
|
||||
}
|
||||
(protocol, params) => {
|
||||
error!("Invalid params for protocol '{:?}'", protocol);
|
||||
panic!("Invalid protocol '{protocol:?}' with parameters of type {params:?}")
|
||||
@@ -97,19 +110,85 @@ impl Builder {
|
||||
Self::build_ssh_opts(params, config_client).into()
|
||||
}
|
||||
|
||||
#[cfg(smb_unix)]
|
||||
fn smb_client(params: SmbParams) -> SmbFs {
|
||||
let mut credentials = SmbCredentials::default()
|
||||
.server(format!("smb://{}:{}", params.address, params.port))
|
||||
.share(params.share);
|
||||
|
||||
if let Some(username) = params.username {
|
||||
credentials = credentials.username(username);
|
||||
}
|
||||
if let Some(password) = params.password {
|
||||
credentials = credentials.password(password);
|
||||
}
|
||||
if let Some(workgroup) = params.workgroup {
|
||||
credentials = credentials.workgroup(workgroup);
|
||||
}
|
||||
|
||||
match SmbFs::try_new(
|
||||
credentials,
|
||||
SmbOptions::default()
|
||||
.one_share_per_server(true)
|
||||
.case_sensitive(false),
|
||||
) {
|
||||
Ok(fs) => fs,
|
||||
Err(e) => {
|
||||
error!("Invalid params for protocol SMB: {e}");
|
||||
panic!("Invalid params for protocol SMB: {e}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn smb_client(params: SmbParams) -> SmbFs {
|
||||
let mut credentials = SmbCredentials::new(params.address, params.share);
|
||||
|
||||
if let Some(username) = params.username {
|
||||
credentials = credentials.username(username);
|
||||
}
|
||||
if let Some(password) = params.password {
|
||||
credentials = credentials.password(password);
|
||||
}
|
||||
|
||||
SmbFs::new(credentials)
|
||||
}
|
||||
|
||||
/// Build ssh options from generic protocol params and client configuration
|
||||
fn build_ssh_opts(params: GenericProtocolParams, config_client: &ConfigClient) -> SshOpts {
|
||||
let mut opts = SshOpts::new(params.address)
|
||||
let mut opts = SshOpts::new(params.address.clone())
|
||||
.key_storage(Box::new(Self::make_ssh_storage(config_client)))
|
||||
.port(params.port);
|
||||
//* get username. Case 1 provided in params
|
||||
if let Some(username) = params.username {
|
||||
opts = opts.username(username);
|
||||
} else if let Some(ssh_config) = config_client.get_ssh_config().and_then(|x| {
|
||||
//* case 2: found in ssh2 config
|
||||
debug!("reading ssh config at {}", x);
|
||||
ssh_utils::parse_ssh2_config(x).ok()
|
||||
}) {
|
||||
debug!("no username was provided, checking whether a user is set for this host");
|
||||
if let Some(username) = ssh_config.query(¶ms.address).user {
|
||||
debug!("found username from config: {username}");
|
||||
opts = opts.username(username);
|
||||
} else {
|
||||
//* case 3: use system username; can't be None
|
||||
debug!("no username was provided, using current username");
|
||||
opts = opts.username(whoami::username());
|
||||
}
|
||||
} else {
|
||||
//* case 3: use system username; can't be None
|
||||
debug!("no username was provided, using current username");
|
||||
opts = opts.username(whoami::username());
|
||||
}
|
||||
if let Some(password) = params.password {
|
||||
opts = opts.password(password);
|
||||
}
|
||||
if let Some(config_path) = config_client.get_ssh_config() {
|
||||
opts = opts.config_file(PathBuf::from(config_path));
|
||||
opts = opts.config_file(
|
||||
PathBuf::from(config_path),
|
||||
SshConfigParseRule::ALLOW_UNKNOWN_FIELDS,
|
||||
);
|
||||
}
|
||||
opts
|
||||
}
|
||||
@@ -123,11 +202,12 @@ impl Builder {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use tempfile::TempDir;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_build_aws_s3_fs() {
|
||||
let params = ProtocolParams::AwsS3(
|
||||
@@ -182,6 +262,14 @@ mod test {
|
||||
let _ = Builder::build(FileTransferProtocol::Sftp, params, &config_client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(smb)]
|
||||
fn should_build_smb_fs() {
|
||||
let params = ProtocolParams::Smb(SmbParams::new("localhost", "share"));
|
||||
let config_client = get_config_client();
|
||||
let _ = Builder::build(FileTransferProtocol::Smb, params, &config_client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn should_not_build_fs() {
|
||||
|
||||
@@ -13,10 +13,11 @@ pub use params::{FileTransferParams, ProtocolParams};
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum FileTransferProtocol {
|
||||
Sftp,
|
||||
Scp,
|
||||
Ftp(bool), // Bool is for secure (true => ftps)
|
||||
AwsS3,
|
||||
Ftp(bool), // Bool is for secure (true => ftps)
|
||||
Scp,
|
||||
Sftp,
|
||||
Smb,
|
||||
}
|
||||
|
||||
// Traits
|
||||
@@ -24,13 +25,14 @@ pub enum FileTransferProtocol {
|
||||
impl std::string::ToString for FileTransferProtocol {
|
||||
fn to_string(&self) -> String {
|
||||
String::from(match self {
|
||||
FileTransferProtocol::AwsS3 => "S3",
|
||||
FileTransferProtocol::Ftp(secure) => match secure {
|
||||
true => "FTPS",
|
||||
false => "FTP",
|
||||
},
|
||||
FileTransferProtocol::Scp => "SCP",
|
||||
FileTransferProtocol::Sftp => "SFTP",
|
||||
FileTransferProtocol::AwsS3 => "S3",
|
||||
FileTransferProtocol::Smb => "SMB",
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -41,9 +43,10 @@ impl std::str::FromStr for FileTransferProtocol {
|
||||
match s.to_ascii_uppercase().as_str() {
|
||||
"FTP" => Ok(FileTransferProtocol::Ftp(false)),
|
||||
"FTPS" => Ok(FileTransferProtocol::Ftp(true)),
|
||||
"S3" => Ok(FileTransferProtocol::AwsS3),
|
||||
"SCP" => Ok(FileTransferProtocol::Scp),
|
||||
"SFTP" => Ok(FileTransferProtocol::Sftp),
|
||||
"S3" => Ok(FileTransferProtocol::AwsS3),
|
||||
"SMB" => Ok(FileTransferProtocol::Smb),
|
||||
_ => Err(s.to_string()),
|
||||
}
|
||||
}
|
||||
@@ -54,12 +57,13 @@ impl std::str::FromStr for FileTransferProtocol {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_filetransfer_mod_protocol() {
|
||||
assert_eq!(
|
||||
@@ -103,6 +107,14 @@ mod tests {
|
||||
FileTransferProtocol::from_str("scp").ok().unwrap(),
|
||||
FileTransferProtocol::Scp
|
||||
);
|
||||
assert_eq!(
|
||||
FileTransferProtocol::from_str("SMB").ok().unwrap(),
|
||||
FileTransferProtocol::Smb
|
||||
);
|
||||
assert_eq!(
|
||||
FileTransferProtocol::from_str("smb").ok().unwrap(),
|
||||
FileTransferProtocol::Smb
|
||||
);
|
||||
assert_eq!(
|
||||
FileTransferProtocol::from_str("S3").ok().unwrap(),
|
||||
FileTransferProtocol::AwsS3
|
||||
@@ -125,5 +137,6 @@ mod tests {
|
||||
assert_eq!(FileTransferProtocol::Scp.to_string(), String::from("SCP"));
|
||||
assert_eq!(FileTransferProtocol::Sftp.to_string(), String::from("SFTP"));
|
||||
assert_eq!(FileTransferProtocol::AwsS3.to_string(), String::from("S3"));
|
||||
assert_eq!(FileTransferProtocol::Smb.to_string(), String::from("SMB"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
//!
|
||||
//! file transfer parameters
|
||||
|
||||
use super::FileTransferProtocol;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// ### FileTransferParams
|
||||
///
|
||||
use super::FileTransferProtocol;
|
||||
|
||||
/// Holds connection parameters for file transfers
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FileTransferParams {
|
||||
@@ -21,6 +19,7 @@ pub struct FileTransferParams {
|
||||
pub enum ProtocolParams {
|
||||
Generic(GenericProtocolParams),
|
||||
AwsS3(AwsS3Params),
|
||||
Smb(SmbParams),
|
||||
}
|
||||
|
||||
/// Protocol params used by most common protocols
|
||||
@@ -46,6 +45,19 @@ pub struct AwsS3Params {
|
||||
pub new_path_style: bool,
|
||||
}
|
||||
|
||||
/// Connection parameters for SMB protocol
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SmbParams {
|
||||
pub address: String,
|
||||
#[cfg(unix)]
|
||||
pub port: u16,
|
||||
pub share: String,
|
||||
pub username: Option<String>,
|
||||
pub password: Option<String>,
|
||||
#[cfg(unix)]
|
||||
pub workgroup: Option<String>,
|
||||
}
|
||||
|
||||
impl FileTransferParams {
|
||||
/// Instantiates a new `FileTransferParams`
|
||||
pub fn new(protocol: FileTransferProtocol, params: ProtocolParams) -> Self {
|
||||
@@ -68,6 +80,7 @@ impl FileTransferParams {
|
||||
match &self.params {
|
||||
ProtocolParams::AwsS3(params) => params.password_missing(),
|
||||
ProtocolParams::Generic(params) => params.password_missing(),
|
||||
ProtocolParams::Smb(params) => params.password_missing(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +89,7 @@ impl FileTransferParams {
|
||||
match &mut self.params {
|
||||
ProtocolParams::AwsS3(params) => params.set_default_secret(secret),
|
||||
ProtocolParams::Generic(params) => params.set_default_secret(secret),
|
||||
ProtocolParams::Smb(params) => params.set_default_secret(secret),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +107,6 @@ impl Default for ProtocolParams {
|
||||
}
|
||||
|
||||
impl ProtocolParams {
|
||||
#[cfg(test)]
|
||||
/// Retrieve generic parameters from protocol params if any
|
||||
pub fn generic_params(&self) -> Option<&GenericProtocolParams> {
|
||||
match self {
|
||||
@@ -119,6 +132,15 @@ impl ProtocolParams {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Retrieve SMB parameters if any
|
||||
pub fn smb_params(&self) -> Option<&SmbParams> {
|
||||
match self {
|
||||
ProtocolParams::Smb(params) => Some(params),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Generic protocol params
|
||||
@@ -237,12 +259,68 @@ impl AwsS3Params {
|
||||
}
|
||||
}
|
||||
|
||||
// -- SMB params
|
||||
|
||||
impl SmbParams {
|
||||
/// Instantiates a new `AwsS3Params` struct
|
||||
pub fn new<S: AsRef<str>>(address: S, share: S) -> Self {
|
||||
Self {
|
||||
address: address.as_ref().to_string(),
|
||||
#[cfg(unix)]
|
||||
port: 445,
|
||||
share: share.as_ref().to_string(),
|
||||
username: None,
|
||||
password: None,
|
||||
#[cfg(unix)]
|
||||
workgroup: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn port(mut self, port: u16) -> Self {
|
||||
self.port = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn username(mut self, username: Option<impl ToString>) -> Self {
|
||||
self.username = username.map(|x| x.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn password(mut self, password: Option<impl ToString>) -> Self {
|
||||
self.password = password.map(|x| x.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn workgroup(mut self, workgroup: Option<impl ToString>) -> Self {
|
||||
self.workgroup = workgroup.map(|x| x.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns whether a password is supposed to be required for this protocol params.
|
||||
/// The result true is returned ONLY if the supposed secret is MISSING!!!
|
||||
pub fn password_missing(&self) -> bool {
|
||||
self.password.is_none()
|
||||
}
|
||||
|
||||
/// Set password
|
||||
#[cfg(unix)]
|
||||
pub fn set_default_secret(&mut self, secret: String) {
|
||||
self.password = Some(secret);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn set_default_secret(&mut self, _secret: String) {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_filetransfer_params() {
|
||||
let params: FileTransferParams =
|
||||
@@ -305,6 +383,53 @@ mod test {
|
||||
assert_eq!(params.new_path_style, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_init_smb_params() {
|
||||
let params = SmbParams::new("localhost", "temp");
|
||||
assert_eq!(¶ms.address, "localhost");
|
||||
|
||||
#[cfg(unix)]
|
||||
assert_eq!(params.port, 445);
|
||||
assert_eq!(¶ms.share, "temp");
|
||||
|
||||
#[cfg(unix)]
|
||||
assert!(params.username.is_none());
|
||||
#[cfg(unix)]
|
||||
assert!(params.password.is_none());
|
||||
#[cfg(unix)]
|
||||
assert!(params.workgroup.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn should_init_smb_params_with_optionals() {
|
||||
let params = SmbParams::new("localhost", "temp")
|
||||
.port(3456)
|
||||
.username(Some("foo"))
|
||||
.password(Some("bar"))
|
||||
.workgroup(Some("baz"));
|
||||
|
||||
assert_eq!(¶ms.address, "localhost");
|
||||
assert_eq!(params.port, 3456);
|
||||
assert_eq!(¶ms.share, "temp");
|
||||
assert_eq!(params.username.as_deref().unwrap(), "foo");
|
||||
assert_eq!(params.password.as_deref().unwrap(), "bar");
|
||||
assert_eq!(params.workgroup.as_deref().unwrap(), "baz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn should_init_smb_params_with_optionals() {
|
||||
let params = SmbParams::new("localhost", "temp")
|
||||
.username(Some("foo"))
|
||||
.password(Some("bar"));
|
||||
|
||||
assert_eq!(¶ms.address, "localhost");
|
||||
assert_eq!(¶ms.share, "temp");
|
||||
assert_eq!(params.username.as_deref().unwrap(), "foo");
|
||||
assert_eq!(params.password.as_deref().unwrap(), "bar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references() {
|
||||
let mut params =
|
||||
|
||||
@@ -3,19 +3,20 @@
|
||||
//! `host` is the module which provides functionalities to host file system
|
||||
|
||||
// ext
|
||||
// Metadata ext
|
||||
#[cfg(unix)]
|
||||
use std::fs::set_permissions;
|
||||
use std::fs::{self, File as StdFile, OpenOptions};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use filetime::{self, FileTime};
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
use remotefs::fs::UnixPex;
|
||||
use remotefs::fs::{File, FileType, Metadata};
|
||||
use std::fs::{self, File as StdFile, OpenOptions};
|
||||
use std::path::{Path, PathBuf};
|
||||
use thiserror::Error;
|
||||
use wildmatch::WildMatch;
|
||||
// Metadata ext
|
||||
#[cfg(target_family = "unix")]
|
||||
use std::fs::set_permissions;
|
||||
#[cfg(target_family = "unix")]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
// Locals
|
||||
use crate::utils::path;
|
||||
@@ -41,8 +42,6 @@ pub enum HostErrorType {
|
||||
DeleteFailed,
|
||||
}
|
||||
|
||||
/// ### HostError
|
||||
///
|
||||
/// HostError is a wrapper for the error type and the exact io error
|
||||
#[derive(Debug)]
|
||||
pub struct HostError {
|
||||
@@ -421,7 +420,7 @@ impl Localhost {
|
||||
filetime::set_file_atime(path, atime)
|
||||
.map_err(|e| HostError::new(HostErrorType::FileNotAccessible, Some(e), path))?;
|
||||
}
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
if let Some(mode) = metadata.mode {
|
||||
self.chmod(path, mode)?;
|
||||
}
|
||||
@@ -455,7 +454,7 @@ impl Localhost {
|
||||
}
|
||||
|
||||
/// Change file mode to file, according to UNIX permissions
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
pub fn chmod(&self, path: &Path, pex: UnixPex) -> Result<(), HostError> {
|
||||
let path: PathBuf = self.to_path(path);
|
||||
// Get metadta
|
||||
@@ -587,7 +586,7 @@ impl Localhost {
|
||||
}
|
||||
|
||||
/// Create a symlink at path pointing at target
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
pub fn symlink(&self, path: &Path, target: &Path) -> Result<(), HostError> {
|
||||
let path = self.to_path(path);
|
||||
std::os::unix::fs::symlink(target, path.as_path()).map_err(|e| {
|
||||
@@ -645,21 +644,21 @@ impl Localhost {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(target_family = "unix")]
|
||||
use crate::utils::test_helpers::make_fsentry;
|
||||
use crate::utils::test_helpers::{create_sample_file, make_dir_at, make_file_at};
|
||||
#[cfg(unix)]
|
||||
use std::fs::File as StdFile;
|
||||
#[cfg(unix)]
|
||||
use std::io::Write;
|
||||
use std::ops::AddAssign;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::{symlink, PermissionsExt};
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
#[cfg(target_family = "unix")]
|
||||
use std::fs::File as StdFile;
|
||||
#[cfg(target_family = "unix")]
|
||||
use std::io::Write;
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
use std::os::unix::fs::{symlink, PermissionsExt};
|
||||
use std::time::SystemTime;
|
||||
use std::{ops::AddAssign, time::Duration};
|
||||
use super::*;
|
||||
#[cfg(unix)]
|
||||
use crate::utils::test_helpers::make_fsentry;
|
||||
use crate::utils::test_helpers::{create_sample_file, make_dir_at, make_file_at};
|
||||
|
||||
#[test]
|
||||
fn test_host_error_new() {
|
||||
@@ -670,7 +669,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn test_host_localhost_new() {
|
||||
let host: Localhost = Localhost::new(PathBuf::from("/dev")).ok().unwrap();
|
||||
assert_eq!(host.wrkdir, PathBuf::from("/dev"));
|
||||
@@ -684,7 +683,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
fn test_host_localhost_new() {
|
||||
let host: Localhost = Localhost::new(PathBuf::from("C:\\users")).ok().unwrap();
|
||||
assert_eq!(host.wrkdir, PathBuf::from("C:\\users"));
|
||||
@@ -706,14 +705,14 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn test_host_localhost_pwd() {
|
||||
let host: Localhost = Localhost::new(PathBuf::from("/dev")).ok().unwrap();
|
||||
assert_eq!(host.pwd(), PathBuf::from("/dev"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn test_host_localhost_list_files() {
|
||||
let host: Localhost = Localhost::new(PathBuf::from("/dev")).ok().unwrap();
|
||||
// Scan dir
|
||||
@@ -726,7 +725,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn test_host_localhost_change_dir() {
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from("/dev")).ok().unwrap();
|
||||
let new_dir: PathBuf = PathBuf::from("/dev");
|
||||
@@ -742,7 +741,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
#[should_panic]
|
||||
fn test_host_localhost_change_dir_failed() {
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from("/dev")).ok().unwrap();
|
||||
@@ -751,7 +750,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn test_host_localhost_open_read() {
|
||||
let host: Localhost = Localhost::new(PathBuf::from("/dev")).ok().unwrap();
|
||||
// Create temp file
|
||||
@@ -760,7 +759,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
#[should_panic]
|
||||
fn test_host_localhost_open_read_err_no_such_file() {
|
||||
let host: Localhost = Localhost::new(PathBuf::from("/dev")).ok().unwrap();
|
||||
@@ -781,7 +780,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn test_host_localhost_open_write() {
|
||||
let host: Localhost = Localhost::new(PathBuf::from("/dev")).ok().unwrap();
|
||||
// Create temp file
|
||||
@@ -800,7 +799,7 @@ mod tests {
|
||||
assert!(host.open_file_write(file.path()).is_err());
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_host_localhost_symlinks() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
@@ -838,7 +837,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn test_host_localhost_mkdir() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
|
||||
@@ -863,7 +862,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn test_host_localhost_remove() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
// Create sample file
|
||||
@@ -892,7 +891,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn test_host_localhost_rename() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
// Create sample file
|
||||
@@ -945,7 +944,7 @@ mod tests {
|
||||
assert_eq!(new_metadata.metadata().modified, Some(new_mtime));
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_host_chmod() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
@@ -964,7 +963,7 @@ mod tests {
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_host_copy_file_absolute() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
@@ -994,7 +993,7 @@ mod tests {
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_host_copy_file_relative() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
@@ -1016,7 +1015,7 @@ mod tests {
|
||||
assert_eq!(host.files.len(), 2);
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_host_copy_directory_absolute() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
@@ -1047,7 +1046,7 @@ mod tests {
|
||||
assert!(host.stat(test_file_path.as_path()).is_ok());
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_host_copy_directory_relative() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
@@ -1082,9 +1081,9 @@ mod tests {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
let host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
|
||||
// Execute
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
assert_eq!(host.exec("echo 5").ok().unwrap().as_str(), "5\n");
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
assert_eq!(host.exec("echo 5").ok().unwrap().as_str(), "5\r\n");
|
||||
}
|
||||
|
||||
@@ -1121,7 +1120,7 @@ mod tests {
|
||||
assert_eq!(result[1].name(), "examples.csv");
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn should_create_symlink() {
|
||||
let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap();
|
||||
|
||||
@@ -136,8 +136,6 @@ fn parse_remote_address(remote: &str) -> Result<FileTransferParams, String> {
|
||||
utils::parser::parse_remote_opt(remote).map_err(|e| format!("Bad address option: {e}"))
|
||||
}
|
||||
|
||||
/// ### run
|
||||
///
|
||||
/// Run task and return rc
|
||||
fn run(run_opts: RunOpts) -> i32 {
|
||||
match run_opts.task {
|
||||
|
||||
@@ -3,18 +3,15 @@
|
||||
//! this module exposes some extra run modes for termscp, meant to be used for "support", such as installing themes
|
||||
|
||||
// mod
|
||||
use crate::system::{
|
||||
auto_update::{Update, UpdateStatus},
|
||||
config_client::ConfigClient,
|
||||
environment,
|
||||
notifications::Notification,
|
||||
theme_provider::ThemeProvider,
|
||||
};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// ### import_theme
|
||||
///
|
||||
use crate::system::auto_update::{Update, UpdateStatus};
|
||||
use crate::system::config_client::ConfigClient;
|
||||
use crate::system::environment;
|
||||
use crate::system::notifications::Notification;
|
||||
use crate::system::theme_provider::ThemeProvider;
|
||||
|
||||
/// Import theme at provided path into termscp
|
||||
pub fn import_theme(p: &Path) -> Result<(), String> {
|
||||
if !p.exists() {
|
||||
@@ -34,8 +31,6 @@ pub fn import_theme(p: &Path) -> Result<(), String> {
|
||||
.map_err(|e| format!("Could not import theme: {e}"))
|
||||
}
|
||||
|
||||
/// ### install_update
|
||||
///
|
||||
/// Install latest version of termscp if an update is available
|
||||
pub fn install_update() -> Result<String, String> {
|
||||
match Update::default()
|
||||
@@ -65,8 +60,6 @@ pub fn install_update() -> Result<String, String> {
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_config_dir
|
||||
///
|
||||
/// Get configuration directory
|
||||
fn get_config_dir() -> Result<PathBuf, String> {
|
||||
match environment::init_config_dir() {
|
||||
@@ -80,8 +73,6 @@ fn get_config_dir() -> Result<PathBuf, String> {
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_config_client
|
||||
///
|
||||
/// Get configuration client
|
||||
fn get_config_client() -> Option<ConfigClient> {
|
||||
match get_config_dir() {
|
||||
|
||||
@@ -2,16 +2,13 @@
|
||||
//!
|
||||
//! Automatic update module. This module is used to upgrade the current version of termscp to the latest available on Github
|
||||
|
||||
use self_update::backends::github::Update as GithubUpdater;
|
||||
pub use self_update::errors::Error as UpdateError;
|
||||
use self_update::update::Release as UpdRelease;
|
||||
use self_update::{cargo_crate_version, Status};
|
||||
|
||||
use crate::utils::parser::parse_semver;
|
||||
|
||||
pub use self_update::errors::Error as UpdateError;
|
||||
use self_update::{
|
||||
backends::github::Update as GithubUpdater, cargo_crate_version, update::Release as UpdRelease,
|
||||
Status,
|
||||
};
|
||||
|
||||
/// ### UpdateStatus
|
||||
///
|
||||
/// The status of the update in case of success
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum UpdateStatus {
|
||||
@@ -133,10 +130,10 @@ impl From<UpdRelease> for Release {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn auto_update_default() {
|
||||
let upd: Update = Update::default();
|
||||
|
||||
@@ -3,9 +3,16 @@
|
||||
//! `bookmarks_client` is the module which provides an API between the Bookmarks module and the system
|
||||
|
||||
// Crate
|
||||
// Ext
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::string::ToString;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use super::keys::filestorage::FileStorage;
|
||||
#[cfg(feature = "with-keyring")]
|
||||
use super::keys::keyringstorage::KeyringStorage;
|
||||
use super::keys::{filestorage::FileStorage, KeyStorage, KeyStorageError};
|
||||
use super::keys::{KeyStorage, KeyStorageError};
|
||||
// Local
|
||||
use crate::config::{
|
||||
bookmarks::{Bookmark, UserHosts},
|
||||
@@ -15,11 +22,6 @@ use crate::filetransfer::FileTransferParams;
|
||||
use crate::utils::crypto;
|
||||
use crate::utils::fmt::fmt_time;
|
||||
use crate::utils::random::random_alphanumeric_with_len;
|
||||
// Ext
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::string::ToString;
|
||||
use std::time::SystemTime;
|
||||
|
||||
/// BookmarksClient provides a layer between the host system and the bookmarks module
|
||||
pub struct BookmarksClient {
|
||||
@@ -370,15 +372,16 @@ impl BookmarksClient {
|
||||
#[cfg(not(target_os = "macos"))] // CI/CD blocks
|
||||
mod tests {
|
||||
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
|
||||
use super::*;
|
||||
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams};
|
||||
use crate::filetransfer::{FileTransferProtocol, ProtocolParams};
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
|
||||
fn test_system_bookmarks_new() {
|
||||
@@ -395,28 +398,6 @@ mod tests {
|
||||
assert_eq!(client.recents_size, 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
fn test_system_bookmarks_new_err() {
|
||||
assert!(BookmarksClient::new(
|
||||
Path::new("/tmp/oifoif/omar"),
|
||||
Path::new("/tmp/efnnu/omar"),
|
||||
16
|
||||
)
|
||||
.is_err());
|
||||
|
||||
let tmp_dir: tempfile::TempDir = TempDir::new().ok().unwrap();
|
||||
let (cfg_path, _): (PathBuf, PathBuf) = get_paths(tmp_dir.path());
|
||||
assert!(
|
||||
BookmarksClient::new(cfg_path.as_path(), Path::new("/tmp/efnnu/omar"), 16).is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
fn test_system_bookmarks_new_from_existing() {
|
||||
@@ -730,7 +711,7 @@ mod tests {
|
||||
// Limit is 2
|
||||
assert_eq!(client.iter_recents().count(), 2);
|
||||
// Check that 192.168.1.1 has been removed
|
||||
let key: String = client.iter_recents().nth(0).unwrap().to_string();
|
||||
let key: String = client.iter_recents().next().unwrap().to_string();
|
||||
assert!(matches!(
|
||||
client
|
||||
.hosts
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
//! `config_client` is the module which provides an API between the Config module and the system
|
||||
|
||||
// Locals
|
||||
use crate::config::{
|
||||
params::{UserConfig, DEFAULT_NOTIFICATION_TRANSFER_THRESHOLD},
|
||||
serialization::{deserialize, serialize, SerializerError, SerializerErrorKind},
|
||||
};
|
||||
use crate::explorer::GroupDirs;
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
// Ext
|
||||
use std::fs::{create_dir, remove_file, File, OpenOptions};
|
||||
use std::io::Write;
|
||||
@@ -16,6 +10,11 @@ use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
|
||||
use crate::config::params::{UserConfig, DEFAULT_NOTIFICATION_TRANSFER_THRESHOLD};
|
||||
use crate::config::serialization::{deserialize, serialize, SerializerError, SerializerErrorKind};
|
||||
use crate::explorer::GroupDirs;
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
|
||||
// Types
|
||||
pub type SshHost = (String, String, PathBuf); // 0: host, 1: username, 2: RSA key path
|
||||
|
||||
@@ -414,14 +413,15 @@ impl ConfigClient {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
|
||||
use super::*;
|
||||
use crate::config::UserConfig;
|
||||
use crate::utils::random::random_alphanumeric_with_len;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::io::Read;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn test_system_config_new() {
|
||||
let tmp_dir: TempDir = TempDir::new().ok().unwrap();
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
// Ext
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// ### get_config_dir
|
||||
///
|
||||
/// Get termscp configuration directory path.
|
||||
/// Returns None, if it's not possible to get it
|
||||
/// Get termscp config directory path and initialize it.
|
||||
/// Returns None if it's not possible to initialize it
|
||||
pub fn init_config_dir() -> Result<Option<PathBuf>, String> {
|
||||
// Get file
|
||||
#[cfg(not(test))]
|
||||
@@ -19,27 +17,51 @@ pub fn init_config_dir() -> Result<Option<PathBuf>, String> {
|
||||
lazy_static! {
|
||||
static ref CONF_DIR: Option<PathBuf> = Some(std::env::temp_dir());
|
||||
}
|
||||
if CONF_DIR.is_some() {
|
||||
// Get path of bookmarks
|
||||
let mut p: PathBuf = CONF_DIR.as_ref().unwrap().clone();
|
||||
// Append termscp dir
|
||||
p.push("termscp/");
|
||||
// If directory doesn't exist, create it
|
||||
if p.exists() {
|
||||
return Ok(Some(p));
|
||||
}
|
||||
// directory doesn't exist; create dir recursively
|
||||
match std::fs::create_dir_all(p.as_path()) {
|
||||
Ok(_) => Ok(Some(p)),
|
||||
Err(err) => Err(err.to_string()),
|
||||
}
|
||||
|
||||
if let Some(dir) = CONF_DIR.as_deref() {
|
||||
init_dir(dir).map(Option::Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// ### get_bookmarks_paths
|
||||
///
|
||||
/// Get termscp cache directory path and initialize it.
|
||||
/// Returns None if it's not possible to initialize it
|
||||
pub fn init_cache_dir() -> Result<Option<PathBuf>, String> {
|
||||
// Get file
|
||||
#[cfg(not(test))]
|
||||
lazy_static! {
|
||||
static ref CACHE_DIR: Option<PathBuf> = dirs::cache_dir();
|
||||
}
|
||||
#[cfg(test)]
|
||||
lazy_static! {
|
||||
static ref CACHE_DIR: Option<PathBuf> = Some(std::env::temp_dir());
|
||||
}
|
||||
|
||||
if let Some(dir) = CACHE_DIR.as_deref() {
|
||||
init_dir(dir).map(Option::Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Init a termscp env dir
|
||||
fn init_dir(p: &Path) -> Result<PathBuf, String> {
|
||||
// Get path of bookmarks
|
||||
let mut p: PathBuf = p.to_path_buf();
|
||||
// Append termscp dir
|
||||
p.push("termscp/");
|
||||
// If directory doesn't exist, create it
|
||||
if p.exists() {
|
||||
return Ok(p);
|
||||
}
|
||||
// directory doesn't exist; create dir recursively
|
||||
match std::fs::create_dir_all(p.as_path()) {
|
||||
Ok(_) => Ok(p),
|
||||
Err(err) => Err(err.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get paths for bookmarks client
|
||||
/// Returns: path of bookmarks.toml
|
||||
pub fn get_bookmarks_paths(config_dir: &Path) -> PathBuf {
|
||||
@@ -49,8 +71,6 @@ pub fn get_bookmarks_paths(config_dir: &Path) -> PathBuf {
|
||||
bookmarks_file
|
||||
}
|
||||
|
||||
/// ### get_config_paths
|
||||
///
|
||||
/// Returns paths for config client
|
||||
/// Returns: path of config.toml and path for ssh keys
|
||||
pub fn get_config_paths(config_dir: &Path) -> (PathBuf, PathBuf) {
|
||||
@@ -62,17 +82,13 @@ pub fn get_config_paths(config_dir: &Path) -> (PathBuf, PathBuf) {
|
||||
(bookmarks_file, keys_dir)
|
||||
}
|
||||
|
||||
/// ### get_log_paths
|
||||
///
|
||||
/// Returns the path for the supposed log file
|
||||
pub fn get_log_paths(config_dir: &Path) -> PathBuf {
|
||||
let mut log_file: PathBuf = PathBuf::from(config_dir);
|
||||
pub fn get_log_paths(cache_dir: &Path) -> PathBuf {
|
||||
let mut log_file: PathBuf = PathBuf::from(cache_dir);
|
||||
log_file.push("termscp.log");
|
||||
log_file
|
||||
}
|
||||
|
||||
/// ### get_theme_path
|
||||
///
|
||||
/// Get paths for theme provider
|
||||
/// Returns: path of theme.toml
|
||||
pub fn get_theme_path(config_dir: &Path) -> PathBuf {
|
||||
@@ -85,12 +101,13 @@ pub fn get_theme_path(config_dir: &Path) -> PathBuf {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use serial_test::serial;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
@@ -101,6 +118,15 @@ mod tests {
|
||||
assert!(std::fs::remove_dir_all(conf_dir.as_path()).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn should_get_cache_dir() {
|
||||
// Create and get cache_dir
|
||||
let cache_dir: PathBuf = init_cache_dir().ok().unwrap().unwrap();
|
||||
// Remove dir
|
||||
assert!(std::fs::remove_dir_all(cache_dir.as_path()).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_system_environment_get_config_dir_err() {
|
||||
@@ -148,8 +174,8 @@ mod tests {
|
||||
#[serial]
|
||||
fn test_system_environment_get_log_paths() {
|
||||
assert_eq!(
|
||||
get_log_paths(Path::new("/home/omar/.config/termscp/")),
|
||||
PathBuf::from("/home/omar/.config/termscp/termscp.log"),
|
||||
get_log_paths(Path::new("/home/omar/.cache/termscp/")),
|
||||
PathBuf::from("/home/omar/.cache/termscp/termscp.log"),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
//! `filestorage` provides an implementation of the `KeyStorage` trait using a file
|
||||
|
||||
// Local
|
||||
use super::{KeyStorage, KeyStorageError};
|
||||
// Ext
|
||||
use std::fs::{OpenOptions, Permissions};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::{KeyStorage, KeyStorageError};
|
||||
|
||||
/// File storage is an implementation o the `KeyStorage` which uses a file to store the key
|
||||
pub struct FileStorage {
|
||||
dir_path: PathBuf,
|
||||
@@ -90,10 +91,10 @@ impl KeyStorage for FileStorage {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_system_keys_filestorage_make_dir() {
|
||||
let storage: FileStorage = FileStorage::new(Path::new("/tmp/"));
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
//! `keyringstorage` provides an implementation of the `KeyStorage` trait using the OS keyring
|
||||
|
||||
// Local
|
||||
use super::{KeyStorage, KeyStorageError};
|
||||
// Ext
|
||||
use keyring::{Entry as Keyring, Error as KeyringError};
|
||||
|
||||
use super::{KeyStorage, KeyStorageError};
|
||||
|
||||
/// provides a `KeyStorage` implementation using the keyring crate
|
||||
pub struct KeyringStorage {
|
||||
username: String,
|
||||
@@ -75,11 +76,11 @@ impl KeyStorage for KeyringStorage {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use whoami::username;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_system_keys_keyringstorage() {
|
||||
let username: String = username();
|
||||
|
||||
@@ -7,10 +7,9 @@ pub mod filestorage;
|
||||
#[cfg(feature = "with-keyring")]
|
||||
pub mod keyringstorage;
|
||||
// ext
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(feature = "with-keyring")]
|
||||
use keyring::Error as KeyringError;
|
||||
use thiserror::Error;
|
||||
|
||||
/// defines the error type for the `KeyStorage`
|
||||
#[derive(Debug, Error)]
|
||||
@@ -53,10 +52,10 @@ pub trait KeyStorage {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_system_keys_mod_errors() {
|
||||
#[cfg(feature = "with-keyring")]
|
||||
|
||||
@@ -2,32 +2,27 @@
|
||||
//!
|
||||
//! `logging` is the module which initializes the logging system for termscp
|
||||
|
||||
// locals
|
||||
use crate::system::environment::{get_log_paths, init_config_dir};
|
||||
use crate::utils::file::open_file;
|
||||
// ext
|
||||
pub use simplelog::LevelFilter as LogLevel;
|
||||
use simplelog::{ConfigBuilder, WriteLogger};
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// ### init
|
||||
///
|
||||
use super::environment::{get_log_paths, init_cache_dir};
|
||||
use crate::utils::file::open_file;
|
||||
|
||||
/// Initialize logger
|
||||
pub fn init(level: LogLevel) -> Result<(), String> {
|
||||
// Init config dir
|
||||
let config_dir: PathBuf = match init_config_dir() {
|
||||
// Init cache dir
|
||||
let cache_dir = match init_cache_dir() {
|
||||
Ok(Some(p)) => p,
|
||||
Ok(None) => {
|
||||
return Err(String::from(
|
||||
"This system doesn't seem to support CONFIG_DIR",
|
||||
"This system doesn't seem to support CACHE_DIR",
|
||||
))
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let log_file_path: PathBuf = get_log_paths(config_dir.as_path());
|
||||
let log_file_path = get_log_paths(cache_dir.as_path());
|
||||
// Open log file
|
||||
let file: File = open_file(log_file_path.as_path(), true, true, false)
|
||||
let file = open_file(log_file_path.as_path(), true, true, false)
|
||||
.map_err(|e| format!("Failed to open file {}: {}", log_file_path.display(), e))?;
|
||||
// Prepare log config
|
||||
let config = ConfigBuilder::new().set_time_format_rfc3339().build();
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
//! `SshKeyStorage` is the module which behaves a storage for ssh keys
|
||||
|
||||
// Locals
|
||||
use super::config_client::ConfigClient;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
// Ext
|
||||
use remotefs_ssh::SshKeyStorage as SshKeyStorageTrait;
|
||||
use ssh2_config::SshConfig;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::config_client::ConfigClient;
|
||||
use crate::utils::ssh as ssh_utils;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SshKeyStorage {
|
||||
@@ -32,19 +35,6 @@ impl SshKeyStorage {
|
||||
self.hosts.insert(key, p);
|
||||
}
|
||||
|
||||
/// Parse ssh2 config
|
||||
fn parse_ssh2_config(path: &str) -> Result<SshConfig, String> {
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
|
||||
let mut reader = File::open(path)
|
||||
.map_err(|e| format!("failed to open {path}: {e}"))
|
||||
.map(BufReader::new)?;
|
||||
SshConfig::default()
|
||||
.parse(&mut reader)
|
||||
.map_err(|e| format!("Failed to parse ssh2 config: {e}"))
|
||||
}
|
||||
|
||||
/// Resolve host via termscp ssh keys storage
|
||||
fn resolve_host_in_termscp_storage(&self, host: &str, username: &str) -> Option<&Path> {
|
||||
let key: String = Self::make_mapkey(host, username);
|
||||
@@ -87,7 +77,7 @@ impl From<&ConfigClient> for SshKeyStorage {
|
||||
// read ssh2 config
|
||||
let ssh_config = cfg_client.get_ssh_config().and_then(|x| {
|
||||
debug!("reading ssh config at {}", x);
|
||||
Self::parse_ssh2_config(x).ok()
|
||||
ssh_utils::parse_ssh2_config(x).ok()
|
||||
});
|
||||
let mut hosts: HashMap<String, PathBuf> =
|
||||
HashMap::with_capacity(cfg_client.iter_ssh_keys().count());
|
||||
@@ -117,13 +107,14 @@ impl From<&ConfigClient> for SshKeyStorage {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::system::config_client::ConfigClient;
|
||||
use crate::utils::test_helpers;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn test_system_sshkey_storage_new() {
|
||||
let tmp_dir: tempfile::TempDir = tempfile::TempDir::new().ok().unwrap();
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
//! `theme_provider` is the module which provides an API between the theme configuration and the system
|
||||
|
||||
// Locals
|
||||
use crate::config::{
|
||||
serialization::{deserialize, serialize, SerializerError, SerializerErrorKind},
|
||||
themes::Theme,
|
||||
};
|
||||
// Ext
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::string::ToString;
|
||||
|
||||
use crate::config::serialization::{deserialize, serialize, SerializerError, SerializerErrorKind};
|
||||
use crate::config::themes::Theme;
|
||||
|
||||
/// ThemeProvider provides a high level API to communicate with the termscp theme
|
||||
pub struct ThemeProvider {
|
||||
theme: Theme, // Theme loaded
|
||||
@@ -142,12 +141,12 @@ impl ThemeProvider {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
use tuirealm::tui::style::Color;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_system_theme_provider_new() {
|
||||
let tmp_dir: tempfile::TempDir = TempDir::new().ok().unwrap();
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
//!
|
||||
//! this module exposes the types to describe a change to sync on the remote file system
|
||||
|
||||
use crate::utils::path as path_utils;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::utils::path as path_utils;
|
||||
|
||||
/// Describes an operation on the remote file system to sync
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum FsChange {
|
||||
@@ -190,10 +190,10 @@ fn remote_relative_path(
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_get_remote_relative_path_from_subdir() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
mod change;
|
||||
|
||||
// -- export
|
||||
pub use change::FsChange;
|
||||
|
||||
use crate::utils::path as path_utils;
|
||||
|
||||
use notify::{
|
||||
watcher, DebouncedEvent, Error as WatcherError, RecommendedWatcher, RecursiveMode, Watcher,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::mpsc::{channel, Receiver, RecvTimeoutError};
|
||||
use std::time::Duration;
|
||||
|
||||
pub use change::FsChange;
|
||||
use notify::{
|
||||
watcher, DebouncedEvent, Error as WatcherError, RecommendedWatcher, RecursiveMode, Watcher,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::utils::path as path_utils;
|
||||
|
||||
type FsWatcherResult<T> = Result<T, FsWatcherError>;
|
||||
|
||||
/// Describes an error returned by the `FsWatcher`
|
||||
@@ -172,14 +172,13 @@ impl FsWatcher {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::utils::test_helpers;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
|
||||
use super::*;
|
||||
#[cfg(target_os = "macos")]
|
||||
use crate::utils::test_helpers;
|
||||
|
||||
#[test]
|
||||
fn should_init_fswatcher() {
|
||||
let watcher = FsWatcher::init(Duration::from_secs(5)).unwrap();
|
||||
@@ -330,7 +329,7 @@ mod test {
|
||||
|
||||
/*
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
fn should_poll_file_moved() {
|
||||
let mut watcher = FsWatcher::init(Duration::from_millis(100)).unwrap();
|
||||
let tempdir = TempDir::new().unwrap();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
// Locals
|
||||
use super::{AuthActivity, FileTransferParams};
|
||||
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams};
|
||||
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams};
|
||||
|
||||
impl AuthActivity {
|
||||
/// Delete bookmark
|
||||
@@ -157,6 +157,7 @@ impl AuthActivity {
|
||||
match bookmark.params {
|
||||
ProtocolParams::AwsS3(params) => self.load_bookmark_s3_into_gui(params),
|
||||
ProtocolParams::Generic(params) => self.load_bookmark_generic_into_gui(params),
|
||||
ProtocolParams::Smb(params) => self.load_bookmark_smb_into_gui(params),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,4 +179,15 @@ impl AuthActivity {
|
||||
self.mount_s3_session_token(params.session_token.as_deref().unwrap_or(""));
|
||||
self.mount_s3_new_path_style(params.new_path_style);
|
||||
}
|
||||
|
||||
fn load_bookmark_smb_into_gui(&mut self, params: SmbParams) {
|
||||
self.mount_address(params.address.as_str());
|
||||
#[cfg(unix)]
|
||||
self.mount_port(params.port);
|
||||
self.mount_username(params.username.as_deref().unwrap_or(""));
|
||||
self.mount_password(params.password.as_deref().unwrap_or(""));
|
||||
self.mount_smb_share(¶ms.share);
|
||||
#[cfg(unix)]
|
||||
self.mount_smb_workgroup(params.workgroup.as_deref().unwrap_or(""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
//!
|
||||
//! auth activity bookmarks components
|
||||
|
||||
use super::{FormMsg, Msg, UiMsg};
|
||||
|
||||
use tui_realm_stdlib::{Input, List, Radio};
|
||||
use tuirealm::command::{Cmd, CmdResult, Direction, Position};
|
||||
use tuirealm::event::{Key, KeyEvent, KeyModifiers};
|
||||
use tuirealm::props::{Alignment, BorderSides, BorderType, Borders, Color, InputType, TextSpan};
|
||||
use tuirealm::{Component, Event, MockComponent, NoUserEvent, State, StateValue};
|
||||
|
||||
use super::{FormMsg, Msg, UiMsg};
|
||||
|
||||
// -- bookmark list
|
||||
|
||||
#[derive(MockComponent)]
|
||||
|
||||
@@ -2,14 +2,19 @@
|
||||
//!
|
||||
//! auth activity components for file transfer params form
|
||||
|
||||
use super::{FileTransferProtocol, FormMsg, Msg, UiMsg};
|
||||
|
||||
use tui_realm_stdlib::{Input, Radio};
|
||||
use tuirealm::command::{Cmd, CmdResult, Direction, Position};
|
||||
use tuirealm::event::{Key, KeyEvent, KeyModifiers};
|
||||
use tuirealm::props::{Alignment, BorderType, Borders, Color, InputType, Style};
|
||||
use tuirealm::{Component, Event, MockComponent, NoUserEvent, State, StateValue};
|
||||
|
||||
use crate::ui::activities::auth::{
|
||||
RADIO_PROTOCOL_FTP, RADIO_PROTOCOL_FTPS, RADIO_PROTOCOL_S3, RADIO_PROTOCOL_SCP,
|
||||
RADIO_PROTOCOL_SFTP, RADIO_PROTOCOL_SMB,
|
||||
};
|
||||
|
||||
use super::{FileTransferProtocol, FormMsg, Msg, UiMsg};
|
||||
|
||||
// -- protocol
|
||||
|
||||
#[derive(MockComponent)]
|
||||
@@ -26,7 +31,11 @@ impl ProtocolRadio {
|
||||
.color(color)
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.choices(&["SFTP", "SCP", "FTP", "FTPS", "S3"])
|
||||
.choices(if cfg!(smb) {
|
||||
&["SFTP", "SCP", "FTP", "FTPS", "S3", "SMB"]
|
||||
} else {
|
||||
&["SFTP", "SCP", "FTP", "FTPS", "S3"]
|
||||
})
|
||||
.foreground(color)
|
||||
.rewind(true)
|
||||
.title("Protocol", Alignment::Left)
|
||||
@@ -37,10 +46,11 @@ impl ProtocolRadio {
|
||||
/// Convert radio index for protocol into a `FileTransferProtocol`
|
||||
fn protocol_opt_to_enum(protocol: usize) -> FileTransferProtocol {
|
||||
match protocol {
|
||||
1 => FileTransferProtocol::Scp,
|
||||
2 => FileTransferProtocol::Ftp(false),
|
||||
3 => FileTransferProtocol::Ftp(true),
|
||||
4 => FileTransferProtocol::AwsS3,
|
||||
RADIO_PROTOCOL_SCP => FileTransferProtocol::Scp,
|
||||
RADIO_PROTOCOL_FTP => FileTransferProtocol::Ftp(false),
|
||||
RADIO_PROTOCOL_FTPS => FileTransferProtocol::Ftp(true),
|
||||
RADIO_PROTOCOL_S3 => FileTransferProtocol::AwsS3,
|
||||
RADIO_PROTOCOL_SMB => FileTransferProtocol::Smb,
|
||||
_ => FileTransferProtocol::Sftp,
|
||||
}
|
||||
}
|
||||
@@ -48,11 +58,12 @@ impl ProtocolRadio {
|
||||
/// Convert `FileTransferProtocol` enum into radio group index
|
||||
fn protocol_enum_to_opt(protocol: FileTransferProtocol) -> usize {
|
||||
match protocol {
|
||||
FileTransferProtocol::Sftp => 0,
|
||||
FileTransferProtocol::Scp => 1,
|
||||
FileTransferProtocol::Ftp(false) => 2,
|
||||
FileTransferProtocol::Ftp(true) => 3,
|
||||
FileTransferProtocol::AwsS3 => 4,
|
||||
FileTransferProtocol::Sftp => RADIO_PROTOCOL_SFTP,
|
||||
FileTransferProtocol::Scp => RADIO_PROTOCOL_SCP,
|
||||
FileTransferProtocol::Ftp(false) => RADIO_PROTOCOL_FTP,
|
||||
FileTransferProtocol::Ftp(true) => RADIO_PROTOCOL_FTPS,
|
||||
FileTransferProtocol::AwsS3 => RADIO_PROTOCOL_S3,
|
||||
FileTransferProtocol::Smb => RADIO_PROTOCOL_SMB,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -673,3 +684,72 @@ fn handle_input_ev(
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(MockComponent)]
|
||||
pub struct InputSmbShare {
|
||||
component: Input,
|
||||
}
|
||||
|
||||
impl InputSmbShare {
|
||||
pub fn new(host: &str, color: Color) -> Self {
|
||||
Self {
|
||||
component: Input::default()
|
||||
.borders(
|
||||
Borders::default()
|
||||
.color(color)
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.foreground(color)
|
||||
.title("Share", Alignment::Left)
|
||||
.input_type(InputType::Text)
|
||||
.value(host),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Msg, NoUserEvent> for InputSmbShare {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
handle_input_ev(
|
||||
self,
|
||||
ev,
|
||||
Msg::Ui(UiMsg::SmbShareBlurDown),
|
||||
Msg::Ui(UiMsg::SmbShareBlurUp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[derive(MockComponent)]
|
||||
pub struct InputSmbWorkgroup {
|
||||
component: Input,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl InputSmbWorkgroup {
|
||||
pub fn new(host: &str, color: Color) -> Self {
|
||||
Self {
|
||||
component: Input::default()
|
||||
.borders(
|
||||
Borders::default()
|
||||
.color(color)
|
||||
.modifiers(BorderType::Rounded),
|
||||
)
|
||||
.foreground(color)
|
||||
.title("Workgroup", Alignment::Left)
|
||||
.input_type(InputType::Text)
|
||||
.value(host),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl Component<Msg, NoUserEvent> for InputSmbWorkgroup {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
handle_input_ev(
|
||||
self,
|
||||
ev,
|
||||
Msg::Ui(UiMsg::SmbWorkgroupDown),
|
||||
Msg::Ui(UiMsg::SmbWorkgroupUp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,18 @@ pub use bookmarks::{
|
||||
BookmarkName, BookmarkSavePassword, BookmarksList, DeleteBookmarkPopup, DeleteRecentPopup,
|
||||
RecentsList,
|
||||
};
|
||||
#[cfg(unix)]
|
||||
pub use form::InputSmbWorkgroup;
|
||||
pub use form::{
|
||||
InputAddress, InputPassword, InputPort, InputRemoteDirectory, InputS3AccessKey, InputS3Bucket,
|
||||
InputS3Endpoint, InputS3Profile, InputS3Region, InputS3SecretAccessKey, InputS3SecurityToken,
|
||||
InputS3SessionToken, InputUsername, ProtocolRadio, RadioS3NewPathStyle,
|
||||
InputS3SessionToken, InputSmbShare, InputUsername, ProtocolRadio, RadioS3NewPathStyle,
|
||||
};
|
||||
pub use popup::{
|
||||
ErrorPopup, InfoPopup, InstallUpdatePopup, Keybindings, QuitPopup, ReleaseNotes, WaitPopup,
|
||||
WindowSizeError,
|
||||
};
|
||||
pub use text::{HelpFooter, NewVersionDisclaimer, Subtitle, Title};
|
||||
|
||||
use tui_realm_stdlib::Phantom;
|
||||
use tuirealm::event::{Event, Key, KeyEvent, KeyModifiers, NoUserEvent};
|
||||
use tuirealm::{Component, MockComponent};
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
//!
|
||||
//! auth activity popups
|
||||
|
||||
use super::{FormMsg, Msg, UiMsg};
|
||||
|
||||
use tui_realm_stdlib::{List, Paragraph, Radio, Textarea};
|
||||
use tuirealm::command::{Cmd, CmdResult, Direction, Position};
|
||||
use tuirealm::event::{Key, KeyEvent, KeyModifiers};
|
||||
use tuirealm::props::{Alignment, BorderType, Borders, Color, TableBuilder, TextSpan};
|
||||
use tuirealm::{Component, Event, MockComponent, NoUserEvent, State, StateValue};
|
||||
|
||||
use super::{FormMsg, Msg, UiMsg};
|
||||
|
||||
// -- error popup
|
||||
|
||||
#[derive(MockComponent)]
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
//!
|
||||
//! auth activity texts
|
||||
|
||||
use super::Msg;
|
||||
|
||||
use tui_realm_stdlib::{Label, Span};
|
||||
use tuirealm::props::{Color, TextModifiers, TextSpan};
|
||||
use tuirealm::{Component, Event, MockComponent, NoUserEvent};
|
||||
|
||||
use super::Msg;
|
||||
|
||||
// -- Title
|
||||
|
||||
#[derive(MockComponent)]
|
||||
|
||||
@@ -14,6 +14,7 @@ impl AuthActivity {
|
||||
FileTransferProtocol::Sftp | FileTransferProtocol::Scp => 22,
|
||||
FileTransferProtocol::Ftp(_) => 21,
|
||||
FileTransferProtocol::AwsS3 => 22, // Doesn't matter, since not used
|
||||
FileTransferProtocol::Smb => 445,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +37,10 @@ impl AuthActivity {
|
||||
pub(super) fn collect_host_params(&self) -> Result<FileTransferParams, &'static str> {
|
||||
match self.protocol {
|
||||
FileTransferProtocol::AwsS3 => self.collect_s3_host_params(),
|
||||
protocol => self.collect_generic_host_params(protocol),
|
||||
FileTransferProtocol::Smb => self.collect_smb_host_params(),
|
||||
FileTransferProtocol::Ftp(_)
|
||||
| FileTransferProtocol::Scp
|
||||
| FileTransferProtocol::Sftp => self.collect_generic_host_params(self.protocol),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +76,25 @@ impl AuthActivity {
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn collect_smb_host_params(&self) -> Result<FileTransferParams, &'static str> {
|
||||
let params = self.get_smb_params_input();
|
||||
if params.address.is_empty() {
|
||||
return Err("Invalid address");
|
||||
}
|
||||
#[cfg(unix)]
|
||||
if params.port == 0 {
|
||||
return Err("Invalid port");
|
||||
}
|
||||
if params.share.is_empty() {
|
||||
return Err("Invalid share");
|
||||
}
|
||||
Ok(FileTransferParams {
|
||||
protocol: FileTransferProtocol::Smb,
|
||||
params: ProtocolParams::Smb(params),
|
||||
entry_directory: self.get_input_remote_directory(),
|
||||
})
|
||||
}
|
||||
|
||||
// -- update install
|
||||
|
||||
/// If enabled in configuration, check for updates from Github
|
||||
|
||||
@@ -10,16 +10,26 @@ mod update;
|
||||
mod view;
|
||||
|
||||
// locals
|
||||
// Includes
|
||||
use std::time::Duration;
|
||||
|
||||
use tuirealm::application::PollStrategy;
|
||||
use tuirealm::listener::EventListenerCfg;
|
||||
use tuirealm::{Application, NoUserEvent, Update};
|
||||
|
||||
use super::{Activity, Context, ExitReason};
|
||||
use crate::config::themes::Theme;
|
||||
use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
|
||||
use crate::system::bookmarks_client::BookmarksClient;
|
||||
use crate::system::config_client::ConfigClient;
|
||||
|
||||
// Includes
|
||||
use std::time::Duration;
|
||||
use tuirealm::listener::EventListenerCfg;
|
||||
use tuirealm::{application::PollStrategy, Application, NoUserEvent, Update};
|
||||
// radio
|
||||
const RADIO_PROTOCOL_SFTP: usize = 0;
|
||||
const RADIO_PROTOCOL_SCP: usize = 1;
|
||||
const RADIO_PROTOCOL_FTP: usize = 2;
|
||||
const RADIO_PROTOCOL_FTPS: usize = 3;
|
||||
const RADIO_PROTOCOL_S3: usize = 4;
|
||||
const RADIO_PROTOCOL_SMB: usize = 5;
|
||||
|
||||
// -- components
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
|
||||
@@ -53,6 +63,9 @@ pub enum Id {
|
||||
S3SecretAccessKey,
|
||||
S3SecurityToken,
|
||||
S3SessionToken,
|
||||
SmbShare,
|
||||
#[cfg(unix)]
|
||||
SmbWorkgroup,
|
||||
Subtitle,
|
||||
Title,
|
||||
Username,
|
||||
@@ -123,6 +136,12 @@ pub enum UiMsg {
|
||||
S3SecurityTokenBlurUp,
|
||||
S3SessionTokenBlurDown,
|
||||
S3SessionTokenBlurUp,
|
||||
SmbShareBlurDown,
|
||||
SmbShareBlurUp,
|
||||
#[cfg(unix)]
|
||||
SmbWorkgroupDown,
|
||||
#[cfg(unix)]
|
||||
SmbWorkgroupUp,
|
||||
BookmarkNameBlur,
|
||||
SaveBookmarkPasswordBlur,
|
||||
ShowDeleteBookmarkPopup,
|
||||
@@ -141,14 +160,13 @@ pub enum UiMsg {
|
||||
enum InputMask {
|
||||
Generic,
|
||||
AwsS3,
|
||||
Smb,
|
||||
}
|
||||
|
||||
// Store keys
|
||||
const STORE_KEY_LATEST_VERSION: &str = "AUTH_LATEST_VERSION";
|
||||
const STORE_KEY_RELEASE_NOTES: &str = "AUTH_RELEASE_NOTES";
|
||||
|
||||
/// ### AuthActivity
|
||||
///
|
||||
/// AuthActivity is the data holder for the authentication activity
|
||||
pub struct AuthActivity {
|
||||
app: Application<Id, Msg, NoUserEvent>,
|
||||
@@ -218,6 +236,7 @@ impl AuthActivity {
|
||||
FileTransferProtocol::Ftp(_)
|
||||
| FileTransferProtocol::Scp
|
||||
| FileTransferProtocol::Sftp => InputMask::Generic,
|
||||
FileTransferProtocol::Smb => InputMask::Smb,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
//!
|
||||
//! Update impl
|
||||
|
||||
use super::{AuthActivity, ExitReason, FormMsg, Id, InputMask, Msg, UiMsg, Update};
|
||||
|
||||
use tuirealm::{State, StateValue};
|
||||
|
||||
use super::{AuthActivity, ExitReason, FormMsg, Id, InputMask, Msg, UiMsg, Update};
|
||||
|
||||
impl Update<Msg> for AuthActivity {
|
||||
fn update(&mut self, msg: Option<Msg>) -> Option<Msg> {
|
||||
self.redraw = true;
|
||||
@@ -68,6 +68,7 @@ impl AuthActivity {
|
||||
.app
|
||||
.active(match self.input_mask() {
|
||||
InputMask::Generic => &Id::Password,
|
||||
InputMask::Smb => &Id::Password,
|
||||
InputMask::AwsS3 => &Id::S3Bucket,
|
||||
})
|
||||
.is_ok());
|
||||
@@ -79,6 +80,7 @@ impl AuthActivity {
|
||||
.app
|
||||
.active(match self.input_mask() {
|
||||
InputMask::Generic => &Id::Password,
|
||||
InputMask::Smb => &Id::Password,
|
||||
InputMask::AwsS3 => &Id::S3Bucket,
|
||||
})
|
||||
.is_ok());
|
||||
@@ -113,7 +115,12 @@ impl AuthActivity {
|
||||
fn update_ui(&mut self, msg: UiMsg) -> Option<Msg> {
|
||||
match msg {
|
||||
UiMsg::AddressBlurDown => {
|
||||
assert!(self.app.active(&Id::Port).is_ok());
|
||||
let id = if cfg!(windows) && self.input_mask() == InputMask::Smb {
|
||||
&Id::SmbShare
|
||||
} else {
|
||||
&Id::Port
|
||||
};
|
||||
assert!(self.app.active(id).is_ok());
|
||||
}
|
||||
UiMsg::AddressBlurUp => {
|
||||
assert!(self.app.active(&Id::Protocol).is_ok());
|
||||
@@ -155,13 +162,30 @@ impl AuthActivity {
|
||||
assert!(self.app.active(&Id::BookmarksList).is_ok());
|
||||
}
|
||||
UiMsg::PasswordBlurDown => {
|
||||
assert!(self.app.active(&Id::RemoteDirectory).is_ok());
|
||||
assert!(self
|
||||
.app
|
||||
.active(match self.input_mask() {
|
||||
InputMask::Generic => &Id::RemoteDirectory,
|
||||
#[cfg(unix)]
|
||||
InputMask::Smb => &Id::SmbWorkgroup,
|
||||
#[cfg(windows)]
|
||||
InputMask::Smb => &Id::RemoteDirectory,
|
||||
InputMask::AwsS3 => panic!("this shouldn't happen (password on s3)"),
|
||||
})
|
||||
.is_ok());
|
||||
}
|
||||
UiMsg::PasswordBlurUp => {
|
||||
assert!(self.app.active(&Id::Username).is_ok());
|
||||
}
|
||||
UiMsg::PortBlurDown => {
|
||||
assert!(self.app.active(&Id::Username).is_ok());
|
||||
assert!(self
|
||||
.app
|
||||
.active(match self.input_mask() {
|
||||
InputMask::Generic => &Id::Username,
|
||||
InputMask::Smb => &Id::SmbShare,
|
||||
InputMask::AwsS3 => panic!("this shouldn't happen (port on s3)"),
|
||||
})
|
||||
.is_ok());
|
||||
}
|
||||
UiMsg::PortBlurUp => {
|
||||
assert!(self.app.active(&Id::Address).is_ok());
|
||||
@@ -171,6 +195,7 @@ impl AuthActivity {
|
||||
.app
|
||||
.active(match self.input_mask() {
|
||||
InputMask::Generic => &Id::Address,
|
||||
InputMask::Smb => &Id::Address,
|
||||
InputMask::AwsS3 => &Id::S3Bucket,
|
||||
})
|
||||
.is_ok());
|
||||
@@ -189,6 +214,10 @@ impl AuthActivity {
|
||||
.app
|
||||
.active(match self.input_mask() {
|
||||
InputMask::Generic => &Id::Password,
|
||||
#[cfg(unix)]
|
||||
InputMask::Smb => &Id::SmbWorkgroup,
|
||||
#[cfg(windows)]
|
||||
InputMask::Smb => &Id::Password,
|
||||
InputMask::AwsS3 => &Id::S3NewPathStyle,
|
||||
})
|
||||
.is_ok());
|
||||
@@ -247,6 +276,25 @@ impl AuthActivity {
|
||||
UiMsg::S3NewPathStyleBlurUp => {
|
||||
assert!(self.app.active(&Id::S3SessionToken).is_ok());
|
||||
}
|
||||
UiMsg::SmbShareBlurDown => {
|
||||
assert!(self.app.active(&Id::Username).is_ok());
|
||||
}
|
||||
UiMsg::SmbShareBlurUp => {
|
||||
let id = if cfg!(windows) && self.input_mask() == InputMask::Smb {
|
||||
&Id::Address
|
||||
} else {
|
||||
&Id::Port
|
||||
};
|
||||
assert!(self.app.active(id).is_ok());
|
||||
}
|
||||
#[cfg(unix)]
|
||||
UiMsg::SmbWorkgroupDown => {
|
||||
assert!(self.app.active(&Id::RemoteDirectory).is_ok());
|
||||
}
|
||||
#[cfg(unix)]
|
||||
UiMsg::SmbWorkgroupUp => {
|
||||
assert!(self.app.active(&Id::Password).is_ok());
|
||||
}
|
||||
UiMsg::SaveBookmarkPasswordBlur => {
|
||||
assert!(self.app.active(&Id::BookmarkName).is_ok());
|
||||
}
|
||||
@@ -272,7 +320,14 @@ impl AuthActivity {
|
||||
assert!(self.app.active(&Id::Password).is_ok());
|
||||
}
|
||||
UiMsg::UsernameBlurUp => {
|
||||
assert!(self.app.active(&Id::Port).is_ok());
|
||||
assert!(self
|
||||
.app
|
||||
.active(match self.input_mask() {
|
||||
InputMask::Generic => &Id::Port,
|
||||
InputMask::Smb => &Id::SmbShare,
|
||||
InputMask::AwsS3 => panic!("this shouldn't happen (username on s3)"),
|
||||
})
|
||||
.is_ok());
|
||||
}
|
||||
UiMsg::WindowResized => {
|
||||
self.redraw = true;
|
||||
|
||||
@@ -3,17 +3,18 @@
|
||||
//! `auth_activity` is the module which implements the authentication activity
|
||||
|
||||
// Locals
|
||||
use super::{components, AuthActivity, Context, FileTransferProtocol, Id, InputMask};
|
||||
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams};
|
||||
use crate::filetransfer::FileTransferParams;
|
||||
use crate::utils::ui::{Popup, Size};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use tuirealm::tui::layout::{Constraint, Direction, Layout};
|
||||
use tuirealm::tui::widgets::Clear;
|
||||
use tuirealm::{State, StateValue, Sub, SubClause, SubEventClause};
|
||||
|
||||
use super::{components, AuthActivity, Context, FileTransferProtocol, Id, InputMask};
|
||||
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams, SmbParams};
|
||||
use crate::filetransfer::FileTransferParams;
|
||||
use crate::utils::ui::{Popup, Size};
|
||||
|
||||
impl AuthActivity {
|
||||
/// Initialize view, mounting all startup components inside the view
|
||||
pub(super) fn init(&mut self) {
|
||||
@@ -55,6 +56,9 @@ impl AuthActivity {
|
||||
self.mount_s3_security_token("");
|
||||
self.mount_s3_session_token("");
|
||||
self.mount_s3_new_path_style(false);
|
||||
self.mount_smb_share("");
|
||||
#[cfg(unix)]
|
||||
self.mount_smb_workgroup("");
|
||||
// Version notice
|
||||
if let Some(version) = self
|
||||
.context()
|
||||
@@ -149,7 +153,7 @@ impl AuthActivity {
|
||||
InputMask::Generic => Layout::default()
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length(3), // host
|
||||
Constraint::Length(3), // address
|
||||
Constraint::Length(3), // port
|
||||
Constraint::Length(3), // username
|
||||
Constraint::Length(3), // password
|
||||
@@ -159,6 +163,36 @@ impl AuthActivity {
|
||||
)
|
||||
.direction(Direction::Vertical)
|
||||
.split(auth_chunks[4]),
|
||||
#[cfg(unix)]
|
||||
InputMask::Smb => Layout::default()
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length(3), // address
|
||||
Constraint::Length(3), // port
|
||||
Constraint::Length(3), // share
|
||||
Constraint::Length(3), // username
|
||||
Constraint::Length(3), // password
|
||||
Constraint::Length(3), // workgroup
|
||||
Constraint::Length(3), // remote directory
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.direction(Direction::Vertical)
|
||||
.split(auth_chunks[4]),
|
||||
#[cfg(windows)]
|
||||
InputMask::Smb => Layout::default()
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length(3), // address
|
||||
Constraint::Length(3), // share
|
||||
Constraint::Length(3), // username
|
||||
Constraint::Length(3), // password
|
||||
Constraint::Length(3), // remote directory
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.direction(Direction::Vertical)
|
||||
.split(auth_chunks[4]),
|
||||
};
|
||||
// Create bookmark chunks
|
||||
let bookmark_chunks = Layout::default()
|
||||
@@ -187,6 +221,13 @@ impl AuthActivity {
|
||||
self.app.view(&view_ids[2], f, input_mask[2]);
|
||||
self.app.view(&view_ids[3], f, input_mask[3]);
|
||||
}
|
||||
InputMask::Smb => {
|
||||
let view_ids = self.get_smb_view();
|
||||
self.app.view(&view_ids[0], f, input_mask[0]);
|
||||
self.app.view(&view_ids[1], f, input_mask[1]);
|
||||
self.app.view(&view_ids[2], f, input_mask[2]);
|
||||
self.app.view(&view_ids[3], f, input_mask[3]);
|
||||
}
|
||||
}
|
||||
// Bookmark chunks
|
||||
self.app.view(&Id::BookmarksList, f, bookmark_chunks[0]);
|
||||
@@ -712,6 +753,31 @@ impl AuthActivity {
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
pub(crate) fn mount_smb_share(&mut self, share: &str) {
|
||||
let color = self.theme().auth_password;
|
||||
assert!(self
|
||||
.app
|
||||
.remount(
|
||||
Id::SmbShare,
|
||||
Box::new(components::InputSmbShare::new(share, color)),
|
||||
vec![]
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(crate) fn mount_smb_workgroup(&mut self, workgroup: &str) {
|
||||
let color = self.theme().auth_address;
|
||||
assert!(self
|
||||
.app
|
||||
.remount(
|
||||
Id::SmbWorkgroup,
|
||||
Box::new(components::InputSmbWorkgroup::new(workgroup, color)),
|
||||
vec![]
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
// -- query
|
||||
|
||||
/// Collect input values from view
|
||||
@@ -747,6 +813,37 @@ impl AuthActivity {
|
||||
.new_path_style(new_path_style)
|
||||
}
|
||||
|
||||
/// Collect s3 input values from view
|
||||
#[cfg(unix)]
|
||||
pub(super) fn get_smb_params_input(&self) -> SmbParams {
|
||||
let share: String = self.get_input_smb_share();
|
||||
let workgroup: Option<String> = self.get_input_smb_workgroup();
|
||||
|
||||
let address: String = self.get_input_addr();
|
||||
let port: u16 = self.get_input_port();
|
||||
let username = self.get_input_username();
|
||||
let password = self.get_input_password();
|
||||
|
||||
SmbParams::new(address, share)
|
||||
.port(port)
|
||||
.username(username)
|
||||
.password(password)
|
||||
.workgroup(workgroup)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(super) fn get_smb_params_input(&self) -> SmbParams {
|
||||
let share: String = self.get_input_smb_share();
|
||||
|
||||
let address: String = self.get_input_addr();
|
||||
let username = self.get_input_username();
|
||||
let password = self.get_input_password();
|
||||
|
||||
SmbParams::new(address, share)
|
||||
.username(username)
|
||||
.password(password)
|
||||
}
|
||||
|
||||
pub(super) fn get_input_remote_directory(&self) -> Option<PathBuf> {
|
||||
match self.app.state(&Id::RemoteDirectory) {
|
||||
Ok(State::One(StateValue::String(x))) if !x.is_empty() => {
|
||||
@@ -850,6 +947,21 @@ impl AuthActivity {
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn get_input_smb_share(&self) -> String {
|
||||
match self.app.state(&Id::SmbShare) {
|
||||
Ok(State::One(StateValue::String(x))) => x,
|
||||
_ => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(super) fn get_input_smb_workgroup(&self) -> Option<String> {
|
||||
match self.app.state(&Id::SmbWorkgroup) {
|
||||
Ok(State::One(StateValue::String(x))) => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get new bookmark params
|
||||
pub(super) fn get_new_bookmark(&self) -> (String, bool) {
|
||||
let name = match self.app.state(&Id::BookmarkName) {
|
||||
@@ -873,6 +985,7 @@ impl AuthActivity {
|
||||
match self.input_mask() {
|
||||
InputMask::AwsS3 => 12,
|
||||
InputMask::Generic => 12,
|
||||
InputMask::Smb => 12,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -912,6 +1025,25 @@ impl AuthActivity {
|
||||
protocol, username, params.address, params.port
|
||||
)
|
||||
}
|
||||
#[cfg(unix)]
|
||||
ProtocolParams::Smb(params) => {
|
||||
let username: String = match params.username {
|
||||
None => String::default(),
|
||||
Some(u) => format!("{u}@"),
|
||||
};
|
||||
format!(
|
||||
"\\\\{username}{}:{}\\{}",
|
||||
params.address, params.port, params.share
|
||||
)
|
||||
}
|
||||
#[cfg(windows)]
|
||||
ProtocolParams::Smb(params) => {
|
||||
let username: String = match params.username {
|
||||
None => String::default(),
|
||||
Some(u) => format!("{u}@"),
|
||||
};
|
||||
format!("\\\\{username}{}\\{}", params.address, params.share)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -965,6 +1097,40 @@ impl AuthActivity {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_smb_view(&self) -> [Id; 4] {
|
||||
match self.app.focus() {
|
||||
Some(&Id::Address | &Id::Port | &Id::SmbShare | &Id::Username) => {
|
||||
[Id::Address, Id::Port, Id::SmbShare, Id::Username]
|
||||
}
|
||||
Some(&Id::Password) => [Id::Port, Id::SmbShare, Id::Username, Id::Password],
|
||||
Some(&Id::SmbWorkgroup) => [Id::SmbShare, Id::Username, Id::Password, Id::SmbWorkgroup],
|
||||
Some(&Id::RemoteDirectory) => [
|
||||
Id::Username,
|
||||
Id::Password,
|
||||
Id::SmbWorkgroup,
|
||||
Id::RemoteDirectory,
|
||||
],
|
||||
_ => [Id::Address, Id::Port, Id::SmbShare, Id::Username],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_smb_view(&self) -> [Id; 4] {
|
||||
match self.app.focus() {
|
||||
Some(&Id::Address | &Id::Password | &Id::SmbShare | &Id::Username) => {
|
||||
[Id::Address, Id::SmbShare, Id::Username, Id::Password]
|
||||
}
|
||||
Some(&Id::RemoteDirectory) => [
|
||||
Id::SmbShare,
|
||||
Id::Username,
|
||||
Id::Password,
|
||||
Id::RemoteDirectory,
|
||||
],
|
||||
_ => [Id::Address, Id::SmbShare, Id::Username, Id::Password],
|
||||
}
|
||||
}
|
||||
|
||||
fn init_global_listener(&mut self) {
|
||||
use tuirealm::event::{Key, KeyEvent, KeyModifiers};
|
||||
assert!(self
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use super::{FileExplorerTab, FileTransferActivity, LogLevel, Msg, PendingActionMsg};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use remotefs::File;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::{FileExplorerTab, FileTransferActivity, LogLevel, Msg, PendingActionMsg};
|
||||
|
||||
/// Describes destination for sync browsing
|
||||
enum SyncBrowsingDestination {
|
||||
|
||||
101
src/ui/activities/filetransfer/actions/chmod.rs
Normal file
101
src/ui/activities/filetransfer/actions/chmod.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use remotefs::fs::UnixPex;
|
||||
|
||||
use super::{FileTransferActivity, LogLevel};
|
||||
|
||||
impl FileTransferActivity {
|
||||
#[cfg(unix)]
|
||||
pub fn action_local_chmod(&mut self, mode: UnixPex) {
|
||||
let files = self.get_local_selected_entries().get_files();
|
||||
|
||||
for file in files {
|
||||
if let Err(err) = self.host.chmod(file.path(), mode) {
|
||||
self.log_and_alert(
|
||||
LogLevel::Error,
|
||||
format!(
|
||||
"could not change mode for {}: {}",
|
||||
file.path().display(),
|
||||
err
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
self.log(
|
||||
LogLevel::Info,
|
||||
format!("changed mode to {:#o} for {}", u32::from(mode), file.name()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn action_remote_chmod(&mut self, mode: UnixPex) {
|
||||
let files = self.get_remote_selected_entries().get_files();
|
||||
|
||||
for file in files {
|
||||
let mut metadata = file.metadata.clone();
|
||||
metadata.mode = Some(mode);
|
||||
|
||||
if let Err(err) = self.client.setstat(file.path(), metadata) {
|
||||
self.log_and_alert(
|
||||
LogLevel::Error,
|
||||
format!(
|
||||
"could not change mode for {}: {}",
|
||||
file.path().display(),
|
||||
err
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
self.log(
|
||||
LogLevel::Info,
|
||||
format!("changed mode to {:#o} for {}", u32::from(mode), file.name()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn action_find_local_chmod(&mut self, mode: UnixPex) {
|
||||
let files = self.get_found_selected_entries().get_files();
|
||||
|
||||
for file in files {
|
||||
if let Err(err) = self.host.chmod(file.path(), mode) {
|
||||
self.log_and_alert(
|
||||
LogLevel::Error,
|
||||
format!(
|
||||
"could not change mode for {}: {}",
|
||||
file.path().display(),
|
||||
err
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
self.log(
|
||||
LogLevel::Info,
|
||||
format!("changed mode to {:#o} for {}", u32::from(mode), file.name()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn action_find_remote_chmod(&mut self, mode: UnixPex) {
|
||||
let files = self.get_found_selected_entries().get_files();
|
||||
|
||||
for file in files {
|
||||
let mut metadata = file.metadata.clone();
|
||||
metadata.mode = Some(mode);
|
||||
|
||||
if let Err(err) = self.client.setstat(file.path(), metadata) {
|
||||
self.log_and_alert(
|
||||
LogLevel::Error,
|
||||
format!(
|
||||
"could not change mode for {}: {}",
|
||||
file.path().display(),
|
||||
err
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
self.log(
|
||||
LogLevel::Info,
|
||||
format!("changed mode to {:#o} for {}", u32::from(mode), file.name()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,11 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use super::{FileTransferActivity, LogLevel, SelectedFile, TransferPayload};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use remotefs::{File, RemoteErrorType};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::{FileTransferActivity, LogLevel, SelectedFile, TransferPayload};
|
||||
|
||||
impl FileTransferActivity {
|
||||
/// Copy file on local
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use super::{FileTransferActivity, LogLevel, SelectedFile};
|
||||
|
||||
use remotefs::File;
|
||||
|
||||
use super::{FileTransferActivity, LogLevel, SelectedFile};
|
||||
|
||||
impl FileTransferActivity {
|
||||
pub(crate) fn action_local_delete(&mut self) {
|
||||
match self.get_local_selected_entries() {
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use super::{FileTransferActivity, LogLevel, SelectedFile, TransferPayload};
|
||||
|
||||
// ext
|
||||
use remotefs::File;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::SystemTime;
|
||||
|
||||
// ext
|
||||
use remotefs::File;
|
||||
|
||||
use super::{FileTransferActivity, LogLevel, SelectedFile, TransferPayload};
|
||||
|
||||
impl FileTransferActivity {
|
||||
pub(crate) fn action_edit_local_file(&mut self) {
|
||||
let entries: Vec<File> = match self.get_local_selected_entries() {
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::super::browser::FileExplorerTab;
|
||||
use super::{File, FileTransferActivity, LogLevel, SelectedFile, TransferOpts, TransferPayload};
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
impl FileTransferActivity {
|
||||
pub(crate) fn action_local_find(&mut self, input: String) -> Result<Vec<File>, String> {
|
||||
match self.host.find(input.as_str()) {
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use super::{FileTransferActivity, LogLevel};
|
||||
use remotefs::fs::UnixPex;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use remotefs::fs::UnixPex;
|
||||
|
||||
use super::{FileTransferActivity, LogLevel};
|
||||
|
||||
impl FileTransferActivity {
|
||||
pub(crate) fn action_local_mkdir(&mut self, input: String) {
|
||||
match self.host.mkdir(PathBuf::from(input.as_str()).as_path()) {
|
||||
|
||||
@@ -2,15 +2,19 @@
|
||||
//!
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
pub(self) use super::{
|
||||
browser::FileExplorerTab, FileTransferActivity, Id, LogLevel, Msg, PendingActionMsg,
|
||||
TransferMsg, TransferOpts, TransferPayload, UiMsg,
|
||||
};
|
||||
use remotefs::fs::UnixPex;
|
||||
pub(self) use remotefs::File;
|
||||
use tuirealm::{State, StateValue};
|
||||
|
||||
pub(self) use super::browser::FileExplorerTab;
|
||||
pub(self) use super::{
|
||||
FileTransferActivity, Id, LogLevel, Msg, PendingActionMsg, TransferMsg, TransferOpts,
|
||||
TransferPayload, UiMsg,
|
||||
};
|
||||
|
||||
// actions
|
||||
pub(crate) mod change_dir;
|
||||
pub(crate) mod chmod;
|
||||
pub(crate) mod copy;
|
||||
pub(crate) mod delete;
|
||||
pub(crate) mod edit;
|
||||
@@ -33,6 +37,27 @@ pub(crate) enum SelectedFile {
|
||||
None,
|
||||
}
|
||||
|
||||
impl SelectedFile {
|
||||
/// Get file mode for `SelectedFile`
|
||||
/// In case is `Many` the first item mode is returned
|
||||
pub fn unix_pex(&self) -> Option<UnixPex> {
|
||||
match self {
|
||||
Self::Many(files) => files.iter().next().and_then(|file| file.metadata().mode),
|
||||
Self::One(file) => file.metadata().mode,
|
||||
Self::None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get files as vec
|
||||
pub fn get_files(self) -> Vec<File> {
|
||||
match self {
|
||||
Self::One(file) => vec![file],
|
||||
Self::Many(files) => files,
|
||||
Self::None => vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum SelectedFileIndex {
|
||||
One(usize),
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use super::{File, FileTransferActivity, LogLevel};
|
||||
use std::fs::File as StdFile;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::{File, FileTransferActivity, LogLevel};
|
||||
|
||||
impl FileTransferActivity {
|
||||
pub(crate) fn action_local_newfile(&mut self, input: String) {
|
||||
// Check if file exists
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use super::{File, FileTransferActivity, LogLevel, SelectedFile, TransferPayload};
|
||||
// ext
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::{File, FileTransferActivity, LogLevel, SelectedFile, TransferPayload};
|
||||
|
||||
impl FileTransferActivity {
|
||||
/// Open local file
|
||||
pub(crate) fn action_open_local(&mut self) {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//! this little module exposes the routine to create a pending action on the file transfer activity.
|
||||
//! A pending action is an action which blocks the execution of the application in await of a certain `Msg`.
|
||||
|
||||
use super::{FileTransferActivity, Msg};
|
||||
|
||||
use tuirealm::{PollStrategy, Update};
|
||||
|
||||
use super::{FileTransferActivity, Msg};
|
||||
|
||||
impl FileTransferActivity {
|
||||
/// Block execution of activity, preventing ANY kind of message not specified in the `wait_for` argument.
|
||||
/// Once `wait_for` clause is satisfied, the function returns.
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use super::{File, FileTransferActivity, LogLevel, SelectedFile};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use remotefs::RemoteErrorType;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::{File, FileTransferActivity, LogLevel, SelectedFile};
|
||||
|
||||
impl FileTransferActivity {
|
||||
pub(crate) fn action_local_rename(&mut self, input: String) {
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::{
|
||||
File, FileTransferActivity, LogLevel, Msg, PendingActionMsg, SelectedFile, TransferOpts,
|
||||
TransferPayload,
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
impl FileTransferActivity {
|
||||
pub(crate) fn action_local_saveas(&mut self, input: String) {
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
// locals
|
||||
use super::{FileTransferActivity, LogLevel, SelectedFile};
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::{FileTransferActivity, LogLevel, SelectedFile};
|
||||
|
||||
impl FileTransferActivity {
|
||||
/// Create symlink on localhost
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
pub(crate) fn action_local_symlink(&mut self, name: String) {
|
||||
if let SelectedFile::One(entry) = self.get_local_selected_entries() {
|
||||
match self
|
||||
@@ -33,7 +33,7 @@ impl FileTransferActivity {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_family = "windows")]
|
||||
#[cfg(windows)]
|
||||
pub(crate) fn action_local_symlink(&mut self, _name: String) {
|
||||
self.mount_error("Symlinks are not supported on Windows hosts");
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
//!
|
||||
//! actions associated to the file watcher
|
||||
|
||||
use super::{FileTransferActivity, LogLevel, Msg, SelectedFile, TransferMsg, UiMsg};
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::{FileTransferActivity, LogLevel, Msg, SelectedFile, TransferMsg, UiMsg};
|
||||
|
||||
impl FileTransferActivity {
|
||||
pub fn action_show_radio_watch(&mut self) {
|
||||
// return if fswatcher is not working
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
//!
|
||||
//! log tab component
|
||||
|
||||
use super::{Msg, UiMsg};
|
||||
|
||||
use tuirealm::command::{Cmd, CmdResult, Direction, Position};
|
||||
use tuirealm::event::{Key, KeyEvent};
|
||||
use tuirealm::props::{Alignment, AttrValue, Attribute, Borders, Color, Style, Table};
|
||||
@@ -11,6 +9,8 @@ use tuirealm::tui::layout::Corner;
|
||||
use tuirealm::tui::widgets::{List as TuiList, ListItem, ListState};
|
||||
use tuirealm::{Component, Event, MockComponent, NoUserEvent, Props, State, StateValue};
|
||||
|
||||
use super::{Msg, UiMsg};
|
||||
|
||||
pub struct Log {
|
||||
props: Props,
|
||||
states: OwnStates,
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
//!
|
||||
//! file transfer activity components
|
||||
|
||||
use super::Msg;
|
||||
|
||||
use tui_realm_stdlib::Span;
|
||||
use tuirealm::props::{Color, TextSpan};
|
||||
use tuirealm::{Component, Event, MockComponent, NoUserEvent};
|
||||
|
||||
use super::Msg;
|
||||
|
||||
#[derive(MockComponent)]
|
||||
pub struct FooterBar {
|
||||
component: Span,
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
//!
|
||||
//! file transfer activity components
|
||||
|
||||
use super::{Msg, PendingActionMsg, TransferMsg, UiMsg};
|
||||
|
||||
use tui_realm_stdlib::Phantom;
|
||||
use tuirealm::{
|
||||
event::{Event, Key, KeyEvent, KeyModifiers},
|
||||
Component, MockComponent, NoUserEvent,
|
||||
};
|
||||
use tuirealm::event::{Event, Key, KeyEvent, KeyModifiers};
|
||||
use tuirealm::{Component, MockComponent, NoUserEvent};
|
||||
|
||||
use super::{Msg, PendingActionMsg, TransferMsg, UiMsg};
|
||||
|
||||
// -- export
|
||||
mod log;
|
||||
@@ -16,17 +14,18 @@ mod misc;
|
||||
mod popups;
|
||||
mod transfer;
|
||||
|
||||
pub use self::log::Log;
|
||||
pub use misc::FooterBar;
|
||||
pub use popups::{
|
||||
CopyPopup, DeletePopup, DisconnectPopup, ErrorPopup, ExecPopup, FatalPopup, FileInfoPopup,
|
||||
FindPopup, GoToPopup, KeybindingsPopup, MkdirPopup, NewfilePopup, OpenWithPopup,
|
||||
ChmodPopup, CopyPopup, DeletePopup, DisconnectPopup, ErrorPopup, ExecPopup, FatalPopup,
|
||||
FileInfoPopup, FindPopup, GoToPopup, KeybindingsPopup, MkdirPopup, NewfilePopup, OpenWithPopup,
|
||||
ProgressBarFull, ProgressBarPartial, QuitPopup, RenamePopup, ReplacePopup,
|
||||
ReplacingFilesListPopup, SaveAsPopup, SortingPopup, StatusBarLocal, StatusBarRemote,
|
||||
SymlinkPopup, SyncBrowsingMkdirPopup, WaitPopup, WatchedPathsList, WatcherPopup,
|
||||
};
|
||||
pub use transfer::{ExplorerFind, ExplorerLocal, ExplorerRemote};
|
||||
|
||||
pub use self::log::Log;
|
||||
|
||||
#[derive(Default, MockComponent)]
|
||||
pub struct GlobalListener {
|
||||
component: Phantom,
|
||||
|
||||
@@ -2,15 +2,10 @@
|
||||
//!
|
||||
//! popups components
|
||||
|
||||
use super::super::Browser;
|
||||
use super::{Msg, PendingActionMsg, TransferMsg, UiMsg};
|
||||
use crate::explorer::FileSorting;
|
||||
use crate::utils::fmt::fmt_time;
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
use bytesize::ByteSize;
|
||||
use remotefs::File;
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
use tui_realm_stdlib::{Input, List, Paragraph, ProgressBar, Radio, Span};
|
||||
use tuirealm::command::{Cmd, CmdResult, Direction, Position};
|
||||
use tuirealm::event::{Key, KeyEvent, KeyModifiers};
|
||||
@@ -18,9 +13,18 @@ use tuirealm::props::{
|
||||
Alignment, BorderSides, BorderType, Borders, Color, InputType, Style, TableBuilder, TextSpan,
|
||||
};
|
||||
use tuirealm::{Component, Event, MockComponent, NoUserEvent, State, StateValue};
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
use users::{get_group_by_gid, get_user_by_uid};
|
||||
|
||||
use super::super::Browser;
|
||||
use super::{Msg, PendingActionMsg, TransferMsg, UiMsg};
|
||||
use crate::explorer::FileSorting;
|
||||
use crate::utils::fmt::fmt_time;
|
||||
|
||||
mod chmod;
|
||||
|
||||
pub use chmod::ChmodPopup;
|
||||
|
||||
#[derive(MockComponent)]
|
||||
pub struct CopyPopup {
|
||||
component: Input,
|
||||
@@ -441,7 +445,7 @@ impl FileInfoPopup {
|
||||
.add_col(TextSpan::from("Last access time: "))
|
||||
.add_col(TextSpan::new(atime.as_str()).fg(Color::LightRed));
|
||||
// User
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
let username: String = match file.metadata().uid {
|
||||
Some(uid) => match get_user_by_uid(uid) {
|
||||
Some(user) => user.name().to_string_lossy().to_string(),
|
||||
@@ -449,10 +453,10 @@ impl FileInfoPopup {
|
||||
},
|
||||
None => String::from("0"),
|
||||
};
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
let username: String = format!("{}", file.metadata().uid.unwrap_or(0));
|
||||
// Group
|
||||
#[cfg(target_family = "unix")]
|
||||
#[cfg(unix)]
|
||||
let group: String = match file.metadata().gid {
|
||||
Some(gid) => match get_group_by_gid(gid) {
|
||||
Some(group) => group.name().to_string_lossy().to_string(),
|
||||
@@ -460,7 +464,7 @@ impl FileInfoPopup {
|
||||
},
|
||||
None => String::from("0"),
|
||||
};
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
let group: String = format!("{}", file.metadata().gid.unwrap_or(0));
|
||||
texts
|
||||
.add_row()
|
||||
@@ -746,6 +750,8 @@ impl KeybindingsPopup {
|
||||
.add_col(TextSpan::from(
|
||||
" Open text file with preferred editor",
|
||||
))
|
||||
.add_col(TextSpan::new("<P>").bold().fg(key_color))
|
||||
.add_col(TextSpan::from(" Toggle log panel"))
|
||||
.add_row()
|
||||
.add_col(TextSpan::new("<Q|F10>").bold().fg(key_color))
|
||||
.add_col(TextSpan::from(" Quit termscp"))
|
||||
@@ -779,6 +785,8 @@ impl KeybindingsPopup {
|
||||
.add_col(TextSpan::from(
|
||||
" Toggle synchronized browsing",
|
||||
))
|
||||
.add_col(TextSpan::new("<Z>").bold().fg(key_color))
|
||||
.add_col(TextSpan::from(" Change file permissions"))
|
||||
.add_row()
|
||||
.add_col(TextSpan::new("<DEL|F8|E>").bold().fg(key_color))
|
||||
.add_col(TextSpan::from(" Delete selected file"))
|
||||
|
||||
267
src/ui/activities/filetransfer/components/popups/chmod.rs
Normal file
267
src/ui/activities/filetransfer/components/popups/chmod.rs
Normal file
@@ -0,0 +1,267 @@
|
||||
use remotefs::fs::{UnixPex, UnixPexClass};
|
||||
use tui_realm_stdlib::Checkbox;
|
||||
use tuirealm::command::{Cmd, CmdResult, Direction};
|
||||
use tuirealm::event::{Key, KeyEvent};
|
||||
use tuirealm::props::{Alignment, AttrValue, Attribute, BorderSides, Borders, Color};
|
||||
use tuirealm::tui::layout::{Constraint, Direction as LayoutDirection, Layout};
|
||||
use tuirealm::{Component, Event, MockComponent, NoUserEvent, Props, State, StateValue};
|
||||
|
||||
use super::{Msg, TransferMsg, UiMsg};
|
||||
|
||||
#[derive(Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Item {
|
||||
#[default]
|
||||
User,
|
||||
Group,
|
||||
Others,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct States {
|
||||
focus: Item,
|
||||
}
|
||||
|
||||
/// Permissions popup for chmod command
|
||||
pub struct ChmodPopup {
|
||||
props: Props,
|
||||
states: States,
|
||||
title: String,
|
||||
color: Color,
|
||||
user: Checkbox,
|
||||
group: Checkbox,
|
||||
others: Checkbox,
|
||||
}
|
||||
|
||||
/// Make checkbox values from unix pex class
|
||||
fn make_pex_values(mode: UnixPexClass) -> Vec<usize> {
|
||||
let mut values = Vec::with_capacity(3);
|
||||
if mode.read() {
|
||||
values.push(0);
|
||||
}
|
||||
if mode.write() {
|
||||
values.push(1);
|
||||
}
|
||||
if mode.execute() {
|
||||
values.push(2);
|
||||
}
|
||||
|
||||
values
|
||||
}
|
||||
|
||||
impl ChmodPopup {
|
||||
pub fn new(pex: UnixPex, color: Color, title: String) -> Self {
|
||||
Self {
|
||||
props: Props::default(),
|
||||
color,
|
||||
title,
|
||||
states: States {
|
||||
focus: Item::default(),
|
||||
},
|
||||
user: Checkbox::default()
|
||||
.foreground(color)
|
||||
.choices(&["Read", "Write", "Execute"])
|
||||
.title("User", Alignment::Left)
|
||||
.borders(Borders::default().sides(BorderSides::NONE))
|
||||
.values(&make_pex_values(pex.user()))
|
||||
.rewind(true),
|
||||
group: Checkbox::default()
|
||||
.foreground(color)
|
||||
.choices(&["Read", "Write", "Execute"])
|
||||
.title("Group", Alignment::Left)
|
||||
.borders(Borders::default().sides(BorderSides::NONE))
|
||||
.values(&make_pex_values(pex.group()))
|
||||
.rewind(true),
|
||||
others: Checkbox::default()
|
||||
.foreground(color)
|
||||
.choices(&["Read", "Write", "Execute"])
|
||||
.title("Others", Alignment::Left)
|
||||
.borders(Borders::default().sides(BorderSides::NONE))
|
||||
.values(&make_pex_values(pex.others()))
|
||||
.rewind(true),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_active_checkbox(&mut self) -> &'_ mut Checkbox {
|
||||
match self.states.focus {
|
||||
Item::Group => &mut self.group,
|
||||
Item::Others => &mut self.others,
|
||||
Item::User => &mut self.user,
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_checkbox_focus(&mut self, value: bool) {
|
||||
match self.states.focus {
|
||||
Item::User => self.user.attr(Attribute::Focus, AttrValue::Flag(value)),
|
||||
Item::Group => self.group.attr(Attribute::Focus, AttrValue::Flag(value)),
|
||||
Item::Others => self.others.attr(Attribute::Focus, AttrValue::Flag(value)),
|
||||
}
|
||||
}
|
||||
|
||||
fn active_checkbox_up(&mut self) {
|
||||
self.toggle_checkbox_focus(false);
|
||||
let next = match self.states.focus {
|
||||
Item::User => Item::Others,
|
||||
Item::Group => Item::User,
|
||||
Item::Others => Item::Group,
|
||||
};
|
||||
|
||||
self.states.focus = next;
|
||||
|
||||
self.toggle_checkbox_focus(true);
|
||||
}
|
||||
|
||||
fn active_checkbox_down(&mut self) {
|
||||
self.toggle_checkbox_focus(false);
|
||||
let next = match self.states.focus {
|
||||
Item::User => Item::Group,
|
||||
Item::Group => Item::Others,
|
||||
Item::Others => Item::User,
|
||||
};
|
||||
|
||||
self.states.focus = next;
|
||||
|
||||
self.toggle_checkbox_focus(true);
|
||||
}
|
||||
|
||||
fn checkbox_state_to_pex_class(state: State) -> UnixPexClass {
|
||||
let values: Vec<usize> = state
|
||||
.unwrap_vec()
|
||||
.into_iter()
|
||||
.map(|x| x.unwrap_usize())
|
||||
.collect();
|
||||
|
||||
UnixPexClass::new(
|
||||
values.contains(&0),
|
||||
values.contains(&1),
|
||||
values.contains(&2),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_mode(&self) -> UnixPex {
|
||||
UnixPex::new(
|
||||
Self::checkbox_state_to_pex_class(self.user.state()),
|
||||
Self::checkbox_state_to_pex_class(self.group.state()),
|
||||
Self::checkbox_state_to_pex_class(self.others.state()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl MockComponent for ChmodPopup {
|
||||
fn attr(&mut self, attr: tuirealm::Attribute, value: AttrValue) {
|
||||
self.props.set(attr, value.clone());
|
||||
|
||||
if attr == Attribute::Focus {
|
||||
self.get_active_checkbox().attr(attr, value);
|
||||
} else {
|
||||
self.user.attr(attr, value.clone());
|
||||
self.group.attr(attr, value.clone());
|
||||
self.others.attr(attr, value);
|
||||
}
|
||||
}
|
||||
|
||||
fn perform(&mut self, cmd: Cmd) -> CmdResult {
|
||||
match cmd {
|
||||
Cmd::Move(Direction::Left) | Cmd::Move(Direction::Right) => {
|
||||
self.get_active_checkbox().perform(cmd)
|
||||
}
|
||||
Cmd::Move(Direction::Up) => {
|
||||
self.active_checkbox_up();
|
||||
CmdResult::None
|
||||
}
|
||||
Cmd::Move(Direction::Down) => {
|
||||
self.active_checkbox_down();
|
||||
CmdResult::None
|
||||
}
|
||||
Cmd::Toggle => self.get_active_checkbox().perform(cmd),
|
||||
Cmd::Submit => CmdResult::Submit(self.state()),
|
||||
_ => CmdResult::None,
|
||||
}
|
||||
}
|
||||
|
||||
fn query(&self, attr: tuirealm::Attribute) -> Option<AttrValue> {
|
||||
self.props.get(attr)
|
||||
}
|
||||
|
||||
fn state(&self) -> State {
|
||||
State::One(StateValue::U32(self.get_mode().into()))
|
||||
}
|
||||
|
||||
fn view(&mut self, frame: &mut tuirealm::Frame, area: tuirealm::tui::layout::Rect) {
|
||||
if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) != AttrValue::Flag(true) {
|
||||
return;
|
||||
}
|
||||
let chunks = Layout::default()
|
||||
.direction(LayoutDirection::Vertical)
|
||||
.margin(1)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length(3),
|
||||
Constraint::Length(3),
|
||||
Constraint::Length(3),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(area);
|
||||
|
||||
let focus = self
|
||||
.props
|
||||
.get_or(Attribute::Focus, AttrValue::Flag(false))
|
||||
.unwrap_flag();
|
||||
|
||||
let div = tui_realm_stdlib::utils::get_block(
|
||||
Borders::default().color(self.color),
|
||||
Some((self.title.clone(), Alignment::Center)),
|
||||
focus,
|
||||
None,
|
||||
);
|
||||
|
||||
frame.render_widget(div, area);
|
||||
|
||||
self.user.view(frame, chunks[0]);
|
||||
self.group.view(frame, chunks[1]);
|
||||
self.others.view(frame, chunks[2]);
|
||||
}
|
||||
}
|
||||
|
||||
impl Component<Msg, NoUserEvent> for ChmodPopup {
|
||||
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||
match ev {
|
||||
Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => {
|
||||
Some(Msg::Ui(UiMsg::CloseChmodPopup))
|
||||
}
|
||||
Event::Keyboard(KeyEvent {
|
||||
code: Key::Left, ..
|
||||
}) => {
|
||||
self.perform(Cmd::Move(Direction::Left));
|
||||
Some(Msg::None)
|
||||
}
|
||||
Event::Keyboard(KeyEvent {
|
||||
code: Key::Right, ..
|
||||
}) => {
|
||||
self.perform(Cmd::Move(Direction::Right));
|
||||
Some(Msg::None)
|
||||
}
|
||||
Event::Keyboard(KeyEvent { code: Key::Up, .. }) => {
|
||||
self.perform(Cmd::Move(Direction::Up));
|
||||
Some(Msg::None)
|
||||
}
|
||||
Event::Keyboard(KeyEvent {
|
||||
code: Key::Down, ..
|
||||
}) => {
|
||||
self.perform(Cmd::Move(Direction::Down));
|
||||
Some(Msg::None)
|
||||
}
|
||||
Event::Keyboard(KeyEvent {
|
||||
code: Key::Char(' '),
|
||||
..
|
||||
}) => {
|
||||
self.perform(Cmd::Toggle);
|
||||
Some(Msg::None)
|
||||
}
|
||||
Event::Keyboard(KeyEvent {
|
||||
code: Key::Enter, ..
|
||||
}) => Some(Msg::Transfer(TransferMsg::Chmod(self.get_mode()))),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ use super::{Msg, TransferMsg, UiMsg};
|
||||
|
||||
mod file_list;
|
||||
use file_list::FileList;
|
||||
|
||||
use tuirealm::command::{Cmd, Direction, Position};
|
||||
use tuirealm::event::{Key, KeyEvent, KeyModifiers};
|
||||
use tuirealm::props::{Alignment, Borders, Color, TextSpan};
|
||||
@@ -128,6 +127,10 @@ impl Component<Msg, NoUserEvent> for ExplorerFind {
|
||||
code: Key::Char('w'),
|
||||
modifiers: KeyModifiers::NONE,
|
||||
}) => Some(Msg::Ui(UiMsg::ShowOpenWithPopup)),
|
||||
Event::Keyboard(KeyEvent {
|
||||
code: Key::Char('z'),
|
||||
modifiers: KeyModifiers::NONE,
|
||||
}) => Some(Msg::Ui(UiMsg::ShowChmodPopup)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -309,6 +312,10 @@ impl Component<Msg, NoUserEvent> for ExplorerLocal {
|
||||
code: Key::Char('w'),
|
||||
modifiers: KeyModifiers::NONE,
|
||||
}) => Some(Msg::Ui(UiMsg::ShowOpenWithPopup)),
|
||||
Event::Keyboard(KeyEvent {
|
||||
code: Key::Char('z'),
|
||||
modifiers: KeyModifiers::NONE,
|
||||
}) => Some(Msg::Ui(UiMsg::ShowChmodPopup)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -490,6 +497,10 @@ impl Component<Msg, NoUserEvent> for ExplorerRemote {
|
||||
code: Key::Char('w'),
|
||||
modifiers: KeyModifiers::NONE,
|
||||
}) => Some(Msg::Ui(UiMsg::ShowOpenWithPopup)),
|
||||
Event::Keyboard(KeyEvent {
|
||||
code: Key::Char('z'),
|
||||
modifiers: KeyModifiers::NONE,
|
||||
}) => Some(Msg::Ui(UiMsg::ShowChmodPopup)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::path::Path;
|
||||
|
||||
use super::{FileTransferActivity, LogLevel, TransferPayload};
|
||||
use crate::system::watcher::FsChange;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
impl FileTransferActivity {
|
||||
/// poll file watcher
|
||||
pub(super) fn poll_watcher(&mut self) {
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
//!
|
||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||
|
||||
use crate::explorer::{builder::FileExplorerBuilder, FileExplorer, FileSorting, GroupDirs};
|
||||
use crate::system::config_client::ConfigClient;
|
||||
use std::path::Path;
|
||||
|
||||
use remotefs::File;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::explorer::builder::FileExplorerBuilder;
|
||||
use crate::explorer::{FileExplorer, FileSorting, GroupDirs};
|
||||
use crate::system::config_client::ConfigClient;
|
||||
|
||||
/// File explorer tab
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user