diff --git a/CHANGELOG.md b/CHANGELOG.md index dfba0f2..9c1abbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,13 +28,20 @@ Released on ?? > 🍁 Autumn update πŸ‡ - **Aws S3** - - Added support for the aws-s3 protocol - - Operate on your bucket directly from the file explorer - - You can also save your buckets as bookmarks + - Added support for the aws-s3 protocol. + - Operate on your bucket directly from the file explorer. + - You can also save your buckets as bookmarks. - Aws s3 reads credentials directly from your credentials file at `$HOME/.aws/credentials` or from environment. Read more in the user manual. +- **Auto update** ⬇️ + - Possibility to update termscp directly via GUI or CLI. + - Install update via CLI running `(sudo) termscp --update`. + - Install update via GUI from auth form: when the "new version message" is displayed press ``, then enter `YES` in the radio input asking whether to install the update. - Dependencies: + - Added `rust-s3 0.27-rc4` + - Added `self_update 0.27.0` - Updated `argh` to `0.1.6` - Updated `tui-realm-stdlib` to `0.6.2` + - Removed `ureq` ## 0.6.1 diff --git a/Cargo.lock b/Cargo.lock index d00746f..1236ac0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aes" version = "0.6.0" @@ -263,12 +269,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "chunked_transfer" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" - [[package]] name = "cipher" version = "0.2.5" @@ -287,6 +287,21 @@ dependencies = [ "bitflags", ] +[[package]] +name = "console" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "regex", + "terminal_size", + "unicode-width", + "winapi", +] + [[package]] name = "content_inspector" version = "0.2.4" @@ -346,6 +361,15 @@ dependencies = [ "debug-helper", ] +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crossterm" version = "0.20.0" @@ -477,6 +501,45 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "filetime" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.10", + "winapi", +] + +[[package]] +name = "flate2" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80edafed416a46fb378521624fab1cfa2eb514784fd8921adbe8a8d8321da811" +dependencies = [ + "cfg-if 1.0.0", + "crc32fast", + "libc", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -508,12 +571,55 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures-channel" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +dependencies = [ + "futures-core", +] + [[package]] name = "futures-core" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +[[package]] +name = "futures-io" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" + +[[package]] +name = "futures-sink" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" + +[[package]] +name = "futures-task" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" + +[[package]] +name = "futures-util" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +dependencies = [ + "autocfg", + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.4" @@ -546,6 +652,25 @@ dependencies = [ "wasi 0.10.0+wasi-snapshot-preview1", ] +[[package]] +name = "h2" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f3675cfef6a30c8031cf9e6493ebdc3bb3272a3fea3923c4210d1830e6a472" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.9.1" @@ -555,6 +680,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + [[package]] name = "heck" version = "0.3.3" @@ -564,6 +695,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" @@ -612,6 +752,66 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" + +[[package]] +name = "httpdate" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" + +[[package]] +name = "hyper" +version = "0.14.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13f67199e765030fa08fe0bd581af683f0d5bc04ea09c2b1102012c5fb90e7fd" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "idna" version = "0.2.3" @@ -623,6 +823,28 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown 0.11.2", +] + +[[package]] +name = "indicatif" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7baab56125e25686df467fe470785512329883aab42696d661247aca2a2896e4" +dependencies = [ + "console", + "lazy_static", + "number_prefix", + "regex", +] + [[package]] name = "instant" version = "0.1.10" @@ -632,6 +854,12 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "ipnet" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" + [[package]] name = "itoa" version = "0.4.8" @@ -787,6 +1015,12 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + [[package]] name = "minidom" version = "0.13.0" @@ -796,6 +1030,16 @@ dependencies = [ "quick-xml", ] +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + [[package]] name = "mio" version = "0.7.13" @@ -921,6 +1165,22 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a" + [[package]] name = "once_cell" version = "1.8.0" @@ -983,7 +1243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" dependencies = [ "dlv-list", - "hashbrown", + "hashbrown 0.9.1", ] [[package]] @@ -1062,12 +1322,27 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "pin-project-lite" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkg-config" version = "0.3.19" @@ -1252,18 +1527,38 @@ dependencies = [ ] [[package]] -name = "ring" -version = "0.16.20" +name = "reqwest" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22" dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", "web-sys", - "winapi", + "winreg", ] [[package]] @@ -1316,19 +1611,6 @@ dependencies = [ "url", ] -[[package]] -name = "rustls" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" -dependencies = [ - "base64", - "log", - "ring", - "sct", - "webpki", -] - [[package]] name = "ryu" version = "1.0.5" @@ -1351,16 +1633,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "sct" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "secret-service" version = "1.1.3" @@ -1423,6 +1695,45 @@ dependencies = [ "libc", ] +[[package]] +name = "self_update" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb85f1802f7b987237b8525c0fde86ea86f31c957c1875467c727d5b921179c" +dependencies = [ + "either", + "flate2", + "hyper", + "indicatif", + "log", + "quick-xml", + "regex", + "reqwest", + "semver", + "serde_json", + "tar", + "tempfile", + "zip", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.130" @@ -1466,6 +1777,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.9.8" @@ -1520,6 +1843,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "slab" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" + [[package]] name = "smallvec" version = "1.6.1" @@ -1533,10 +1862,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" [[package]] -name = "spin" -version = "0.5.2" +name = "socket2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad" +dependencies = [ + "libc", + "winapi", +] [[package]] name = "ssh2" @@ -1580,6 +1913,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tar" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f5515d3add52e0bbdcad7b83c388bb36ba7b754dda3b5f5bc2d38640cdba5c" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.2.0" @@ -1603,6 +1947,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "termscp" version = "0.7.0" @@ -1627,6 +1981,7 @@ dependencies = [ "regex", "rpassword", "rust-s3", + "self_update", "serde", "simplelog", "ssh2", @@ -1637,7 +1992,6 @@ dependencies = [ "toml", "tui-realm-stdlib", "tuirealm", - "ureq", "users", "whoami", "wildmatch 2.1.0", @@ -1718,7 +2072,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4efe6fc2395938c8155973d7be49fe8d03a843726e285e100a8a383cc0154ce" dependencies = [ "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", "pin-project-lite", + "winapi", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", ] [[package]] @@ -1732,6 +2102,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-util" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.5.8" @@ -1741,6 +2125,38 @@ dependencies = [ "serde", ] +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ca517f43f0fb96e0c3072ed5c275fe5eece87e8cb52f4a77b69226d3b1c9df8" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + [[package]] name = "tui" version = "0.16.0" @@ -1781,6 +2197,12 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-bidi" version = "0.3.6" @@ -1823,30 +2245,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "ureq" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3131cd6cb18488da91da1d10ed31e966f453c06b65bf010d35638456976a3fd7" -dependencies = [ - "base64", - "chunked_transfer", - "log", - "once_cell", - "rustls", - "serde", - "serde_json", - "url", - "webpki", - "webpki-roots", -] - [[package]] name = "url" version = "2.2.2" @@ -1881,6 +2279,16 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -1900,6 +2308,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e68338db6becec24d3c7977b5bf8a48be992c934b5d07177e3931f5dc9b076c" dependencies = [ "cfg-if 1.0.0", + "serde", + "serde_json", "wasm-bindgen-macro", ] @@ -1918,6 +2328,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fded345a6559c2cfee778d562300c581f7d4ff3edb9b0d230d69800d213972" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.77" @@ -1957,25 +2379,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" -dependencies = [ - "webpki", -] - [[package]] name = "which" version = "4.2.2" @@ -2040,8 +2443,39 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi", +] + +[[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +dependencies = [ + "libc", +] + [[package]] name = "xml-rs" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + +[[package]] +name = "zip" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" +dependencies = [ + "byteorder", + "crc32fast", + "flate2", + "thiserror", + "time", +] diff --git a/Cargo.toml b/Cargo.toml index 91c18a9..ac0e6b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ rand = "0.8.4" regex = "1.5.4" rpassword = "5.0.1" rust-s3 = { version = "0.27.0-rc4", default-features = false, features = [ "sync-native-tls", "sync" ] } +self_update = { version = "0.27.0", features = [ "archive-tar", "archive-zip", "compression-flate2", "compression-zip-deflate" ] } serde = { version = "^1.0.0", features = [ "derive" ] } simplelog = "0.10.0" ssh2 = "0.9.0" @@ -55,7 +56,6 @@ thiserror = "^1.0.0" toml = "0.5.8" tui-realm-stdlib = "0.6.2" tuirealm = "0.6.0" -ureq = { version = "2.1.0", features = [ "json" ] } whoami = "1.1.1" wildmatch = "2.0.0" diff --git a/README.md b/README.md index 3d2b535..412cec9 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ ## About termscp πŸ–₯ -Termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/S3. So basically is a terminal utility with an TUI to connect to a remote server to retrieve and upload files and to interact with the local file system. It is **Linux**, **MacOS**, **BSD** and **Windows** compatible and supports SFTP, SCP, FTP, FTPS and S3. +Termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/S3. So basically is a terminal utility with an TUI to connect to a remote server to retrieve and upload files and to interact with the local file system. It is **Linux**, **MacOS**, **FreeBSD** and **Windows** compatible and supports SFTP, SCP, FTP, FTPS and S3. ![Explorer](assets/images/explorer.gif) @@ -33,10 +33,10 @@ Termscp is a feature rich terminal file transfer and explorer, with support for ## Features 🎁 - πŸ“ Different communication protocols - - SFTP - - SCP - - FTP and FTPS - - Aws S3 + - **SFTP** + - **SCP** + - **FTP** and **FTPS** + - **Aws S3** - πŸ–₯ 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 @@ -71,6 +71,8 @@ while if you're a Windows user, you can install termscp with [Chocolatey](https: For more information or other platforms, please visit [veeso.github.io](https://veeso.github.io/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` ⚠️ + ### Requirements ❗ - **Linux** users: @@ -157,6 +159,7 @@ termscp is powered by these aweseome projects: - [open-rs](https://github.com/Byron/open-rs) - [rpassword](https://github.com/conradkleinespel/rpassword) - [rust-s3](https://github.com/durch/rust-s3) +- [self_update](https://github.com/jaemk/self_update) - [ssh2-rs](https://github.com/alexcrichton/ssh2-rs) - [suppaftp](https://github.com/veeso/suppaftp) - [textwrap](https://github.com/mgeisler/textwrap) diff --git a/dist/build/deploy.sh b/dist/build/docker.sh similarity index 72% rename from dist/build/deploy.sh rename to dist/build/docker.sh index 89f836d..237c8e2 100755 --- a/dist/build/deploy.sh +++ b/dist/build/docker.sh @@ -1,7 +1,7 @@ #!/bin/bash if [ -z "$1" ]; then - echo "Usage: deploy.sh " + echo "Usage: docker.sh " exit 1 fi @@ -19,8 +19,15 @@ cd x86_64_debian9/ docker build --tag termscp-${VERSION}-x86_64_debian9 . cd - mkdir -p ${PKGS_DIR}/deb/ +mkdir -p ${PKGS_DIR}/x86_64-unknown-linux-gnu/ CONTAINER_NAME=$(docker create termscp-${VERSION}-x86_64_debian9 termscp-${VERSION}-x86_64_debian9) docker cp ${CONTAINER_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}_amd64.deb ${PKGS_DIR}/deb/ +docker cp ${CONTAINER_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/x86_64-unknown-linux-gnu/ +# Make tar.gz +cd ${PKGS_DIR}/x84_64-unknown-linux-gnu/ +tar cvzf termscp-v${VERSION}-x86_64-unknown-linux-gnu.tar.gz termscp +rm termscp +cd - # Build x86_64_centos7 cd x86_64_centos7/ docker build --tag termscp-${VERSION}-x86_64_centos7 . diff --git a/dist/build/freebsd.sh b/dist/build/freebsd.sh new file mode 100755 index 0000000..753b8e9 --- /dev/null +++ b/dist/build/freebsd.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +if [ -z "$1" ]; then + echo "Usage: freebsd.sh " + exit 1 +fi + +VERSION=$1 + +set -e # Don't fail + +# Go to root dir +cd ../../ +# Check if in correct directory +if [ ! -f Cargo.toml ]; then + echo "Please start freebsd.sh from dist/build/ directory" + exit 1 +fi + +# Build release +cargo build --release && cargo strip +# Make pkg +cd target/release/ +PKG="termscp-v${VERSION}-x86_64-unknown-freebsd.tar.gz" +tar czf $PKG termscp +sha256sum $PKG +mkdir -p ../../dist/pkgs/freebsd/ +mv $PKG ../../dist/pkgs/freebsd/$PKG + +exit $? diff --git a/dist/build/macos.sh b/dist/build/macos.sh new file mode 100755 index 0000000..37dab50 --- /dev/null +++ b/dist/build/macos.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +if [ -z "$1" ]; then + echo "Usage: macos.sh " + exit 1 +fi + +VERSION=$1 + +set -e # Don't fail + +# Go to root dir +cd ../../ +# Check if in correct directory +if [ ! -f Cargo.toml ]; then + echo "Please start macos.sh from dist/build/ directory" + exit 1 +fi + +# Build release +cargo build --release && cargo strip +# Make pkg +cd target/release/ +PKG="termscp-v${VERSION}-x86_64-apple-darwin.tar.gz" +tar czf $PKG termscp +sha256sum $PKG +mkdir -p ../../dist/pkgs/macos/ +mv $PKG ../../dist/pkgs/macos/$PKG + +exit $? diff --git a/dist/build/windows.ps1 b/dist/build/windows.ps1 new file mode 100755 index 0000000..419bd90 --- /dev/null +++ b/dist/build/windows.ps1 @@ -0,0 +1,20 @@ +$ErrorActionPreference = 'Stop'; + +if ($args.Count -eq 0) { + Write-Output "Usage: windows.ps1 " + exit 1 +} + +$version = $args[0] + +# Go to root directory +Set-Location ..\..\ +# Build +cargo build --release +# Make zip +$zipName = "termscp-v$version-x86_64-pc-windows-msvc.zip" +Set-Location .\target\release\ +Compress-Archive termscp $zipName +# Get checksum +checksum.exe -t sha256 $zipName +Move-Item $zipName .\..\..\dist\pkgs\windows\$zipName diff --git a/dist/build/x86_64/Dockerfile b/dist/build/x86_64/Dockerfile index e776f22..38b3849 100644 --- a/dist/build/x86_64/Dockerfile +++ b/dist/build/x86_64/Dockerfile @@ -4,16 +4,21 @@ WORKDIR /usr/src/ # Add toolchains RUN rustup target add x86_64-unknown-linux-gnu # Install dependencies -RUN apt update && apt install -y rpm +RUN apt update && apt install -y \ + git \ + gcc \ + pkg-config \ + libssl-dev \ + libssh2-1-dev \ + libdbus-1-dev \ + curl # Clone repository RUN git clone https://github.com/veeso/termscp.git # Set workdir to termscp WORKDIR /usr/src/termscp/ # Install cargo RPM/Deb -RUN cargo install cargo-deb cargo-rpm cargo-strip +RUN cargo install cargo-strip # Build for x86_64 RUN cargo build --release --target x86_64-unknown-linux-gnu && cargo strip -# Build pkgs -RUN cargo deb && cargo rpm init && cargo rpm build CMD ["sh"] diff --git a/docs/man.md b/docs/man.md index d635fae..07d4012 100644 --- a/docs/man.md +++ b/docs/man.md @@ -37,6 +37,7 @@ termscp can be started with the following options: - `-c, --config` Open termscp starting from the configuration page - `-q, --quiet` Disable logging - `-t, --theme ` Import specified theme +- `-u, --update` Update termscp to latest version - `-v, --version` Print version info - `-h, --help` Print help page diff --git a/src/lib.rs b/src/lib.rs index 40475e5..4e9aa6c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,13 +53,13 @@ extern crate path_slash; extern crate rand; extern crate regex; extern crate s3; +extern crate self_update; extern crate ssh2; extern crate suppaftp; extern crate tempfile; extern crate textwrap; extern crate tui_realm_stdlib; extern crate tuirealm; -extern crate ureq; #[cfg(target_family = "unix")] extern crate users; extern crate whoami; diff --git a/src/main.rs b/src/main.rs index 126bbee..c1e37bb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,6 +62,7 @@ use system::logging; enum Task { Activity(NextActivity), ImportTheme(PathBuf), + InstallUpdate, } #[derive(FromArgs)] @@ -84,6 +85,12 @@ struct Args { quiet: bool, #[argh(option, short = 't', description = "import specified theme")] theme: Option, + #[argh( + switch, + short = 'u', + description = "update termscp to the latest version" + )] + update: bool, #[argh( option, short = 'T', @@ -177,6 +184,9 @@ fn parse_args(args: Args) -> Result { if let Some(theme) = args.theme { run_opts.task = Task::ImportTheme(PathBuf::from(theme)); } + if args.update { + run_opts.task = Task::InstallUpdate; + } // @! Ordinary mode // Remote argument if let Some(remote) = args.positional.get(0) { @@ -256,6 +266,16 @@ fn run(mut run_opts: RunOpts) -> i32 { 1 } }, + Task::InstallUpdate => match support::install_update() { + Ok(msg) => { + println!("{}", msg); + 0 + } + Err(err) => { + eprintln!("Could not install update: {}", err); + 1 + } + }, Task::Activity(activity) => { // Get working directory let wrkdir: PathBuf = match env::current_dir() { diff --git a/src/support.rs b/src/support.rs index 150fb42..b564ada 100644 --- a/src/support.rs +++ b/src/support.rs @@ -26,7 +26,11 @@ * SOFTWARE. */ // mod -use crate::system::{environment, theme_provider::ThemeProvider}; +use crate::system::{ + auto_update::{Update, UpdateStatus}, + environment, + theme_provider::ThemeProvider, +}; use std::fs; use std::path::{Path, PathBuf}; @@ -51,6 +55,23 @@ 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 { + match Update::default() + .show_progress(true) + .ask_confirm(true) + .upgrade() + { + Ok(UpdateStatus::AlreadyUptodate) => Ok("termscp is already up to date".to_string()), + Ok(UpdateStatus::UpdateInstalled(v)) => { + Ok(format!("termscp has been updated to version {}", v)) + } + Err(err) => Err(err.to_string()), + } +} + /// ### get_config_dir /// /// Get configuration directory diff --git a/src/system/auto_update.rs b/src/system/auto_update.rs new file mode 100644 index 0000000..40ff3a2 --- /dev/null +++ b/src/system/auto_update.rs @@ -0,0 +1,233 @@ +//! ## Auto update +//! +//! Automatic update module. This module is used to upgrade the current version of termscp to the latest available on Github + +/** + * MIT License + * + * termscp - Copyright (c) 2021 Christian Visintin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +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 { + /// Termscp is already up to date + AlreadyUptodate, + /// The update has been correctly installed + UpdateInstalled(String), +} + +/// ## Release +/// +/// Info related to a github release +#[derive(Debug)] +pub struct Release { + pub version: String, + pub body: String, +} + +/// ## Update +/// +/// The update structure defines the options used to install the update. +/// Once you're fine with the options, just call the `upgrade()` method to upgrade termscp. +#[derive(Debug)] +pub struct Update { + ask_confirm: bool, + progress: bool, +} + +impl Update { + /// ### show_progress + /// + /// Set whether to show or not the progress bar + pub fn show_progress(mut self, opt: bool) -> Self { + self.progress = opt; + self + } + + /// ### ask_confirm + /// + /// Set whether to ask for confirm when updating + pub fn ask_confirm(mut self, opt: bool) -> Self { + self.ask_confirm = opt; + self + } + + pub fn upgrade(self) -> Result { + info!("Updating termscp..."); + GithubUpdater::configure() + // Set default options + .repo_owner("veeso") + .repo_name("termscp") + .bin_name("termscp") + .current_version(cargo_crate_version!()) + .no_confirm(!self.ask_confirm) + .show_download_progress(self.progress) + .show_output(self.progress) + .build()? + .update() + .map(UpdateStatus::from) + } + + /// ### is_new_version_available + /// + /// Returns whether a new version of termscp is available + /// In case of success returns Ok(Option), where the Option is Some(new_version); + /// otherwise if no version is available, return None + /// In case of error returns Error with the error description + pub fn is_new_version_available() -> Result, UpdateError> { + info!("Checking whether a new version is available..."); + GithubUpdater::configure() + // Set default options + .repo_owner("veeso") + .repo_name("termscp") + .bin_name("termscp") + .current_version(cargo_crate_version!()) + .no_confirm(true) + .show_download_progress(false) + .show_output(false) + .build()? + .get_latest_release() + .map(Release::from) + .map(Self::check_version) + } + + /// ### check_version + /// + /// In case received version is newer than current one, version as Some is returned; otherwise None + fn check_version(r: Release) -> Option { + match parse_semver(r.version.as_str()) { + Some(new_version) => { + // Check if version is different + debug!( + "New version: {}; current version: {}", + new_version, + cargo_crate_version!() + ); + if new_version.as_str() > "cargo_crate_version!()" { + Some(r) // New version is available + } else { + None // No new version + } + } + None => None, + } + } +} + +impl Default for Update { + fn default() -> Self { + Self { + progress: false, + ask_confirm: false, + } + } +} + +impl From for UpdateStatus { + fn from(s: Status) -> Self { + match s { + Status::UpToDate(_) => Self::AlreadyUptodate, + Status::Updated(v) => Self::UpdateInstalled(v), + } + } +} + +impl From for Release { + fn from(r: UpdRelease) -> Self { + Self { + version: r.version, + body: r.body.unwrap_or_default(), + } + } +} + +#[cfg(test)] +mod test { + + use super::*; + + use pretty_assertions::assert_eq; + + #[test] + fn auto_update_default() { + let upd: Update = Update::default(); + assert_eq!(upd.ask_confirm, false); + assert_eq!(upd.progress, false); + let upd = upd.ask_confirm(true).show_progress(true); + assert_eq!(upd.ask_confirm, true); + assert_eq!(upd.progress, true); + } + + #[test] + fn auto_update() { + // Wno version + assert_eq!( + Update::default() + .show_progress(true) + .upgrade() + .ok() + .unwrap(), + UpdateStatus::AlreadyUptodate, + ); + } + + #[test] + fn check_for_updates() { + println!("{:?}", Update::is_new_version_available()); + assert!(Update::is_new_version_available().is_ok()); + } + + #[test] + fn update_status() { + assert_eq!( + UpdateStatus::from(Status::Updated(String::from("0.6.0"))), + UpdateStatus::UpdateInstalled(String::from("0.6.0")) + ); + assert_eq!( + UpdateStatus::from(Status::UpToDate(String::from("0.6.0"))), + UpdateStatus::AlreadyUptodate + ); + } + + #[test] + fn release() { + let release: UpdRelease = UpdRelease { + name: String::from("termscp 0.7.0"), + version: String::from("0.7.0"), + date: String::from("2021-09-12T00:00:00Z"), + body: Some(String::from("fixed everything")), + assets: vec![], + }; + let release: Release = Release::from(release); + assert_eq!(release.body.as_str(), "fixed everything"); + assert_eq!(release.version.as_str(), "0.7.0"); + } +} diff --git a/src/system/mod.rs b/src/system/mod.rs index c702b60..1f201a7 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -26,6 +26,7 @@ * SOFTWARE. */ // modules +pub mod auto_update; pub mod bookmarks_client; pub mod config_client; pub mod environment; diff --git a/src/ui/activities/auth/misc.rs b/src/ui/activities/auth/misc.rs index ecdf57e..a18dd03 100644 --- a/src/ui/activities/auth/misc.rs +++ b/src/ui/activities/auth/misc.rs @@ -27,6 +27,9 @@ */ use super::{AuthActivity, FileTransferParams, FileTransferProtocol}; use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams}; +use crate::system::auto_update::{Update, UpdateStatus}; + +use tuirealm::tui::style::Color; impl AuthActivity { /// ### protocol_opt_to_enum @@ -151,4 +154,31 @@ impl AuthActivity { entry_directory: None, }) } + + // -- update install + + /// ### install_update + /// + /// Install latest termscp version via GUI + pub(super) fn install_update(&mut self) { + // Umount release notes + self.umount_release_notes(); + // Mount wait box + self.mount_wait("Installing update. Please wait…"); + // Install update + let result = Update::default().show_progress(false).upgrade(); + // Umount wait + self.umount_wait(); + // Show outcome + match result { + Ok(UpdateStatus::AlreadyUptodate) => { + self.mount_info("termscp is already up to date!", Color::Cyan) + } + Ok(UpdateStatus::UpdateInstalled(ver)) => self.mount_info( + format!("termscp has been updated to version {}!", ver), + Color::Green, + ), + Err(err) => self.mount_error(format!("Could not install update: {}", err)), + } + } } diff --git a/src/ui/activities/auth/mod.rs b/src/ui/activities/auth/mod.rs index 5fa1bfc..248263c 100644 --- a/src/ui/activities/auth/mod.rs +++ b/src/ui/activities/auth/mod.rs @@ -35,8 +35,8 @@ mod view; use super::{Activity, Context, ExitReason}; use crate::config::themes::Theme; use crate::filetransfer::{FileTransferParams, FileTransferProtocol}; +use crate::system::auto_update::{Release, Update as TermscpUpdate}; use crate::system::bookmarks_client::BookmarksClient; -use crate::utils::git; // Includes use crossterm::event::Event; @@ -51,6 +51,8 @@ const COMPONENT_TEXT_NEW_VERSION_NOTES: &str = "TEXTAREA_NEW_VERSION"; const COMPONENT_TEXT_FOOTER: &str = "TEXT_FOOTER"; const COMPONENT_TEXT_HELP: &str = "TEXT_HELP"; const COMPONENT_TEXT_ERROR: &str = "TEXT_ERROR"; +const COMPONENT_TEXT_INFO: &str = "TEXT_INFO"; +const COMPONENT_TEXT_WAIT: &str = "TEXT_WAIT"; const COMPONENT_TEXT_SIZE_ERR: &str = "TEXT_SIZE_ERR"; const COMPONENT_INPUT_ADDR: &str = "INPUT_ADDRESS"; const COMPONENT_INPUT_PORT: &str = "INPUT_PORT"; @@ -65,6 +67,7 @@ const COMPONENT_RADIO_QUIT: &str = "RADIO_QUIT"; const COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK: &str = "RADIO_DELETE_BOOKMARK"; const COMPONENT_RADIO_BOOKMARK_DEL_RECENT: &str = "RADIO_DELETE_RECENT"; const COMPONENT_RADIO_BOOKMARK_SAVE_PWD: &str = "RADIO_SAVE_PASSWORD"; +const COMPONENT_RADIO_INSTALL_UPDATE: &str = "RADIO_INSTALL_UPDATE"; const COMPONENT_BOOKMARKS_LIST: &str = "BOOKMARKS_LIST"; const COMPONENT_RECENTS_LIST: &str = "RECENTS_LIST"; @@ -119,12 +122,12 @@ impl AuthActivity { if ctx.config().get_check_for_updates() { debug!("Check for updates is enabled"); // Send request - match git::check_for_updates(env!("CARGO_PKG_VERSION")) { - Ok(Some(git::GithubTag { tag_name, body })) => { + match TermscpUpdate::is_new_version_available() { + Ok(Some(Release { version, body })) => { // If some, store version and release notes - info!("Latest version is: {}", tag_name); + info!("Latest version is: {}", version); ctx.store_mut() - .set_string(STORE_KEY_LATEST_VERSION, tag_name); + .set_string(STORE_KEY_LATEST_VERSION, version); ctx.store_mut().set_string(STORE_KEY_RELEASE_NOTES, body); } Ok(None) => { diff --git a/src/ui/activities/auth/update.rs b/src/ui/activities/auth/update.rs index da9ed83..de76419 100644 --- a/src/ui/activities/auth/update.rs +++ b/src/ui/activities/auth/update.rs @@ -32,8 +32,9 @@ use super::{ COMPONENT_INPUT_S3_BUCKET, COMPONENT_INPUT_S3_PROFILE, COMPONENT_INPUT_S3_REGION, COMPONENT_INPUT_USERNAME, COMPONENT_RADIO_BOOKMARK_DEL_BOOKMARK, COMPONENT_RADIO_BOOKMARK_DEL_RECENT, COMPONENT_RADIO_BOOKMARK_SAVE_PWD, - COMPONENT_RADIO_PROTOCOL, COMPONENT_RADIO_QUIT, COMPONENT_RECENTS_LIST, COMPONENT_TEXT_ERROR, - COMPONENT_TEXT_HELP, COMPONENT_TEXT_NEW_VERSION_NOTES, COMPONENT_TEXT_SIZE_ERR, + COMPONENT_RADIO_INSTALL_UPDATE, COMPONENT_RADIO_PROTOCOL, COMPONENT_RADIO_QUIT, + COMPONENT_RECENTS_LIST, COMPONENT_TEXT_ERROR, COMPONENT_TEXT_HELP, COMPONENT_TEXT_INFO, + COMPONENT_TEXT_NEW_VERSION_NOTES, COMPONENT_TEXT_SIZE_ERR, COMPONENT_TEXT_WAIT, }; use crate::ui::keymap::*; use tui_realm_stdlib::InputPropsBuilder; @@ -252,15 +253,44 @@ impl Update for AuthActivity { self.umount_error(); None } - (COMPONENT_TEXT_ERROR, _) => None, - (COMPONENT_TEXT_NEW_VERSION_NOTES, key) - if key == &MSG_KEY_ESC || key == &MSG_KEY_ENTER => - { + // -- Text info + (COMPONENT_TEXT_INFO, key) if key == &MSG_KEY_ESC || key == &MSG_KEY_ENTER => { + // Umount text info + self.umount_info(); + None + } + (COMPONENT_TEXT_ERROR, _) | (COMPONENT_TEXT_INFO, _) => None, + // -- Text wait + (COMPONENT_TEXT_WAIT, _) => None, + // -- Release notes + (COMPONENT_TEXT_NEW_VERSION_NOTES, key) if key == &MSG_KEY_ESC => { // Umount release notes self.umount_release_notes(); None } + (COMPONENT_TEXT_NEW_VERSION_NOTES, key) if key == &MSG_KEY_TAB => { + // Focus to radio update + self.view.active(COMPONENT_RADIO_INSTALL_UPDATE); + None + } (COMPONENT_TEXT_NEW_VERSION_NOTES, _) => None, + // -- Install update radio + (COMPONENT_RADIO_INSTALL_UPDATE, Msg::OnSubmit(Payload::One(Value::Usize(0)))) => { + // Install update + self.install_update(); + None + } + (COMPONENT_RADIO_INSTALL_UPDATE, Msg::OnSubmit(Payload::One(Value::Usize(1)))) => { + // Umount + self.umount_release_notes(); + None + } + (COMPONENT_RADIO_INSTALL_UPDATE, key) if key == &MSG_KEY_TAB => { + // Focus to changelog + self.view.active(COMPONENT_TEXT_NEW_VERSION_NOTES); + None + } + (COMPONENT_RADIO_INSTALL_UPDATE, _) => None, // Help (_, key) if key == &MSG_KEY_CTRL_H => { // Show help diff --git a/src/ui/activities/auth/view.rs b/src/ui/activities/auth/view.rs index f546963..91863df 100644 --- a/src/ui/activities/auth/view.rs +++ b/src/ui/activities/auth/view.rs @@ -209,7 +209,7 @@ impl AuthActivity { .with_spans(vec![ TextSpan::from("termscp "), TextSpan::new(version.as_str()).underlined().bold(), - TextSpan::from(" is NOW available! Get it from ; view release notes with "), + TextSpan::from(" is NOW available! Install update and view release notes with "), ]) .build(), )), @@ -360,6 +360,22 @@ impl AuthActivity { self.view.render(super::COMPONENT_TEXT_ERROR, f, popup); } } + if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_INFO) { + if props.visible { + let popup = draw_area_in(f.size(), 50, 10); + f.render_widget(Clear, popup); + // make popup + self.view.render(super::COMPONENT_TEXT_INFO, f, popup); + } + } + if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_WAIT) { + if props.visible { + let popup = draw_area_in(f.size(), 50, 10); + f.render_widget(Clear, popup); + // make popup + self.view.render(super::COMPONENT_TEXT_WAIT, f, popup); + } + } if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_SIZE_ERR) { if props.visible { let popup = draw_area_in(f.size(), 80, 20); @@ -403,10 +419,22 @@ impl AuthActivity { if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_NEW_VERSION_NOTES) { if props.visible { // make popup - let popup = draw_area_in(f.size(), 90, 90); + let popup = draw_area_in(f.size(), 90, 85); f.render_widget(Clear, popup); + let popup_chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Percentage(90), // Notes + Constraint::Length(3), // Install radio + ] + .as_ref(), + ) + .split(popup); self.view - .render(super::COMPONENT_TEXT_NEW_VERSION_NOTES, f, popup); + .render(super::COMPONENT_TEXT_NEW_VERSION_NOTES, f, popup_chunks[0]); + self.view + .render(super::COMPONENT_RADIO_INSTALL_UPDATE, f, popup_chunks[1]); } } if let Some(props) = self.view.get_props(super::COMPONENT_TEXT_HELP) { @@ -515,7 +543,7 @@ impl AuthActivity { /// ### mount_error /// /// Mount error box - pub(super) fn mount_error(&mut self, text: &str) { + pub(super) fn mount_error>(&mut self, text: S) { // Mount let err_color = self.theme().misc_error_dialog; self.view.mount( @@ -526,7 +554,7 @@ impl AuthActivity { .with_borders(Borders::ALL, BorderType::Thick, err_color) .bold() .with_text_alignment(Alignment::Center) - .with_texts(vec![TextSpan::from(text)]) + .with_texts(vec![TextSpan::from(text.as_ref().to_string())]) .build(), )), ); @@ -541,6 +569,61 @@ impl AuthActivity { self.view.umount(super::COMPONENT_TEXT_ERROR); } + /// ### mount_info + /// + /// Mount info box + pub(super) fn mount_info>(&mut self, text: S, color: Color) { + // Mount + self.view.mount( + super::COMPONENT_TEXT_INFO, + Box::new(Paragraph::new( + ParagraphPropsBuilder::default() + .with_borders(Borders::ALL, BorderType::Thick, color) + .bold() + .with_text_alignment(Alignment::Center) + .with_texts(vec![TextSpan::from(text.as_ref().to_string())]) + .with_foreground(color) + .build(), + )), + ); + // Give focus to error + self.view.active(super::COMPONENT_TEXT_INFO); + } + + /// ### umount_info + /// + /// Umount info message + pub(super) fn umount_info(&mut self) { + self.view.umount(super::COMPONENT_TEXT_INFO); + } + + /// ### mount_error + /// + /// Mount wait box + pub(super) fn mount_wait(&mut self, text: &str) { + // Mount + self.view.mount( + super::COMPONENT_TEXT_WAIT, + Box::new(Paragraph::new( + ParagraphPropsBuilder::default() + .with_borders(Borders::ALL, BorderType::Thick, Color::Reset) + .bold() + .with_text_alignment(Alignment::Center) + .with_texts(vec![TextSpan::from(text)]) + .build(), + )), + ); + // Give focus to error + self.view.active(super::COMPONENT_TEXT_WAIT); + } + + /// ### umount_wait + /// + /// Umount wait message + pub(super) fn umount_wait(&mut self) { + self.view.umount(super::COMPONENT_TEXT_WAIT); + } + /// ### mount_size_err /// /// Mount size error @@ -785,7 +868,22 @@ impl AuthActivity { .build(), )), ); - self.view.active(super::COMPONENT_TEXT_NEW_VERSION_NOTES); + // Mount install popup + self.view.mount( + super::COMPONENT_RADIO_INSTALL_UPDATE, + Box::new(Radio::new( + RadioPropsBuilder::default() + .with_color(Color::LightYellow) + .with_inverted_color(Color::Black) + .with_borders(Borders::ALL, BorderType::Rounded, Color::LightYellow) + .with_title("Install new version?", Alignment::Left) + .with_options(&["Yes", "No"]) + .with_value(0) + .rewind(true) + .build(), + )), + ); + self.view.active(super::COMPONENT_RADIO_INSTALL_UPDATE); } } } @@ -795,6 +893,7 @@ impl AuthActivity { /// Umount release notes text area pub(super) fn umount_release_notes(&mut self) { self.view.umount(super::COMPONENT_TEXT_NEW_VERSION_NOTES); + self.view.umount(super::COMPONENT_RADIO_INSTALL_UPDATE); } /// ### get_protocol diff --git a/src/utils/git.rs b/src/utils/git.rs deleted file mode 100644 index 7ed9bea..0000000 --- a/src/utils/git.rs +++ /dev/null @@ -1,95 +0,0 @@ -//! ## git -//! -//! `git` is the module which provides utilities to interact through the GIT API and to perform some stuff at git level - -/** - * MIT License - * - * termscp - Copyright (c) 2021 Christian Visintin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -// Locals -use super::parser::parse_semver; -// Others -use serde::Deserialize; - -#[derive(Debug, Deserialize)] -/// ## GithubTag -/// -/// Info related to a github tag -pub struct GithubTag { - pub tag_name: String, - pub body: String, -} - -/// ### check_for_updates -/// -/// Check if there is a new version available for termscp. -/// This is performed through the Github API -/// In case of success returns Ok(Option), where the Option is Some(new_version); otherwise if no version is available, return None -/// In case of error returns Error with the error description - -pub fn check_for_updates(current_version: &str) -> Result, String> { - // Send request - let github_tag: Result = - match ureq::get("https://api.github.com/repos/veeso/termscp/releases/latest").call() { - Ok(response) => response.into_json::().map_err(|x| x.to_string()), - Err(err) => Err(err.to_string()), - }; - // Check version - match github_tag { - Err(err) => Err(err), - Ok(tag) => { - // Parse version - match parse_semver(tag.tag_name.as_str()) { - Some(new_version) => { - // Check if version is different - if new_version.as_str() > current_version { - Ok(Some(tag)) // New version is available - } else { - Ok(None) // No new version - } - } - None => Err(String::from("Got bad response from Github")), - } - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - #[cfg(not(all( - any( - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd", - target_os = "netbsd" - ), - feature = "github-actions" - )))] - fn test_utils_git_check_for_updates() { - assert!(check_for_updates("100.0.0").ok().unwrap().is_none()); - assert!(check_for_updates("0.0.1").ok().unwrap().is_some()); - } -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 71d2835..f12692e 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -29,7 +29,6 @@ pub mod crypto; pub mod file; pub mod fmt; -pub mod git; pub mod parser; pub mod path; pub mod random;