Compare commits
973 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f54c50f6ef | |||
| 325c8ceee7 | |||
| ebfaeb956c | |||
| 133ec898d8 | |||
| 1587d3d625 | |||
| 751f68f6d4 | |||
| e966a83220 | |||
| d99c76b43c | |||
| 7434c51063 | |||
| 9fbd617f88 | |||
| 2bbe560ec5 | |||
| 7472ca98a0 | |||
| 974b6d6917 | |||
| 98a1ce42dc | |||
| afbc74113f | |||
| 08c51a32cc | |||
| 739517f7e4 | |||
| 77281ed926 | |||
| 4b6325ebe3 | |||
| 6933a98cda | |||
| 5cee1184dc | |||
| 4a9da89642 | |||
| 282f75c3f3 | |||
| 535ed23540 | |||
| 70bd7d7330 | |||
| 352eec4762 | |||
| 3a5327f5b1 | |||
| b1601fb17e | |||
| bca261b7b2 | |||
| 904befaea8 | |||
| afe7b05830 | |||
| 837592e48a | |||
| ab5de031e3 | |||
| f3085161e6 | |||
| 1dafc76850 | |||
| f066d6a387 | |||
| 987751d732 | |||
| 1ca8abbfe8 | |||
| 26e71a2f1d | |||
| b1d77c78fe | |||
| 2a7d48a92b | |||
| 82141e7f2b | |||
| 14bc15cfca | |||
| 85fa99e4cc | |||
| 3ff3cdb587 | |||
| 726443ae21 | |||
| 0bd449e7bc | |||
| c24f08691d | |||
| 14e6872432 | |||
| 88900a80b8 | |||
| ce619bcff2 | |||
| 5a16467e71 | |||
| b6ca8c57f0 | |||
| 660c17a0df | |||
| aed4ecc522 | |||
| ee69ba6ef8 | |||
| 0db3ea43d2 | |||
| 6a61eb16f7 | |||
| e32ed613cc | |||
| dbd61f0fab | |||
| a18fa0ca5a | |||
| c8846266d7 | |||
| 40440832be | |||
| 34c03841be | |||
| ded71dce48 | |||
| eefa1b3db0 | |||
| a2d766d688 | |||
| f92cb93755 | |||
| d070825dd7 | |||
| 3774156873 | |||
| bbeefc557e | |||
| 3ee21aba2f | |||
| 6cf5bf18cf | |||
| d7b7ab7fa1 | |||
| 48b387de14 | |||
| e381484022 | |||
| 203a6da387 | |||
| 3379940ec9 | |||
| 2153164484 | |||
| 0cc7362bd9 | |||
| 5c84a0e88d | |||
| a25b17a4e5 | |||
| d670aed079 | |||
| 6fa3c042b1 | |||
| fc7e789390 | |||
| 3c4356af92 | |||
| ba513850c1 | |||
| f56dd60868 | |||
| f544a63d19 | |||
| 02fec64d35 | |||
| a54ff078cc | |||
| c27748272d | |||
| f6d65cf09d | |||
| 930e76814f | |||
| cdd4c60805 | |||
| c652ca18b8 | |||
| 0ad18ea5e7 | |||
| 2ed71c7ff8 | |||
| 49102985a4 | |||
| bc59df494b | |||
| 080c013fab | |||
| 6252df2959 | |||
| 9160c52cb0 | |||
| 38f1fccfd0 | |||
| 6ceaf048b5 | |||
| 534c16427e | |||
| 9b19240925 | |||
| 0ddbf3b104 | |||
| 126e58503f | |||
| 0be8b60c7d | |||
| 4ed6b118ca | |||
| a48b226d9b | |||
| e11af03fdd | |||
| f044e6ace2 | |||
| e056afbd28 | |||
| 9442e3b150 | |||
| 9c00b9a86c | |||
| 622cfe260a | |||
| 0c3ced012e | |||
| d60c5007f9 | |||
| 7e10b8e68b | |||
| 08509caf1b | |||
| 89de2d2dfa | |||
| abc80b93ad | |||
| 1b79a6fc91 | |||
| 5a3aa64fba | |||
| bc4b096077 | |||
| 0025b87b0f | |||
| bd0843d3da | |||
| 0ba43d5714 | |||
| 97e1ca789a | |||
| 2df13fac10 | |||
| 186313f57c | |||
| 8b0be49609 | |||
| e062ee0447 | |||
| c81cf39fe9 | |||
| 9cfef867a9 | |||
| 18314e6a2e | |||
| 9f3df1a79a | |||
| fe424107e9 | |||
| d97535894c | |||
| 4d65e48b3c | |||
| 0d24662b3d | |||
| bc14b049c0 | |||
| d32c588f15 | |||
| 60e86aff2a | |||
| 5f83a1468c | |||
| 5758a12c3b | |||
| 49a74d02ea | |||
| f6d35f1eea | |||
| 3fb61a76fe | |||
| ff4452c971 | |||
| fd1d8a0e26 | |||
| b0d6da8e23 | |||
| 4ca0865fe3 | |||
| b8115362f8 | |||
| 155f747563 | |||
| b04976bde3 | |||
| 5f7a0d8a46 | |||
| 694232564a | |||
| 54b674ad43 | |||
| c32822037e | |||
| abb5c212c5 | |||
| e9b54a227b | |||
| befc32198a | |||
| 7e5103ff7e | |||
| 2cb600083e | |||
| 47d23673e6 | |||
| a0b357cf8c | |||
| 75943f2b93 | |||
| 085ab721f9 | |||
| f4156a5059 | |||
| 4bebec369f | |||
| 05c8613279 | |||
| 205d2813ad | |||
| 86660a0cc9 | |||
| 05830db206 | |||
| 3c79e812eb | |||
| 0287e7706a | |||
| 67a14c2725 | |||
| df03c5c1bf | |||
| 3ce3ffee3d | |||
| c0b32a1847 | |||
| 81ae0035c3 | |||
| 783da22ca2 | |||
| 8715c2b6f9 | |||
| 98a748dccc | |||
| bef031a414 | |||
| ce0e953182 | |||
| 9a5caf75c3 | |||
| 446f4a3a32 | |||
| da75912d26 | |||
| 4ed23c2a18 | |||
| 23ae334bef | |||
| ec75ae1486 | |||
| 368570592f | |||
| 806793421e | |||
| 1f377b242d | |||
| a4906b129a | |||
| 5c6e8925ad | |||
| a18eff689d | |||
| 274742d6d9 | |||
| cdebcbd4dc | |||
| cdf303a847 | |||
| dd35fe825c | |||
| 5c4a971aca | |||
| 7522b4d0ff | |||
| b0f314837e | |||
| 8a9ba7745a | |||
| b7d75a2749 | |||
| fe0d9b0aa6 | |||
| 7dba691ccc | |||
| 099e2154ba | |||
| f2efb25ad7 | |||
| e45c3d5b4e | |||
| 69f821baef | |||
| 11559d0962 | |||
| 79c33095fc | |||
| 0ec6bcbcef | |||
| 3cde067339 | |||
| c05ef32270 | |||
| 7eb913ec7b | |||
| 4e63093d25 | |||
| e5d50698d2 | |||
| 79c31c2d84 | |||
| aab266a661 | |||
| a4c9acb49f | |||
| 6205c7f3c5 | |||
| e4af014013 | |||
| c9f649f40f | |||
| 1f27ca2607 | |||
| a1288c7480 | |||
| 4bfec52ba5 | |||
| 3f01be3baa | |||
| 8e2ffeabce | |||
| fc68e2621b | |||
| b2a8a3041c | |||
| c507d54700 | |||
| 31c5ad7534 | |||
| 14ac10547c | |||
| ae1638ee17 | |||
| c5f76ec51c | |||
| d319a2fae4 | |||
| 72a5703a08 | |||
| 91b4d4e463 | |||
| 17719ea370 | |||
| 707a3faa54 | |||
| dfe58e6147 | |||
| c49dab3888 | |||
| 47ff07e496 | |||
| 61a8fb95e4 | |||
| f757336d75 | |||
| cf529c1678 | |||
| 631f09b9a8 | |||
| 65aed76605 | |||
| 9036d83635 | |||
| 179c4de4ed | |||
| f3b84c97e1 | |||
| b5b3aeb645 | |||
| e5172d4207 | |||
| 50e7f5f5d0 | |||
| 88cdae79a8 | |||
| 4f3b97b198 | |||
| 54a8317d0e | |||
| 3a46aa74f9 | |||
| aca5b37898 | |||
| 0394a12c9f | |||
| e61d04aa1b | |||
| c0c9f7c0dd | |||
| 905fe5fc9f | |||
| 89ab53a71b | |||
| 7dccac6105 | |||
| 44051ec718 | |||
| c7469b8594 | |||
| 5dfee2cbd9 | |||
| 679a829744 | |||
| 2a51ab984c | |||
| 2b2ebadd6a | |||
| 2b15a23fe8 | |||
| d30c3dfadd | |||
| ef8dbb6305 | |||
| 623ba806e1 | |||
| ea9dd03f55 | |||
| 92d20f33fe | |||
| 15caef83e6 | |||
| 19992402e2 | |||
| 182bbb94a2 | |||
| 20c3e22572 | |||
| d3c2c084db | |||
| cfbecc049d | |||
| 9de171fb83 | |||
| 2f48c765e3 | |||
| ca005cbecd | |||
| ee28d34f29 | |||
| 295191b9eb | |||
| 16b2aa8596 | |||
| 522ee0355e | |||
| e5ca956897 | |||
| a071f3d420 | |||
| 66888c418c | |||
| b5f712fa04 | |||
| 1509401599 | |||
| 6506f4ae59 | |||
| 5a5fa52b57 | |||
| b7d4c68ebe | |||
| 00a6c53178 | |||
| 67bc1a2a08 | |||
| 0bb3c9a26e | |||
| 4394941c71 | |||
| 175ea23bfc | |||
| cef100e5d9 | |||
| afba6c32c5 | |||
| 31f5bd095b | |||
| e1add0ed28 | |||
| 79bc6a684b | |||
| bae4db8e27 | |||
| 4cbba3f3cb | |||
| e9fbb7f317 | |||
| 044f2436f8 | |||
| b7369162d2 | |||
| a13663e5e9 | |||
| 79dd9e2303 | |||
| b4fa50a666 | |||
| 5a67fc7b0e | |||
| 9dab34e7ee | |||
| c5eeae74b7 | |||
| 9009002b6e | |||
| 9bf23b3f6b | |||
| 3ec94c17bc | |||
| ed8ba628e5 | |||
| 7c638473d6 | |||
| d37140ead6 | |||
| fdb0d97a61 | |||
| 0c1e9c0d60 | |||
| e1a2255a58 | |||
| f6b2c814c0 | |||
| efb30231ee | |||
| 8cb6c19210 | |||
| 51c2618b5a | |||
| 279df59b5d | |||
| d8373d0eba | |||
| 74fe97f2e2 | |||
| e62f15f375 | |||
| 21dc73b556 | |||
| a10325f6fb | |||
| 1ecef6fc16 | |||
| 67df3dc76a | |||
| 7ecfaea278 | |||
| 97151d18bf | |||
| 7ad7a1580d | |||
| 46f2954bc4 | |||
| 0c88f559e2 | |||
| 8a0979578a | |||
| 7ee28a00ae | |||
| 82330f870e | |||
| 54aecdc478 | |||
| d5038a22ee | |||
| c0bc493d21 | |||
| 1c75c7d386 | |||
| 251b125cbb | |||
| efd2235ff3 | |||
| 1db2ff7ec5 | |||
| 4d5f3a6b63 | |||
| 62003308a7 | |||
| cb037cfca9 | |||
| 15fffdf0c9 | |||
| c1b245b4c9 | |||
| d14225c0b9 | |||
| d60be7dc80 | |||
| 146a1f3ed6 | |||
| 12fe10100b | |||
| 298d590306 | |||
| 8e6aae08b6 | |||
| cb33ba114e | |||
| 6369ead491 | |||
| ae350b4bfa | |||
| cd5bb28fb7 | |||
| f27a4e2a02 | |||
| 0f432d0375 | |||
| 8b67c59247 | |||
| fdd7901f7e | |||
| 2eec7c4b2b | |||
| 64e3848c97 | |||
| 833cd7d3ba | |||
| 2f1b644a40 | |||
| 6a5c248d35 | |||
| 96df152220 | |||
| a22c5025d7 | |||
| cce0c92c0b | |||
| 90d7083b24 | |||
| b3ab76e573 | |||
| 66913d5fc1 | |||
| f5174ccac0 | |||
| 82489e7459 | |||
| ad562a7b09 | |||
| 08c42e5acf | |||
| aac9cf4fa0 | |||
| a26b21da89 | |||
| bb95c9a4d0 | |||
| 80dea3f71a | |||
| 0057a657d2 | |||
| 816270d545 | |||
| 2caa0432df | |||
| e0d8b80cdf | |||
| f094979ddb | |||
| 0c8144aaa8 | |||
| 3249e82873 | |||
| 66adad3135 | |||
| f2e5bf4441 | |||
| 601b0595d4 | |||
| c47fcb2225 | |||
| 550c7ca62a | |||
| 3256c276b4 | |||
| 04f43fff63 | |||
| 82e8c84000 | |||
| 31203d76ce | |||
| 572a948f2c | |||
| b6ee49cfa6 | |||
| 0334c5db78 | |||
| c45ebec261 | |||
| ad2781b62c | |||
| 35dc11cce3 | |||
| 8d9e7443ec | |||
| 697ab225ea | |||
| babbc5eadb | |||
| f28dba7660 | |||
| c5eba4b56a | |||
| 0b70819781 | |||
| 069fe8cae2 | |||
| 043f54e707 | |||
| b635554e52 | |||
| 9e35616568 | |||
| 615dbda583 | |||
| 4b421a4a87 | |||
| 0fe06eb52b | |||
| e8c6b8306f | |||
| d1457253c4 | |||
| 1bcdaa5614 | |||
| 85dd67721f | |||
| a25ee67cd3 | |||
| 67d48e7a79 | |||
| 49e69277af | |||
| 332284fec3 | |||
| 4897253932 | |||
| 6559c6b083 | |||
| 587d7da2cb | |||
| 7d55563556 | |||
| 53271966da | |||
| ec4daf8e25 | |||
| edd0842273 | |||
| c1edc20462 | |||
| ced7573241 | |||
| 24788fa894 | |||
| dab98f4292 | |||
| 84cb775679 | |||
| 4e802f1dc5 | |||
| b8efe6985f | |||
| e047179ea0 | |||
| 197b3095b6 | |||
| 54c23079be | |||
| a93dbde0c8 | |||
| 2a3d4f2670 | |||
| e6ba4d8430 | |||
| 9284f101c8 | |||
| 685444655c | |||
| 027545f14c | |||
| 2e0322bc0e | |||
| df7a4381c4 | |||
| 25dd1b9b0a | |||
| a1a1631fd2 | |||
| 47f3ffef7b | |||
| 54b5583d1a | |||
| 30851a78e8 | |||
| bc6b7b582e | |||
| 3927fb2a39 | |||
| 028f64a588 | |||
| 26ff496829 | |||
| cb583f305c | |||
| 88b29d3183 | |||
| 02fdb27cc5 | |||
| 5fd53c1b2b | |||
| 696e3ae582 | |||
| e7a29b7f1a | |||
| e53120f3c2 | |||
| 3f463f4b73 | |||
| 83964026ec | |||
| f79658a93c | |||
| 23fd37559e | |||
| 1fadc53743 | |||
| 0eaa898e15 | |||
| 0aeca76f63 | |||
| 8cf6c1fce3 | |||
| 736dd820a6 | |||
| db73d1e45f | |||
| 6c31c1f2d8 | |||
| fcce9b778b | |||
| b309a55ed6 | |||
| 8b2b834818 | |||
| 9a63f5b2cc | |||
| a7a116cb33 | |||
| bc90fb1038 | |||
| e307b6a8ac | |||
| c9e8589689 | |||
| e09682c219 | |||
| 967babbcb7 | |||
| 4973bf8cbe | |||
| 6421b74c66 | |||
| 463329a080 | |||
| fd2144f8e9 | |||
| 18a579a204 | |||
| 58d5ea264f | |||
| 4b9d23cc3a | |||
| f3e694d3d6 | |||
| b9a0e516c6 | |||
| 198d421ab0 | |||
| 6caf34b17a | |||
| f0a91b1579 | |||
| c3e5663cf4 | |||
| bcc6fcd2e7 | |||
| 3c3d681ca0 | |||
| 3e83c26cd5 | |||
| ec841d5382 | |||
| d2e4252487 | |||
| 7660dad4eb | |||
| ddfa973c19 | |||
| def0eb8586 | |||
| c39ee82ac5 | |||
| e1bde1971d | |||
| 79c90c5b97 | |||
| 06ffbaa2f4 | |||
| 63e7023342 | |||
| 88a0685097 | |||
| ed3225ed84 | |||
| 96c997c38a | |||
| c824d00986 | |||
| c052796d52 | |||
| 1077204965 | |||
| 77476596f4 | |||
| efd5443be4 | |||
| 8c88fbe10f | |||
| 06a67de14f | |||
| 8bb05406c8 | |||
| 3f31800158 | |||
| f69489fc8f | |||
| 1f115dea92 | |||
| f81424f1db | |||
| 1d09095ab9 | |||
| bf6f25310c | |||
| 4c1e4fef7a | |||
| ddd4824567 | |||
| f31f58aa79 | |||
| 22bb143820 | |||
| 78b918087e | |||
| 91ce709d7b | |||
| 214ec0c5a5 | |||
| 0cb9254e63 | |||
| 4bbb339844 | |||
| 92b081c076 | |||
| 32ab0267fb | |||
| 8a0f190474 | |||
| a189a4c754 | |||
| b7b765c16e | |||
| 7713c6c21d | |||
| c49184dcb1 | |||
| fc3803991a | |||
| f6011543c0 | |||
| 7390bb58c5 | |||
| 81482b47f4 | |||
| 6cb1dcaa43 | |||
| 78e4a4899c | |||
| d15997cca0 | |||
| 1558f4ffe4 | |||
| 764cca73d1 | |||
| 1757eb5bec | |||
| 6cfac57162 | |||
| d36d330244 | |||
| 4203de6d3f | |||
| 098e3c709a | |||
| 1a8e151efb | |||
| 6c8d22d396 | |||
| a0ee1d886a | |||
| bf6f1625ec | |||
| 3271377b7e | |||
| f36bb65b45 | |||
| c722982c39 | |||
| e1109fff15 | |||
| 59c6567ff3 | |||
| 61f6901767 | |||
| 8277c80860 | |||
| 4093ba169c | |||
| e3a9d253f7 | |||
| 80c67c8aa8 | |||
| 421969c3da | |||
| e15b79750b | |||
| 37abe596c7 | |||
| e6b44e1461 | |||
| b9cb961da6 | |||
| 55c4b777fb | |||
| 2231727adb | |||
| 0a7e29d92f | |||
| a105a42519 | |||
| d20c2c786b | |||
| 14abed44a5 | |||
| 65fee64132 | |||
| 348688b5ce | |||
| 0cb84fc531 | |||
| 8a36c459d5 | |||
| c7414ab070 | |||
| d16f9e7ad8 | |||
| 3cbd2ed013 | |||
| 398f518b2f | |||
| 97a62def11 | |||
| 7ed49126a4 | |||
| d976a34705 | |||
| 8b01c71819 | |||
| 1ee5e368f6 | |||
| 8fc71aae66 | |||
| 0589cc2f0c | |||
| 931a66498f | |||
| 8ec0a0289a | |||
| 2d8ce475f8 | |||
| f8766722d4 | |||
| 1319e0b17b | |||
| 5e17bf0736 | |||
| ca50bddc56 | |||
| c78fc583b0 | |||
| 04cafc4181 | |||
| f8300fa587 | |||
| 407ca567f1 | |||
| 320fd5c2dd | |||
| e4c616245a | |||
| 5986130dfa | |||
| 19610479bd | |||
| e3d2151bad | |||
| 89d205e946 | |||
| 15d13af7d5 | |||
| 3df8ed13a4 | |||
| 5a4a364250 | |||
| 00bee04c2c | |||
| 4475e8c24c | |||
| 5a49987338 | |||
| 76f1f1dcf3 | |||
| 0175cfbfb6 | |||
| 48483a5c99 | |||
| 71e4cc9413 | |||
| a00c0117a2 | |||
| c1bc81c664 | |||
| 1b7ef30a50 | |||
| efad2b96db | |||
| 56a200499e | |||
| 1c58f1d623 | |||
| 6cdd56e22f | |||
| 53acb847bc | |||
| 2b006457c7 | |||
| fbc1672e3d | |||
| 542123ce04 | |||
| 59eb7f7935 | |||
| 74482d6e2c | |||
| 529ac2f778 | |||
| b73c3228e4 | |||
| 26f7c1f9d1 | |||
| f078232499 | |||
| 8cd91f6df3 | |||
| 5670c0f975 | |||
| 99d4177e89 | |||
| d07b1c86be | |||
| fe494c52b1 | |||
| bc50328006 | |||
| 90afe204b1 | |||
| d981b77ed7 | |||
| 541a9a55b5 | |||
| cd3fc15bcb | |||
| 4e50038b41 | |||
| a8354ee38f | |||
| c4907c8ce5 | |||
| 3c3c680b00 | |||
| 3a32f45334 | |||
| 8e1843f90b | |||
| dc01de98dc | |||
| 971061d231 | |||
| d04dd831e4 | |||
| 8dcfda9787 | |||
| c938021bef | |||
| 3fcf0fb72a | |||
| e99406fbe4 | |||
| 60073be993 | |||
| d3df4c7020 | |||
| adce92e312 | |||
| 4973545fe1 | |||
| 8425c97102 | |||
| 1876b8bdc7 | |||
| 99ff3a8e45 | |||
| cae251905c | |||
| f738ce90e0 | |||
| 2f2bb20550 | |||
| 591ede0507 | |||
| 09665fead3 | |||
| 60ee2f1c2b | |||
| d6d8197869 | |||
| b1da42b543 | |||
| e874550d29 | |||
| 6cd9657446 | |||
| 2790c613aa | |||
| 7b868bc60b | |||
| c1b3511c06 | |||
| 1e3c859ae0 | |||
| faab67800f | |||
| 7f9d92cbe9 | |||
| 4e287a0231 | |||
| 8c9c331d7e | |||
| 37ce54051e | |||
| f31b047671 | |||
| aaff616332 | |||
| cfc1b73c74 | |||
| 0d2967423b | |||
| cb3681ffdd | |||
| 4c343c6f34 | |||
| ff158add1f | |||
| 2c64cd5cce | |||
| c43ab28fb0 | |||
| dd00e1f55a | |||
| 2b3acee97c | |||
| d96558c3df | |||
| b8db557ffe | |||
| 300256b196 | |||
| 7ba1b316f7 | |||
| 822d41e885 | |||
| 0253572975 | |||
| 0328c1de81 | |||
| c6ee9dedb9 | |||
| 88136811b9 | |||
| 7c816d0822 | |||
| a5fe62e502 | |||
| 892be42988 | |||
| c0eb98c3f9 | |||
| 1ddbd0aa4e | |||
| 4f1e505a7a | |||
| dcec804681 | |||
| a127f46a06 | |||
| c8d277c51d | |||
| 42477d6893 | |||
| 4c1fb826be | |||
| a0c29d1174 | |||
| 2f0b340fe0 | |||
| cbe242bb94 | |||
| a088c6dbd3 | |||
| 036aba2420 | |||
| 60269c7777 | |||
| e90f561584 | |||
| 4bd18c1386 | |||
| fe51185f74 | |||
| a35395bd51 | |||
| f1225b1ff3 | |||
| 63d727d5c5 | |||
| 46864ee23a | |||
| 46728d8bc3 | |||
| daa9a7c012 | |||
| 0f595b8cbf | |||
| 26b001a5fc | |||
| 3704d2520d | |||
| 41e89605f0 | |||
| 065ea59114 | |||
| 64bb2ed101 | |||
| c48c73909d | |||
| 68d113f335 | |||
| 8bb66b53e0 | |||
| 84c36f1789 | |||
| 2214c1dee3 | |||
| 150a3cf346 | |||
| b31de185c5 | |||
| 477930bef9 | |||
| 03bbd6420e | |||
| b21607cd77 | |||
| 6c6dadc4e7 | |||
| 08b8946429 | |||
| 23882df474 | |||
| d8547d8f21 | |||
| c6de101808 | |||
| d0688be5cb | |||
| 35f37cc2d3 | |||
| 81ae310e3d | |||
| 3be890c63a | |||
| 64a08e1440 | |||
| fe5c35d789 | |||
| df391dfb6f | |||
| f5ac4207e8 | |||
| b8c54b53d9 | |||
| 6be9294e11 | |||
| 7676e6e3a1 | |||
| 9776ecbe60 | |||
| a1632492ed | |||
| 8d74d4c4e5 | |||
| e29ce3d0dd | |||
| e6b952966c | |||
| 1ba139aed1 | |||
| f136057484 | |||
| 47cd112e69 | |||
| 871a02c8b5 | |||
| 44ba1111af | |||
| 52b35f9232 | |||
| f8a448f5e9 | |||
| 37da49f4f8 | |||
| c0ae922264 | |||
| 91081cb86a | |||
| af678802bb | |||
| 66068ec73c | |||
| 32e939c183 | |||
| b610da16a9 | |||
| 5dfcba3c51 | |||
| d48e05cd74 | |||
| 6f4cb46d94 | |||
| 5886d90d16 | |||
| ade7160c20 | |||
| 0c22b322ae | |||
| a5ba118393 | |||
| 7acf119c77 | |||
| bd00ba7971 | |||
| f94a811dd9 | |||
| deb46eaf41 | |||
| 7812d1c37b | |||
| c2d401723f | |||
| 142169ee42 | |||
| 55e884889c | |||
| 67e36fa38f | |||
| 3dbe024029 | |||
| 96b7aff3b6 | |||
| 1ad75adf87 | |||
| 423f84353d | |||
| de3983e53f | |||
| 15bea93da8 | |||
| f5f84ac346 | |||
| d44e2d8eb0 | |||
| 39bcd5e83b | |||
| 3dd6dbbb37 | |||
| 5a5d2fb162 | |||
| 08b855e779 | |||
| 8a22259eba | |||
| 24d727dec8 | |||
| 93c4d1c2e3 | |||
| 66f9ace7bd | |||
| f3788ef61a | |||
| b9d801e8bc | |||
| 3a1c6cac95 | |||
| 8ff7040a0a | |||
| 118467e079 | |||
| 51f0c56b84 | |||
| 88a014807f | |||
| 7a5861f32f | |||
| 63a627e4d0 | |||
| f0d87ff8c4 | |||
| 30c2aa144b | |||
| bf4f24ceec | |||
| 3520499289 | |||
| 977becd5c9 | |||
| fd4c4a3772 | |||
| 7c6a22d3e1 | |||
| 41360bb2c5 | |||
| 9b00feb286 | |||
| f2681ba0b9 | |||
| 7c9548c668 | |||
| 7caa4575bd | |||
| 16a8fc3ad8 | |||
| cd31cc1fc9 | |||
| 2f3c1e7f7f | |||
| 61404cfbec | |||
| 12ec87235f | |||
| b822e2131a | |||
| 3b99a5401f | |||
| 5156928bdc | |||
| 20e7a66ded | |||
| 411f734aef | |||
| 2c898a91da | |||
| 28f8c82ccf | |||
| 54342178e0 | |||
| 11af0666ea | |||
| a72ecb39e0 | |||
| 47c23c6828 | |||
| 00e2a1db31 | |||
| 36cc6f445a | |||
| ad9ed8facf | |||
| 4a7eb831b8 | |||
| 28d51fdcf6 | |||
| 4ebb8a3b51 | |||
| e76dcd4638 | |||
| eaada667b3 | |||
| 5bc46dd720 | |||
| fe6e0eeab5 | |||
| 7e075c5b3d | |||
| 86dfc2bf97 | |||
| bda69c661f | |||
| 8f3fe14843 | |||
| 5c952169b3 | |||
| 371ba5c399 | |||
| 0f4649ab8d | |||
| 2b6f7e4868 | |||
| 2e3dc7f7a5 | |||
| 2d1af97590 | |||
| 1e813b0d4d | |||
| cdbfb3977b | |||
| e9d3684f87 | |||
| 021bcf0c97 | |||
| fba6da8120 | |||
| 9dbfbd0dc3 | |||
| 5980bc1fcb | |||
| b2aaf5c57f | |||
| e17224184e | |||
| 042007d9ed | |||
| c832a6cb6f | |||
| 3aed691cb8 | |||
| 7b92bd22e7 | |||
| 581badd101 | |||
| c4bc0af58a | |||
| f75dd5d4e3 | |||
| a4544e35f6 | |||
| 56d705e253 | |||
| 43c177e04d | |||
| 5a2d0b7b0b | |||
| 43298dee1c | |||
| 26014ecb58 | |||
| 57dd06d774 | |||
| e21eb72705 | |||
| 00b1dbdffa | |||
| 55f74a8244 | |||
| db0c54b781 | |||
| 5c9cb7eece | |||
| b2d816d20c | |||
| 5b832cea8b | |||
| c1780230e9 | |||
| b90953f65e | |||
| 44041863ad | |||
| 2692041329 | |||
| 4a8ea185e6 | |||
| 98861a6bbd | |||
| 135d947c39 | |||
| f3cbbb8d81 | |||
| 3ecf172fb5 | |||
| c9871a0079 | |||
| 744e5a251a | |||
| e89198d9bb | |||
| e61e0c018c | |||
| b57763e688 | |||
| 3ccbb325b3 | |||
| 3ea345ee8f | |||
| ed2c50daac | |||
| f27d5ea08f | |||
| 35ab9ae202 | |||
| bd99665d1c | |||
| 93bab299ec | |||
| eb33f93322 | |||
| d165b699f0 | |||
| 7817295d8e | |||
| a986e531d9 | |||
| 8a3b652dcd | |||
| efbea63154 | |||
| 61045fa548 | |||
| da5e1f315d | |||
| 85c57ce027 | |||
| 6682c07eb6 | |||
| 4e887c3429 | |||
| 6435271be8 | |||
| c9a77fa65d | |||
| cc5399d36e | |||
| ca1aa5675a | |||
| e21bfbbd14 | |||
| e948d598b0 | |||
| 0173d67a3b | |||
| 025547a3dc | |||
| af830d603d | |||
| 669fd23868 | |||
| 4ff7fc079c | |||
| 7f24d6db5c | |||
| 8c8d01c29c | |||
| d23e6bb60c |
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# termscp pre-commit hook.
|
||||
#
|
||||
# Runs two gates before a commit is recorded:
|
||||
# 1. dprint -- check formatting (Markdown, TOML, YAML, Rust)
|
||||
# 2. cargo-deny -- advisories, licenses, bans, and sources
|
||||
#
|
||||
# Install with `just setup_githooks` (sets core.hooksPath to .githooks).
|
||||
# Bypass in an emergency with `git commit --no-verify`.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
fail() {
|
||||
echo "pre-commit: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
command -v just >/dev/null 2>&1 || fail "just not found; install it to run the pre-commit checks"
|
||||
|
||||
if ! git diff --cached --quiet --diff-filter=ACMR --; then
|
||||
# Check the exact tree that will be committed, not possibly different
|
||||
# working-tree contents. The trailing slash is required by checkout-index.
|
||||
index_tree="$(mktemp -d)"
|
||||
cleanup() {
|
||||
rm -rf -- "$index_tree"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
git checkout-index --all --prefix="$index_tree/"
|
||||
|
||||
echo "pre-commit: checking staged-tree formatting"
|
||||
(
|
||||
cd "$index_tree"
|
||||
just fmt_check
|
||||
)
|
||||
|
||||
echo "pre-commit: checking staged-tree dependencies"
|
||||
(
|
||||
cd "$index_tree"
|
||||
just deny
|
||||
)
|
||||
fi
|
||||
|
||||
echo "pre-commit: all checks passed"
|
||||
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: veeso
|
||||
liberapay: veeso
|
||||
@@ -1,10 +1,9 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help me improving TermSCP
|
||||
title: "[BUG]"
|
||||
about: Create a report of the bug you've encountered
|
||||
title: "[BUG] - ISSUE_TITLE"
|
||||
labels: bug
|
||||
assignees: ChristianVisintin
|
||||
|
||||
assignees: veeso
|
||||
---
|
||||
|
||||
## Description
|
||||
@@ -24,10 +23,15 @@ A clear and concise description of what you expected to happen.
|
||||
- OS: [e.g. GNU/Linux Debian 10]
|
||||
- Architecture [Arm, x86_64, ...]
|
||||
- Rust version
|
||||
- TermSCP version
|
||||
- termscp version
|
||||
- Protocol used
|
||||
- Remote server version and name
|
||||
|
||||
## Log
|
||||
|
||||
Report the snippet of the log file containing the unexpected behaviour.
|
||||
If there is any information you consider to be confidential, shadow it.
|
||||
|
||||
## Additional information
|
||||
|
||||
Add any other context about the problem here.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: Copy
|
||||
about: Report a typo/error in a repository document
|
||||
title: "[COPY] - ISSUE_TITLE"
|
||||
labels: documentation
|
||||
assignees: veeso
|
||||
---
|
||||
|
||||
## Report
|
||||
|
||||
### DOCUMENT NAME
|
||||
|
||||
This sentence at row ROW_NUMBER doesn't seem right:
|
||||
|
||||
> Write down here the wrong sentence
|
||||
|
||||
and I think it should be changed to:
|
||||
|
||||
> Write down here the correct sentence
|
||||
|
||||
`Copy paste the template above for all the sentences to fix`
|
||||
|
||||
---
|
||||
|
||||
`Copy paste the template above for all the documents to fix`
|
||||
|
||||
## Additional information
|
||||
|
||||
> ❗ Report LANGUAGE checks only if it concerns the documents above
|
||||
> ❗ If the documents concerns more than one language, copy paste the checks below for each check you want to report
|
||||
> ❗ The PR mention regards the indicated language. If you check the box, I may add you to a PR where I need to translate a new section of the user manual/README or other documents. I promise I won't stress you anyway.
|
||||
|
||||
- [ ] I am C1/C2 speaker for this language: LANGUAGE
|
||||
- [ ] You can mention me in a PR in case a review for translations is needed
|
||||
@@ -1,12 +1,22 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for TermSCP
|
||||
title: "[Feature Request]"
|
||||
labels: enhancement
|
||||
assignees: ChristianVisintin
|
||||
|
||||
about: Suggest an idea to improve termscp
|
||||
title: "[Feature Request] - FEATURE_TITLE"
|
||||
labels: "new feature"
|
||||
assignees: veeso
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Describe the feature you'd like to be added
|
||||
Put here a brief introduction to your suggestion.
|
||||
|
||||
### Changes
|
||||
|
||||
The following changes to the application are expected
|
||||
|
||||
- ...
|
||||
|
||||
## Implementation
|
||||
|
||||
Provide any kind of suggestion you propose on how to implement the feature.
|
||||
If you have none, delete this section.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask what you want about the project
|
||||
title: "[QUESTION] - TITLE"
|
||||
labels: question
|
||||
assignees: veeso
|
||||
---
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Security report
|
||||
about: Create a report of a security vulnerability
|
||||
title: "[SECURITY] - ISSUE_TITLE"
|
||||
labels: security
|
||||
assignees: veeso
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Severity:
|
||||
|
||||
- [ ] **critical**
|
||||
- [ ] high
|
||||
- [ ] medium
|
||||
- [ ] low
|
||||
|
||||
A clear and concise description of the security vulnerability.
|
||||
|
||||
## Additional information
|
||||
|
||||
Add any other context about the problem here.
|
||||
@@ -1,31 +1,15 @@
|
||||
# Pull Request Title
|
||||
# Description
|
||||
|
||||
Fixes # (issue)
|
||||
|
||||
## Description
|
||||
|
||||
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
|
||||
|
||||
List here your changes
|
||||
|
||||
- I made this...
|
||||
- I made also that...
|
||||
|
||||
## Type of change
|
||||
|
||||
Please select relevant options.
|
||||
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] This change requires a documentation update
|
||||
<!--
|
||||
Provide a brief description of the changes you made in this pull request. If your changes are related to a specific issue, please mention the issue number (e.g., "Fixes #123").
|
||||
-->
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] My code follows the contribution guidelines of this project
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have made corresponding changes to the documentation
|
||||
- [ ] My changes generate no new warnings
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] Any dependent changes have been merged and published in downstream modules
|
||||
- [ ] I have read the [AI Policy](https://github.com/veeso/termscp/blob/main/AI_POLICY.md) and the [contributing guidelines](https://github.com/veeso/termscp/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## AI Disclosure
|
||||
|
||||
<!--
|
||||
Describe how you used AI tools in this contribution. If you did not use any AI tools, write "N/A".
|
||||
-->
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
branch: false
|
||||
ignore-not-existing: true
|
||||
llvm: true
|
||||
output-type: lcov
|
||||
ignore:
|
||||
- "/*"
|
||||
- "C:/*"
|
||||
- "../*"
|
||||
- src/main.rs
|
||||
- src/activity_manager.rs
|
||||
- src/cli_opts.rs
|
||||
- src/support.rs
|
||||
- src/system/notifications.rs
|
||||
- "src/ui/activities/*"
|
||||
- src/ui/context.rs
|
||||
- src/ui/input.rs
|
||||
@@ -1,21 +0,0 @@
|
||||
name: aur-pub
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
jobs:
|
||||
aur-publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Publish AUR package
|
||||
uses: KSXGitHub/github-actions-deploy-aur@v2.2.3
|
||||
with:
|
||||
pkgname: termscp
|
||||
pkgbuild: ./dist/pkgs/arch/PKGBUILD
|
||||
commit_username: ${{ secrets.AUR_USERNAME }}
|
||||
commit_email: ${{ secrets.AUR_EMAIL }}
|
||||
ssh_private_key: ${{ secrets.AUR_KEY }}
|
||||
commit_message: Update AUR package
|
||||
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
|
||||
@@ -0,0 +1,138 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "*.md"
|
||||
- "site/**"
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "*.md"
|
||||
- "site/**"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
toolchain:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
channel: ${{ steps.extract.outputs.result }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Extract toolchain channel from rust-toolchain.toml
|
||||
id: extract
|
||||
uses: mikefarah/yq@c14f446382944492701b16c1ddb48bb9dbe683e3 # v4.53.6
|
||||
with:
|
||||
cmd: yq '.toolchain.channel' rust-toolchain.toml
|
||||
|
||||
fmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Rust (nightly)
|
||||
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: rustfmt
|
||||
- name: Check formatting
|
||||
uses: dprint/check@9cb3a2b17a8e606d37aae341e49df3654933fc23 # v2.3
|
||||
|
||||
install-scripts:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Check install scripts
|
||||
run: just check_install_scripts
|
||||
|
||||
crates:
|
||||
needs: toolchain
|
||||
name: crates-${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Linux dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev libsmbclient-dev
|
||||
- name: Install macOS dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew update
|
||||
brew install \
|
||||
pkg-config \
|
||||
samba
|
||||
brew link --force samba
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
|
||||
with:
|
||||
toolchain: ${{ needs.toolchain.outputs.channel }}
|
||||
components: clippy
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Build
|
||||
run: just build_crates
|
||||
- name: Test (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: just test "--no-default-features --features github-actions --no-fail-fast"
|
||||
- name: Test
|
||||
if: runner.os != 'Linux'
|
||||
run: just test "--verbose --features github-actions"
|
||||
- name: Clippy
|
||||
run: just clippy "-- -D warnings"
|
||||
|
||||
doc:
|
||||
needs: toolchain
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Linux dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev libsmbclient-dev
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
|
||||
with:
|
||||
toolchain: ${{ needs.toolchain.outputs.channel }}
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Build documentation
|
||||
run: just doc
|
||||
|
||||
deny:
|
||||
needs: toolchain
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
|
||||
with:
|
||||
toolchain: ${{ needs.toolchain.outputs.channel }}
|
||||
- name: Install cargo-deny
|
||||
uses: taiki-e/install-action@37f7c5781271959fb65b6b35224e28652ff2b63d # v2.87.0
|
||||
with:
|
||||
tool: cargo-deny
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Check dependencies
|
||||
run: just deny
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Install.sh
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install termscp from script
|
||||
run: |
|
||||
./install.sh -f
|
||||
which termscp || exit 1
|
||||
termscp --version
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Linux
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all-features --no-fail-fast
|
||||
env:
|
||||
CARGO_INCREMENTAL: "0"
|
||||
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
|
||||
RUSTDOCFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
|
||||
- name: Clippy
|
||||
run: cargo clippy
|
||||
- name: Coverage with grcov
|
||||
uses: actions-rs/grcov@v0.1
|
||||
- name: Upload to codecov.io
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@@ -1,19 +0,0 @@
|
||||
name: MacOS
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
- name: Clippy
|
||||
run: cargo clippy
|
||||
@@ -0,0 +1,66 @@
|
||||
name: Deploy docs to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "docs/**"
|
||||
- ".github/workflows/pages.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pages: write
|
||||
id-token: write
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install mdBook
|
||||
uses: peaceiris/actions-mdbook@ee69d230fe19748b7abf22df32acaa93833fad08 # v2
|
||||
with:
|
||||
mdbook-version: latest
|
||||
- name: Install mdbook-mermaid
|
||||
run: cargo install mdbook-mermaid
|
||||
- name: Build en-US
|
||||
run: mdbook build docs/en-US
|
||||
- name: Build zh-CN
|
||||
run: mdbook build docs/zh-CN
|
||||
- name: Assemble site
|
||||
run: |
|
||||
rm -rf site_out
|
||||
mkdir -p site_out/en-US site_out/zh-CN
|
||||
cp -r docs/en-US/book/* site_out/en-US/
|
||||
cp -r docs/zh-CN/book/* site_out/zh-CN/
|
||||
cp -r docs/shared site_out/shared
|
||||
cp docs/shared/og_preview.jpg site_out/og_preview.jpg
|
||||
cp docs/shared/favicon.ico site_out/favicon.ico
|
||||
cp docs/CNAME site_out/CNAME
|
||||
cat > site_out/index.html <<'HTML'
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>termscp docs</title>
|
||||
<meta http-equiv="refresh" content="0; url=./en-US/">
|
||||
<link rel="canonical" href="./en-US/">
|
||||
<a href="./en-US/">termscp documentation</a>
|
||||
HTML
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
||||
with:
|
||||
path: site_out
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
|
||||
@@ -0,0 +1,475 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Version to release, e.g. 1.1.0 (no leading v)"
|
||||
required: true
|
||||
type: string
|
||||
dry_run:
|
||||
description: "Dry run: build & compute everything, push/publish nothing"
|
||||
required: true
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ inputs.version }}
|
||||
prepared_ref: ${{ steps.prepared-ref.outputs.ref }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_PAT }}
|
||||
persist-credentials: true
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Validate version
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
if [[ ! "$VERSION" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
|
||||
echo "invalid release version: $VERSION (expected MAJOR.MINOR.PATCH)" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
- name: Configure git identity
|
||||
run: |
|
||||
git config user.name "veeso"
|
||||
git config user.email "christian.visintin@veeso.dev"
|
||||
|
||||
- name: Install git-cliff
|
||||
uses: taiki-e/install-action@e67fa11c4b9316fa714ddf0abed07a0c3143b95b # v2.87.4
|
||||
with:
|
||||
tool: git-cliff,dprint
|
||||
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
|
||||
- name: Bump version
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: dist/release/bump_version.sh "$VERSION" "$(date +%F)"
|
||||
|
||||
- name: Generate CHANGELOG
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: just changelog "$VERSION"
|
||||
|
||||
- name: Generate release notes
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: git-cliff --unreleased --tag "v$VERSION" --strip header -o RELEASE_NOTES.md
|
||||
|
||||
- name: Verify Cargo.lock is unchanged
|
||||
run: git diff --exit-code -- Cargo.lock
|
||||
|
||||
- name: Upload release notes
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: release-notes
|
||||
path: RELEASE_NOTES.md
|
||||
retention-days: 1
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Show diff (dry run)
|
||||
if: ${{ inputs.dry_run }}
|
||||
run: git --no-pager diff
|
||||
|
||||
- name: Commit & push version bump
|
||||
if: ${{ !inputs.dry_run }}
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
rm -f RELEASE_NOTES.md
|
||||
git add -A -- . ':!Cargo.lock'
|
||||
git diff --cached --exit-code -- Cargo.lock
|
||||
git commit -m "chore: release v$VERSION"
|
||||
git push origin HEAD:main
|
||||
|
||||
- name: Export prepared ref
|
||||
id: prepared-ref
|
||||
env:
|
||||
DRY_RUN: ${{ inputs.dry_run }}
|
||||
run: |
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo "ref=$GITHUB_SHA" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "ref=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
build:
|
||||
needs: prepare
|
||||
name: build-${{ matrix.target }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-linux-musl
|
||||
os: ubuntu-24.04
|
||||
kind: linux
|
||||
- target: aarch64-unknown-linux-musl
|
||||
os: ubuntu-24.04-arm
|
||||
kind: linux
|
||||
- target: aarch64-apple-darwin
|
||||
os: macos-latest
|
||||
kind: macos
|
||||
features: "--features smb-vendored"
|
||||
- target: x86_64-apple-darwin
|
||||
os: macos-latest
|
||||
kind: macos
|
||||
features: "--no-default-features --features keyring"
|
||||
- target: x86_64-pc-windows-msvc
|
||||
os: windows-latest
|
||||
kind: windows
|
||||
- target: aarch64-pc-windows-msvc
|
||||
os: windows-11-arm
|
||||
kind: windows
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
FEATURES: ${{ matrix.features }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
ref: ${{ needs.prepare.outputs.prepared_ref }}
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- name: Prepare release version
|
||||
shell: bash
|
||||
run: |
|
||||
dist/release/bump_version.sh "$VERSION" "$(date +%F)"
|
||||
cargo update --package termscp --precise "$VERSION"
|
||||
cargo metadata --locked --no-deps --format-version 1 > /dev/null
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Install Rust target
|
||||
if: matrix.kind == 'macos'
|
||||
run: rustup target add "$TARGET"
|
||||
- name: Install Rust target
|
||||
if: matrix.kind == 'windows'
|
||||
run: rustup target add "$env:TARGET"
|
||||
|
||||
# ---- Linux: static musl build in a pinned Alpine container ----
|
||||
- name: Install cargo-deb (Linux)
|
||||
if: matrix.kind == 'linux'
|
||||
run: cargo install cargo-deb --locked
|
||||
- name: Build (Linux)
|
||||
if: matrix.kind == 'linux'
|
||||
run: just build_musl "$TARGET"
|
||||
- name: Build deb (Linux)
|
||||
if: matrix.kind == 'linux'
|
||||
run: cargo deb --locked --no-build --target "$TARGET" --features smb-vendored
|
||||
- name: Verify deb declares no runtime dependencies (Linux)
|
||||
if: matrix.kind == 'linux'
|
||||
run: |
|
||||
deb=$(ls target/"$TARGET"/debian/*.deb)
|
||||
depends=$(dpkg-deb -f "$deb" Depends)
|
||||
if [ -n "$depends" ]; then
|
||||
echo "static deb must have no Depends, got: $depends" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---- macOS ----
|
||||
- name: Install deps (macOS)
|
||||
if: matrix.kind == 'macos'
|
||||
run: |
|
||||
brew update
|
||||
brew install bison cpanminus cups flex gettext gmp gnutls icu4c jansson \
|
||||
libarchive libbsd libunistring libgit2 libtirpc openldap pkg-config zlib
|
||||
for p in bison cups flex gettext gmp gnutls icu4c jansson libarchive \
|
||||
libbsd libgit2 libtirpc libunistring openldap zlib; do brew link --force "$p"; done
|
||||
cpanm Parse::Yapp::Driver
|
||||
- name: Build (macOS)
|
||||
if: matrix.kind == 'macos'
|
||||
run: just build_release "$TARGET" "$FEATURES"
|
||||
|
||||
# ---- Windows ----
|
||||
- name: Build (Windows)
|
||||
if: matrix.kind == 'windows'
|
||||
run: just build_release "$env:TARGET" "--features smb-vendored"
|
||||
|
||||
# ---- Package posix (tar.gz) ----
|
||||
- name: Package (posix)
|
||||
if: matrix.kind != 'windows'
|
||||
run: |
|
||||
mkdir -p artifact
|
||||
cp "target/$TARGET/release/termscp" artifact/termscp
|
||||
tar -czf "artifact/termscp-v$VERSION-$TARGET.tar.gz" -C artifact termscp
|
||||
shasum -a 256 "artifact/termscp-v$VERSION-$TARGET.tar.gz" | awk '{print $1}' > "artifact/$TARGET.sha256"
|
||||
|
||||
# ---- Package windows (zip) ----
|
||||
- name: Package (windows)
|
||||
if: matrix.kind == 'windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
New-Item -ItemType Directory -Force artifact | Out-Null
|
||||
Copy-Item "target/$env:TARGET/release/termscp.exe" artifact/termscp.exe
|
||||
Compress-Archive -Path artifact/termscp.exe -DestinationPath "artifact/termscp-v$env:VERSION-$env:TARGET.zip"
|
||||
(Get-FileHash "artifact/termscp-v$env:VERSION-$env:TARGET.zip" -Algorithm SHA256).Hash.ToLower() | Out-File -NoNewline "artifact/$env:TARGET.sha256"
|
||||
|
||||
- name: Move deb into artifact dir (Linux)
|
||||
if: matrix.kind == 'linux'
|
||||
run: cp target/"$TARGET"/debian/*.deb artifact/
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: build-${{ matrix.target }}
|
||||
path: artifact/*
|
||||
retention-days: 1
|
||||
if-no-files-found: error
|
||||
|
||||
publish-homebrew:
|
||||
needs: [prepare, build, release]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
steps:
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
pattern: build-*
|
||||
path: dl
|
||||
merge-multiple: true
|
||||
|
||||
- name: Checkout homebrew tap
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
repository: veeso/homebrew-termscp
|
||||
token: ${{ secrets.RELEASE_PAT }}
|
||||
path: tap
|
||||
persist-credentials: true
|
||||
|
||||
- name: Rewrite formula
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
SHA_MAC_ARM=$(cat dl/aarch64-apple-darwin.sha256)
|
||||
SHA_MAC_X64=$(cat dl/x86_64-apple-darwin.sha256)
|
||||
SHA_LIN_ARM=$(cat dl/aarch64-unknown-linux-musl.sha256)
|
||||
SHA_LIN_X64=$(cat dl/x86_64-unknown-linux-musl.sha256)
|
||||
BASE="https://github.com/veeso/termscp/releases/latest/download"
|
||||
cat > tap/Formula/termscp.rb <<EOF
|
||||
class Termscp < Formula
|
||||
desc "A feature rich terminal file transfer and explorer with support for SCP/SFTP/FTP/S3/GCS/Kube/SMB/WebDAV"
|
||||
homepage "https://termscp.rs/"
|
||||
license "MIT"
|
||||
version "$VERSION"
|
||||
|
||||
on_macos do
|
||||
depends_on "bison"
|
||||
depends_on "cups"
|
||||
depends_on "flex"
|
||||
depends_on "gettext"
|
||||
depends_on "gmp"
|
||||
depends_on "gnutls"
|
||||
depends_on "icu4c"
|
||||
depends_on "jansson"
|
||||
depends_on "libarchive"
|
||||
depends_on "libbsd"
|
||||
depends_on "libgit2"
|
||||
depends_on "libtirpc"
|
||||
depends_on "libunistring"
|
||||
depends_on "openldap"
|
||||
depends_on "zlib"
|
||||
|
||||
on_arm do
|
||||
url "$BASE/termscp-v$VERSION-aarch64-apple-darwin.tar.gz"
|
||||
sha256 "$SHA_MAC_ARM"
|
||||
end
|
||||
on_intel do
|
||||
url "$BASE/termscp-v$VERSION-x86_64-apple-darwin.tar.gz"
|
||||
sha256 "$SHA_MAC_X64"
|
||||
end
|
||||
end
|
||||
|
||||
on_linux do
|
||||
on_arm do
|
||||
url "$BASE/termscp-v$VERSION-aarch64-unknown-linux-musl.tar.gz"
|
||||
sha256 "$SHA_LIN_ARM"
|
||||
end
|
||||
on_intel do
|
||||
url "$BASE/termscp-v$VERSION-x86_64-unknown-linux-musl.tar.gz"
|
||||
sha256 "$SHA_LIN_X64"
|
||||
end
|
||||
end
|
||||
|
||||
def install
|
||||
bin.install "termscp"
|
||||
end
|
||||
end
|
||||
EOF
|
||||
|
||||
- name: Show formula (dry run)
|
||||
if: ${{ inputs.dry_run }}
|
||||
run: cat tap/Formula/termscp.rb
|
||||
|
||||
- name: Commit & push formula
|
||||
if: ${{ !inputs.dry_run }}
|
||||
run: |
|
||||
cd tap
|
||||
git config user.name "veeso"
|
||||
git config user.email "christian.visintin@veeso.dev"
|
||||
git add Formula/termscp.rb
|
||||
git commit -m "termscp $VERSION"
|
||||
git push
|
||||
|
||||
release:
|
||||
needs: [prepare, build]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_PAT }}
|
||||
ref: ${{ needs.prepare.outputs.prepared_ref }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Prepare release version
|
||||
run: |
|
||||
dist/release/bump_version.sh "$VERSION" "$(date +%F)"
|
||||
cargo update --package termscp --precise "$VERSION"
|
||||
cargo metadata --locked --no-deps --format-version 1 > /dev/null
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
pattern: build-*
|
||||
path: dl
|
||||
merge-multiple: true
|
||||
|
||||
- name: Download release notes
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: release-notes
|
||||
path: notes
|
||||
|
||||
- name: Patch chocolatey checksums & pack
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SHA_WIN_X64=$(cat dl/x86_64-pc-windows-msvc.sha256)
|
||||
SHA_WIN_ARM=$(cat dl/aarch64-pc-windows-msvc.sha256)
|
||||
PS=dist/chocolatey/tools/chocolateyinstall.ps1
|
||||
# arm checksum is the first $checksum line, x64 the second (matches file order)
|
||||
SHA_WIN_ARM="$SHA_WIN_ARM" SHA_WIN_X64="$SHA_WIN_X64" \
|
||||
perl -0pi -e 'BEGIN{our $n=0} s/(\$checksum\s*=\s*'"'"')[0-9a-f]*('"'"')/ $n++==0 ? "${1}$ENV{SHA_WIN_ARM}${2}" : "${1}$ENV{SHA_WIN_X64}${2}" /ge' "$PS"
|
||||
docker run --rm -v "$PWD/dist/chocolatey:/work" -w /work \
|
||||
chocolatey/choco:latest choco pack --output-directory /work
|
||||
|
||||
- name: Assemble release assets
|
||||
run: |
|
||||
mkdir -p out
|
||||
cp dl/*.tar.gz dl/*.deb dl/*.zip out/ 2>/dev/null || true
|
||||
cp dist/chocolatey/*.nupkg out/
|
||||
|
||||
- name: Upload assets artifact (dry run)
|
||||
if: ${{ inputs.dry_run }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: release-assets-dryrun
|
||||
path: out/*
|
||||
retention-days: 3
|
||||
|
||||
- name: Create GitHub release
|
||||
if: ${{ !inputs.dry_run }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
|
||||
run: |
|
||||
gh release create "v$VERSION" out/* \
|
||||
--title "v$VERSION" \
|
||||
--notes-file notes/RELEASE_NOTES.md
|
||||
|
||||
publish-crate:
|
||||
needs: [prepare, release]
|
||||
if: ${{ !inputs.dry_run }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
ref: ${{ needs.prepare.outputs.prepared_ref }}
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- name: Prepare release version
|
||||
run: |
|
||||
dist/release/bump_version.sh "$VERSION" "$(date +%F)"
|
||||
cargo update --package termscp --precise "$VERSION"
|
||||
cargo metadata --locked --no-deps --format-version 1 > /dev/null
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
|
||||
- name: Install dependencies (Linux)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
make \
|
||||
libgit2-dev \
|
||||
build-essential \
|
||||
pkg-config \
|
||||
libbsd-dev \
|
||||
libcap-dev \
|
||||
libcups2-dev \
|
||||
libgnutls28-dev \
|
||||
libicu-dev \
|
||||
libjansson-dev \
|
||||
libkeyutils-dev \
|
||||
libldap2-dev \
|
||||
zlib1g-dev \
|
||||
libpam0g-dev \
|
||||
libacl1-dev \
|
||||
libarchive-dev \
|
||||
flex \
|
||||
bison \
|
||||
libntirpc-dev \
|
||||
libtracker-sparql-3.0-dev \
|
||||
libglib2.0-dev \
|
||||
libdbus-1-dev \
|
||||
libsasl2-dev \
|
||||
libunistring-dev \
|
||||
cpanminus
|
||||
sudo cpanm Parse::Yapp::Driver
|
||||
|
||||
- name: Authenticate to crates.io
|
||||
id: auth
|
||||
uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5
|
||||
|
||||
- name: Publish to crates.io
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
|
||||
run: just publish_crate
|
||||
|
||||
publish-choco:
|
||||
needs: [prepare, release]
|
||||
if: ${{ !inputs.dry_run }}
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
steps:
|
||||
- name: Download nupkg from release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
|
||||
run: gh release download "v$env:VERSION" --repo veeso/termscp --pattern "*.nupkg"
|
||||
|
||||
- name: Push to Chocolatey
|
||||
env:
|
||||
CHOCO_API_KEY: ${{ secrets.CHOCO_API_KEY }}
|
||||
run: |
|
||||
choco apikey --key $env:CHOCO_API_KEY --source https://push.chocolatey.org/
|
||||
choco push (Get-ChildItem *.nupkg).Name --source https://push.chocolatey.org/
|
||||
@@ -0,0 +1,36 @@
|
||||
name: Site
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-site:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: site/package-lock.json
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Install dependencies
|
||||
run: just site_install
|
||||
- name: Format
|
||||
run: just site_fmt_check
|
||||
- name: Lint
|
||||
run: just site_check
|
||||
- name: Test
|
||||
run: just site_test
|
||||
- name: Build
|
||||
run: just site_build
|
||||
@@ -0,0 +1,27 @@
|
||||
name: Close inactive issues
|
||||
on:
|
||||
schedule:
|
||||
- cron: "30 1 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
close-issues:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
|
||||
with:
|
||||
days-before-issue-stale: 30
|
||||
days-before-issue-close: 7
|
||||
stale-issue-label: "stale"
|
||||
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
|
||||
close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale."
|
||||
days-before-pr-stale: -1
|
||||
days-before-pr-close: -1
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
exempt-issue-labels: "backlog"
|
||||
exempt-all-milestones: true
|
||||
@@ -1,19 +0,0 @@
|
||||
name: Windows
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-2019
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
- name: Clippy
|
||||
run: cargo clippy
|
||||
@@ -21,3 +21,14 @@ dist/pkgs/arch/*.tar.gz
|
||||
|
||||
# Macos
|
||||
.DS_Store
|
||||
|
||||
dist/pkgs/
|
||||
dist/build/macos/openssl/
|
||||
|
||||
.idea/
|
||||
.claude/
|
||||
|
||||
|
||||
# brainstorming visual companion
|
||||
.superpowers/
|
||||
docs/*/book/
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
// Markdown lint config for the termscp docs site (mdBook).
|
||||
"config": {
|
||||
// Line length is impractical for keyboard/style tables and long prose;
|
||||
// mdBook reflows in the browser, so we don't enforce a hard wrap.
|
||||
"MD013": false,
|
||||
// Table column alignment can't be satisfied for CJK (zh-CN) content:
|
||||
// markdownlint counts code points while CJK glyphs are double-width, so a
|
||||
// visually aligned table never matches. Rendering is unaffected.
|
||||
"MD060": false
|
||||
},
|
||||
"globs": ["docs/en-US/**/*.md", "docs/zh-CN/**/*.md"],
|
||||
"ignores": [
|
||||
// mdBook build output.
|
||||
"**/book/**",
|
||||
// SUMMARY.md uses multiple level-1 headings as mdBook part titles.
|
||||
"**/SUMMARY.md",
|
||||
// GitHub READMEs (not part of the book) keep centered HTML badges.
|
||||
"**/README.md"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
# AI Policy
|
||||
|
||||
The maintainers of this project don't want to interact directly with bots.
|
||||
Contributions must come from a human who understands the submitted code or text,
|
||||
can explain it, and is responsible for its quality as if they wrote it
|
||||
themselves. Using AI as a tool to help you write or reason about a contribution
|
||||
is fine; submitting AI output you don't understand, or relaying messages
|
||||
between a maintainer and an AI, is not.
|
||||
|
||||
If you wish to include context from an interaction with AI in your comments, it
|
||||
must be in a quote block (e.g., using `>`) and disclosed as such. It must be
|
||||
accompanied by human commentary explaining the relevance and implications of
|
||||
the context.
|
||||
|
||||
If you plan to contribute to termscp using AI tools, you **must** read,
|
||||
understand and follow this policy.
|
||||
|
||||
## Disclosure
|
||||
|
||||
You **must** disclose the use of AI tools in your contributions. You
|
||||
**must** perform this disclosure through the pull request template; filing
|
||||
PRs without using the pull request template is a violation of this policy.
|
||||
|
||||
This applies to any AI tool that generated or substantially shaped the content
|
||||
you submit — code, prose or commit messages — including agents, chat assistants
|
||||
and AI-assisted editors. Mechanical editor autocompletion of a few characters
|
||||
does not need to be disclosed; if in doubt, disclose.
|
||||
|
||||
## Translations
|
||||
|
||||
AI is useful when communicating as a non-native English speaker. If you are
|
||||
using AI to edit your comments for this purpose, please take the time to ensure
|
||||
it reflects your own voice and ideas.
|
||||
|
||||
## Provenance and licensing
|
||||
|
||||
You are responsible for the provenance of anything you submit. AI tools can
|
||||
reproduce code or text from their training data verbatim, which may carry a
|
||||
license incompatible with this project. By contributing, you confirm the work
|
||||
is yours to submit under the project's license and does not infringe a third
|
||||
party's rights. The same standard that applies to code you write by hand.
|
||||
|
||||
## Consequences
|
||||
|
||||
Violating this policy may get your contribution rejected and, for repeated or
|
||||
egregious violations, get you blocked from the project without further warning.
|
||||
|
||||
## Examples
|
||||
|
||||
Examples of things that are not allowed:
|
||||
|
||||
- Point an agent to a GitHub issue, ask it to solve the issue and open a PR,
|
||||
without understanding the issue, the PR, or testing the solution yourself.
|
||||
- Copy responses from the AI when replying to questions from maintainers,
|
||||
without understanding the question or the response.
|
||||
In other words, you should not "play telephone" between your AI-generated code,
|
||||
the reviewer, and the AI tool.
|
||||
|
||||
## Inspiration
|
||||
|
||||
This AI policy was inspired by:
|
||||
|
||||
- [release-plz](https://github.com/release-plz/.github/blob/main/AI_POLICY.md)
|
||||
@@ -0,0 +1,116 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
termscp is a terminal file transfer client with a TUI (Terminal User Interface), supporting SFTP, SCP, FTP/FTPS, Kube, S3, GCS, SMB, and WebDAV protocols. It features a dual-pane file explorer (local + remote), bookmarks, system keyring integration, file watching/sync, an embedded terminal, and customizable themes.
|
||||
|
||||
- **Language**: Rust (edition 2024, MSRV 1.98.0)
|
||||
- **UI Framework**: tuirealm v3 (built on crossterm)
|
||||
- **File Transfer**: remotefs ecosystem
|
||||
|
||||
## Build & Development Commands
|
||||
|
||||
Task runner is `just` (modular recipes under `just/*.just`, imported by root `justfile`). Run `just --list` for the full set.
|
||||
|
||||
```bash
|
||||
# Build
|
||||
just build_crates # cargo build --workspace
|
||||
just build_crates "--release"
|
||||
cargo build --no-default-features # minimal build without SMB/keyring (no just recipe)
|
||||
|
||||
# Test (CI-equivalent)
|
||||
just test "--no-default-features --features github-actions --no-fail-fast"
|
||||
|
||||
# Run a single test / a module (use cargo directly, just recipes don't take test names)
|
||||
cargo test <test_name> -- --nocapture
|
||||
cargo test --lib filetransfer::
|
||||
cargo test --lib config::params::tests
|
||||
|
||||
# Lint
|
||||
just clippy "-- -D warnings"
|
||||
|
||||
# Format (dprint: Markdown, TOML, YAML, and Rust via nightly rustfmt)
|
||||
just fmt_check # check only
|
||||
just fmt # fix
|
||||
|
||||
# All code checks at once (fmt_check, clippy -D warnings, doc, deny, install script lint)
|
||||
just check_code
|
||||
```
|
||||
|
||||
### System Dependencies (for building)
|
||||
|
||||
- **Linux**: `libdbus-1-dev`, `libsmbclient-dev`
|
||||
- **macOS**: `pkg-config`, `samba` (brew, with force link)
|
||||
|
||||
## Feature Flags
|
||||
|
||||
- **`smb`** (default): SMB/Samba protocol support
|
||||
- **`keyring`** (default): System keyring integration for password storage
|
||||
- **`smb-vendored`**: Vendored SMB library (for static builds)
|
||||
- **`github-actions`**: CI flag — disables real keyring in tests, uses file-based storage
|
||||
- **`isolated-tests`**: For parallel test isolation
|
||||
|
||||
## Architecture
|
||||
|
||||
### Application Lifecycle
|
||||
|
||||
```
|
||||
main.rs → parse CLI args → ActivityManager::new() → ActivityManager::run()
|
||||
↓
|
||||
Activity loop (draw → poll → update)
|
||||
├── AuthActivity (login/bookmarks)
|
||||
├── FileTransferActivity (dual-pane explorer)
|
||||
└── SetupActivity (configuration)
|
||||
```
|
||||
|
||||
`ActivityManager` owns a `Context` that is passed between activities. Each activity takes ownership of the Context on `on_create()` and returns it on `on_destroy()`.
|
||||
|
||||
### Key Modules
|
||||
|
||||
| Module | Path | Purpose |
|
||||
| -------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| **activity_manager** | `src/activity_manager.rs` | Orchestrates activity lifecycle and transitions |
|
||||
| **ui/activities** | `src/ui/activities/{auth,filetransfer,setup}/` | Three main screens, each implementing the `Activity` trait |
|
||||
| **ui/context** | `src/ui/context.rs` | Shared `Context` struct (terminal, config, bookmarks, theme) |
|
||||
| **filetransfer** | `src/filetransfer/` | Protocol enum, `RemoteFsBuilder`, connection parameters |
|
||||
| **host** | `src/host/` | `HostBridge` trait — abstracts local (`Localhost`) and remote (`RemoteBridged`) file operations |
|
||||
| **explorer** | `src/explorer/` | `FileExplorer` — directory navigation, sorting, filtering, transfer queue |
|
||||
| **system** | `src/system/` | `BookmarksClient`, `ConfigClient`, `ThemeProvider`, `SshKeyStorage`, `KeyStorage` trait |
|
||||
| **config** | `src/config/` | TOML-based serialization for themes, bookmarks, user params |
|
||||
|
||||
### Core Traits
|
||||
|
||||
- **`Activity`** (`src/ui/activities/mod.rs`): `on_create`, `on_draw`, `will_umount`, `on_destroy` — UI screen lifecycle
|
||||
- **`HostBridge`** (`src/host/bridge.rs`): Unified file operations interface (connect, list_dir, open_file, mkdir, remove, rename, copy, etc.)
|
||||
- **`KeyStorage`** (`src/system/keys/mod.rs`): `get_key`/`set_key` — password storage abstraction (keyring or encrypted file fallback)
|
||||
|
||||
### Conditional Compilation
|
||||
|
||||
The `build.rs` defines cfg aliases via `cfg_aliases`:
|
||||
|
||||
- `posix`, `macos`, `linux`, `win` — platform shortcuts
|
||||
- `smb`, `smb_unix`, `smb_windows` — feature + platform combinations
|
||||
|
||||
Platform-specific dependencies: SSH and FTP crates use different TLS backends on Unix vs Windows. SMB support is completely gated behind the `smb` feature flag.
|
||||
|
||||
### File Transfer Protocols
|
||||
|
||||
`FileTransferProtocol` enum maps to protocol-specific parameter types (`ProtocolParams` enum) and `RemoteFsBuilder` constructs the appropriate `RemoteFs` client. Each protocol has its own params struct (e.g., `GenericProtocolParams` for SSH-based, `AwsS3Params`, `GoogleCloudStorageParams`, `KubeProtocolParams`, `SmbParams`, `WebDAVProtocolParams`).
|
||||
|
||||
## Code Conventions
|
||||
|
||||
- **rustfmt**: `group_imports = "StdExternalCrate"`, `imports_granularity = "Module"`
|
||||
- **Error handling**: Custom error types with `thiserror`, module-level Result aliases (e.g., `HostResult<T>`)
|
||||
- **Builder pattern**: Used for `RemoteFsBuilder`, `HostBridgeBuilder`
|
||||
- **Client pattern**: System services wrapped as clients (`BookmarksClient`, `ConfigClient`)
|
||||
- **Tests**: Unit tests in `#[cfg(test)]` blocks within source files. Tests requiring serial execution use `#[serial]` from `serial_test`
|
||||
- **Encryption**: Bookmark passwords encrypted with `magic-crypt`; keys stored in system keyring or encrypted file
|
||||
|
||||
## Other conventions
|
||||
|
||||
- Always run `just fmt` and `just clippy "-- -D warnings"` after modifying Rust code
|
||||
- Always put plans to `./.claude/plans/`
|
||||
- When changing behavior that is documented under `docs/` (paths, config keys, commands, flags, etc.), update BOTH `docs/en-US/` and `docs/zh-CN/` to keep the translations in sync
|
||||
- All code must be cross-platform compatible (Windows, macOS, Linux) — avoid POSIX-only APIs, hardcoded path separators, or shell-specific behavior unless gated behind the `posix`/`win` cfg aliases
|
||||
@@ -2,75 +2,131 @@
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official email address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at christian.visintin1997@gmail.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[INSERT CONTACT METHOD].
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
<https://www.contributor-covenant.org/faq>
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
||||
@@ -1,15 +1,107 @@
|
||||
# Contributing
|
||||
|
||||
Before contributing to this repository, please first discuss the change you wish to make via issue of this repository before making a change.
|
||||
Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
|
||||
Please note we have a [code of conduct](CODE_OF_CONDUCT.md). Please follow it in all your interactions with the project.
|
||||
|
||||
- [Contributing](#contributing)
|
||||
- [Project mission](#project-mission)
|
||||
- [Project goals](#project-goals)
|
||||
- [Open an issue](#open-an-issue)
|
||||
- [Questions](#questions)
|
||||
- [Bug reports](#bug-reports)
|
||||
- [Copy error](#copy-error)
|
||||
- [Feature requests](#feature-requests)
|
||||
- [Preferred contributions](#preferred-contributions)
|
||||
- [Pull Request Process](#pull-request-process)
|
||||
- [Software guidelines](#software-guidelines)
|
||||
- [Developer contributions guide](#developer-contributions-guide)
|
||||
- [How TermSCP works](#how-termscp-works)
|
||||
- [Activities](#activities)
|
||||
- [Implementing File Transfers](#implementing-file-transfers)
|
||||
|
||||
---
|
||||
|
||||
## Project mission
|
||||
|
||||
termscp was born because, as a terminal lover and Linux user, I wanted something like WinSCP on Linux and on terminal. At my previous job, I used SFTP/SCP practically everyday and that made me desire an application like termscp so much that eventually I started to work on it in my spare time.
|
||||
|
||||
I saw there was a very cool library to create terminal user interfaces (`tui-rs`, now `ratatui`), so I started to code it.
|
||||
|
||||
I wrote termscp as an experiment. I didn't design anything at the time. I just said,
|
||||
|
||||
> "Ok, there must be a FileTransfer trait somehow. I'll have more views, so I'll use something like Android activities, and there must be a module to interact with the local host."
|
||||
|
||||
And so in december 2020 I had the first version of termscp running and it worked, but was very simple, raw and minimal.
|
||||
A lot of things have changed since them, both the features the project provides and my personal view of this project.
|
||||
|
||||
Today I don't see termscp as a WinSCP clone anymore. I've also thought about changing the name as the time passed by, but I liked it and it would be hard to change the name on the registries, etc.
|
||||
|
||||
Right now I see termscp as a **rich-featured file transfer client for terminals**. All I want is to provide all the features users need to use it correctly, I want it to be **safe and reliable** and eventually I want people to consider termscp **the first choice as a file transfer client**.
|
||||
|
||||
### Project goals
|
||||
|
||||
- Have support for all the most used file transfer protocol
|
||||
- Provide all the features a file explorer requires
|
||||
- Have a well designed application
|
||||
- Make a reliable, safe and fast application
|
||||
|
||||
---
|
||||
|
||||
## Open an issue
|
||||
|
||||
Open an issue when:
|
||||
|
||||
- You have questions or concerns regarding the project or the application itself.
|
||||
- You have a bug to report.
|
||||
- You have a copy error to report. (Error in documentation; bad translation or sentence)
|
||||
- You have a feature or a suggestion to improve termscp to submit.
|
||||
|
||||
### Questions
|
||||
|
||||
If you have a question open an issue using the `Question` template.
|
||||
By default your question should already be labeled with the `question` label, if you need help with your installation, please also add the `help wanted` label.
|
||||
Check the issue is always assigned to `veeso`.
|
||||
|
||||
### Bug reports
|
||||
|
||||
If you want to report an issue or a bug you've encountered while using termscp, open an issue using the `Bug report` template.
|
||||
The `Bug` label should already be set and the issue should already be assigned to `veeso`.
|
||||
Don't set other labels to your issue, not even priority.
|
||||
|
||||
When you open a bug try to be the most precise as possible in describing your issue. I'm not saying you should always be that precise, since sometimes it's very easy for maintainers to understand what you're talking about. Just try to be reasonable to understand sometimes we might not know what you're talking about or we just don't have the technical knowledge you might think.
|
||||
Please always provide the environment you're working on and consider that we don't provide any support for older version of termscp, at least for those not classified as LTS (if we'll ever have them).
|
||||
If you can, provide the log file or the snippet involving your issue. You can find in the [user manual](https://docs.termscp.rs/en-US/configuration/logging.html) the location of the log file. Please, if you can, enable the **debug mode**, before submitting the log, in order to provide us with a better overview of the problem.
|
||||
Last but not least: the template I've written must be used. Full stop.
|
||||
|
||||
Maintainers will may add additional labels to your issue:
|
||||
|
||||
- **duplicate**: the issue is duplicated; the reference to the related issue will be added to your description. Your issue will be closed.
|
||||
- **priority**: this must be fixed asap
|
||||
- **sorcery**: it is not possible to find out what's causing your bug, nor is reproducible on our test environments.
|
||||
- **wontfix**: your bug has a very high ratio between the difficulty to fix it and the probability to encounter it, or it just isn't a bug, but a feature.
|
||||
|
||||
### Copy error
|
||||
|
||||
If you want to report a copy error, create an issue using the `copy` template.
|
||||
The `Documentation` label should already be set and the issue should already be assigned to `veeso`.
|
||||
|
||||
If you want to fix the copy by yourself you can fork the project and open a PR, otherwise I will fix it by myself.
|
||||
The copy issue is accepted **also if you're not a C1/C2 speaker**, but a speaker of that level in case the language is different from Italian/English is preferred.
|
||||
Please fullfil the form on the bottom of the template if you want.
|
||||
|
||||
### Feature requests
|
||||
|
||||
Whenever you have a good idea which chould improve the project, it is a good idea to submit it to the project owner.
|
||||
The first thing you should do though, is not starting to write the code, but is to become concern about how termscp works, what kind
|
||||
of contribution I appreciate and what kind of contribution I won't consider.
|
||||
Said so, follow these steps:
|
||||
|
||||
- Read the contributing guidelines, entirely
|
||||
- Think on whether your idea would fit in the project mission and guidelines or not
|
||||
- Think about the impact your idea would have on the project
|
||||
- Open an issue using the `feature request` template describing with accuracy your suggestion
|
||||
- Wait for the maintainer feedback on your idea
|
||||
|
||||
It is very important to follow these steps, since it will prevent you from working on a feature that will be rejected and trust me, none of us wants to deal with this situation.
|
||||
|
||||
Always mind that your suggestion, may be rejected: I'll always provide a feedback on the reasons that brought me to reject your feature, just try not to get mad about that.
|
||||
|
||||
---
|
||||
|
||||
@@ -17,192 +109,46 @@ Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in
|
||||
|
||||
At the moment, these kind of contributions are more appreciated and should be preferred:
|
||||
|
||||
- Fix for issues described in [Known Issues](./README.md#known-issues) or [issues reported by the community](https://github.com/veeso/termscp/issues)
|
||||
- New file transfers: for further details see [Implementing File Transfer](#implementing-file-transfers)
|
||||
- Code optimizations: any optimization to the code is welcome
|
||||
- Fix for issues described in [Known Issues](./README.md#known-issues-) or [issues reported by the community](https://github.com/veeso/termscp/issues)
|
||||
- **New file transfers**: for further details see [Implementing File Transfer](#implementing-file-transfers). ⚠️ this is going to be deprecated SOON! We're moving the file transfers into another library. Please see [remotefs-rs](https://github.com/veeso/remotefs-rs).
|
||||
- **Code optimizations**: any optimization to the code is welcome
|
||||
- See also features described in [Upcoming features](./README.md##upcoming-features-). Open an issue first though.
|
||||
- README/User manual **translations**: really appreciated atm. Please just add a folder into `docs/` with the language code. Language code with two characters is used in case the language is understandable by all the countries where this language is spoken (e.g. `it-CH`, `it-IT` are not really different, so I just created `it`, but there is a big difference from `zh-CN` and `zh-TW` for instance). Don't worry about flags in README, I will implement that part if it's too complicated.
|
||||
|
||||
For any other kind of contribution, especially for new features, please submit an issue first.
|
||||
For any other kind of contribution, especially for new features, please submit a new issue first.
|
||||
|
||||
## Pull Request Process
|
||||
|
||||
Let's make it simple and clear:
|
||||
|
||||
1. Open an issue with an **appropriate label** (e.g. bug, enhancement, ...).
|
||||
2. Write a **properly documentation** compliant with **rustdoc** standard.
|
||||
3. Write tests for your code. This doesn't apply necessarily for implementation regarding the user-interface module (`ui`) and (if a test server is not available) for file transfers.
|
||||
4. Report changes to the issue you opened, writing a report of what you changed and what you have introduced.
|
||||
5. Update the `CHANGELOG.md` file with details of changes to the application. In changelog report changes under a chapter called `PR{PULL_REQUEST_NUMBER}` (e.g. PR12).
|
||||
6. Request maintainers to merge your changes.
|
||||
1. Open a PR with an **appropriate label** (e.g. bug, enhancement, ...).
|
||||
2. Write a **properly documentation** for your software compliant with **rustdoc** standard.
|
||||
3. Write tests for your code. This doesn't apply necessarily for implementation regarding the user-interface module (`ui/activities`) and (if a test server is not available) for file transfers.
|
||||
4. Check your code with `cargo clippy`.
|
||||
5. Check if the CI for your commits reports three-green.
|
||||
6. Report changes to the PR you opened, writing a report of what you changed and what you have introduced.
|
||||
7. Update the `CHANGELOG.md` file with details of changes to the application. In changelog report changes under a chapter called `PR{PULL_REQUEST_NUMBER}` (e.g. PR12).
|
||||
8. Assign a maintainer to the reviewers.
|
||||
9. Wait for a maintainer to fullfil the acceptance tests
|
||||
10. Wait for a maintainer to complete the acceptance tests
|
||||
11. Request maintainers to merge your changes.
|
||||
|
||||
### Software guidelines
|
||||
|
||||
In addition to the process described for the PRs, I've also decided to introduce a list of guidelines to follow when writing the code, that should be followed:
|
||||
|
||||
1. **Let's stop the NPM apocalypse**: personally I'm against the abuse of dependencies we make in software projects and I think that NodeJS has opened the way to this drama (and has already gone too far). Nowadays nobody cares about adding hundreds of dependencies to their projects. Don't misunderstand me: I think that package managers are cool, but I'm totally against the abuse we're making of them. I think when we work on a project, we should try to use the minor quantity of dependencies as possible, especially because it's not hard to see how many libraries are getting abandoned right now, causing compatibility issues after a while. So please, when working on termscp, try not to add useless dependencies.
|
||||
2. **No C-bindings**: personally I think that Rust still relies too much on C. And that's bad, really bad. Many libraries in Rust are just wrappers to C libraries, which is a huge problem, especially considering this is a multiplatform project. Everytime you add a C-binding to your project, you're forcing your users to install additional libraries to their systems. Sometimes these libraries are already installed on their systems (as happens for openssl in this case), but sometimes not. So if you really have to add a dependency to this project, please AVOID completely adding C-bounded libraries.
|
||||
3. **Test units matter**: Whenever you implement something new to this project, always implement test units which cover the most cases as possible.
|
||||
4. **Comments are useful**: Many people say that the code should be that simple to talk by itself about what it does, and comments should then be useless. I personally don't agree. I'm not saying they're wrong, but I'm just saying that this approach has, in my personal opinion, many aspects which are underrated:
|
||||
1. What's obvious for me, might not be for the others.
|
||||
2. Our capacity to work on a code depends mostly on **time and experience**, not on complexity: I'm not denying complexity matter, but the most decisive factor when working on code is the experience we've acquired working on it and the time we've spent. As the author of the project, I know the project like the back of my hands, but if I didn't work on it for a year, then I would probably have some problems in working on it again as the same speed as before. And do you know what's really time-saving in these cases? Comments.
|
||||
|
||||
## Developer contributions guide
|
||||
|
||||
Welcome to the contributions guide for TermSCP. This chapter DOESN'T contain the documentation for TermSCP, which can instead be found on Rust Docs at <https://docs.rs/termscp>
|
||||
This chapter describes how TermSCP works and the guide lines to implement stuff such as file transfers and add features to the user interface.
|
||||
|
||||
### How TermSCP works
|
||||
|
||||
TermSCP is basically made up of 4 components:
|
||||
|
||||
- the **filetransfer**: the filetransfer takes care of managing the remote file system; it provides function to establish a connection with the remote, operating on the remote server file system (e.g. remove files, make directories, rename files, ...), read files and write files. The FileTransfer, as we'll see later, is actually a trait, and for each protocol a FileTransfer must be implement the trait.
|
||||
- the **host**: the host module provides functions to interact with the local host file system.
|
||||
- the **ui**: this module contains the implementation of the user interface, as we'll see in the next chapter, this is achieved through **activities**.
|
||||
- the **activity_manager**: the activity manager takes care of managing activities, basically it runs the activities of the user interface, and chooses, based on their state, when is the moment to terminate the current activity and which activity to run after the current one.
|
||||
|
||||
#### Activities
|
||||
|
||||
Just a little paragraph about activities. Really, read the code and the documentation to have a clear idea of how the ui works.
|
||||
I think there are many ways to implement a user interface; for termscp, I decided to go for a **Android-like** approach.
|
||||
Android works with Activity, each activity represents a view and there is a context shared between them, and so it works here.
|
||||
|
||||
Just a little note about activities, activities work with a `Context`, the context is a data holder for different data, which are shared and common between the activities.
|
||||
|
||||
I've implemented a Trait called `Activity`, which, is a very very reduced version of the Android activity of course.
|
||||
This trait provides only 3 methods:
|
||||
|
||||
- `on_create`: this method must initialize the activity; the context is passed to the activity, which will be the only owner of the Context, until the activity terminates.
|
||||
- `on_draw`: this method must be called each time you want to perform an update of the user interface. This is basically the run method of the activity. This method also cares about handling input events. The developer shouldn't draw the interface on each call of this method (consider that this method might be called hundreds of times per second), but only when actually something has changed (for example after an input event has been raised).
|
||||
- `on_destroy`: this method finalizes the activity and drops it; this method returns the Context to the caller (the activity manager).
|
||||
You can view the developer guide [here](https://docs.termscp.rs/en-US/developer/developer.html).
|
||||
|
||||
---
|
||||
|
||||
### Implementing File Transfers
|
||||
|
||||
This chapter describes how to implement a file transfer in TermSCP. A file transfer is a module which implements the `FileTransfer` trait. The file transfer provides different modules to interact with a remote server, which in addition to the most obvious methods, used to download and upload files, provides also methods to list files, delete files, create directories etc.
|
||||
|
||||
In the following steps I will describe how to implement a new file transfer, in this case I will be implementing the SCP file transfer (which I'm actually implementing the moment I'm writing this lines).
|
||||
|
||||
1. Add the Scp protocol to the `FileTransferProtocol` enum.
|
||||
|
||||
Move to `src/filetransfer/mod.rs` and add `Scp` to the `FileTransferProtocol` enum
|
||||
|
||||
```rs
|
||||
/// ## FileTransferProtocol
|
||||
///
|
||||
/// This enum defines the different transfer protocol available in TermSCP
|
||||
#[derive(std::cmp::PartialEq, std::fmt::Debug, std::clone::Clone)]
|
||||
pub enum FileTransferProtocol {
|
||||
Sftp,
|
||||
Ftp(bool), // Bool is for secure (true => ftps)
|
||||
Scp, // <-- here
|
||||
}
|
||||
```
|
||||
|
||||
In this case Scp is a "plain" enum type. If you need particular options, follow the implementation of `Ftp` which uses a boolean flag for indicating if using FTPS or FTP.
|
||||
|
||||
2. Implement the FileTransfer struct
|
||||
|
||||
Create a file at `src/filetransfer/mytransfer.rs`
|
||||
|
||||
Declare your file transfer struct
|
||||
|
||||
```rs
|
||||
/// ## ScpFileTransfer
|
||||
///
|
||||
/// SFTP file transfer structure
|
||||
pub struct ScpFileTransfer {
|
||||
session: Option<Session>,
|
||||
sftp: Option<Sftp>,
|
||||
wrkdir: PathBuf,
|
||||
}
|
||||
```
|
||||
|
||||
3. Implement the `FileTransfer` trait for it
|
||||
|
||||
You'll have to implement the following methods for your file transfer:
|
||||
|
||||
- connect: connect to remote server
|
||||
- disconnect: disconnect from remote server
|
||||
- is_connected: returns whether the file transfer is connected to remote
|
||||
- pwd: get working directory
|
||||
- change_dir: change working directory.
|
||||
- list_dir: get files and directories at a certain path
|
||||
- mkdir: make a new directory. Return an error in case the directory already exists
|
||||
- remove: remove a file or a directory. In case the protocol doesn't support recursive removing of directories you MUST implement this through a recursive algorithm
|
||||
- rename: rename a file or a directory
|
||||
- stat: returns detail for a certain path
|
||||
- send_file: opens a stream to a remote path for write purposes (write a remote file)
|
||||
- recv_file: opens a stream to a remote path for read purposes (write a local file)
|
||||
- on_sent: finalize a stream when writing a remote file. In case it's not necessary just return `Ok(())`
|
||||
- on_recv: fianlize a stream when reading a remote file. In case it's not necessary just return `Ok(())`
|
||||
|
||||
In case the protocol you're working on doesn't support any of this features, just return `Err(FileTransferError::new(FileTransferErrorType::UnsupportedFeature))`
|
||||
|
||||
4. Add your transfer to filetransfers:
|
||||
|
||||
Move to `src/filetransfer/mod.rs` and declare your file transfer:
|
||||
|
||||
```rs
|
||||
// Transfers
|
||||
pub mod ftp_transfer;
|
||||
pub mod scp_transfer; // <-- here
|
||||
pub mod sftp_transfer;
|
||||
```
|
||||
|
||||
5. Handle FileTransfer in `FileTransferActivity::new`
|
||||
|
||||
Move to `src/ui/activities/filetransfer_activity/mod.rs` and add the new protocol to the client match
|
||||
|
||||
```rs
|
||||
client: match protocol {
|
||||
FileTransferProtocol::Sftp => Box::new(SftpFileTransfer::new()),
|
||||
FileTransferProtocol::Ftp(ftps) => Box::new(FtpFileTransfer::new(ftps)),
|
||||
FileTransferProtocol::Scp => Box::new(ScpFileTransfer::new()), // <--- here
|
||||
},
|
||||
```
|
||||
|
||||
6. Handle right/left input events in `AuthActivity`:
|
||||
|
||||
Move to `src/ui/activities/auth_activity.rs` and handle the new protocol in `handle_input_event_mode_text` for `KeyCode::Left` and `KeyCode::Right`.
|
||||
Consider that the order they "rotate" must match the way they will be drawned in the interface.
|
||||
For newer protocols, please put them always at the end of the list. In this list I won't, because Scp is more important than Ftp imo.
|
||||
|
||||
```rs
|
||||
KeyCode::Left => {
|
||||
// If current field is Protocol handle event... (move element left)
|
||||
if self.selected_field == InputField::Protocol {
|
||||
self.protocol = match self.protocol {
|
||||
FileTransferProtocol::Sftp => FileTransferProtocol::Ftp(true), // End of list (wrap)
|
||||
FileTransferProtocol::Scp => FileTransferProtocol::Sftp,
|
||||
FileTransferProtocol::Ftp(ftps) => match ftps {
|
||||
false => FileTransferProtocol::Scp,
|
||||
true => FileTransferProtocol::Ftp(false),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
KeyCode::Right => {
|
||||
// If current field is Protocol handle event... ( move element right )
|
||||
if self.selected_field == InputField::Protocol {
|
||||
self.protocol = match self.protocol {
|
||||
FileTransferProtocol::Sftp => FileTransferProtocol::Scp,
|
||||
FileTransferProtocol::Scp => FileTransferProtocol::Ftp(false),
|
||||
FileTransferProtocol::Ftp(ftps) => match ftps {
|
||||
false => FileTransferProtocol::Ftp(true),
|
||||
true => FileTransferProtocol::Sftp, // End of list (wrap)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
7. Add your new file transfer to the protocol input field
|
||||
|
||||
Move to `AuthActivity::draw_protocol_select` method.
|
||||
Here add your new protocol to the `Spans` vector and to the match case, which chooses which element to highlight.
|
||||
|
||||
```rs
|
||||
let protocols: Vec<Spans> = vec![Spans::from("SFTP"), Spans::from("SCP"), Spans::from("FTP"), Spans::from("FTPS")];
|
||||
let index: usize = match self.protocol {
|
||||
FileTransferProtocol::Sftp => 0,
|
||||
FileTransferProtocol::Scp => 1,
|
||||
FileTransferProtocol::Ftp(ftps) => match ftps {
|
||||
false => 2,
|
||||
true => 3,
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Thank you for any contribution!
|
||||
Thank you for any contribution!\
|
||||
Christian Visintin
|
||||
|
||||
@@ -1,54 +1,17 @@
|
||||
[package]
|
||||
name = "termscp"
|
||||
version = "0.3.2"
|
||||
authors = ["Christian Visintin"]
|
||||
edition = "2018"
|
||||
license = "GPL-3.0"
|
||||
keywords = ["scp-client", "sftp-client", "ftp-client", "winscp", "command-line-utility"]
|
||||
version = "1.2.0"
|
||||
authors = ["Christian Visintin <christian.visintin@veeso.dev>"]
|
||||
categories = ["command-line-utilities"]
|
||||
description = "TermSCP is a SCP/SFTP/FTPS client for command line with an integrated UI to explore the remote file system. Basically WinSCP on a terminal."
|
||||
homepage = "https://github.com/veeso/termscp"
|
||||
repository = "https://github.com/veeso/termscp"
|
||||
documentation = "https://docs.rs/termscp"
|
||||
edition = "2024"
|
||||
homepage = "https://termscp.rs"
|
||||
include = ["/src/**/*", "/build.rs", "/LICENSE", "/README.md", "/CHANGELOG.md"]
|
||||
keywords = ["terminal", "ftp", "scp", "sftp", "tui"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
include = ["src/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.2.1"
|
||||
bytesize = "1.0.1"
|
||||
chrono = "0.4.19"
|
||||
content_inspector = "0.2.4"
|
||||
crossterm = "0.19.0"
|
||||
dirs = "3.0.1"
|
||||
edit = "0.1.2"
|
||||
ftp4 = { version = "^4.0.2", features = ["secure"] }
|
||||
getopts = "0.2.21"
|
||||
hostname = "0.3.1"
|
||||
lazy_static = "1.4.0"
|
||||
magic-crypt = "3.1.6"
|
||||
rand = "0.8.2"
|
||||
regex = "1.4.2"
|
||||
rpassword = "5.0.1"
|
||||
serde = { version = "1.0.121", features = ["derive"] }
|
||||
ssh2 = "0.9.0"
|
||||
tempfile = "3.1.0"
|
||||
textwrap = "0.13.1"
|
||||
toml = "0.5.8"
|
||||
tui = { version = "0.14.0", features = ["crossterm"], default-features = false }
|
||||
unicode-width = "0.1.7"
|
||||
whoami = "1.1.0"
|
||||
|
||||
[target.'cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))'.dependencies]
|
||||
users = "0.11.0"
|
||||
|
||||
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies]
|
||||
keyring = "0.10.1"
|
||||
|
||||
[[bin]]
|
||||
name = "termscp"
|
||||
path = "src/main.rs"
|
||||
repository = "https://github.com/veeso/termscp"
|
||||
rust-version = "1.98.0"
|
||||
description = "termscp is a feature rich terminal file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/GCS/SMB/WebDAV"
|
||||
|
||||
[package.metadata.rpm]
|
||||
package = "termscp"
|
||||
@@ -58,3 +21,116 @@ buildflags = ["--release"]
|
||||
|
||||
[package.metadata.rpm.targets]
|
||||
termscp = { path = "/usr/bin/termscp" }
|
||||
|
||||
[package.metadata.deb]
|
||||
maintainer = "Christian Visintin <christian.visintin@veeso.dev>"
|
||||
copyright = "2025, Christian Visintin <christian.visintin@veeso.dev>"
|
||||
depends = ""
|
||||
extended-description-file = "docs/misc/README.deb.txt"
|
||||
|
||||
[features]
|
||||
default = ["keyring", "smb"]
|
||||
github-actions = []
|
||||
isolated-tests = []
|
||||
keyring = []
|
||||
smb = ["dep:remotefs-smb"]
|
||||
smb-vendored = ["remotefs-smb/vendored"]
|
||||
|
||||
[dependencies]
|
||||
aes = "0.9"
|
||||
aes-gcm = "0.11"
|
||||
argh = "0.1"
|
||||
base64 = "0.23"
|
||||
bitflags = "2"
|
||||
bytesize = "2"
|
||||
cbc = { version = "0.2", features = ["alloc"] }
|
||||
chrono = "0.4"
|
||||
content_inspector = "0.2"
|
||||
dirs = "6"
|
||||
edit = "0.1"
|
||||
filetime = "0.2"
|
||||
keyring-core = "1"
|
||||
lazy-regex = "3"
|
||||
log = "0.4"
|
||||
md-5 = "0.11"
|
||||
notify = "8"
|
||||
notify-rust = { version = "4", default-features = false, features = ["d"] }
|
||||
nucleo = "0.5"
|
||||
open = "5"
|
||||
rand = "0.10"
|
||||
regex = "1"
|
||||
remotefs = "0.3"
|
||||
remotefs-aws-s3 = "0.4"
|
||||
remotefs-gcs = "0.1"
|
||||
remotefs-kube = "0.4"
|
||||
remotefs-smb = { version = "0.5", default-features = false, optional = true, features = ["find", "pavao"] }
|
||||
remotefs-ssh = { version = "0.9", default-features = false, features = ["russh"] }
|
||||
remotefs-webdav = "0.2"
|
||||
rpassword = "7"
|
||||
self_update = { version = "0.42", default-features = false, features = ["archive-tar", "archive-zip", "compression-flate2", "compression-zip-deflate", "rustls"] }
|
||||
semver = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
shellexpand = "3"
|
||||
simplelog = "0.12"
|
||||
ssh2-config = "0.8"
|
||||
tempfile = "3"
|
||||
thiserror = "2"
|
||||
tokio = { version = "1", features = ["rt"] }
|
||||
toml = "1"
|
||||
tui-realm-stdlib = "4"
|
||||
tui-term = "0.3"
|
||||
tuirealm = "4"
|
||||
unicode-width = "0.2"
|
||||
whoami = "2"
|
||||
wildmatch = "2"
|
||||
|
||||
[target."cfg(any(target_os = \"linux\", target_os = \"freebsd\"))".dependencies]
|
||||
dbus-secret-service-keyring-store = { version = "1", features = ["crypto-rust", "vendored"] }
|
||||
|
||||
[target."cfg(target_family = \"unix\")".dependencies]
|
||||
remotefs-ftp = { version = "0.4", features = ["native-tls", "native-tls-vendored"] }
|
||||
uzers = "0.12"
|
||||
|
||||
[target."cfg(target_family = \"windows\")".dependencies]
|
||||
remotefs-ftp = { version = "0.4", features = ["native-tls"] }
|
||||
|
||||
[target."cfg(target_os = \"macos\")".dependencies]
|
||||
apple-native-keyring-store = { version = "1", features = ["keychain"] }
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies]
|
||||
windows-native-keyring-store = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1"
|
||||
serial_test = "4"
|
||||
|
||||
[build-dependencies]
|
||||
cfg_aliases = "0.2"
|
||||
|
||||
[[bin]]
|
||||
name = "termscp"
|
||||
path = "src/main.rs"
|
||||
|
||||
[lints.rust]
|
||||
trivial_numeric_casts = "warn"
|
||||
unsafe_op_in_unsafe_fn = "warn"
|
||||
unused_lifetimes = "warn"
|
||||
|
||||
[lints.clippy]
|
||||
complexity = { level = "warn", priority = -1 }
|
||||
correctness = { level = "warn", priority = -1 }
|
||||
cloned_instead_of_copied = "warn"
|
||||
implicit_clone = "warn"
|
||||
manual_string_new = "warn"
|
||||
perf = { level = "warn", priority = -1 }
|
||||
redundant_closure_for_method_calls = "warn"
|
||||
style = { level = "warn", priority = -1 }
|
||||
suspicious = { level = "warn", priority = -1 }
|
||||
unnested_or_patterns = "warn"
|
||||
|
||||
[profile.dev]
|
||||
incremental = true
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import "./just/build.just"
|
||||
import "./just/changelog.just"
|
||||
import "./just/code_check.just"
|
||||
import "./just/publish.just"
|
||||
import "./just/run.just"
|
||||
import "./just/site.just"
|
||||
import "./just/test.just"
|
||||
|
||||
# Lists all the available commands
|
||||
default:
|
||||
@just --list
|
||||
@@ -1,674 +1,21 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
TermSCP
|
||||
Copyright (C) 2020-2021 Christian Visintin
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
TermSCP Copyright (C) 2020-2021 Christian Visintin
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2022 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.
|
||||
|
||||
@@ -1,398 +1,202 @@
|
||||
# TermSCP
|
||||
# termscp
|
||||
|
||||
[](https://www.gnu.org/licenses/gpl-3.0) [](https://github.com/veeso/termscp) [](https://crates.io/crates/termscp) [](https://crates.io/crates/termscp) [](https://docs.rs/termscp)
|
||||
<p align="center">
|
||||
<img src="/assets/images/termscp.svg" alt="termscp logo" width="256" height="256" />
|
||||
</p>
|
||||
|
||||
[](https://github.com/veeso/termscp/actions) [](https://github.com/veeso/termscp/actions) [](https://github.com/veeso/termscp/actions) [](https://codecov.io/gh/veeso/termscp)
|
||||
<p align="center">~ A feature rich terminal file transfer ~</p>
|
||||
<p align="center">
|
||||
<a href="https://termscp.rs" target="_blank">Website</a>
|
||||
·
|
||||
<a href="https://termscp.rs/install" target="_blank">Installation</a>
|
||||
·
|
||||
<a href="https://docs.termscp.rs" target="_blank">User manual</a>
|
||||
</p>
|
||||
|
||||
~ Basically, WinSCP on a terminal ~
|
||||
Developed by Christian Visintin
|
||||
Current version: 0.3.2 (24/01/2021)
|
||||
<p align="center">
|
||||
<a
|
||||
href="/docs/zh-CN/README.md"
|
||||
><img
|
||||
height="20"
|
||||
src="/assets/images/flags/cn.png"
|
||||
alt="简体中文"
|
||||
/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">Developed by <a href="https://veeso.me/" target="_blank">@veeso</a></p>
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://github.com/veeso/termscp/stargazers)
|
||||
[](https://crates.io/crates/termscp)
|
||||
[](https://crates.io/crates/termscp)
|
||||
[](https://github.com/veeso/termscp/actions/workflows/ci.yml)
|
||||
|
||||
---
|
||||
|
||||
- [TermSCP](#termscp)
|
||||
- [About TermSCP 🖥](#about-termscp-)
|
||||
- [Why TermSCP 🤔](#why-termscp-)
|
||||
- [Features 🎁](#features-)
|
||||
- [Installation 🛠](#installation-)
|
||||
- [Cargo 🦀](#cargo-)
|
||||
- [Deb package 📦](#deb-package-)
|
||||
- [RPM package 📦](#rpm-package-)
|
||||
- [AUR Package 🔼](#aur-package-)
|
||||
- [Chocolatey 🍫](#chocolatey-)
|
||||
- [Brew 🍻](#brew-)
|
||||
- [Usage ❓](#usage-)
|
||||
- [Address argument 🌎](#address-argument-)
|
||||
- [How Password can be provided 🔐](#how-password-can-be-provided-)
|
||||
- [Bookmarks ⭐](#bookmarks-)
|
||||
- [Are my passwords Safe 😈](#are-my-passwords-safe-)
|
||||
- [Text Editor ✏](#text-editor-)
|
||||
- [How do I configure the text editor 🦥](#how-do-i-configure-the-text-editor-)
|
||||
- [Configuration ⚙️](#configuration-️)
|
||||
- [SSH Key Storage 🔐](#ssh-key-storage-)
|
||||
- [File Explorer Format](#file-explorer-format)
|
||||
- [Keybindings ⌨](#keybindings-)
|
||||
- [Documentation 📚](#documentation-)
|
||||
- [Known issues 🧻](#known-issues-)
|
||||
- [Upcoming Features 🧪](#upcoming-features-)
|
||||
- [Contributions 🤝🏻](#contributions-)
|
||||
- [Changelog ⏳](#changelog-)
|
||||
- [Powered by 🚀](#powered-by-)
|
||||
- [Gallery 🎬](#gallery-)
|
||||
- [License 📃](#license-)
|
||||
## About termscp 🖥
|
||||
|
||||
---
|
||||
|
||||
## About TermSCP 🖥
|
||||
|
||||
TermSCP is basically a porting of WinSCP to terminal. 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 works both on **Linux**, **MacOS**, **BSD** and **Windows** and supports SFTP, SCP, FTP and FTPS.
|
||||
Termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/Kube/S3/Google Cloud Storage (GCS)/WebDAV. 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**, **NetBSD** and **Windows** compatible.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### Why TermSCP 🤔
|
||||
|
||||
It happens quite often to me, when using SCP at work to forget the path of a file on a remote machine, which forces me then to connect through SSH, gather the file path and finally download it through SCP. I could use WinSCP, but I use Linux and I pratically use the terminal for everything, so I wanted something like WinSCP on my terminal. Yeah, I know there is midnight commander too, but actually I don't like it very much tbh (and hasn't a decent support for scp).
|
||||
|
||||
## Features 🎁
|
||||
|
||||
- Different communication protocols
|
||||
- SFTP
|
||||
- SCP
|
||||
- FTP and FTPS
|
||||
- Compatible with Windows, Linux, BSD and MacOS
|
||||
- Practical user interface to explore and operate on the remote and on the local machine file system
|
||||
- Bookmarks and recent connections can be saved to access quickly to your favourite hosts
|
||||
- Supports text editors to view and edit text files
|
||||
- Supports both SFTP/SCP authentication through SSH keys and username/password
|
||||
- Customizations:
|
||||
- 📁 Different communication protocols
|
||||
- **SFTP**
|
||||
- **SCP**
|
||||
- **FTP** and **FTPS**
|
||||
- **Kube**
|
||||
- **S3**
|
||||
- **Google Cloud Storage (GCS)**
|
||||
- **SMB**
|
||||
- **WebDAV**
|
||||
- 🖥 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
|
||||
- 📝 View and edit files with your favourite applications
|
||||
- 💁 SFTP/SCP authentication with SSH keys and username/password
|
||||
- 🐧 Compatible with Windows, Linux, FreeBSD, NetBSD and MacOS
|
||||
- 🐚 Embedded terminal for executing commands on the system.
|
||||
- 🎨 Make it yours!
|
||||
- Themes
|
||||
- Custom file explorer format
|
||||
- Customizable text editor
|
||||
- Customizable file sorting
|
||||
- SSH key storage
|
||||
- Written in Rust
|
||||
- Easy to extend with new file transfers protocols
|
||||
- Developed keeping an eye on performance
|
||||
- and many other parameters...
|
||||
- 📫 Get notified via Desktop Notifications when a large file has been transferred
|
||||
- 🔭 Keep file changes synchronized with the remote host
|
||||
- 🔐 Save your password in your operating system key vault
|
||||
- 🦀 Rust-powered
|
||||
- 👀 Developed keeping an eye on performance
|
||||
- 🦄 Frequent awesome updates
|
||||
|
||||
---
|
||||
|
||||
## Installation 🛠
|
||||
## Get started 🚀
|
||||
|
||||
If you're considering to install TermSCP I want to thank you 💛 ! I hope you will enjoy TermSCP!
|
||||
If you want to contribute to this project, don't forget to check out our contribute guide. [Read More](CONTRIBUTING.md)
|
||||
If you're considering to install termscp I want to thank you 💜 ! I hope you will enjoy termscp!\
|
||||
If you want to contribute to this project, don't forget to check out our [contribute guide](CONTRIBUTING.md).
|
||||
|
||||
### Cargo 🦀
|
||||
If you are a Linux, a FreeBSD or a MacOS user this simple shell script will install termscp on your system with a single command:
|
||||
|
||||
```sh
|
||||
# Install termscp through cargo
|
||||
cargo install termscp
|
||||
curl --proto '=https' --tlsv1.2 -sSLf https://termscp.rs/install.sh | sh
|
||||
```
|
||||
|
||||
Requirements:
|
||||
> ❗ MacOs installation requires [Homebrew](https://brew.sh/), otherwise the Rust compiler will be installed
|
||||
|
||||
- Linux
|
||||
- pkg-config
|
||||
- libssh2
|
||||
- openssl
|
||||
if you're a Windows user, you can install termscp from PowerShell with a single command:
|
||||
|
||||
### Deb package 📦
|
||||
|
||||
Get `deb` package from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp_0.3.2_amd64.deb)
|
||||
or run `wget https://github.com/veeso/termscp/releases/latest/download/termscp_0.3.2_amd64.deb`
|
||||
|
||||
then install through dpkg:
|
||||
|
||||
```sh
|
||||
dpkg -i termscp_*.deb
|
||||
# Or even better with gdebi
|
||||
gdebi termscp_*.deb
|
||||
```ps
|
||||
irm https://termscp.rs/install.ps1 | iex
|
||||
```
|
||||
|
||||
### RPM package 📦
|
||||
|
||||
Get `rpm` package from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp-0.3.2-1.x86_64.rpm)
|
||||
or run `wget https://github.com/veeso/termscp/releases/latest/download/termscp-0.3.2-1.x86_64.rpm`
|
||||
|
||||
then install through rpm:
|
||||
|
||||
```sh
|
||||
rpm -U termscp_*.rpm
|
||||
```
|
||||
|
||||
### AUR Package 🔼
|
||||
|
||||
On Arch Linux based distribution, you can install termscp using for example [yay](https://github.com/Jguer/yay), which I recommend to install AUR packages.
|
||||
|
||||
```sh
|
||||
yay -S termscp
|
||||
```
|
||||
|
||||
### Chocolatey 🍫
|
||||
|
||||
You can install TermSCP on Windows using [chocolatey](https://chocolatey.org/)
|
||||
|
||||
Start PowerShell as administrator and run
|
||||
or, alternatively, with [Chocolatey](https://chocolatey.org/):
|
||||
|
||||
```ps
|
||||
choco install termscp
|
||||
```
|
||||
|
||||
Alternatively you can download the ZIP file from [HERE](https://github.com/veeso/termscp/releases/latest/download/termscp.0.3.2.nupkg)
|
||||
|
||||
and then with PowerShell started with administrator previleges, run:
|
||||
|
||||
```ps
|
||||
choco install termscp -s .
|
||||
```
|
||||
|
||||
### Brew 🍻
|
||||
|
||||
You can install TermSCP on MacOS using [brew](https://brew.sh/)
|
||||
|
||||
From your terminal run
|
||||
NetBSD users can install termscp from the official repositories.
|
||||
|
||||
```sh
|
||||
brew tap veeso/termscp
|
||||
brew install termscp
|
||||
pkgin install termscp
|
||||
```
|
||||
|
||||
---
|
||||
Arch Linux users can install termscp from the official repositories.
|
||||
|
||||
## Usage ❓
|
||||
|
||||
TermSCP can be started with the following options:
|
||||
|
||||
- `-P, --password <password>` if address is provided, password will be this argument
|
||||
- `-v, --version` Print version info
|
||||
- `-h, --help` Print help page
|
||||
|
||||
TermSCP can be started in two different mode, if no extra arguments is provided, TermSCP will show the authentication form, where the user will be able to provide the parameters required to connect to the remote peer.
|
||||
|
||||
Alternatively, the user can provide an address as argument to skip the authentication form and starting directly the connection to the remote server.
|
||||
|
||||
### Address argument 🌎
|
||||
|
||||
The address argument has the following syntax:
|
||||
|
||||
```txt
|
||||
[protocol]://[username@]<address>[:port]
|
||||
```sh
|
||||
pacman -S termscp
|
||||
```
|
||||
|
||||
Let's see some example of this particular syntax, since it's very comfortable and you'll probably going to use this instead of the other one...
|
||||
For more information or other platforms, please visit [termscp.rs](https://termscp.rs/install) to view all installation methods.
|
||||
|
||||
- Connect using default protocol (*defined in configuration*) to 192.168.1.31, port is default for this protocol (22); username is current user's name
|
||||
⚠️ If you're looking on how to update termscp just run termscp from CLI with: `(sudo) termscp update` ⚠️
|
||||
|
||||
```sh
|
||||
termscp 192.168.1.31
|
||||
```
|
||||
### Requirements ❗
|
||||
|
||||
- Connect using default protocol (*defined in configuration*) to 192.168.1.31, port is default for this protocol (22); username is `root`
|
||||
The official Linux binaries and `.deb` packages are statically linked against
|
||||
musl and have **no runtime requirements**: they run on any distribution and
|
||||
any glibc version.
|
||||
|
||||
```sh
|
||||
termscp root@192.168.1.31
|
||||
```
|
||||
These are only required to build termscp from source:
|
||||
|
||||
- Connect using scp to 192.168.1.31, port is 4022; username is `omar`
|
||||
- **Linux** users:
|
||||
- libdbus-1
|
||||
- pkg-config
|
||||
- libsmbclient
|
||||
- **FreeBSD** or, **NetBSD** users:
|
||||
- dbus
|
||||
- pkgconf
|
||||
- libsmbclient
|
||||
|
||||
```sh
|
||||
termscp scp://omar@192.168.1.31:4022
|
||||
```
|
||||
### Optional Requirements ✔️
|
||||
|
||||
#### How Password can be provided 🔐
|
||||
These requirements are not forced required to run termscp, but to enjoy all of its features
|
||||
|
||||
You have probably noticed, that, when providing the address as argument, there's no way to provide the password.
|
||||
Password can be basically provided through 3 ways when address argument is provided:
|
||||
|
||||
- `-P, --password` option: just use this CLI option providing the password. I strongly unrecommend this method, since it's very unsecure (since you might keep the password in the shell history)
|
||||
- Via `sshpass`: you can provide password via `sshpass`, e.g. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31`
|
||||
- You will be prompted for it: if you don't use any of the previous methods, you will be prompted for the password, as happens with the more classics tools such as `scp`, `ssh`, etc.
|
||||
- **Linux/FreeBSD** users:
|
||||
- To **open** files via `V` (at least one of these)
|
||||
- _xdg-open_
|
||||
- _gio_
|
||||
- _gnome-open_
|
||||
- _kde-open_
|
||||
- **Linux** users:
|
||||
- A keyring manager: read more in the [User manual](https://docs.termscp.rs/en-US/configuration/password-security.html#linux-keyring)
|
||||
- **WSL** users
|
||||
- To **open** files via `V` (at least one of these)
|
||||
- [wslu](https://github.com/wslutilities/wslu)
|
||||
|
||||
---
|
||||
|
||||
## Bookmarks ⭐
|
||||
## User manual 📚
|
||||
|
||||
In TermSCP it is possible to save favourites hosts, which can be then loaded quickly from the main layout of termscp.
|
||||
TermSCP will also save the last 16 hosts you connected to.
|
||||
This feature allows you to load all the parameters required to connect to a certain remote, simply selecting the bookmark in the tab under the authentication form.
|
||||
|
||||
Bookmarks will be saved, if possible at:
|
||||
|
||||
- `$HOME/.config/termscp/` on Linux/BSD
|
||||
- `$HOME/Library/Application Support/termscp` on MacOs
|
||||
- `FOLDERID_RoamingAppData\termscp\` on Windows
|
||||
|
||||
For bookmarks only (this won't apply to recent hosts) it is also possible to save the password used to authenticate. The password is not saved by default and must be specified through the prompt when saving a new Bookmark.
|
||||
|
||||
> I was very undecided about storing passwords in termscp. The reason? Saving a password on your computer might give access to a hacker to any server you've registered. But I must admit by myself that for many machines typing the password everytime is really boring, also many times I have to work with machines in LAN, which wouldn't provide any advantage to an attacker, So I came out with a good compromise for passwords.
|
||||
|
||||
I warmly suggest you to follow these guidelines in order to decide whether you should or you shouldn't save passwords:
|
||||
|
||||
- **DON'T** save passwords for machines which are exposed on the internet, save passwords only for machines in LAN
|
||||
- Make sure your machine is protected by attackers. If possible encrypt your disk and don't leave your PC unlocked while you're away.
|
||||
- Preferably, save passwords only when a compromising of the target machine wouldn't be a problem.
|
||||
|
||||
To create a bookmark, just fulfill the authentication form and then input `CTRL+S`; you'll then be asked to give a name to your bookmark, and tadah, the bookmark has been created.
|
||||
If you go to [gallery](#gallery-), there is a GIF showing how bookmarks work 💪.
|
||||
|
||||
### Are my passwords Safe 😈
|
||||
|
||||
Well, kinda.
|
||||
As said before, bookmarks are saved in your configuration directory along with passwords. Passwords are obviously not plain text, they are encrypted with **AES-128**. Does this make them safe? Well, depends on your operating system:
|
||||
|
||||
On Windows and MacOS the passwords are stored, if possible (but should be), in respectively the Windows Vault and the Keychain. This is actually super-safe and is directly managed by your operating system.
|
||||
|
||||
On Linux and BSD, on the other hand, the key used to encrypt your passwords is stored on your drive (at $HOME/.config/termscp). It is then, still possible to retrieve the key to decrypt passwords. Luckily, the location of the key guarantees your key can't be read by users different from yours, but yeah, I still wouldn't save the password for a server exposed on the internet 😉.
|
||||
Actually [keyring-rs](https://github.com/hwchen/keyring-rs), supports Linux, but for different reasons I preferred not to make it available for this configuration. If you want to read more about my decision read [this issue](https://github.com/veeso/termscp/issues/2), while if you think this might have been implemented differently feel free to open an issue with your proposal.
|
||||
|
||||
---
|
||||
|
||||
## Text Editor ✏
|
||||
|
||||
TermSCP has, as you might have noticed, many features, one of these is the possibility to view and edit text file. It doesn't matter if the file is located on the local host or on the remote host, termscp provides the possibility to open a file in your favourite text editor.
|
||||
In case the file is located on remote host, the file will be first downloaded into your temporary file directory and then, **only** if changes were made to the file, re-uploaded to the remote host. TermSCP checks if you made changes to the file verifying the last modification time of the file.
|
||||
|
||||
Just a reminder: **you can edit only textual file**; binary files are not supported.
|
||||
|
||||
### How do I configure the text editor 🦥
|
||||
|
||||
Text editor is automatically found using this [awesome crate](https://github.com/milkey-mouse/edit), if you want to change the text editor to use, change it in termscp configuration. [View more](#configuration-️)
|
||||
|
||||
---
|
||||
|
||||
## Configuration ⚙️
|
||||
|
||||
TermSCP supports some user defined parameters, which can be defined in the configuration.
|
||||
Underhood termscp has a TOML file and some other directories where all the parameters will be saved, but don't worry, you won't touch any of these files, since I made possible to configure termscp from its user interface entirely.
|
||||
|
||||
termscp, like for bookmarks, just requires to have these paths accessible:
|
||||
|
||||
- `$HOME/.config/termscp/` on Linux/BSD
|
||||
- `$HOME/Library/Application Support/termscp` on MacOs
|
||||
- `FOLDERID_RoamingAppData\termscp\` on Windows
|
||||
|
||||
To access configuration, you just have to press `<CTRL+C>` from the home of termscp.
|
||||
|
||||
These parameters can be changed:
|
||||
|
||||
- **Default Protocol**: the default protocol is the default value for the file transfer protocol to be used in termscp. This applies for the login page and for the address CLI argument.
|
||||
- **Text Editor**: the text editor to use. By default termscp will find the default editor for you; with this option you can force an editor to be used (e.g. `vim`). **Also GUI editors are supported**, unless they `nohup` from the parent process so if you ask: yes, you can use `notepad.exe`, and no: **Visual Studio Code doesn't work**.
|
||||
- **Show Hidden Files**: select whether hidden files shall be displayed by default. You will be able to decide whether to show or not hidden files at runtime pressing `A` anyway.
|
||||
- **Group Dirs**: select whether directories should be groupped or not in file explorers. If `Display first` is selected, directories will be sorted using the configured method but displayed before files, viceversa if `Display last` is selected.
|
||||
|
||||
### SSH Key Storage 🔐
|
||||
|
||||
Along with configuration, termscp provides also an **essential** feature for **SFTP/SCP clients**: the SSH key storage.
|
||||
|
||||
You can access the SSH key storage, from configuration moving to the `SSH Keys` tab, once there you can:
|
||||
|
||||
- **Add a new key**: just press `<CTRL+N>` and you will be prompted to create a new key. Provide the hostname/ip address and the username associated to the key and finally a text editor will open up: paste the **PRIVATE** ssh key into the text editor, save and quit.
|
||||
- **Remove an existing key**: just press `<DEL>` or `<CTRL+E>` on the key you want to remove, to delete persistently the key from termscp.
|
||||
- **Edit an existing key**: just press `<ENTER>` on the key you want to edit, to change the private key.
|
||||
|
||||
> Q: Wait, my private key is protected with password, can I use it?
|
||||
> A: Of course you can. The password provided for authentication in termscp, is valid both for username/password authentication and for RSA key authentication.
|
||||
|
||||
### File Explorer Format
|
||||
|
||||
It is possible through configuration to define a custom format for the file explorer. This field, with name `File formatter syntax` will define how the files will be displayed in the file explorer.
|
||||
The syntax for the formatter is the following `{KEY1}... {KEY2}... {KEYn}...`.
|
||||
Each key in bracket will be replaced with the related attribute, while everything outside brackets will be left unchanged.
|
||||
These are the keys supported by the formatter:
|
||||
|
||||
- `ATIME`: Last access time (with syntax `%b %d %Y %H:%M`)
|
||||
- `CTIME`: Creation time (with syntax `%b %d %Y %H:%M`)
|
||||
- `GROUP`: Owner group
|
||||
- `MTIME`: Last change time (with syntax `%b %d %Y %H:%M`)
|
||||
- `NAME`: File name (Elided if longer than 24)
|
||||
- `PEX`: File permissions (UNIX format)
|
||||
- `SIZE`: File size (omitted for directories)
|
||||
- `SYMLINK`: Symlink (if any `-> {FILE_PATH}`)
|
||||
- `USER`: Owner user
|
||||
|
||||
If left empty, the default formatter syntax will be used: `{NAME} {PEX} {USER} {SIZE} {MTIME}`
|
||||
|
||||
---
|
||||
|
||||
## Keybindings ⌨
|
||||
|
||||
| Key | Command | Reminder |
|
||||
|---------------|-------------------------------------------------------|-------------|
|
||||
| `<ESC>` | Disconnect from remote; return to authentication page | |
|
||||
| `<TAB>` | Switch between log tab and explorer | |
|
||||
| `<BACKSPACE>` | Go to previous directory in stack | |
|
||||
| `<RIGHT>` | Move to remote explorer tab | |
|
||||
| `<LEFT>` | Move to local explorer tab | |
|
||||
| `<UP>` | Move up in selected list | |
|
||||
| `<DOWN>` | Move down in selected list | |
|
||||
| `<PGUP>` | Move up in selected list by 8 rows | |
|
||||
| `<PGDOWN>` | Move down in selected list by 8 rows | |
|
||||
| `<ENTER>` | Enter directory | |
|
||||
| `<SPACE>` | Upload / download selected file | |
|
||||
| `<A>` | Toggle hidden files | All |
|
||||
| `<B>` | Sort files by | Bubblesort? |
|
||||
| `<C>` | Copy file/directory | Copy |
|
||||
| `<D>` | Make directory | Directory |
|
||||
| `<E>` | Delete file (Same as `DEL`) | Erase |
|
||||
| `<G>` | Go to supplied path | Go to |
|
||||
| `<H>` | Show help | Help |
|
||||
| `<I>` | Show info about selected file or directory | Info |
|
||||
| `<L>` | Reload current directory's content | List |
|
||||
| `<N>` | Create new file with provided name | New |
|
||||
| `<O>` | Edit file; see [Text editor](#text-editor-) | Open |
|
||||
| `<Q>` | Quit TermSCP | Quit |
|
||||
| `<R>` | Rename file | Rename |
|
||||
| `<U>` | Go to parent directory | Upper |
|
||||
| `<DEL>` | Delete file | |
|
||||
| `<CTRL+C>` | Abort file transfer process | |
|
||||
|
||||
---
|
||||
|
||||
## Documentation 📚
|
||||
|
||||
The developer documentation can be found on Rust Docs at <https://docs.rs/termscp>
|
||||
|
||||
---
|
||||
|
||||
## Known issues 🧻
|
||||
|
||||
- `NoSuchFileOrDirectory` on connect (WSL): I know about this issue and it's a glitch of WSL I guess. Don't worry about it, just move the termscp executable into another PATH location, such as `/usr/bin`, or install it through the appropriate package format (e.g. deb).
|
||||
The user manual can be found on [termscp's documentation website](https://docs.termscp.rs).
|
||||
|
||||
---
|
||||
|
||||
## Upcoming Features 🧪
|
||||
|
||||
- **Custom explorer format**: possibility to customize the file line in the explorer directly from configuration, with the possibility to choose with information to display.
|
||||
- **Find command in explorer**: possibility to search for files in explorers.
|
||||
See [Milestones](https://github.com/veeso/termscp/milestones)
|
||||
|
||||
---
|
||||
|
||||
## Contributions 🤝🏻
|
||||
## Contributing and issues 🤝🏻
|
||||
|
||||
Contributions are welcome! 😉
|
||||
Contributions, bug reports, new features and questions are welcome! 😉
|
||||
If you have any question or concern, or you want to suggest a new feature, or you want just want to improve termscp, feel free to open an issue or a PR.
|
||||
|
||||
If you think you can contribute to TermSCP, please follow [TermSCP's contributions guide](CONTRIBUTING.md)
|
||||
An **appreciated** contribution would be a translation of the user manual and readme in **other languages**
|
||||
|
||||
Please follow [our contributing guidelines](CONTRIBUTING.md)
|
||||
|
||||
---
|
||||
|
||||
## Changelog ⏳
|
||||
|
||||
View TermSCP's changelog [HERE](CHANGELOG.md)
|
||||
View termscp's changelog [HERE](CHANGELOG.md)
|
||||
|
||||
---
|
||||
|
||||
## Powered by 🚀
|
||||
## Powered by 💪
|
||||
|
||||
TermSCP is powered by these aweseome projects:
|
||||
termscp is powered by these awesome projects:
|
||||
|
||||
- [bytesize](https://github.com/hyunsik/bytesize)
|
||||
- [crossterm](https://github.com/crossterm-rs/crossterm)
|
||||
- [edit](https://github.com/milkey-mouse/edit)
|
||||
- [keyring-rs](https://github.com/hwchen/keyring-rs)
|
||||
- [kube](https://github.com/kube-rs/kube)
|
||||
- [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)
|
||||
- [rust-ftp](https://github.com/mattnenterprise/rust-ftp)
|
||||
- [ssh2-rs](https://github.com/alexcrichton/ssh2-rs)
|
||||
- [textwrap](https://github.com/mgeisler/textwrap)
|
||||
- [tui-rs](https://github.com/fdehau/tui-rs)
|
||||
- [self_update](https://github.com/jaemk/self_update)
|
||||
- [ratatui](https://github.com/ratatui-org/ratatui)
|
||||
- [tui-realm](https://github.com/veeso/tui-realm)
|
||||
- [whoami](https://github.com/libcala/whoami)
|
||||
- [wildmatch](https://github.com/becheran/wildmatch)
|
||||
|
||||
---
|
||||
|
||||
@@ -418,10 +222,6 @@ TermSCP is powered by these aweseome projects:
|
||||
|
||||
## License 📃
|
||||
|
||||
Licensed under the GNU GPLv3 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
<http://www.gnu.org/licenses/gpl-3.0.txt>
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
termscp is licensed under the MIT license.
|
||||
|
||||
You can read the entire license [HERE](LICENSE)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Only latst version of termscp has the latest security updates.
|
||||
Because of that, **you should always consider updating termscp to the latest version**.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you have any security vulnerability or concern to report, please open an issue using the `Security report` template.
|
||||
|
Before Width: | Height: | Size: 314 KiB After Width: | Height: | Size: 336 KiB |
|
Before Width: | Height: | Size: 292 KiB After Width: | Height: | Size: 231 KiB |
|
Before Width: | Height: | Size: 689 KiB After Width: | Height: | Size: 937 KiB |
|
Before Width: | Height: | Size: 635 KiB After Width: | Height: | Size: 3.2 MiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 1002 B |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 484 B |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500"><circle style="fill:#31363b" cx="250" cy="250" r="250"/><circle style="fill:#ea4444" cx="225" cy="40" r="7.344"/><circle style="fill:#eac944" cx="58.177" cy="22.745" r="7.344" transform="matrix(1, 0, 0, 1.031863, 191.822998, 16.530386)"/><circle style="fill:#34b938" cx="57.564" cy="22.269" r="7.344" transform="matrix(1, 0, 0, 1.031863, 217.43605, 17.021263)"/><polygon style="stroke:#000;fill:#f0f0f0" points="83.462 135.575 200 252.112 87.687 364.425 48.108 324.846 122.07 250.881 45.738 174.55"/><g transform="matrix(0.408921, 0, 0, 0.408921, 241.338654, 169.687912)"><polygon style="fill:#f0f0f0" points="196.4 0 292 49.2 388 98 292 147.2 196.4 196.4 100.8 147.2 4.8 98 100.8 49.2"/><polygon style="fill:#31363b" points="316 179.6 316 135.2 268 159.6 268 204 294.4 171.6"/><polygon style="fill:#f0f0f0" points="196.4 196.4 196.4 392.8 388 294.8 388 98 316 135.2 314.4 136 314.4 179.2 294.4 171.6 268 204 268 159.6"/><polygon style="fill:#f0f0f0" points="196.4 392.8 196.4 196.4 100.8 147.2 4.8 98 4.8 294.8"/><polygon style="fill:#31363b" points="76.8 61.2 268 159.6 314.4 136 316 135.2 124.8 36.8 100.8 49.2"/></g><rect style="fill:#f0f0f0" width="200" height="35.702" x="222.229" y="364.298" rx="10" ry="10"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 224 KiB |
@@ -0,0 +1,16 @@
|
||||
use cfg_aliases::cfg_aliases;
|
||||
|
||||
fn main() {
|
||||
// Setup cfg aliases
|
||||
cfg_aliases! {
|
||||
// Platforms
|
||||
macos: { target_os = "macos" },
|
||||
linux: { target_os = "linux" },
|
||||
posix: { target_family = "unix" },
|
||||
win: { target_family = "windows" },
|
||||
// exclusive features
|
||||
smb: { feature = "smb" },
|
||||
smb_unix: { all(unix, feature = "smb") },
|
||||
smb_windows: { all(windows, feature = "smb") }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
[changelog]
|
||||
body = """
|
||||
## {{ version | trim_start_matches(pat="v") }}
|
||||
|
||||
Released on {{ timestamp | date(format="%Y-%m-%d") }}
|
||||
{%- if commits | filter(attribute="breaking", value=true) | length > 0 %}
|
||||
|
||||
### ⚠ Breaking Changes
|
||||
|
||||
{%- for commit in commits | filter(attribute="breaking", value=true) %}
|
||||
- {% if commit.scope %}**{{ commit.scope }}:** {% endif %}{{ commit.message | split(pat="\n") | first | trim }}
|
||||
{%- if commit.breaking_description %}
|
||||
> {{ commit.breaking_description }}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{%- for group, commits in commits | group_by(attribute="group") %}
|
||||
|
||||
### {{ group | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.breaking %}💥 {% endif %}{% if commit.scope %}**{{ commit.scope }}:** {% endif %}{{ commit.message | split(pat="\n") | first | trim }}
|
||||
{%- if commit.body %}
|
||||
> {{ commit.body | split(pat="\n") | join(sep="\n > ") }}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- endfor %}
|
||||
"""
|
||||
trim = false
|
||||
|
||||
[git]
|
||||
conventional_commits = true
|
||||
filter_unconventional = true
|
||||
split_commits = false
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "Added" },
|
||||
{ message = "^fix", group = "Fixed" },
|
||||
{ message = "^refactor", group = "Changed" },
|
||||
{ message = "^perf", group = "Performance" },
|
||||
{ message = "^doc", group = "Documentation" },
|
||||
{ message = "^test", group = "Testing" },
|
||||
{ message = "^ci", group = "CI" },
|
||||
{ message = "^chore", skip = true },
|
||||
]
|
||||
filter_commits = false
|
||||
tag_pattern = "v[0-9].*"
|
||||
sort_commits = "oldest"
|
||||
@@ -1,7 +0,0 @@
|
||||
ignore:
|
||||
- src/main.rs
|
||||
- src/lib.rs
|
||||
- src/activity_manager.rs
|
||||
- src/ui/
|
||||
fixes:
|
||||
- "/::"
|
||||
@@ -0,0 +1,84 @@
|
||||
# cargo-deny configuration for termscp.
|
||||
#
|
||||
# Run locally with `just deny`. The same command runs in CI and enforces
|
||||
# advisories, licenses, bans, and dependency sources.
|
||||
#
|
||||
# Docs: https://embarkstudios.github.io/cargo-deny/
|
||||
|
||||
[graph]
|
||||
all-features = true
|
||||
|
||||
[output]
|
||||
feature-depth = 1
|
||||
|
||||
[advisories]
|
||||
db-urls = ["https://github.com/rustsec/advisory-db"]
|
||||
yanked = "deny"
|
||||
unmaintained = "all"
|
||||
# These are temporary, reachable transitive-risk acceptances owned by the
|
||||
# termscp maintainers. Review or remove every exception by 2026-12-31. The
|
||||
# upgrade target is a remotefs/self_update release line that accepts each fixed
|
||||
# dependency version; until then, connections to untrusted endpoints remain an
|
||||
# acknowledged denial-of-service and certificate-validation risk.
|
||||
ignore = [
|
||||
# h2 0.3 is retained transitively by the reqwest 0.11/AWS HTTP stack; its
|
||||
# dependency constraints cannot select the fixed h2 0.4 release.
|
||||
{ id = "RUSTSEC-2026-0258", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade reqwest/AWS stack to fixed h2" },
|
||||
# number_prefix is retained by self_update through indicatif. It is
|
||||
# unmaintained, but has no reported vulnerability or compatible replacement.
|
||||
{ id = "RUSTSEC-2025-0119", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade self_update/indicatif" },
|
||||
# Both affected quick-xml lines are constrained by remotefs-webdav and
|
||||
# self_update to versions older than the fixed 0.41 release.
|
||||
{ id = "RUSTSEC-2026-0194", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade remotefs-webdav/self_update to quick-xml >=0.41" },
|
||||
{ id = "RUSTSEC-2026-0195", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade remotefs-webdav/self_update to quick-xml >=0.41" },
|
||||
# The SSH stack requires RSA, for which RustSec reports no safe upgrade.
|
||||
{ id = "RUSTSEC-2023-0071", reason = "owner: termscp maintainers; review by 2026-12-31; replace RSA dependency when upstream fix exists" },
|
||||
# rustls-pemfile is retained by the WebDAV and Kubernetes clients. Both
|
||||
# versions are unmaintained but have no reported vulnerability.
|
||||
{ id = "RUSTSEC-2025-0134", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade WebDAV/Kubernetes clients away from rustls-pemfile" },
|
||||
]
|
||||
|
||||
[licenses]
|
||||
allow = [
|
||||
"Apache-2.0",
|
||||
"BSD-1-Clause",
|
||||
"BSD-2-Clause",
|
||||
"BSD-3-Clause",
|
||||
"BSL-1.0",
|
||||
"CC0-1.0",
|
||||
"CDLA-Permissive-2.0",
|
||||
"ISC",
|
||||
"MIT",
|
||||
"MIT-0",
|
||||
"MPL-2.0",
|
||||
"Unicode-3.0",
|
||||
"Unlicense",
|
||||
"Zlib",
|
||||
]
|
||||
confidence-threshold = 0.8
|
||||
exceptions = [
|
||||
# The WebDAV backend currently depends on rustydav, which declares GPL-3.0.
|
||||
# Keep this exception crate-scoped so no other GPL dependency is admitted.
|
||||
{ allow = ["GPL-3.0"], crate = "rustydav" },
|
||||
]
|
||||
|
||||
[licenses.private]
|
||||
ignore = false
|
||||
|
||||
[bans]
|
||||
multiple-versions = "warn"
|
||||
wildcards = "deny"
|
||||
allow-wildcard-paths = true
|
||||
highlight = "all"
|
||||
workspace-default-features = "allow"
|
||||
external-default-features = "allow"
|
||||
allow = []
|
||||
deny = []
|
||||
skip = []
|
||||
skip-tree = []
|
||||
|
||||
[sources]
|
||||
unknown-registry = "deny"
|
||||
unknown-git = "deny"
|
||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||
allow-git = []
|
||||
@@ -1,25 +0,0 @@
|
||||
# Build with Docker
|
||||
|
||||
- [Build with Docker](#build-with-docker)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Build](#build)
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker
|
||||
|
||||
## Build
|
||||
|
||||
1. Build x86_64
|
||||
|
||||
this will build termscp for:
|
||||
|
||||
- Linux x86_64 Deb packages
|
||||
- Linux x86_64 RPM packages
|
||||
- Windows x86_64 MSVC packages
|
||||
|
||||
```sh
|
||||
|
||||
```
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: deploy.sh <version>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION=$1
|
||||
|
||||
# Create pkgs directory
|
||||
cd ..
|
||||
PKGS_DIR=$(pwd)/pkgs
|
||||
cd -
|
||||
mkdir -p ${PKGS_DIR}/
|
||||
# Build x86_64
|
||||
cd x86_64/
|
||||
docker build --tag termscp-${VERSION}-x86_64 .
|
||||
# Create container and get deb, rpm
|
||||
cd -
|
||||
mkdir -p ${PKGS_DIR}/deb/
|
||||
mkdir -p ${PKGS_DIR}/rpm/
|
||||
CONTAINER_NAME=$(docker create termscp-${VERSION}-x86_64 termscp-${VERSION}-x86_64)
|
||||
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/rpmbuild/RPMS/x86_64/termscp-${VERSION}-1.x86_64.rpm ${PKGS_DIR}/rpm/
|
||||
# Build x86_64_archlinux
|
||||
cd x86_64_archlinux/
|
||||
docker build --tag termscp-${VERSION}-x86_64_archlinux .
|
||||
# Create container and get AUR pkg
|
||||
cd -
|
||||
mkdir -p ${PKGS_DIR}/arch/
|
||||
CONTAINER_NAME=$(docker create termscp-${VERSION}-x86_64_archlinux termscp-${VERSION}-x86_64_archlinux)
|
||||
docker cp ${CONTAINER_NAME}:/usr/src/termscp/termscp-${VERSION}-x86_64.tar.gz ${PKGS_DIR}/arch/
|
||||
docker cp ${CONTAINER_NAME}:/usr/src/termscp/PKGBUILD ${PKGS_DIR}/arch/
|
||||
docker cp ${CONTAINER_NAME}:/usr/src/termscp/.SRCINFO ${PKGS_DIR}/arch/
|
||||
# Replace termscp-bin with termscp in PKGBUILD
|
||||
sed -i 's/termscp-bin/termscp/g' ${PKGS_DIR}/arch/PKGBUILD
|
||||
|
||||
exit $?
|
||||
@@ -1,19 +0,0 @@
|
||||
FROM rust:1.48.0 AS builder
|
||||
|
||||
WORKDIR /usr/src/
|
||||
# Add toolchains
|
||||
RUN rustup target add x86_64-unknown-linux-gnu
|
||||
# Install dependencies
|
||||
RUN apt update && apt install -y rpm
|
||||
# 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
|
||||
# Build for x86_64
|
||||
RUN cargo build --release --target x86_64-unknown-linux-gnu
|
||||
# Build pkgs
|
||||
RUN cargo deb && cargo rpm init && cargo rpm build
|
||||
|
||||
CMD ["sh"]
|
||||
@@ -1,33 +0,0 @@
|
||||
FROM archlinux/archlinux:latest as builder
|
||||
|
||||
WORKDIR /usr/src/
|
||||
# Install dependencies
|
||||
RUN pacman -Syu --noconfirm \
|
||||
git \
|
||||
gcc \
|
||||
openssl \
|
||||
pkg-config \
|
||||
sudo
|
||||
# Create build user
|
||||
RUN useradd build -m && \
|
||||
passwd -d build && \
|
||||
mkdir -p termscp && \
|
||||
chown -R build.build termscp/
|
||||
# Install rust
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rust.sh && \
|
||||
chmod +x /tmp/rust.sh && \
|
||||
/tmp/rust.sh -y
|
||||
# Clone repository
|
||||
RUN git clone https://github.com/veeso/termscp.git
|
||||
# Set workdir to termscp
|
||||
WORKDIR /usr/src/termscp/
|
||||
# Install cargo arxch
|
||||
RUN source $HOME/.cargo/env && cargo install cargo-aur
|
||||
# Build for x86_64
|
||||
RUN source $HOME/.cargo/env && cargo build --release
|
||||
# Build pkgs
|
||||
RUN source $HOME/.cargo/env && cargo aur
|
||||
# Create SRCINFO
|
||||
RUN chown -R build.build ../termscp/ && sudo -u build bash -c 'makepkg --printsrcinfo > .SRCINFO'
|
||||
|
||||
CMD ["sh"]
|
||||
@@ -0,0 +1,8 @@
|
||||
# Chocolatey How To
|
||||
|
||||
Just:
|
||||
|
||||
1. Calculate the SHA256 checksum for the latest release of ZIP files both for aarch64 and x86_64 versions.
|
||||
2. Update checksums in `tools/chocolateyinstall.ps1`
|
||||
3. run `choco pack`
|
||||
4. run `choco push termscp.$VERSION.nupkg --source https://push.chocolatey.org/`
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>termscp</id>
|
||||
<version>1.2.0</version>
|
||||
<title>termSCP</title>
|
||||
<authors>Christian Visintin</authors>
|
||||
<owners>Christian Visintin</owners>
|
||||
<projectUrl>https://veeso.github.io/termscp/</projectUrl>
|
||||
<copyright>Christian Visintin (C) 2024</copyright>
|
||||
<licenseUrl>https://github.com/veeso/TermSCP/blob/main/LICENSE</licenseUrl>
|
||||
<iconUrl>https://rawcdn.githack.com/veeso/termscp/c3e5663cf45c4d6a7b50c8b15f89683a2e01b829/assets/images/termscp-512.png</iconUrl>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<projectSourceUrl>https://github.com/veeso/termscp/tree/main/src</projectSourceUrl>
|
||||
<packageSourceUrl>https://github.com/veeso/termscp</packageSourceUrl>
|
||||
<releaseNotes>https://github.com/veeso/termscp/blob/main/CHANGELOG.md</releaseNotes>
|
||||
<docsUrl>https://docs.rs/termscp</docsUrl>
|
||||
<bugTrackerUrl>https://github.com/veeso/termscp/issues</bugTrackerUrl>
|
||||
<tags>termscp winscp rust rust-lang rust-crate scp ssh-client ssh sftp-client ftp-client ftps utility terminal-app terminal command-line-utility command-line-tool tui-rs winscp sftp</tags>
|
||||
<summary>A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/WebDAV/S3</summary>
|
||||
<description>
|
||||
## 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 and FTPS.
|
||||
|
||||
Features:
|
||||
|
||||
- 📁 Different communication protocols
|
||||
- SFTP
|
||||
- Kube
|
||||
- WebDAV
|
||||
- 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
|
||||
- 📝 View and edit text files with your favourite text editor
|
||||
- 💁 SFTP/SCP authentication through SSH keys and username/password
|
||||
- 🐧 Compatible with Windows, Linux, BSD and MacOS
|
||||
- ✏ Customizable
|
||||
- Themes
|
||||
- Custom file explorer format
|
||||
- Customizable text editor
|
||||
- Customizable file sorting
|
||||
- 🔐 Save your password in your operating system key vault
|
||||
- 🦀 Rust-powered
|
||||
- 🤝 Easy to extend with new file transfers protocols
|
||||
- 👀 Developed keeping an eye on performance
|
||||
- 🦄 Frequent awesome updates
|
||||
</description>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="tools/**" target="tools" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -0,0 +1,25 @@
|
||||
$ErrorActionPreference = 'Stop';
|
||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||
|
||||
# Detect arch: PROCESSOR_ARCHITECTURE is "ARM64" on ARM, "AMD64" on x64
|
||||
$is_arm64 = $env:PROCESSOR_ARCHITECTURE -eq 'ARM64' -or $env:PROCESSOR_ARCHITEW6432 -eq 'ARM64'
|
||||
|
||||
if ($is_arm64) {
|
||||
$url = 'https://github.com/veeso/termscp/releases/download/v1.2.0/termscp-v1.2.0-msvc.zip'
|
||||
$checksum = 'f6ad6c62f1578562f9af4bcee93bd4cc429cb52219c3636359b008db8789587e'
|
||||
} else {
|
||||
$url = 'https://github.com/veeso/termscp/releases/download/v1.2.0/termscp-v1.2.0-x86_64-pc-windows-msvc.zip'
|
||||
$checksum = 'd7796081b6f67b82acfa94557aa6852d12a33daab3cca6490660b20e42752005'
|
||||
}
|
||||
|
||||
$packageArgs = @{
|
||||
packageName = $env:ChocolateyPackageName
|
||||
fileType = 'EXE'
|
||||
url = $url
|
||||
unzipLocation = $toolsDir
|
||||
softwareName = 'termscp*'
|
||||
checksum = $checksum
|
||||
checksumType = 'sha256'
|
||||
validExitCodes = @(0, 3010, 1641)
|
||||
}
|
||||
Install-ChocolateyZipPackage @packageArgs
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Installing cargo-deb..."
|
||||
cargo install cargo-deb
|
||||
if [ ! -f "Cargo.toml" ]; then
|
||||
echo "Yout must be in the project root directory"
|
||||
exit 1
|
||||
fi
|
||||
echo "Running cargo-deb"
|
||||
cargo deb
|
||||
exit $?
|
||||
@@ -1,14 +0,0 @@
|
||||
pkgbase = termscp-bin
|
||||
pkgdesc = TermSCP is a SCP/SFTP/FTPS client for command line with an integrated UI to explore the remote file system. Basically WinSCP on a terminal.
|
||||
pkgver = 0.3.2
|
||||
pkgrel = 1
|
||||
url = https://github.com/veeso/termscp
|
||||
arch = x86_64
|
||||
license = GPL-3.0
|
||||
provides = termscp
|
||||
options = strip
|
||||
source = https://github.com/veeso/termscp/releases/download/v0.3.2/termscp-0.3.2-x86_64.tar.gz
|
||||
sha256sums = e2700e2e9b741eb273e2633d5cf24ad620365d059bdd4f2b42f3737a7c28a2c7
|
||||
|
||||
pkgname = termscp-bin
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# Maintainer: Christian Visintin
|
||||
pkgname=termscp
|
||||
pkgver=0.3.2
|
||||
pkgrel=1
|
||||
pkgdesc="TermSCP is a SCP/SFTP/FTPS client for command line with an integrated UI to explore the remote file system. Basically WinSCP on a terminal."
|
||||
url="https://github.com/veeso/termscp"
|
||||
license=("GPL-3.0")
|
||||
arch=("x86_64")
|
||||
provides=("termscp")
|
||||
options=("strip")
|
||||
source=("https://github.com/veeso/termscp/releases/download/v$pkgver/termscp-$pkgver-x86_64.tar.gz")
|
||||
sha256sums=("e2700e2e9b741eb273e2633d5cf24ad620365d059bdd4f2b42f3737a7c28a2c7")
|
||||
|
||||
package() {
|
||||
install -Dm755 termscp -t "$pkgdir/usr/bin/"
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env sh
|
||||
# Builds a static musl termscp release binary for the given target triple
|
||||
# inside a pinned Alpine container.
|
||||
#
|
||||
# Usage: dist/release/build_musl.sh <target-triple>
|
||||
set -eu
|
||||
|
||||
IMAGE="rust:1.98-alpine3.22"
|
||||
|
||||
TARGET="${1:-}"
|
||||
if [ -z "$TARGET" ]; then
|
||||
echo "usage: $0 <target-triple>" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
case "$TARGET" in
|
||||
x86_64-unknown-linux-musl) PLATFORM="linux/amd64" ;;
|
||||
aarch64-unknown-linux-musl) PLATFORM="linux/arm64" ;;
|
||||
*)
|
||||
echo "unsupported target: $TARGET" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
WORKSPACE="$(CDPATH='' cd -- "$(dirname -- "$0")/../.." && pwd)"
|
||||
|
||||
# The container appends a [patch.crates-io] section to Cargo.toml and updates
|
||||
# Cargo.lock; keep byte-exact copies so the workspace is clean afterwards.
|
||||
BACKUP_DIR="$(mktemp -d)"
|
||||
cp -p "$WORKSPACE/Cargo.toml" "$BACKUP_DIR/Cargo.toml"
|
||||
cp -p "$WORKSPACE/Cargo.lock" "$BACKUP_DIR/Cargo.lock"
|
||||
|
||||
restore_manifests() {
|
||||
cp -p "$BACKUP_DIR/Cargo.toml" "$WORKSPACE/Cargo.toml"
|
||||
cp -p "$BACKUP_DIR/Cargo.lock" "$WORKSPACE/Cargo.lock"
|
||||
rm -rf "$BACKUP_DIR"
|
||||
}
|
||||
trap restore_manifests EXIT
|
||||
|
||||
HOST_UID="$(id -u)"
|
||||
HOST_GID="$(id -g)"
|
||||
export TARGET HOST_UID HOST_GID
|
||||
|
||||
docker run --rm \
|
||||
--platform "$PLATFORM" \
|
||||
--env TARGET \
|
||||
--env HOST_UID \
|
||||
--env HOST_GID \
|
||||
--volume "$WORKSPACE:/work" \
|
||||
--workdir /work \
|
||||
"$IMAGE" \
|
||||
sh /work/dist/release/build_musl_container.sh
|
||||
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env sh
|
||||
# Builds a static musl termscp binary. Runs INSIDE the Alpine container
|
||||
# started by dist/release/build_musl.sh; /work is the mounted workspace.
|
||||
#
|
||||
# Required environment: TARGET, HOST_UID, HOST_GID.
|
||||
set -eux
|
||||
|
||||
NETTLE_VERSION="3.10.1"
|
||||
GNUTLS_VERSION="3.8.13"
|
||||
PAVAO_SRC_VERSION="4.24.6"
|
||||
|
||||
cleanup() {
|
||||
chown -R "$HOST_UID:$HOST_GID" /work
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
apk add --no-cache \
|
||||
bison \
|
||||
binutils \
|
||||
build-base \
|
||||
file \
|
||||
flex \
|
||||
git \
|
||||
gnutls-dev \
|
||||
libgit2-dev \
|
||||
libgit2-static \
|
||||
libunistring-dev \
|
||||
libunistring-static \
|
||||
linux-headers \
|
||||
openssl-dev \
|
||||
openssl-libs-static \
|
||||
perl \
|
||||
perl-parse-yapp \
|
||||
pkgconf \
|
||||
python3 \
|
||||
wget \
|
||||
xz \
|
||||
zlib-dev \
|
||||
zlib-static
|
||||
|
||||
rustup target add "$TARGET"
|
||||
cargo fetch --locked
|
||||
|
||||
NATIVE_CFLAGS="-O2 -fPIC"
|
||||
if [ "$TARGET" = "aarch64-unknown-linux-musl" ]; then
|
||||
NATIVE_CFLAGS="$NATIVE_CFLAGS -mno-outline-atomics"
|
||||
fi
|
||||
export CFLAGS="$NATIVE_CFLAGS"
|
||||
|
||||
# -- static nettle (GnuTLS crypto backend); mini-gmp avoids a GMP dependency
|
||||
mkdir -p /tmp/native
|
||||
wget -q "https://ftp.gnu.org/gnu/nettle/nettle-$NETTLE_VERSION.tar.gz" \
|
||||
-O /tmp/native/nettle.tar.gz
|
||||
tar -xzf /tmp/native/nettle.tar.gz -C /tmp/native
|
||||
cd "/tmp/native/nettle-$NETTLE_VERSION"
|
||||
./configure \
|
||||
--prefix=/tmp/native/nettle \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--disable-documentation \
|
||||
--enable-mini-gmp
|
||||
make -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
make install
|
||||
|
||||
# -- static GnuTLS; every optional backend is disabled so nothing links
|
||||
# against a shared library
|
||||
wget -q "https://www.gnupg.org/ftp/gcrypt/gnutls/v3.8/gnutls-$GNUTLS_VERSION.tar.xz" \
|
||||
-O /tmp/native/gnutls.tar.xz
|
||||
tar -xf /tmp/native/gnutls.tar.xz -C /tmp/native
|
||||
cd "/tmp/native/gnutls-$GNUTLS_VERSION"
|
||||
PKG_CONFIG_PATH=/tmp/native/nettle/lib/pkgconfig \
|
||||
./configure \
|
||||
--prefix=/tmp/native/gnutls \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--disable-doc \
|
||||
--disable-tests \
|
||||
--disable-nls \
|
||||
--disable-hardware-acceleration \
|
||||
--with-nettle-mini \
|
||||
--with-included-libtasn1 \
|
||||
--with-included-unistring \
|
||||
--without-idn \
|
||||
--without-p11-kit \
|
||||
--without-brotli \
|
||||
--without-zstd \
|
||||
--without-zlib
|
||||
make -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
make install
|
||||
|
||||
# -- flatten gnutls.pc: pkg-config must hand the linker the static archives
|
||||
# directly, with no Requires.private chain to resolve
|
||||
mkdir -p /tmp/native/pkgconfig
|
||||
sed \
|
||||
-e "s#^Libs:.*#Libs: -L/tmp/native/gnutls/lib -lgnutls -latomic -L/tmp/native/nettle/lib -lhogweed -lnettle#" \
|
||||
-e "/^Requires.private:/d" \
|
||||
-e "s#^Cflags:.*#Cflags: -I/tmp/native/gnutls/include -I/tmp/native/nettle/include#" \
|
||||
/tmp/native/gnutls/lib/pkgconfig/gnutls.pc \
|
||||
> /tmp/native/pkgconfig/gnutls.pc
|
||||
|
||||
# -- pavao-src: Samba's replacement library omits two sources that musl needs
|
||||
cd /work
|
||||
PAVAO_SRC=$(find "${CARGO_HOME:-/usr/local/cargo}/registry/src" \
|
||||
-type d -name "pavao-src-$PAVAO_SRC_VERSION" -print -quit)
|
||||
test -n "$PAVAO_SRC"
|
||||
cp -R "$PAVAO_SRC" /tmp/pavao-src
|
||||
perl -0pi -e "s#( \\\"lib/replace/replace\\.c\\\",\\n)#\$1 \\\"lib/replace/closefrom.c\\\",\\n \\\"lib/replace/strptime.c\\\",\\n#" \
|
||||
/tmp/pavao-src/src/lib.rs
|
||||
|
||||
cat >> Cargo.toml <<EOF
|
||||
|
||||
[patch.crates-io]
|
||||
pavao-src = { path = "/tmp/pavao-src" }
|
||||
EOF
|
||||
cargo update -p "pavao-src@$PAVAO_SRC_VERSION"
|
||||
|
||||
export PKG_CONFIG_ALL_STATIC=1
|
||||
export PKG_CONFIG_PATH=/tmp/native/pkgconfig:/tmp/native/nettle/lib/pkgconfig:/usr/lib/pkgconfig
|
||||
export RUSTFLAGS="-C target-feature=+crt-static -C link-arg=-static"
|
||||
cargo build --locked --release --target "$TARGET" --features smb-vendored
|
||||
|
||||
# -- prove the binary is static: no interpreter, no shared libraries
|
||||
file "target/$TARGET/release/termscp"
|
||||
if readelf -l "target/$TARGET/release/termscp" > /tmp/program-headers.txt; then
|
||||
cat /tmp/program-headers.txt
|
||||
else
|
||||
status=$?
|
||||
cat /tmp/program-headers.txt
|
||||
exit "$status"
|
||||
fi
|
||||
if readelf -d "target/$TARGET/release/termscp" > /tmp/dynamic-section.txt; then
|
||||
cat /tmp/dynamic-section.txt
|
||||
else
|
||||
status=$?
|
||||
cat /tmp/dynamic-section.txt
|
||||
exit "$status"
|
||||
fi
|
||||
if grep -q INTERP /tmp/program-headers.txt; then
|
||||
exit 1
|
||||
fi
|
||||
if grep -q NEEDED /tmp/dynamic-section.txt; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# Bump termscp version across all tracked locations.
|
||||
# Usage: bump_version.sh <version> [date] [root]
|
||||
set -euo pipefail
|
||||
|
||||
VERSION="${1:?usage: bump_version.sh <version> [date] [root]}"
|
||||
if [[ ! "$VERSION" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
|
||||
echo "invalid release version: $VERSION (expected MAJOR.MINOR.PATCH)" >&2
|
||||
exit 2
|
||||
fi
|
||||
DATE="${2:-$(date +%F)}"
|
||||
ROOT="${3:-$(git rev-parse --show-toplevel)}"
|
||||
|
||||
# in-place sed that works on both GNU and BSD/macOS
|
||||
sedi() { perl -0777 -pi -e "$1" "$2"; }
|
||||
|
||||
# Cargo.toml — only the top-level package version (line-anchored), not deps
|
||||
sedi "s/^version = \"[0-9][0-9A-Za-z.\\-]*\"/version = \"$VERSION\"/m" "$ROOT/Cargo.toml"
|
||||
|
||||
# install.sh — the literal default assignment only
|
||||
sedi "s/^TERMSCP_VERSION=\"[0-9][0-9A-Za-z.\\-]*\"/TERMSCP_VERSION=\"$VERSION\"/m" "$ROOT/install.sh"
|
||||
|
||||
# install.ps1 — the default -Version parameter value only
|
||||
sedi "s/\\\$Version = \"[0-9][0-9A-Za-z.\\-]*\"/\\\$Version = \"$VERSION\"/" "$ROOT/install.ps1"
|
||||
|
||||
# README.md — version + release date
|
||||
sedi "s/Current version: [0-9][0-9A-Za-z.\\-]* [0-9]{4}-[0-9]{2}-[0-9]{2}/Current version: $VERSION $DATE/" "$ROOT/README.md"
|
||||
|
||||
# site: version constant displayed on the website
|
||||
sedi "s/^export const VERSION = \"[0-9][0-9A-Za-z.\\-]*\";/export const VERSION = \"$VERSION\";/m" "$ROOT/site/src/consts.ts"
|
||||
|
||||
# chocolatey nuspec
|
||||
sedi "s#<version>[0-9][0-9A-Za-z.\\-]*</version>#<version>$VERSION</version>#" "$ROOT/dist/chocolatey/termscp.nuspec"
|
||||
|
||||
# chocolatey install script — release tag + asset name in the URLs (checksums set later by CI)
|
||||
sedi "s#releases/download/v[0-9][0-9A-Za-z.\\-]*/termscp-v[0-9][0-9A-Za-z.\\-]*-#releases/download/v$VERSION/termscp-v$VERSION-#g" "$ROOT/dist/chocolatey/tools/chocolateyinstall.ps1"
|
||||
|
||||
echo "Bumped to $VERSION ($DATE)"
|
||||
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
BUMP="$SCRIPT_DIR/bump_version.sh"
|
||||
|
||||
ROOT="$(mktemp -d)"
|
||||
trap 'rm -rf "$ROOT"' EXIT
|
||||
|
||||
# --- build a fixture tree mirroring the real layout, all at 1.0.0 ---
|
||||
mkdir -p "$ROOT/site/html" "$ROOT/site/lang" "$ROOT/dist/chocolatey/tools"
|
||||
|
||||
cat > "$ROOT/Cargo.toml" <<'EOF'
|
||||
[package]
|
||||
name = "termscp"
|
||||
version = "1.0.0"
|
||||
|
||||
[dependencies]
|
||||
foo = { version = "1.0.0" }
|
||||
EOF
|
||||
|
||||
cat > "$ROOT/install.sh" <<'EOF'
|
||||
TERMSCP_VERSION="1.0.0"
|
||||
set_termscp_version() {
|
||||
TERMSCP_VERSION="$1"
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > "$ROOT/README.md" <<'EOF'
|
||||
<p align="center">Current version: 1.0.0 2026-04-18</p>
|
||||
EOF
|
||||
|
||||
cat > "$ROOT/site/html/home.html" <<'EOF'
|
||||
<span>termscp 1.0.0 is NOW out! Download it from</span>
|
||||
EOF
|
||||
|
||||
cat > "$ROOT/site/html/get-started.html" <<'EOF'
|
||||
<a href="https://github.com/veeso/termscp/releases/latest/download/termscp.1.0.0.nupkg">Github</a>
|
||||
<pre>wget -O termscp.deb https://github.com/veeso/termscp/releases/latest/download/termscp_1.0.0_amd64.deb</pre>
|
||||
EOF
|
||||
|
||||
for lang in en it fr es zh-CN; do
|
||||
cat > "$ROOT/site/lang/$lang.json" <<'EOF'
|
||||
{ "versionAlert": "termscp 1.0.0 is NOW out! Download it from" }
|
||||
EOF
|
||||
done
|
||||
|
||||
cat > "$ROOT/dist/chocolatey/termscp.nuspec" <<'EOF'
|
||||
<version>1.0.0</version>
|
||||
EOF
|
||||
|
||||
cat > "$ROOT/dist/chocolatey/tools/chocolateyinstall.ps1" <<'EOF'
|
||||
$url = 'https://github.com/veeso/termscp/releases/download/v1.0.0/termscp-v1.0.0-aarch64-pc-windows-msvc.zip'
|
||||
$url = 'https://github.com/veeso/termscp/releases/download/v1.0.0/termscp-v1.0.0-x86_64-pc-windows-msvc.zip'
|
||||
EOF
|
||||
|
||||
# --- run the bump ---
|
||||
"$BUMP" 1.1.0 2026-06-07 "$ROOT"
|
||||
|
||||
fail() { echo "FAIL: $1"; exit 1; }
|
||||
have() { grep -q -- "$2" "$ROOT/$1" || fail "$1 missing: $2"; }
|
||||
missing() { ! grep -q -- "$2" "$ROOT/$1" || fail "$1 still has: $2"; }
|
||||
|
||||
# package version bumped, dependency version NOT touched
|
||||
have "Cargo.toml" 'version = "1.1.0"'
|
||||
have "Cargo.toml" 'foo = { version = "1.0.0" }'
|
||||
|
||||
have "install.sh" 'TERMSCP_VERSION="1.1.0"'
|
||||
have "README.md" 'Current version: 1.1.0 2026-06-07'
|
||||
missing "README.md" '2026-04-18'
|
||||
|
||||
have "site/html/home.html" 'termscp 1.1.0 is NOW out'
|
||||
have "site/lang/en.json" 'termscp 1.1.0 is NOW out'
|
||||
have "site/lang/zh-CN.json" 'termscp 1.1.0 is NOW out'
|
||||
have "site/html/get-started.html" 'termscp.1.1.0.nupkg'
|
||||
have "site/html/get-started.html" 'termscp_1.1.0_amd64.deb'
|
||||
have "dist/chocolatey/termscp.nuspec" '<version>1.1.0</version>'
|
||||
have "dist/chocolatey/tools/chocolateyinstall.ps1" 'releases/download/v1.1.0/termscp-v1.1.0-'
|
||||
missing "dist/chocolatey/tools/chocolateyinstall.ps1" 'v1.0.0'
|
||||
|
||||
# --- idempotency: running again at same version is a no-op (no error) ---
|
||||
"$BUMP" 1.1.0 2026-06-07 "$ROOT"
|
||||
have "Cargo.toml" 'version = "1.1.0"'
|
||||
|
||||
echo "PASS"
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
which rpmbuild > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "You must install rpmbuild on your machine"
|
||||
fi
|
||||
echo "Installing cargo-rpm..."
|
||||
cargo install cargo-rpm
|
||||
if [ ! -f "Cargo.toml" ]; then
|
||||
echo "Yout must be in the project root directory"
|
||||
exit 1
|
||||
fi
|
||||
echo "Running cargo-rpm"
|
||||
cargo rpm init
|
||||
cargo rpm build
|
||||
exit $?
|
||||
@@ -0,0 +1 @@
|
||||
docs.termscp.rs
|
||||
@@ -1 +0,0 @@
|
||||
<mxfile host="Electron" modified="2020-11-21T19:08:13.709Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.3.1 Chrome/83.0.4103.119 Electron/9.0.5 Safari/537.36" etag="CH09h_mpCNwCuwQp3CzT" version="13.3.1" type="device" pages="2"><diagram id="SlpWaeKyUTlHltKKkHdB" name="ScpActivity">7ZlRk5owEMc/DY/HABGEx2rv2pnWmXaczj3nJEKmgdAQD+yn7wJBoOhUrbbcTHwx2SSb5L+/4EoMtEzKDwJn8YqHhBmOFZYGem84ju26FnxVln1j8QO3MUSChqpTZ1jTn0QZ1bhoR0OSDzpKzpmk2dC44WlKNnJgw0LwYthty9lw1gxHZGRYbzAbW59pKGO1C2fe2T8SGsXtzLYXNC0JbjurneQxDnnRM6FHAy0F57IpJeWSsEq8Vpdm3NOJ1sPCBEnlOQOyRbEsv31ixSv+vi6c588r9vXBaby8YrZTG1aLlftWAcF3aUgqJ5aBFkVMJVlneFO1FhBzsMUyYVCzobiljC054wLqKU+h00LNQIQk5cml2wdBgCTCEyLFHrqoAchEqBmzH9JRdCFBgWd6KipxLyJopvpiRUJ0cN+JBQWl1wXaoTeh3azl77R0M8s6pptj+t6dpJsdkc5jMPPiBQqRrLfeGLYc9tkX1fux423DQ14/MN5BB9Ck7BpbL1+qU6g8wUobZ8MJwNyb9MYBxIxGKVQZ2crbxBMo9/58Fo4E1L3XOXB1MK8/nO60YumNYvlEGUlxQkBVnFQapS95Vu/e+semGo8b+seS3nZbGREJzXPK0/w6H7xIiahTIb7L3gC+o2fR/Bi/8Os9GyPs3QvhuUZYI3x1ejQFgn1NsCb4fILNwA96H3+YUaAJAB1ooDXQl2QVbh/o+RDoYAJAt3m6JloT/ddEH/7N/VeibU20JvqStNm0+p/f3klNIeuwxy+3NdIa6bNflE8i0RhfMmiGNcOnGbaHqcYUM43x5c+K5Hl1D+tYL7y8m8wbEBGi2Vw2rJV/u603N8+Oe6NAmEEwkB55Y+l92zUteyz94clzgfZQ7a6S67behTx6/AU=</diagram><diagram id="SK1VvSCf6-f5suE94Ksw" name="AuthActivity">5ZfRbpswFIafhstIAQNtL1OarlI1qUq6RdrNZLADnowPs00ge/qZYCA0ldZOSiqVK+z/2Mec/zuWwEFRXn+RuMi+AqHc8eakdtCd43luEMzNo1H2rXJ9E7RCKhmxiwZhzf5QK9p9ackIVaOFGoBrVozFBISgiR5pWEqoxsu2wMenFjilJ8I6wfxU3TCiM1uFdzXoD5SlWXeyG960kRx3i20lKsMEqiMJLR0USQDdjvI6orwxr/Pl8ennZvUQzVZ3uwXDz8pfPaNZm+z+PVv6EiQV+r9Tb/ax+q59lCz5D/5rN4sf0z71DvPS+mVr1fvOQAmlILRJMnfQbZUxTdcFTppoZVrGaJnOuZm5ZrhlnEfAQZq5AEEbCYS2beEFZo45S4WZcLo1xdzaF6BS0/oFsX+U6/YMTPNSyKmWe7PP9qlvqVXH0K2WHQFHXaNi22hpn2ow0wysn+/w1jvxdlHqzNTEEqwZiKk5HZ7LaPRKE4dcW0dGHoe/S+gCM3XwamEWuH5RD0EzSu3zkCXuhAUhkip12NOGzPvGL5cbrT23kz8HZnf+Rs7+uTj7l+L8BFJPFPJbL/PZIAcXgyxBQwK83aQob74+Jkj8+qOJh5ci/k1RKXBOp3m1++/YDwN9dbGrjZWqQJIWNM4bJiJWxRjyZMCH5wNvpsMP0CF29BuJln8B</diagram></mxfile>
|
||||
@@ -0,0 +1,37 @@
|
||||
# Summary
|
||||
|
||||
[Introduction](index.md)
|
||||
|
||||
# Getting started
|
||||
|
||||
- [Installation](getting-started/installation.md)
|
||||
- [Connecting to a server](getting-started/connecting.md)
|
||||
- [Connection parameters](getting-started/connection-parameters.md)
|
||||
|
||||
# Using termscp
|
||||
|
||||
- [The file explorer](usage/file-explorer.md)
|
||||
- [Keyboard shortcuts](usage/keyboard-shortcuts.md)
|
||||
- [Working with multiple files](usage/multiple-files.md)
|
||||
- [Synchronized browsing](usage/synced-browsing.md)
|
||||
- [Opening and editing files](usage/open-edit-files.md)
|
||||
- [Bookmarks and recent hosts](usage/bookmarks.md)
|
||||
- [Keeping files in sync](usage/file-watcher.md)
|
||||
|
||||
# Configuration
|
||||
|
||||
- [Configuration](configuration/configuration.md)
|
||||
- [File explorer format](configuration/explorer-format.md)
|
||||
- [SSH key storage](configuration/ssh-keys.md)
|
||||
- [Themes](configuration/themes.md)
|
||||
- [Notifications](configuration/notifications.md)
|
||||
- [Logging](configuration/logging.md)
|
||||
- [Password security](configuration/password-security.md)
|
||||
|
||||
# CLI reference
|
||||
|
||||
- [Command-line usage](cli/cli.md)
|
||||
|
||||
# Developer
|
||||
|
||||
- [Developer manual](developer/developer.md)
|
||||
@@ -0,0 +1,22 @@
|
||||
[book]
|
||||
title = "termscp"
|
||||
description = "A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/GCS/SMB/WebDAV"
|
||||
authors = ["Christian Visintin"]
|
||||
language = "en"
|
||||
src = "."
|
||||
|
||||
[output.html]
|
||||
default-theme = "light"
|
||||
preferred-dark-theme = "navy"
|
||||
git-repository-url = "https://github.com/veeso/termscp"
|
||||
edit-url-template = "https://github.com/veeso/termscp/edit/main/docs/en-US/{path}"
|
||||
additional-js = ["lang-switcher.js", "mermaid.min.js", "mermaid-init.js"]
|
||||
|
||||
[output.html.fold]
|
||||
enable = true
|
||||
level = 1
|
||||
|
||||
[preprocessor]
|
||||
|
||||
[preprocessor.mermaid]
|
||||
command = "mdbook-mermaid"
|
||||
@@ -0,0 +1,76 @@
|
||||
# Command-line usage
|
||||
|
||||
termscp can be started with the following invocation forms:
|
||||
|
||||
```sh
|
||||
termscp [options]... [protocol://user@address:port:wrkdir] [protocol://user@address:port:wrkdir] [local-wrkdir]
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
```sh
|
||||
termscp [options]... -b [bookmark-name] -b [bookmark-name] [local-wrkdir]
|
||||
```
|
||||
|
||||
AND any combination of the two.
|
||||
|
||||
If no extra arguments are provided, termscp shows the authentication form. If an
|
||||
address argument or a bookmark name is provided, termscp skips the form and
|
||||
connects directly to the remote server. When an address or bookmark is given,
|
||||
you may also provide the starting working directory for the local host as the
|
||||
last positional argument.
|
||||
|
||||
## Options
|
||||
|
||||
| Key | Description |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `-b <bookmark-name>` | Resolve the positional address argument as a bookmark name. Repeat the flag to open multiple bookmarks. |
|
||||
| `-D` | Enable the `TRACE` log level (debug/verbose logging). |
|
||||
| `-P <password>` | Provide the password from the CLI. Repeat the flag for multiple remotes; the order must match the address arguments. Discouraged. |
|
||||
| `-q` | Disable logging. |
|
||||
| `-T <ticks>` | Set the UI tick interval in milliseconds. Default is `10`. |
|
||||
| `--wno-keyring` | Disable system keyring support. |
|
||||
| `-v` | Print version info. |
|
||||
| `--help` | Print the help page. |
|
||||
|
||||
The `-P` option is discouraged because the password may be kept in the shell
|
||||
history. See the bookmarks and password-security chapters for safer ways to
|
||||
provide credentials.
|
||||
|
||||
## Subcommands
|
||||
|
||||
termscp exposes the following subcommands.
|
||||
|
||||
### Import a theme
|
||||
|
||||
```sh
|
||||
termscp theme <theme-file>
|
||||
```
|
||||
|
||||
Import the theme defined in `<theme-file>`.
|
||||
|
||||
### Install the latest version
|
||||
|
||||
```sh
|
||||
termscp update
|
||||
```
|
||||
|
||||
Download and install the latest available version of termscp.
|
||||
|
||||
### Import ssh hosts
|
||||
|
||||
```sh
|
||||
termscp import-ssh-hosts [ssh-config-file]
|
||||
```
|
||||
|
||||
Import all the hosts from the specified ssh config file as bookmarks in
|
||||
termscp. If `[ssh-config-file]` is not provided, the default location
|
||||
`~/.ssh/config` is used. Identity files are imported as ssh keys in termscp too.
|
||||
|
||||
### Open configuration
|
||||
|
||||
```sh
|
||||
termscp config
|
||||
```
|
||||
|
||||
Start termscp directly in the configuration (setup) screen.
|
||||
@@ -0,0 +1,62 @@
|
||||
# Configuration
|
||||
|
||||
termscp supports a number of user-defined parameters. termscp stores them in a
|
||||
TOML file and a few directories, but you never edit these files by hand:
|
||||
configuration is done entirely from the user interface.
|
||||
|
||||
To enter the configuration, press `<CTRL+C>` from the termscp home.
|
||||
|
||||
termscp requires these paths to be accessible:
|
||||
|
||||
- `$HOME/.config/termscp/` on Linux/BSD
|
||||
- `$HOME/.config/termscp/` on macOS
|
||||
- `%USERPROFILE%\.termscp\` on Windows
|
||||
|
||||
## Parameters
|
||||
|
||||
The following parameters can be configured:
|
||||
|
||||
- **Text Editor**: the text editor to use. By default termscp finds the default
|
||||
editor for you; with this option you can force an editor to be used (e.g.
|
||||
`vim`). GUI editors are also supported, unless they detach (`nohup`) from the
|
||||
parent process.
|
||||
- **Default Protocol**: the default value for the file transfer protocol to be
|
||||
used in termscp. It applies to the login page and to the address CLI argument.
|
||||
- **Show Hidden Files**: whether hidden files are displayed by default. You can
|
||||
also toggle hidden files at runtime by pressing `A`.
|
||||
- **Check for updates**: if set to `yes`, termscp queries the GitHub API to
|
||||
check whether a new version of termscp is available.
|
||||
- **Prompt when replacing existing files**: if set to `yes`, termscp prompts for
|
||||
confirmation whenever a file transfer would replace an existing file on the
|
||||
target host.
|
||||
- **Group Dirs**: whether directories are grouped in the file explorers. If
|
||||
`Display first` is selected, directories are sorted with the configured method
|
||||
but displayed before files; with `Display last` they are displayed after
|
||||
files.
|
||||
- **Remote file formatter syntax**: syntax used to display file info for each
|
||||
file in the remote explorer. See [File explorer format](explorer-format.md).
|
||||
- **Local file formatter syntax**: syntax used to display file info for each file
|
||||
in the local explorer. See [File explorer format](explorer-format.md).
|
||||
- **Enable notifications**: if set to `Yes`, desktop notifications are displayed.
|
||||
See [Notifications](notifications.md).
|
||||
- **Notifications: minimum transfer size**: if the transfer size is greater than
|
||||
or equal to the specified value, transfer notifications are displayed. The
|
||||
accepted format is `{UNSIGNED} B/KB/MB/GB/TB/PB`.
|
||||
- **SSH configuration path**: SSH configuration file to use when connecting to a
|
||||
SCP/SFTP server. If left empty, no file is used. You can specify a path
|
||||
starting with `~` to indicate the home directory (e.g. `~/.ssh/config`). The
|
||||
attributes supported by termscp are listed at
|
||||
[the ssh2-config exposed attributes](https://github.com/veeso/ssh2-config#exposed-attributes).
|
||||
See also [SSH key storage](ssh-keys.md).
|
||||
|
||||
## SSH configuration behavior
|
||||
|
||||
In either SFTP or SCP authentication pane, after you change and leave the
|
||||
`Host` field, termscp keeps the entered alias visible and fills the visible
|
||||
`Port` and `Username` fields from the matching SSH configuration entry. If the
|
||||
new Host does not match an entry, it resets Port to `22` and Username to empty.
|
||||
`HostName` never replaces the alias in the form.
|
||||
|
||||
Bookmarks retain their saved Port and User values; the SSH configuration does
|
||||
not silently override them. The configured file still provides `HostName` and
|
||||
other supported SSH options when termscp connects.
|
||||
@@ -0,0 +1,49 @@
|
||||
# File explorer format
|
||||
|
||||
You can define a custom format for the file explorer through the configuration.
|
||||
This is possible for both the local and the remote host, so you can use two
|
||||
different syntaxes. The fields are named **File formatter syntax (local)** and
|
||||
**File formatter syntax (remote)**, and they define how the file entries are
|
||||
displayed in the file explorer.
|
||||
|
||||
## Syntax
|
||||
|
||||
The syntax for the formatter is the following:
|
||||
|
||||
```text
|
||||
{KEY1}... {KEY2:LENGTH}... {KEY3:LENGTH:EXTRA} {KEYn}...
|
||||
```
|
||||
|
||||
Each key in braces is replaced with the related attribute, while everything
|
||||
outside braces is left unchanged.
|
||||
|
||||
- The key name is mandatory and must be one of the keys below.
|
||||
- `LENGTH` describes the width reserved to display the field. Static attributes
|
||||
do not support it (`GROUP`, `PEX`, `SIZE`, `USER`).
|
||||
- `EXTRA` is supported only by some keys and provides an additional option. See
|
||||
the keys below to check whether `EXTRA` is supported.
|
||||
|
||||
## Keys
|
||||
|
||||
These are the keys supported by the formatter:
|
||||
|
||||
| Key | Description |
|
||||
| --------- | ------------------------------------------------------------------------------------------------ |
|
||||
| `ATIME` | Last access time (default `%b %d %Y %H:%M`); `EXTRA` is the time format (e.g. `{ATIME:8:%H:%M}`) |
|
||||
| `CTIME` | Creation time (default `%b %d %Y %H:%M`); `EXTRA` is the time format (e.g. `{CTIME:8:%H:%M}`) |
|
||||
| `GROUP` | Owner group |
|
||||
| `MTIME` | Last change time (default `%b %d %Y %H:%M`); `EXTRA` is the time format (e.g. `{MTIME:8:%H:%M}`) |
|
||||
| `NAME` | File name (folders between root and first ancestors are elided if longer than `LENGTH`) |
|
||||
| `PATH` | File absolute path (folders between root and first ancestors are elided if longer than `LENGTH`) |
|
||||
| `PEX` | File permissions (UNIX format) |
|
||||
| `SIZE` | File size (omitted for directories) |
|
||||
| `SYMLINK` | Symlink target (if any, `-> {FILE_PATH}`) |
|
||||
| `USER` | Owner user |
|
||||
|
||||
## Default format
|
||||
|
||||
If left empty, the default formatter syntax is used:
|
||||
|
||||
```text
|
||||
{NAME:24} {PEX} {USER} {SIZE} {MTIME:17:%b %d %Y %H:%M}
|
||||
```
|
||||
@@ -0,0 +1,28 @@
|
||||
# Logging
|
||||
|
||||
termscp writes a log file for each session, located at:
|
||||
|
||||
- `$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 is not rotated: it is truncated on each launch of termscp. If you want
|
||||
to report an issue and attach the log file, save the log somewhere safe before
|
||||
launching termscp again.
|
||||
|
||||
By default the log reports at the `INFO` level, so it is not very verbose.
|
||||
|
||||
## Reproducing an issue at TRACE level
|
||||
|
||||
To submit an issue, reproduce the problem with the log level set to `TRACE` by
|
||||
launching termscp with the `-D` CLI option.
|
||||
|
||||
## Disabling logging
|
||||
|
||||
To turn logging off, start termscp with the `-q` or `--quiet` option. You can
|
||||
alias termscp to make it persistent.
|
||||
|
||||
## Security
|
||||
|
||||
The log file does not contain any plaintext password. It exposes the same
|
||||
information as the sibling `bookmarks` file.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Notifications
|
||||
|
||||
termscp sends desktop notifications for the following events:
|
||||
|
||||
- **Transfer completed**: sent once a transfer has been successfully completed.
|
||||
Displayed only if the total transfer size is at least the configured
|
||||
`Notifications: minimum transfer size`.
|
||||
- **Transfer failed**: sent once a transfer has failed due to an error.
|
||||
Displayed only if the total transfer size is at least the configured
|
||||
`Notifications: minimum transfer size`.
|
||||
- **Update available**: sent whenever a new version of termscp is available.
|
||||
- **Update installed**: sent whenever a new version of termscp has been
|
||||
installed.
|
||||
- **Update failed**: sent whenever the installation of an update fails.
|
||||
|
||||
## Disable notifications
|
||||
|
||||
To turn notifications off, enter setup and set `Enable notifications?` to `No`.
|
||||
|
||||
## Change the minimum transfer size
|
||||
|
||||
To change the threshold that gates transfer notifications, enter setup and set
|
||||
`Notifications: minimum transfer size` to the value that suits you.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Password security
|
||||
|
||||
Bookmarks are saved in your configuration directory along with their passwords.
|
||||
Passwords are not stored in plaintext: they are encrypted with AES.
|
||||
|
||||
The key used to encrypt passwords is stored, where possible, in the operating
|
||||
system secret store:
|
||||
|
||||
- The Windows Vault on Windows
|
||||
- The system keyring on Linux
|
||||
- The Keychain on macOS
|
||||
|
||||
This is managed directly by your operating system.
|
||||
|
||||
On BSD and WSL there is no such secret store, so the encryption key is saved on
|
||||
disk at `$HOME/.config/termscp`. The location protects the key with file
|
||||
permissions so that it cannot be read by other users, but you should still avoid
|
||||
saving passwords for servers exposed on the internet on these systems.
|
||||
|
||||
## Linux keyring
|
||||
|
||||
On Linux there might be no keyring installed on your system. The key storage
|
||||
requires a service that exposes `org.freedesktop.secrets` on D-Bus, and only a
|
||||
few services provide it:
|
||||
|
||||
- If you use GNOME as your desktop environment (e.g. Ubuntu users), the keyring
|
||||
is already provided by `gnome-keyring` and everything should work out of the
|
||||
box.
|
||||
- For other desktop environments, you can use [KeepassXC](https://keepassxc.org/)
|
||||
to obtain a keyring. It must be set up to work with termscp; see
|
||||
[KeepassXC setup](#keepassxc-setup) below.
|
||||
- If you do not want to install any of these services, termscp keeps working as
|
||||
usual and falls back to saving the key in a file, as it does for BSD and WSL.
|
||||
|
||||
### KeepassXC setup
|
||||
|
||||
Follow these steps to set up KeepassXC for termscp:
|
||||
|
||||
1. Install KeepassXC.
|
||||
2. Go to "Tools" > "Settings" in the toolbar.
|
||||
3. Select "Secret service integration" and enable "Enable KeepassXC
|
||||
freedesktop.org secret service integration".
|
||||
4. Create a database, if you do not have one yet: from the toolbar, "Database" >
|
||||
"New database".
|
||||
5. From the toolbar, go to "Database" > "Database settings".
|
||||
6. Select "Secret service integration" and enable "Expose entries under this
|
||||
group".
|
||||
7. Select the group where the termscp secret will be kept. Note that any other
|
||||
application can read secrets exposed via D-Bus for that group.
|
||||
@@ -0,0 +1,25 @@
|
||||
# SSH key storage
|
||||
|
||||
Along with configuration, termscp provides an essential feature for SFTP/SCP
|
||||
clients: the SSH key storage.
|
||||
|
||||
To access the SSH key storage, enter the configuration and move to the
|
||||
`SSH Keys` tab.
|
||||
|
||||
## Manage keys
|
||||
|
||||
From the `SSH Keys` tab you can:
|
||||
|
||||
- **Add a new key**: press `<CTRL+N>`. You are prompted to provide the
|
||||
hostname/IP address and the username associated with the key, then a text
|
||||
editor opens: paste the **private** SSH key into the editor, save and quit.
|
||||
- **Remove an existing key**: press `<DEL>` or `<CTRL+E>` on the key you want to
|
||||
remove to delete it persistently from termscp.
|
||||
- **Edit an existing key**: press `<ENTER>` on the key you want to edit to change
|
||||
the private key.
|
||||
|
||||
## Password-protected keys
|
||||
|
||||
Password-protected private keys are supported. The password you provide for
|
||||
authentication in termscp is valid both for username/password authentication and
|
||||
for key authentication.
|
||||
@@ -0,0 +1,113 @@
|
||||
# Themes
|
||||
|
||||
termscp lets you set the colors for several components in the application. There
|
||||
are two ways to customize termscp:
|
||||
|
||||
- From the **configuration menu**
|
||||
- Importing a **theme file**
|
||||
|
||||
## Customize from the configuration menu
|
||||
|
||||
To customize termscp from the configuration menu, enter the configuration from
|
||||
the auth screen by pressing `<CTRL+C>`, then press `<TAB>` twice to reach the
|
||||
`themes` panel. Move with `<UP>` and `<DOWN>` to select the style you want to
|
||||
change, as shown in the gif below:
|
||||
|
||||

|
||||
|
||||
## Import a theme file
|
||||
|
||||
You can also import theme files. You can take inspiration from, or directly use,
|
||||
one of the themes bundled with termscp in the `themes/` directory of the
|
||||
repository. Import a theme by running:
|
||||
|
||||
```sh
|
||||
termscp theme <theme_file>
|
||||
```
|
||||
|
||||
If everything is fine, termscp confirms the theme has been imported.
|
||||
|
||||
## Color syntax
|
||||
|
||||
termscp accepts the following color formats:
|
||||
|
||||
- Explicit hexadecimal: `#rrggbb`
|
||||
- RGB: `rgb(r, g, b)`
|
||||
- [CSS color names](https://www.w3schools.com/cssref/css_colors.asp) (such as
|
||||
`crimson`)
|
||||
- The special keyword `Default`, which uses the situational default foreground
|
||||
or background color (foreground for texts and lines, background otherwise)
|
||||
|
||||
## Recovering from a theme that won't load
|
||||
|
||||
After an update, a saved theme can fail to load. This happens when a new key is
|
||||
added to themes: the previously saved theme no longer contains that key. There
|
||||
are two quick fixes:
|
||||
|
||||
1. Re-import the official theme. After each release the official themes are
|
||||
patched, so download the updated theme from the repository and re-import it:
|
||||
|
||||
```sh
|
||||
termscp theme <theme.toml>
|
||||
```
|
||||
|
||||
2. Edit your theme by hand. If you use a custom theme, edit the file and add the
|
||||
missing key. The theme is located at `$CONFIG_DIR/theme.toml`, where
|
||||
`$CONFIG_DIR` is:
|
||||
|
||||
- FreeBSD/Linux: `$HOME/.config/termscp`
|
||||
- macOS: `$HOME/.config/termscp`
|
||||
- Windows: `%USERPROFILE%\.termscp`
|
||||
|
||||
Missing keys are reported in the CHANGELOG under `BREAKING CHANGES` for the
|
||||
version you have just installed.
|
||||
|
||||
## Styles
|
||||
|
||||
The tables below describe each style field. Note that styles do **not** apply to
|
||||
the configuration page, so it always remains usable in case you change something
|
||||
by mistake.
|
||||
|
||||
### Authentication page
|
||||
|
||||
| Key | Description |
|
||||
| ---------------- | ---------------------------------------- |
|
||||
| `auth_address` | Color of the input field for IP address |
|
||||
| `auth_bookmarks` | Color of the bookmarks panel |
|
||||
| `auth_password` | Color of the input field for password |
|
||||
| `auth_port` | Color of the input field for port number |
|
||||
| `auth_protocol` | Color of the radio group for protocol |
|
||||
| `auth_recents` | Color of the recents panel |
|
||||
| `auth_username` | Color of the input field for username |
|
||||
|
||||
### Transfer page
|
||||
|
||||
| Key | Description |
|
||||
| -------------------------------------- | ------------------------------------------------------------------------- |
|
||||
| `transfer_local_explorer_background` | Background color of localhost explorer |
|
||||
| `transfer_local_explorer_foreground` | Foreground color of localhost explorer |
|
||||
| `transfer_local_explorer_highlighted` | Border and highlighted color for localhost explorer |
|
||||
| `transfer_remote_explorer_background` | Background color of remote explorer |
|
||||
| `transfer_remote_explorer_foreground` | Foreground color of remote explorer |
|
||||
| `transfer_remote_explorer_highlighted` | Border and highlighted color for remote explorer |
|
||||
| `transfer_log_background` | Background color for log panel |
|
||||
| `transfer_log_window` | Window color for log panel |
|
||||
| `transfer_progress_bar_partial` | Partial progress bar color |
|
||||
| `transfer_progress_bar_total` | Total progress bar color |
|
||||
| `transfer_status_hidden` | Color for status bar "hidden" label |
|
||||
| `transfer_status_sorting` | Color for status bar "sorting" label; applies also to file sorting dialog |
|
||||
| `transfer_status_sync_browsing` | Color for status bar "sync browsing" label |
|
||||
|
||||
### Misc
|
||||
|
||||
These styles apply to different parts of the application.
|
||||
|
||||
| Key | Description |
|
||||
| ------------------- | ------------------------------------------- |
|
||||
| `misc_error_dialog` | Color for error messages |
|
||||
| `misc_info_dialog` | Color for info dialogs |
|
||||
| `misc_input_dialog` | Color for input dialogs (such as copy file) |
|
||||
| `misc_keys` | Color of text for key strokes |
|
||||
| `misc_quit_dialog` | Color for quit dialogs |
|
||||
| `misc_save_dialog` | Color for save dialogs |
|
||||
| `misc_warn_dialog` | Color for warn dialogs |
|
||||
@@ -0,0 +1,128 @@
|
||||
# Developer manual
|
||||
|
||||
Welcome to the developer manual for termscp. This chapter does NOT contain the
|
||||
documentation for termscp modules, which can instead be found on Rust Docs at
|
||||
<https://docs.rs/termscp>. This chapter describes how termscp works and the
|
||||
guidelines to implement features such as file transfers and additions to the
|
||||
user interface.
|
||||
|
||||
termscp is written in Rust (edition 2024, MSRV 1.98.0). The user interface is
|
||||
built with [tuirealm](https://github.com/veeso/tui-realm) v3, which runs on top
|
||||
of [crossterm](https://github.com/crossterm-rs/crossterm).
|
||||
|
||||
## How termscp works
|
||||
|
||||
termscp is basically made up of 3 core modules:
|
||||
|
||||
- The **host**: the host module provides functions to interact with file
|
||||
systems. It exposes the `HostBridge` trait, which abstracts file operations
|
||||
over both the local host (`Localhost`) and the remote host (`RemoteBridged`).
|
||||
- The **ui**: this module contains the implementation of the user interface. As
|
||||
shown in the next chapter, this is achieved through **activities**.
|
||||
- The **activity_manager**: the activity manager takes care of managing
|
||||
activities. It runs the activities of the user interface and chooses, based on
|
||||
their state, when to terminate the current activity and which activity to run
|
||||
next.
|
||||
|
||||
In addition to the 3 core modules, others have been added over time:
|
||||
|
||||
- **config**: provides the configuration schema and its serialization methods.
|
||||
- **explorer**: exposes the explorer structures, which are used to handle the
|
||||
file explorer in the ui. They store the current directory model and the view
|
||||
states (e.g. sorting, whether to display hidden files, the transfer queue).
|
||||
- **filetransfer**: defines the `FileTransferProtocol` enum and the
|
||||
`RemoteFsBuilder`, which constructs the appropriate `RemoteFs` client from the
|
||||
connection parameters.
|
||||
- **system**: provides a way to interact with the configuration, the ssh key
|
||||
storage and the bookmarks.
|
||||
- **utils**: contains the utilities used by pretty much all of the project.
|
||||
|
||||
termscp supports the following protocols: SFTP, SCP, FTP/FTPS, Kube, S3, GCS,
|
||||
SMB and WebDAV.
|
||||
|
||||
## Activities
|
||||
|
||||
This paragraph gives a short overview of activities. Read the code and the
|
||||
documentation for a clear idea of how the ui works.
|
||||
|
||||
There are many ways to implement a user interface. This project borrows what
|
||||
works best from different frameworks:
|
||||
|
||||
- **Activities on top**: each "view" is an Activity, and an `Activity Manager`
|
||||
handles them. This approach is inspired by Android. It fits a ui that has
|
||||
different views, each one with its own components and logic. Activities work
|
||||
with the `Context`, which is a data holder used to share data between
|
||||
activities.
|
||||
- **Activities display Applications**: each activity can show different
|
||||
**Applications**. An application contains a **View**, which is basically a list
|
||||
of **components**, each one with its properties. The view is a facade to the
|
||||
components and also handles the focus, which is the current active component.
|
||||
You cannot have more than one active component, so this must be handled; at the
|
||||
same time, focus must be given back to the previously active component if the
|
||||
current one is destroyed. The **Application** takes care of all this. To learn
|
||||
more, read <https://github.com/veeso/tui-realm>.
|
||||
- **Components**: components are built around tui in order to reuse widgets. This
|
||||
is achieved through the `Component` trait, inspired by
|
||||
[React](https://reactjs.org/). Each component has its _Properties_ and can have
|
||||
its _States_. Each component must handle input events, accept new properties,
|
||||
and provide a method to **render** itself. This logic now lives in
|
||||
[tui-realm](https://github.com/veeso/tui-realm).
|
||||
- **Messages: an Elm-based approach**: input events are handled with an approach
|
||||
inspired by [Elm](https://elm-lang.org/). In Elm you implement your ui using
|
||||
three basic functions: **update**, **view** and **init**. termscp implements
|
||||
the equivalent of the Elm update function as a large match case inside a
|
||||
recursive function, which you can find in the `update.rs` file inside each
|
||||
activity. This match case handles the messages produced by the components in
|
||||
response to incoming input events and causes the activity to change its state.
|
||||
|
||||
termscp implements a trait called `Activity`, a much reduced version of the
|
||||
Android activity. This trait provides these methods:
|
||||
|
||||
- `on_create`: initializes the activity. The context is passed to the activity,
|
||||
which becomes the only owner of the Context until the activity terminates.
|
||||
- `on_draw`: called each time the user interface should be updated. This is
|
||||
basically the run method of the activity, and it also handles input events. The
|
||||
interface should not be drawn on every call (this method may be called hundreds
|
||||
of times per second), but only when something has actually changed (for example
|
||||
after an input event).
|
||||
- `will_umount`: returns whether the activity should be destroyed. If so, it
|
||||
returns an `ExitReason`, which indicates why the activity should terminate.
|
||||
Based on the reason, the activity manager chooses whether to stop the execution
|
||||
of termscp or to start a new activity, and which one.
|
||||
- `on_destroy`: finalizes the activity and drops it. This method returns the
|
||||
Context to the caller (the activity manager).
|
||||
|
||||
### The Context
|
||||
|
||||
The context is a structure that holds data shared between activities. Every time
|
||||
an Activity starts, the Context is taken by the activity, until it is destroyed,
|
||||
where the context is finally returned to the activity manager. The context holds
|
||||
the following data:
|
||||
|
||||
- The **Localhost**: the local host structure.
|
||||
- The **File Transfer Params**: the current parameters used to connect to the
|
||||
remote.
|
||||
- The **Config Client**: a structure that provides functions to access the user
|
||||
configuration.
|
||||
- The **Store**: a key-value storage that can hold any kind of data. It can be
|
||||
used to share state between activities or to keep persistence for heavy or slow
|
||||
tasks (such as checking for updates).
|
||||
- The **Terminal**: used to render the tui on the terminal.
|
||||
|
||||
## Achieving an abstract file transfer client
|
||||
|
||||
When the implementation of termscp started, in December 2020, file transfer was
|
||||
at the core of the design, since it is at the heart of termscp. The first
|
||||
implementation consisted of a `filetransfer` module that exposed a trait called
|
||||
`FileTransfer`, which provided methods to generically interact with the remote
|
||||
file system.
|
||||
|
||||
This changed over time, as different users asked for a dedicated library. In the
|
||||
last quarter of 2021, [remotefs](https://github.com/veeso/remotefs-rs) was born:
|
||||
an abstract library to work with remote device file systems. remotefs provides a
|
||||
`RemoteFs` trait that exposes all of the core file-system functionalities, and
|
||||
since version 0.8.0 it has replaced the `FileTransfer` trait.
|
||||
|
||||
The file transfer module still exists, but its only task is to build a
|
||||
`RemoteFs` client implementation from the file transfer parameters through the
|
||||
`RemoteFsBuilder`.
|
||||
@@ -0,0 +1,91 @@
|
||||
# Connecting to a server
|
||||
|
||||
termscp can start in three different ways depending on the arguments you pass.
|
||||
|
||||
- No arguments: termscp opens the authentication form, where you provide the
|
||||
parameters required to connect to the remote host.
|
||||
- An address argument: termscp skips the authentication form and connects
|
||||
directly to the remote host.
|
||||
- A bookmark name with `-b <bookmark-name>`: termscp resolves the argument as a
|
||||
saved bookmark and connects. Repeat `-b` to open several bookmarks.
|
||||
|
||||
When you provide an address argument or a bookmark name, you can also provide a
|
||||
start working directory for the local host.
|
||||
|
||||
## The authentication form
|
||||
|
||||
When termscp starts without an address, it shows the authentication form. Fill
|
||||
in the protocol, address, port, username, and password, then connect. termscp
|
||||
will open the dual-pane explorer once the connection succeeds.
|
||||
|
||||
## SSH configuration precedence
|
||||
|
||||
For SFTP and SCP connections, termscp resolves CLI Username and Port values in
|
||||
this order: explicit `Username`/`Port`, SSH configuration `User`/`Port`, then
|
||||
the current OS user and Port `22`. Username and Port are resolved independently,
|
||||
so an explicit value for one does not prevent SSH configuration from supplying
|
||||
the other.
|
||||
|
||||
For example, `termscp myhost` uses the configured Port and User for `myhost`.
|
||||
`termscp alice@myhost:22` uses `alice` and `22`, regardless of the SSH
|
||||
configuration.
|
||||
|
||||
## Address argument syntax
|
||||
|
||||
The generic address argument has the following syntax:
|
||||
|
||||
```txt
|
||||
[protocol://][username@]<address>[:port][:wrkdir]
|
||||
```
|
||||
|
||||
This syntax is convenient, and you will probably use it instead of the
|
||||
interactive form. Here are some examples.
|
||||
|
||||
Connect using the default protocol (defined in your configuration) to
|
||||
`192.168.1.31`. For SFTP and SCP, an omitted Port or Username is taken from a
|
||||
matching SSH configuration entry. If no value is configured, it falls back to
|
||||
the protocol default port or the current OS user. Other protocols use their
|
||||
default port and the current OS user.
|
||||
|
||||
```sh
|
||||
termscp 192.168.1.31
|
||||
```
|
||||
|
||||
Connect using the default protocol to `192.168.1.31` as user `root`:
|
||||
|
||||
```sh
|
||||
termscp root@192.168.1.31
|
||||
```
|
||||
|
||||
Connect using SCP to `192.168.1.31` on port `4022` as user `omar`:
|
||||
|
||||
```sh
|
||||
termscp scp://omar@192.168.1.31:4022
|
||||
```
|
||||
|
||||
Connect using SCP to `192.168.1.31` on port `4022` as user `omar`, starting in
|
||||
directory `/tmp`:
|
||||
|
||||
```sh
|
||||
termscp scp://omar@192.168.1.31:4022:/tmp
|
||||
```
|
||||
|
||||
For protocol-specific address syntax (S3, GCS, Kube, WebDAV, and SMB), see
|
||||
[Connection parameters](connection-parameters.md).
|
||||
|
||||
## How the password is provided
|
||||
|
||||
When you provide the address as an argument, there is no field for the password
|
||||
in the address itself. You can provide the password in three ways:
|
||||
|
||||
- You will be prompted for it. This is the default: if you don't use any of the
|
||||
methods below, termscp prompts for the password, like classic tools such as
|
||||
`scp` and `ssh`.
|
||||
- `-P, --password` option: pass the password directly on the command line. This
|
||||
method is discouraged because it is insecure: the password may be kept in
|
||||
your shell history.
|
||||
- Via `sshpass`: provide the password through `sshpass`, for example:
|
||||
|
||||
```sh
|
||||
sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31
|
||||
```
|
||||
@@ -0,0 +1,219 @@
|
||||
# Connection parameters
|
||||
|
||||
Each protocol has its own set of authentication-form fields and its own
|
||||
command-line address syntax. This page describes them protocol by protocol.
|
||||
|
||||
## SFTP / SCP
|
||||
|
||||
Authentication-form fields:
|
||||
|
||||
- Host (address)
|
||||
- Port (default `22`)
|
||||
- Username
|
||||
- Password or SSH key
|
||||
|
||||
You can authenticate either with a username and password or with an SSH key.
|
||||
See [SSH key storage](../configuration/ssh-keys.md) for how to manage keys.
|
||||
|
||||
Address syntax:
|
||||
|
||||
```txt
|
||||
[protocol://][username@]<address>[:port][:wrkdir]
|
||||
```
|
||||
|
||||
## FTP / FTPS
|
||||
|
||||
Authentication-form fields:
|
||||
|
||||
- Host (address)
|
||||
- Port (default `21`)
|
||||
- Username
|
||||
- Password
|
||||
- Secure (FTPS): enable TLS to use FTPS instead of plain FTP
|
||||
|
||||
Address syntax:
|
||||
|
||||
```txt
|
||||
[protocol://][username@]<address>[:port][:wrkdir]
|
||||
```
|
||||
|
||||
## Kube
|
||||
|
||||
Authentication-form fields:
|
||||
|
||||
- Namespace
|
||||
- Cluster URL (Kubernetes API URL)
|
||||
- Username
|
||||
- Client certificate path
|
||||
- Client key path
|
||||
|
||||
Address syntax:
|
||||
|
||||
```txt
|
||||
kube://[namespace][@<cluster_url>][$</path>]
|
||||
```
|
||||
|
||||
## S3
|
||||
|
||||
termscp supports both AWS S3 and other S3-compatible endpoints.
|
||||
|
||||
Authentication-form fields:
|
||||
|
||||
- Bucket name
|
||||
- Region (for AWS S3) or endpoint (for other S3-compatible servers)
|
||||
- Profile
|
||||
- Access key
|
||||
- Secret access key
|
||||
- Security token
|
||||
- Session token
|
||||
- New path style
|
||||
|
||||
The required and optional fields differ depending on the endpoint:
|
||||
|
||||
- AWS S3:
|
||||
- bucket name (required)
|
||||
- region (required)
|
||||
- profile (optional; defaults to `default`)
|
||||
- access key (required unless the bucket is public)
|
||||
- secret access key (required unless the bucket is public)
|
||||
- security token (if required)
|
||||
- session token (if required)
|
||||
- new path style: NO
|
||||
- Other S3 endpoints:
|
||||
- bucket name (required)
|
||||
- endpoint (required)
|
||||
- access key (required unless the bucket is public)
|
||||
- secret access key (required unless the bucket is public)
|
||||
- new path style: YES
|
||||
|
||||
Address syntax:
|
||||
|
||||
```txt
|
||||
s3://<bucket>@<region>[:profile][:/wrkdir]
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```txt
|
||||
s3://buckethead@eu-central-1:default:/assets
|
||||
```
|
||||
|
||||
### S3 credentials
|
||||
|
||||
To connect to an AWS S3 bucket you must provide credentials. There are three
|
||||
ways to do this.
|
||||
|
||||
1. Authentication form: provide the access key (usually mandatory), the secret
|
||||
access key (usually mandatory), the security token, and the session token.
|
||||
If you save the S3 connection as a bookmark, the access key and secret access
|
||||
key are saved as an encrypted AES-256/BASE64 string in your bookmarks file.
|
||||
The security token and session token are not saved, since they are meant to
|
||||
be temporary credentials.
|
||||
2. Credentials file: configure the AWS CLI with `aws configure`. Your
|
||||
credentials are then stored at `~/.aws/credentials`. If you use a profile
|
||||
other than `default`, provide it in the profile field of the authentication
|
||||
form.
|
||||
3. Environment variables: provide your credentials as environment variables.
|
||||
These always override the credentials in the credentials file. The following
|
||||
are usually mandatory:
|
||||
|
||||
- `AWS_ACCESS_KEY_ID`: AWS access key ID (usually starts with `AKIA...`)
|
||||
- `AWS_SECRET_ACCESS_KEY`: the secret access key
|
||||
|
||||
If you have configured stronger security, you may also need:
|
||||
|
||||
- `AWS_SECURITY_TOKEN`: security token
|
||||
- `AWS_SESSION_TOKEN`: session token
|
||||
|
||||
Your credentials are safe: termscp does not manipulate these values directly.
|
||||
They are consumed directly by the `s3` crate.
|
||||
|
||||
## Google Cloud Storage
|
||||
|
||||
termscp supports Google Cloud Storage (GCS) buckets through the Google Cloud
|
||||
Storage JSON API.
|
||||
|
||||
Authentication-form fields:
|
||||
|
||||
- Bucket name (required)
|
||||
- Endpoint (defaults to `https://storage.googleapis.com`)
|
||||
- Optional service-account JSON path
|
||||
|
||||
Leave the service-account JSON path empty to use Application Default
|
||||
Credentials (ADC). ADC can obtain credentials from
|
||||
`GOOGLE_APPLICATION_CREDENTIALS`, local gcloud ADC credentials, or the Google
|
||||
Cloud metadata service when termscp runs on Google Cloud infrastructure.
|
||||
|
||||
When a service-account JSON path is supplied, termscp reads that file when it
|
||||
connects. Bookmarks store only the path and never copy the service-account JSON
|
||||
or its private key.
|
||||
|
||||
The dedicated CLI syntax is:
|
||||
|
||||
```txt
|
||||
gcs://<bucket>[:/working/directory]
|
||||
```
|
||||
|
||||
CLI connections use ADC and the default endpoint. Use the authentication form
|
||||
or a bookmark when you need a custom endpoint or a service-account JSON path.
|
||||
The selected ADC identity or service account must have IAM permissions for the
|
||||
storage operations you want to perform.
|
||||
|
||||
## SMB
|
||||
|
||||
Authentication-form fields:
|
||||
|
||||
- Server (address)
|
||||
- Share
|
||||
- Username
|
||||
- Password
|
||||
- Port (other systems only; default `445`)
|
||||
- Workgroup (other systems only)
|
||||
- SMB version (other systems only; default `Auto`)
|
||||
|
||||
On Windows the port, workgroup and SMB version fields are not used: the
|
||||
operating system manages SMB protocol negotiation.
|
||||
|
||||
The SMB version field bounds the dialects offered during negotiation:
|
||||
|
||||
| Selection | Dialects negotiated |
|
||||
| --------- | ----------------------- |
|
||||
| Auto | SMB 2.0.2 through 3.1.1 |
|
||||
| SMB1 | NT1 (CIFS) only |
|
||||
| SMB2 | SMB 2.0.2 through 2.1 |
|
||||
| SMB3 | SMB 3.0 through 3.1.1 |
|
||||
|
||||
`Auto` never negotiates SMB1. SMB1 is deprecated and insecure: select it only
|
||||
for isolated legacy devices that support nothing newer. A warning is shown in
|
||||
the form while SMB1 is selected.
|
||||
|
||||
Bookmarks store the selection under the `dialect` key of the SMB table
|
||||
(`auto`, `smb1`, `smb2` or `smb3`). Bookmarks saved before this option existed
|
||||
have no `dialect` key and behave as `Auto`. The address syntax below does not
|
||||
carry a version; connections started from the command line use `Auto`.
|
||||
|
||||
Windows address syntax:
|
||||
|
||||
```txt
|
||||
\\[username@]<server-name>\<share>[\path\...]
|
||||
```
|
||||
|
||||
Other systems address syntax:
|
||||
|
||||
```txt
|
||||
smb://[username@]<server-name>[:port]/<share>[/path/.../]
|
||||
```
|
||||
|
||||
## WebDAV
|
||||
|
||||
Authentication-form fields:
|
||||
|
||||
- URI (the base WebDAV endpoint)
|
||||
- Username
|
||||
- Password
|
||||
|
||||
Address syntax:
|
||||
|
||||
```txt
|
||||
http(s)://<username>:<password>@<url></path>
|
||||
```
|
||||
@@ -0,0 +1,102 @@
|
||||
# Installation
|
||||
|
||||
termscp is available for many platforms. Pick the method that matches your
|
||||
system below.
|
||||
|
||||
## Linux, FreeBSD, and macOS
|
||||
|
||||
This shell script installs termscp on your system with a single command:
|
||||
|
||||
```sh
|
||||
curl --proto '=https' --tlsv1.2 -sSLf https://termscp.rs/install.sh | sh
|
||||
```
|
||||
|
||||
On macOS the installation requires [Homebrew](https://brew.sh/); otherwise the
|
||||
Rust compiler is installed to build termscp from source.
|
||||
|
||||
## Windows
|
||||
|
||||
Install termscp from PowerShell with a single command:
|
||||
|
||||
```ps
|
||||
irm https://termscp.rs/install.ps1 | iex
|
||||
```
|
||||
|
||||
Alternatively, install it with [Chocolatey](https://chocolatey.org/):
|
||||
|
||||
```ps
|
||||
choco install termscp
|
||||
```
|
||||
|
||||
## NetBSD
|
||||
|
||||
Install termscp from the official repositories:
|
||||
|
||||
```sh
|
||||
pkgin install termscp
|
||||
```
|
||||
|
||||
## Arch Linux
|
||||
|
||||
Install termscp from the official repositories:
|
||||
|
||||
```sh
|
||||
pacman -S termscp
|
||||
```
|
||||
|
||||
## Official binaries
|
||||
|
||||
Official release binaries are published for these targets:
|
||||
|
||||
- GNU/Linux:
|
||||
- `x86_64-unknown-linux-musl`
|
||||
- `aarch64-unknown-linux-musl`
|
||||
- macOS:
|
||||
- `x86_64-apple-darwin`
|
||||
- `aarch64-apple-darwin`
|
||||
- Windows:
|
||||
- `x86_64-pc-windows-msvc`
|
||||
- `aarch64-pc-windows-msvc`
|
||||
|
||||
The Linux binaries, and the `.deb` package built from them, are statically
|
||||
linked against musl. They have no runtime dependencies: they run on any Linux
|
||||
distribution and any glibc version, with no system packages to install.
|
||||
|
||||
## Requirements
|
||||
|
||||
The official binaries do not require these dependencies. They are needed only
|
||||
to build termscp from source, for example with `cargo install termscp`:
|
||||
|
||||
- Linux users:
|
||||
- libdbus-1
|
||||
- pkg-config
|
||||
- libsmbclient
|
||||
- FreeBSD and NetBSD users:
|
||||
- dbus
|
||||
- pkgconf
|
||||
- libsmbclient
|
||||
|
||||
### Optional requirements
|
||||
|
||||
These dependencies are not required to run termscp, but they are needed to
|
||||
enjoy all of its features.
|
||||
|
||||
- Linux and FreeBSD users, to open files via `V` (at least one of these):
|
||||
- xdg-open
|
||||
- gio
|
||||
- gnome-open
|
||||
- kde-open
|
||||
- Linux users: a keyring manager. Read more in the
|
||||
[Password security](../configuration/password-security.md) page.
|
||||
- WSL users, to open files via `V`:
|
||||
- [wslu](https://github.com/wslutilities/wslu)
|
||||
|
||||
## Updating termscp
|
||||
|
||||
To update termscp to the latest version, run it from the command line with:
|
||||
|
||||
```sh
|
||||
(sudo) termscp update
|
||||
```
|
||||
|
||||
For all platforms and methods, see <https://termscp.rs/install>.
|
||||
@@ -0,0 +1,28 @@
|
||||
# termscp
|
||||
|
||||

|
||||
|
||||
termscp is a feature-rich terminal file transfer client and explorer with a
|
||||
TUI (Terminal User Interface). It lets you connect to a remote server to
|
||||
upload and download files while interacting with your local file system at the
|
||||
same time. termscp runs on Linux, macOS, FreeBSD, NetBSD, and Windows.
|
||||
|
||||
## Features
|
||||
|
||||
- Multiple transfer protocols: SFTP, SCP, FTP and FTPS, Kube, S3, GCS, SMB,
|
||||
and WebDAV.
|
||||
- Dual-pane explorer to browse and operate on both the remote and the local
|
||||
file system: create, remove, rename, search, view, and edit files.
|
||||
- Bookmarks and recent connections to quickly reconnect to your favorite
|
||||
hosts.
|
||||
- View and edit files with your favorite editor.
|
||||
- SFTP/SCP authentication with SSH keys or username and password.
|
||||
- Embedded terminal for running commands on your system.
|
||||
- Make it yours: themes, custom file explorer format, customizable text
|
||||
editor, and customizable file sorting.
|
||||
- Desktop notifications when a large file has been transferred.
|
||||
- File watcher that keeps your changes synchronized with the remote host.
|
||||
- Save your passwords in your operating system's key vault.
|
||||
- Rust-powered and built with an eye on performance.
|
||||
|
||||
Ready to try it? See [Installation](getting-started/installation.md).
|
||||
@@ -0,0 +1,47 @@
|
||||
// Injects a language toggle (EN / 中文) into the mdBook menu bar.
|
||||
// Swaps the leading /en-US/ <-> /zh-CN/ path segment, preserving the
|
||||
// rest of the path; falls back to the language root on 404 navigation.
|
||||
(function () {
|
||||
const LANGS = [
|
||||
{ code: "en-US", label: "EN" },
|
||||
{ code: "zh-CN", label: "中文" },
|
||||
];
|
||||
|
||||
function currentLang() {
|
||||
const m = window.location.pathname.match(/\/(en-US|zh-CN)\//);
|
||||
return m ? m[1] : "en-US";
|
||||
}
|
||||
|
||||
function swapTo(code) {
|
||||
const path = window.location.pathname;
|
||||
const cur = currentLang();
|
||||
if (path.includes(`/${cur}/`)) {
|
||||
return path.replace(`/${cur}/`, `/${code}/`);
|
||||
}
|
||||
return `/${code}/`;
|
||||
}
|
||||
|
||||
function build() {
|
||||
const right = document.querySelector(".right-buttons");
|
||||
if (!right) return;
|
||||
const cur = currentLang();
|
||||
const wrap = document.createElement("div");
|
||||
wrap.className = "lang-switcher";
|
||||
wrap.style.display = "inline-flex";
|
||||
wrap.style.gap = "0.5rem";
|
||||
wrap.style.marginInlineStart = "0.5rem";
|
||||
LANGS.forEach((l) => {
|
||||
const a = document.createElement("a");
|
||||
a.textContent = l.label;
|
||||
a.href = swapTo(l.code);
|
||||
a.title = l.code;
|
||||
a.setAttribute("aria-current", l.code === cur ? "true" : "false");
|
||||
if (l.code === cur) a.style.fontWeight = "bold";
|
||||
wrap.appendChild(a);
|
||||
});
|
||||
right.appendChild(wrap);
|
||||
}
|
||||
|
||||
if (document.readyState !== "loading") build();
|
||||
else document.addEventListener("DOMContentLoaded", build);
|
||||
})();
|
||||
@@ -0,0 +1,39 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
(() => {
|
||||
const darkThemes = ['ayu', 'navy', 'coal'];
|
||||
const lightThemes = ['light', 'rust'];
|
||||
|
||||
const classList = document.getElementsByTagName('html')[0].classList;
|
||||
|
||||
let lastThemeWasLight = true;
|
||||
for (const cssClass of classList) {
|
||||
if (darkThemes.includes(cssClass)) {
|
||||
lastThemeWasLight = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const theme = lastThemeWasLight ? 'default' : 'dark';
|
||||
mermaid.initialize({ startOnLoad: true, theme });
|
||||
|
||||
// Simplest way to make mermaid re-render the diagrams in the new theme is via refreshing the page
|
||||
|
||||
for (const darkTheme of darkThemes) {
|
||||
document.getElementById(darkTheme).addEventListener('click', () => {
|
||||
if (lastThemeWasLight) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const lightTheme of lightThemes) {
|
||||
document.getElementById(lightTheme).addEventListener('click', () => {
|
||||
if (!lastThemeWasLight) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,13 @@
|
||||
<link rel="icon" type="image/x-icon" href="/shared/favicon.ico">
|
||||
<link rel="icon" type="image/svg+xml" href="/shared/termscp.svg">
|
||||
|
||||
<meta property="og:title" content="{{#if chapter_title}}{{ chapter_title }} · {{/if}}{{ book_title }}">
|
||||
<meta property="og:description" content="A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/GCS/SMB/WebDAV">
|
||||
<meta property="og:image" content="https://docs.termscp.rs/og_preview.jpg">
|
||||
<meta property="og:url" content="https://docs.termscp.rs/">
|
||||
<meta property="og:type" content="website">
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="{{#if chapter_title}}{{ chapter_title }} · {{/if}}{{ book_title }}">
|
||||
<meta name="twitter:description" content="A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/GCS/SMB/WebDAV">
|
||||
<meta name="twitter:image" content="https://docs.termscp.rs/og_preview.jpg">
|
||||
@@ -0,0 +1,31 @@
|
||||
# Bookmarks and recent hosts
|
||||
|
||||
termscp lets you save your favourite hosts as bookmarks, which can then be loaded quickly from the main layout. termscp also keeps the last 16 hosts you connected to. Both features let you reload all the parameters required to connect to a remote simply by selecting an entry in the tab under the authentication form.
|
||||
|
||||
## Where bookmarks are stored
|
||||
|
||||
Bookmarks are saved, when possible, in the configuration directory:
|
||||
|
||||
- `$HOME/.config/termscp/` on Linux/BSD
|
||||
- `$HOME/.config/termscp/` on macOS
|
||||
- `%USERPROFILE%\.termscp\` on Windows
|
||||
|
||||
## Saving passwords
|
||||
|
||||
For bookmarks only, you can optionally save the password used to authenticate. This does not apply to recent hosts, which never save passwords. The password is not saved by default; you are prompted to choose whether to save it when you create a new bookmark.
|
||||
|
||||
If you are concerned about the security of the passwords saved for your bookmarks, see [Are my passwords safe?](../configuration/password-security.md)
|
||||
|
||||
## Creating a bookmark
|
||||
|
||||
1. Fill in the authentication form with the parameters to connect to your remote server.
|
||||
2. Press `<CTRL+S>`.
|
||||
3. Type the name you want to give to the bookmark.
|
||||
4. Choose whether to remember the password.
|
||||
5. Press `<ENTER>` to submit.
|
||||
|
||||
## Loading a bookmark
|
||||
|
||||
To use a previously saved connection, press `<TAB>` to navigate to the bookmarks list, then press `<ENTER>` to load the bookmark parameters into the form.
|
||||
|
||||

|
||||
@@ -0,0 +1,18 @@
|
||||
# The file explorer
|
||||
|
||||
After you establish a connection with a remote host, termscp shows the file explorer. The explorer is made up of three panels.
|
||||
|
||||
- **Local explorer panel**: displayed on the left of the screen. It shows the entries of the current directory on localhost.
|
||||
- **Remote explorer panel**: displayed on the right of the screen. It shows the entries of the current directory on the remote host.
|
||||
- **Find results panel**: shown after you search for files. Depending on where you searched (local or remote), it replaces the local explorer panel or the remote explorer panel and lists the entries matching your search query.
|
||||
|
||||
## Switching between panels
|
||||
|
||||
Use the following keys to move between panels.
|
||||
|
||||
- `<LEFT>`: move to the local explorer panel.
|
||||
- `<RIGHT>`: move to the remote explorer panel.
|
||||
- `<TAB>`: switch the active explorer tab.
|
||||
- `<ESC>`: while in the find results panel, exit it and return to the previous panel.
|
||||
|
||||
For the complete list of keys available in the explorer, see [Keyboard shortcuts](keyboard-shortcuts.md).
|
||||
@@ -0,0 +1,29 @@
|
||||
# Keeping files in sync
|
||||
|
||||
The file watcher synchronizes local paths to a remote path. When a change is detected on a watched local path, it is propagated to the configured remote path within about 5 seconds.
|
||||
|
||||
You can watch as many paths as you like.
|
||||
|
||||
## Watching a path
|
||||
|
||||
1. Put the cursor on the local explorer, on the file or directory you want to keep synchronized.
|
||||
2. In the remote panel, navigate to the directory where the changes should be reported.
|
||||
3. Press `<T>`.
|
||||
4. Answer `<YES>` to the popup.
|
||||
|
||||
## Unwatching a path
|
||||
|
||||
You can stop watching a path in two ways:
|
||||
|
||||
- Press `<T>` on the watched local path (or any of its subfolders).
|
||||
- Press `<CTRL+T>`, then press `<ENTER>` on the path you want to unwatch.
|
||||
|
||||
## Propagated changes
|
||||
|
||||
The following changes are reported to the remote host:
|
||||
|
||||
- New files and file changes
|
||||
- Files moved or renamed
|
||||
- Files removed or unlinked
|
||||
|
||||
The watcher works in one direction only (local to remote). Changes made on the remote host are **not** synchronized back to the local host.
|
||||