debug log belongs in cache directory not config directory (#179)

* log files are now written to cache dir instead of config dir

* lint

* fmt
This commit is contained in:
Christian Visintin
2023-05-09 15:32:42 +02:00
committed by GitHub
parent 9bf23b3f6b
commit 9009002b6e
26 changed files with 96 additions and 160 deletions
+3 -3
View File
@@ -482,9 +482,9 @@ Just a reminder: **you can edit only textual file**; binary files are not suppor
termscp writes a log file for each session, which is written at termscp writes a log file for each session, which is written at
- `$HOME/.config/termscp/termscp.log` on Linux/BSD - `$HOME/.cache/termscp/termscp.log` on Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` on MacOs - `$HOME/Library/Caches/termscp/termscp.log` on MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` on Windows - `FOLDERID_LocalAppData\termscp\termscp.log` on Windows
the log won't be rotated, but will just be truncated after each launch of termscp, so if you want to report an issue and you want to attach your log file, keep in mind to save the log file in a safe place before using termscp again. the log won't be rotated, but will just be truncated after each launch of termscp, so if you want to report an issue and you want to attach your log file, keep in mind to save the log file in a safe place before using termscp again.
The logging by default reports in *INFO* level, so it is not very verbose. The logging by default reports in *INFO* level, so it is not very verbose.
+3 -3
View File
@@ -481,9 +481,9 @@ En caso de que el archivo esté ubicado en un host remoto, el archivo se descarg
termscp escribe un archivo de registro para cada sesión, que se escribe en termscp escribe un archivo de registro para cada sesión, que se escribe en
- `$HOME/.config/termscp/termscp.log` en Linux/BSD - `$HOME/.cache/termscp/termscp.log` en Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` en MacOs - `$HOME/Library/Caches/termscp/termscp.log` en MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` en Windows - `FOLDERID_LocalAppData\termscp\termscp.log` en Windows
el registro no se rotará, sino que se truncará después de cada lanzamiento de termscp, por lo que si desea informar un problema y desea adjuntar su archivo de registro, recuerde guardar el archivo de registro en un lugar seguro antes de usar termscp de nuevo. el registro no se rotará, sino que se truncará después de cada lanzamiento de termscp, por lo que si desea informar un problema y desea adjuntar su archivo de registro, recuerde guardar el archivo de registro en un lugar seguro antes de usar termscp de nuevo.
El registro por defecto informa en el nivel *INFO*, por lo que no es muy detallado. El registro por defecto informa en el nivel *INFO*, por lo que no es muy detallado.
+3 -3
View File
@@ -479,9 +479,9 @@ Si le fichier se trouve sur l'hôte distant, le fichier sera d'abord télécharg
termscp écrit un fichier journal pour chaque session, qui est écrit à termscp écrit un fichier journal pour chaque session, qui est écrit à
- `$HOME/.config/termscp/termscp.log` sous Linux/BSD - `$HOME/.cache/termscp/termscp.log` sous Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` sous MacOs - `$HOME/Library/Caches/termscp/termscp.log` sous MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` sous Windows - `FOLDERID_LocalAppData\termscp\termscp.log` sous Windows
le journal ne sera pas tourné, mais sera simplement tronqué après chaque lancement de termscp, donc si vous souhaitez signaler un problème et que vous souhaitez joindre votre fichier journal, n'oubliez pas de sauvegarder le fichier journal dans un endroit sûr avant de l'utiliser termescp à nouveau. le journal ne sera pas tourné, mais sera simplement tronqué après chaque lancement de termscp, donc si vous souhaitez signaler un problème et que vous souhaitez joindre votre fichier journal, n'oubliez pas de sauvegarder le fichier journal dans un endroit sûr avant de l'utiliser termescp à nouveau.
+3 -3
View File
@@ -478,9 +478,9 @@ Nel caso il file si trovi su host remoto, il file verrà prima scaricato tempora
termscp scrive un file di log per ogni sessione, nel percorso seguente: termscp scrive un file di log per ogni sessione, nel percorso seguente:
- `$HOME/.config/termscp/termscp.log` su Linux/BSD - `$HOME/.cache/termscp/termscp.log` su Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` su MacOs - `$HOME/Library/Caches/termscp/termscp.log` su MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` su Windows - `FOLDERID_LocalAppData\termscp\termscp.log` su Windows
Il log non viene ruotato, ma viene troncato ad ogni lancio di termscp, quindi se devi riportare un issue, non avviare termscp fino a che non avrai salvato il file di log. Il log non viene ruotato, ma viene troncato ad ogni lancio di termscp, quindi se devi riportare un issue, non avviare termscp fino a che non avrai salvato il file di log.
I log sono di default riportati a livello *INFO*, quindi non sono particolarmente parlanti. I log sono di default riportati a livello *INFO*, quindi non sono particolarmente parlanti.
+3 -3
View File
@@ -480,9 +480,9 @@ In case the file is located on remote host, the file will be first downloaded in
termscp writes a log file for each session, which is written at termscp writes a log file for each session, which is written at
- `$HOME/.config/termscp/termscp.log` on Linux/BSD - `$HOME/.cache/termscp/termscp.log` on Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` on MacOs - `$HOME/Library/Caches/termscp/termscp.log` on MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` on Windows - `FOLDERID_LocalAppData\termscp\termscp.log` on Windows
the log won't be rotated, but will just be truncated after each launch of termscp, so if you want to report an issue and you want to attach your log file, keep in mind to save the log file in a safe place before using termscp again. the log won't be rotated, but will just be truncated after each launch of termscp, so if you want to report an issue and you want to attach your log file, keep in mind to save the log file in a safe place before using termscp again.
The logging by default reports in *INFO* level, so it is not very verbose. The logging by default reports in *INFO* level, so it is not very verbose.
+3 -3
View File
@@ -472,9 +472,9 @@ Termscp有很多功能,你可能已经注意到了,其中之一就是可以
termscp会为每个会话创建一个日志文件,该文件在 termscp会为每个会话创建一个日志文件,该文件在
- `$HOME/.config/termscp/termscp.log` -- Linux/BSD - `$HOME/.cache/termscp/termscp.log` -- Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` -- MacOs - `$HOME/Library/Caches/termscp/termscp.log` -- MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` -- Windows - `FOLDERID_LocalAppData\termscp\termscp.log` -- Windows
日志不会被轮换,但只会在每次启动 termcp 后被截断,因此如果您想报告问题并希望附加您的日志文件,请记住在使用前将日志文件保存在安全的地方 再次termscp。 日志不会被轮换,但只会在每次启动 termcp 后被截断,因此如果您想报告问题并希望附加您的日志文件,请记住在使用前将日志文件保存在安全的地方 再次termscp。
默认情况下,日志记录在 *INFO* 级别报告,因此它不是很详细。 默认情况下,日志记录在 *INFO* 级别报告,因此它不是很详细。
-4
View File
@@ -21,8 +21,6 @@ use crate::utils::tty;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::Duration; use std::time::Duration;
/// ### NextActivity
///
/// NextActivity identifies the next identity to run once the current has ended /// NextActivity identifies the next identity to run once the current has ended
pub enum NextActivity { pub enum NextActivity {
Authentication, Authentication,
@@ -30,8 +28,6 @@ pub enum NextActivity {
SetupActivity, SetupActivity,
} }
/// ### ActivityManager
///
/// The activity manager takes care of running activities and handling them until the application has ended /// The activity manager takes care of running activities and handling them until the application has ended
pub struct ActivityManager { pub struct ActivityManager {
context: Option<Context>, context: Option<Context>,
-4
View File
@@ -49,8 +49,6 @@ impl std::fmt::Display for SerializerError {
} }
} }
/// ### serialize
///
/// Serialize `UserHosts` into TOML and write content to writable /// Serialize `UserHosts` into TOML and write content to writable
pub fn serialize<S>(serializable: &S, mut writable: Box<dyn Write>) -> Result<(), SerializerError> pub fn serialize<S>(serializable: &S, mut writable: Box<dyn Write>) -> Result<(), SerializerError>
where where
@@ -77,8 +75,6 @@ where
} }
} }
/// ### deserialize
///
/// Read data from readable and deserialize its content as TOML /// Read data from readable and deserialize its content as TOML
pub fn deserialize<S>(mut readable: Box<dyn Read>) -> Result<S, SerializerError> pub fn deserialize<S>(mut readable: Box<dyn Read>) -> Result<S, SerializerError>
where where
-2
View File
@@ -9,8 +9,6 @@ use crate::utils::parser::parse_color;
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
use tuirealm::tui::style::Color; use tuirealm::tui::style::Color;
/// ### Theme
///
/// Theme contains all the colors lookup table for termscp /// Theme contains all the colors lookup table for termscp
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub struct Theme { pub struct Theme {
-2
View File
@@ -6,8 +6,6 @@ use super::FileTransferProtocol;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
/// ### FileTransferParams
///
/// Holds connection parameters for file transfers /// Holds connection parameters for file transfers
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FileTransferParams { pub struct FileTransferParams {
-2
View File
@@ -41,8 +41,6 @@ pub enum HostErrorType {
DeleteFailed, DeleteFailed,
} }
/// ### HostError
///
/// HostError is a wrapper for the error type and the exact io error /// HostError is a wrapper for the error type and the exact io error
#[derive(Debug)] #[derive(Debug)]
pub struct HostError { pub struct HostError {
-2
View File
@@ -136,8 +136,6 @@ fn parse_remote_address(remote: &str) -> Result<FileTransferParams, String> {
utils::parser::parse_remote_opt(remote).map_err(|e| format!("Bad address option: {e}")) utils::parser::parse_remote_opt(remote).map_err(|e| format!("Bad address option: {e}"))
} }
/// ### run
///
/// Run task and return rc /// Run task and return rc
fn run(run_opts: RunOpts) -> i32 { fn run(run_opts: RunOpts) -> i32 {
match run_opts.task { match run_opts.task {
-8
View File
@@ -13,8 +13,6 @@ use crate::system::{
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
/// ### import_theme
///
/// Import theme at provided path into termscp /// Import theme at provided path into termscp
pub fn import_theme(p: &Path) -> Result<(), String> { pub fn import_theme(p: &Path) -> Result<(), String> {
if !p.exists() { if !p.exists() {
@@ -34,8 +32,6 @@ pub fn import_theme(p: &Path) -> Result<(), String> {
.map_err(|e| format!("Could not import theme: {e}")) .map_err(|e| format!("Could not import theme: {e}"))
} }
/// ### install_update
///
/// Install latest version of termscp if an update is available /// Install latest version of termscp if an update is available
pub fn install_update() -> Result<String, String> { pub fn install_update() -> Result<String, String> {
match Update::default() match Update::default()
@@ -65,8 +61,6 @@ pub fn install_update() -> Result<String, String> {
} }
} }
/// ### get_config_dir
///
/// Get configuration directory /// Get configuration directory
fn get_config_dir() -> Result<PathBuf, String> { fn get_config_dir() -> Result<PathBuf, String> {
match environment::init_config_dir() { match environment::init_config_dir() {
@@ -80,8 +74,6 @@ fn get_config_dir() -> Result<PathBuf, String> {
} }
} }
/// ### get_config_client
///
/// Get configuration client /// Get configuration client
fn get_config_client() -> Option<ConfigClient> { fn get_config_client() -> Option<ConfigClient> {
match get_config_dir() { match get_config_dir() {
-2
View File
@@ -10,8 +10,6 @@ use self_update::{
Status, Status,
}; };
/// ### UpdateStatus
///
/// The status of the update in case of success /// The status of the update in case of success
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub enum UpdateStatus { pub enum UpdateStatus {
+1 -1
View File
@@ -730,7 +730,7 @@ mod tests {
// Limit is 2 // Limit is 2
assert_eq!(client.iter_recents().count(), 2); assert_eq!(client.iter_recents().count(), 2);
// Check that 192.168.1.1 has been removed // Check that 192.168.1.1 has been removed
let key: String = client.iter_recents().nth(0).unwrap().to_string(); let key: String = client.iter_recents().next().unwrap().to_string();
assert!(matches!( assert!(matches!(
client client
.hosts .hosts
+55 -30
View File
@@ -5,10 +5,8 @@
// Ext // Ext
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
/// ### get_config_dir /// Get termscp config directory path and initialize it.
/// /// Returns None if it's not possible to initialize it
/// Get termscp configuration directory path.
/// Returns None, if it's not possible to get it
pub fn init_config_dir() -> Result<Option<PathBuf>, String> { pub fn init_config_dir() -> Result<Option<PathBuf>, String> {
// Get file // Get file
#[cfg(not(test))] #[cfg(not(test))]
@@ -19,27 +17,51 @@ pub fn init_config_dir() -> Result<Option<PathBuf>, String> {
lazy_static! { lazy_static! {
static ref CONF_DIR: Option<PathBuf> = Some(std::env::temp_dir()); static ref CONF_DIR: Option<PathBuf> = Some(std::env::temp_dir());
} }
if CONF_DIR.is_some() {
// Get path of bookmarks if let Some(dir) = CONF_DIR.as_deref() {
let mut p: PathBuf = CONF_DIR.as_ref().unwrap().clone(); init_dir(dir).map(Option::Some)
// Append termscp dir
p.push("termscp/");
// If directory doesn't exist, create it
if p.exists() {
return Ok(Some(p));
}
// directory doesn't exist; create dir recursively
match std::fs::create_dir_all(p.as_path()) {
Ok(_) => Ok(Some(p)),
Err(err) => Err(err.to_string()),
}
} else { } else {
Ok(None) Ok(None)
} }
} }
/// ### get_bookmarks_paths /// Get termscp cache directory path and initialize it.
/// /// Returns None if it's not possible to initialize it
pub fn init_cache_dir() -> Result<Option<PathBuf>, String> {
// Get file
#[cfg(not(test))]
lazy_static! {
static ref CACHE_DIR: Option<PathBuf> = dirs::cache_dir();
}
#[cfg(test)]
lazy_static! {
static ref CACHE_DIR: Option<PathBuf> = Some(std::env::temp_dir());
}
if let Some(dir) = CACHE_DIR.as_deref() {
init_dir(dir).map(Option::Some)
} else {
Ok(None)
}
}
/// Init a termscp env dir
fn init_dir(p: &Path) -> Result<PathBuf, String> {
// Get path of bookmarks
let mut p: PathBuf = p.to_path_buf();
// Append termscp dir
p.push("termscp/");
// If directory doesn't exist, create it
if p.exists() {
return Ok(p);
}
// directory doesn't exist; create dir recursively
match std::fs::create_dir_all(p.as_path()) {
Ok(_) => Ok(p),
Err(err) => Err(err.to_string()),
}
}
/// Get paths for bookmarks client /// Get paths for bookmarks client
/// Returns: path of bookmarks.toml /// Returns: path of bookmarks.toml
pub fn get_bookmarks_paths(config_dir: &Path) -> PathBuf { pub fn get_bookmarks_paths(config_dir: &Path) -> PathBuf {
@@ -49,8 +71,6 @@ pub fn get_bookmarks_paths(config_dir: &Path) -> PathBuf {
bookmarks_file bookmarks_file
} }
/// ### get_config_paths
///
/// Returns paths for config client /// Returns paths for config client
/// Returns: path of config.toml and path for ssh keys /// Returns: path of config.toml and path for ssh keys
pub fn get_config_paths(config_dir: &Path) -> (PathBuf, PathBuf) { pub fn get_config_paths(config_dir: &Path) -> (PathBuf, PathBuf) {
@@ -62,17 +82,13 @@ pub fn get_config_paths(config_dir: &Path) -> (PathBuf, PathBuf) {
(bookmarks_file, keys_dir) (bookmarks_file, keys_dir)
} }
/// ### get_log_paths
///
/// Returns the path for the supposed log file /// Returns the path for the supposed log file
pub fn get_log_paths(config_dir: &Path) -> PathBuf { pub fn get_log_paths(cache_dir: &Path) -> PathBuf {
let mut log_file: PathBuf = PathBuf::from(config_dir); let mut log_file: PathBuf = PathBuf::from(cache_dir);
log_file.push("termscp.log"); log_file.push("termscp.log");
log_file log_file
} }
/// ### get_theme_path
///
/// Get paths for theme provider /// Get paths for theme provider
/// Returns: path of theme.toml /// Returns: path of theme.toml
pub fn get_theme_path(config_dir: &Path) -> PathBuf { pub fn get_theme_path(config_dir: &Path) -> PathBuf {
@@ -101,6 +117,15 @@ mod tests {
assert!(std::fs::remove_dir_all(conf_dir.as_path()).is_ok()); assert!(std::fs::remove_dir_all(conf_dir.as_path()).is_ok());
} }
#[test]
#[serial]
fn should_get_cache_dir() {
// Create and get cache_dir
let cache_dir: PathBuf = init_cache_dir().ok().unwrap().unwrap();
// Remove dir
assert!(std::fs::remove_dir_all(cache_dir.as_path()).is_ok());
}
#[test] #[test]
#[serial] #[serial]
fn test_system_environment_get_config_dir_err() { fn test_system_environment_get_config_dir_err() {
@@ -148,8 +173,8 @@ mod tests {
#[serial] #[serial]
fn test_system_environment_get_log_paths() { fn test_system_environment_get_log_paths() {
assert_eq!( assert_eq!(
get_log_paths(Path::new("/home/omar/.config/termscp/")), get_log_paths(Path::new("/home/omar/.cache/termscp/")),
PathBuf::from("/home/omar/.config/termscp/termscp.log"), PathBuf::from("/home/omar/.cache/termscp/termscp.log"),
); );
} }
+6 -12
View File
@@ -2,32 +2,26 @@
//! //!
//! `logging` is the module which initializes the logging system for termscp //! `logging` is the module which initializes the logging system for termscp
// locals use super::environment::{get_log_paths, init_cache_dir};
use crate::system::environment::{get_log_paths, init_config_dir};
use crate::utils::file::open_file; use crate::utils::file::open_file;
// ext
pub use simplelog::LevelFilter as LogLevel; pub use simplelog::LevelFilter as LogLevel;
use simplelog::{ConfigBuilder, WriteLogger}; use simplelog::{ConfigBuilder, WriteLogger};
use std::fs::File;
use std::path::PathBuf;
/// ### init
///
/// Initialize logger /// Initialize logger
pub fn init(level: LogLevel) -> Result<(), String> { pub fn init(level: LogLevel) -> Result<(), String> {
// Init config dir // Init cache dir
let config_dir: PathBuf = match init_config_dir() { let cache_dir = match init_cache_dir() {
Ok(Some(p)) => p, Ok(Some(p)) => p,
Ok(None) => { Ok(None) => {
return Err(String::from( return Err(String::from(
"This system doesn't seem to support CONFIG_DIR", "This system doesn't seem to support CACHE_DIR",
)) ))
} }
Err(err) => return Err(err), Err(err) => return Err(err),
}; };
let log_file_path: PathBuf = get_log_paths(config_dir.as_path()); let log_file_path = get_log_paths(cache_dir.as_path());
// Open log file // Open log file
let file: File = open_file(log_file_path.as_path(), true, true, false) let file = open_file(log_file_path.as_path(), true, true, false)
.map_err(|e| format!("Failed to open file {}: {}", log_file_path.display(), e))?; .map_err(|e| format!("Failed to open file {}: {}", log_file_path.display(), e))?;
// Prepare log config // Prepare log config
let config = ConfigBuilder::new().set_time_format_rfc3339().build(); let config = ConfigBuilder::new().set_time_format_rfc3339().build();
-2
View File
@@ -147,8 +147,6 @@ enum InputMask {
const STORE_KEY_LATEST_VERSION: &str = "AUTH_LATEST_VERSION"; const STORE_KEY_LATEST_VERSION: &str = "AUTH_LATEST_VERSION";
const STORE_KEY_RELEASE_NOTES: &str = "AUTH_RELEASE_NOTES"; const STORE_KEY_RELEASE_NOTES: &str = "AUTH_RELEASE_NOTES";
/// ### AuthActivity
///
/// AuthActivity is the data holder for the authentication activity /// AuthActivity is the data holder for the authentication activity
pub struct AuthActivity { pub struct AuthActivity {
app: Application<Id, Msg, NoUserEvent>, app: Application<Id, Msg, NoUserEvent>,
@@ -8,8 +8,6 @@ use std::time::Instant;
// -- States and progress // -- States and progress
/// ### TransferStates
///
/// TransferStates contains the states related to the transfer process /// TransferStates contains the states related to the transfer process
pub struct TransferStates { pub struct TransferStates {
aborted: bool, // Describes whether the transfer process has been aborted aborted: bool, // Describes whether the transfer process has been aborted
@@ -17,8 +15,6 @@ pub struct TransferStates {
pub partial: ProgressStates, // Partial transfer states pub partial: ProgressStates, // Partial transfer states
} }
/// ### ProgressStates
///
/// Progress states describes the states for the progress of a single transfer part /// Progress states describes the states for the progress of a single transfer part
pub struct ProgressStates { pub struct ProgressStates {
started: Instant, started: Instant,
-2
View File
@@ -227,8 +227,6 @@ pub enum ThemeMsg {
// -- store // -- store
const STORE_CONFIG_CHANGED: &str = "SETUP_CONFIG_CHANGED"; const STORE_CONFIG_CHANGED: &str = "SETUP_CONFIG_CHANGED";
/// ### ViewLayout
///
/// Current view layout /// Current view layout
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
pub enum ViewLayout { pub enum ViewLayout {
-4
View File
@@ -5,16 +5,12 @@
// Ext // Ext
use magic_crypt::MagicCryptTrait; use magic_crypt::MagicCryptTrait;
/// ### aes128_b64_crypt
///
/// Crypt a string using AES128; output is returned as a BASE64 string /// Crypt a string using AES128; output is returned as a BASE64 string
pub fn aes128_b64_crypt(key: &str, input: &str) -> String { pub fn aes128_b64_crypt(key: &str, input: &str) -> String {
let crypter = new_magic_crypt!(key, 128); let crypter = new_magic_crypt!(key, 128);
crypter.encrypt_str_to_base64(input) crypter.encrypt_str_to_base64(input)
} }
/// ### aes128_b64_decrypt
///
/// Decrypt a string using AES128 /// Decrypt a string using AES128
pub fn aes128_b64_decrypt(key: &str, secret: &str) -> Result<String, magic_crypt::MagicCryptError> { pub fn aes128_b64_decrypt(key: &str, secret: &str) -> Result<String, magic_crypt::MagicCryptError> {
let crypter = new_magic_crypt!(key, 128); let crypter = new_magic_crypt!(key, 128);
-2
View File
@@ -7,8 +7,6 @@ use std::fs::OpenOptions;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
/// ### open_file
///
/// Open file provided as parameter /// Open file provided as parameter
pub fn open_file<P>(filename: P, create: bool, write: bool, append: bool) -> io::Result<File> pub fn open_file<P>(filename: P, create: bool, write: bool, append: bool) -> io::Result<File>
where where
-16
View File
@@ -10,8 +10,6 @@ use std::time::{Duration, SystemTime};
use tuirealm::tui::style::Color; use tuirealm::tui::style::Color;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
/// ### fmt_pex
///
/// Convert permissions bytes of permissions value into ls notation (e.g. rwx,-wx,--x) /// Convert permissions bytes of permissions value into ls notation (e.g. rwx,-wx,--x)
pub fn fmt_pex(pex: UnixPexClass) -> String { pub fn fmt_pex(pex: UnixPexClass) -> String {
format!( format!(
@@ -31,16 +29,12 @@ pub fn fmt_pex(pex: UnixPexClass) -> String {
) )
} }
/// ### instant_to_str
///
/// Format a `Instant` into a time string /// Format a `Instant` into a time string
pub fn fmt_time(time: SystemTime, fmt: &str) -> String { pub fn fmt_time(time: SystemTime, fmt: &str) -> String {
let datetime: DateTime<Local> = time.into(); let datetime: DateTime<Local> = time.into();
format!("{}", datetime.format(fmt)) format!("{}", datetime.format(fmt))
} }
/// ### fmt_millis
///
/// Format duration as {secs}.{millis} /// Format duration as {secs}.{millis}
pub fn fmt_millis(duration: Duration) -> String { pub fn fmt_millis(duration: Duration) -> String {
let seconds: u128 = duration.as_millis() / 1000; let seconds: u128 = duration.as_millis() / 1000;
@@ -48,16 +42,12 @@ pub fn fmt_millis(duration: Duration) -> String {
format!("{}.{:0width$}", seconds, millis, width = 3) format!("{}.{:0width$}", seconds, millis, width = 3)
} }
/// ### elide_path
///
/// Elide a path if longer than width /// Elide a path if longer than width
/// In this case, the path is formatted to {ANCESTOR[0]}/…/{PARENT[0]}/{BASENAME} /// In this case, the path is formatted to {ANCESTOR[0]}/…/{PARENT[0]}/{BASENAME}
pub fn fmt_path_elide(p: &Path, width: usize) -> String { pub fn fmt_path_elide(p: &Path, width: usize) -> String {
fmt_path_elide_ex(p, width, 0) fmt_path_elide_ex(p, width, 0)
} }
/// ### fmt_path_elide_ex
///
/// Elide a path if longer than width /// Elide a path if longer than width
/// In this case, the path is formatted to {ANCESTOR[0]}/…/{PARENT[0]}/{BASENAME} /// In this case, the path is formatted to {ANCESTOR[0]}/…/{PARENT[0]}/{BASENAME}
/// This function allows to specify an extra length to consider to elide path /// This function allows to specify an extra length to consider to elide path
@@ -90,8 +80,6 @@ pub fn fmt_path_elide_ex(p: &Path, width: usize, extra_len: usize) -> String {
} }
} }
/// ### fmt_color
///
/// Format color /// Format color
pub fn fmt_color(color: &Color) -> String { pub fn fmt_color(color: &Color) -> String {
match color { match color {
@@ -258,15 +246,11 @@ pub fn fmt_color(color: &Color) -> String {
} }
} }
/// ### shadow_password
///
/// Return a string with the same length of input string, but each character is replaced by '*' /// Return a string with the same length of input string, but each character is replaced by '*'
pub fn shadow_password(s: &str) -> String { pub fn shadow_password(s: &str) -> String {
(0..s.len()).map(|_| '*').collect() (0..s.len()).map(|_| '*').collect()
} }
/// ### fmt_bytes
///
/// Format bytes /// Format bytes
pub fn fmt_bytes(v: u64) -> String { pub fn fmt_bytes(v: u64) -> String {
if v >= 1125899906842624 { if v >= 1125899906842624 {
-14
View File
@@ -68,8 +68,6 @@ static BYTESIZE_REGEX: Lazy<Regex> = lazy_regex!(r"(:?([0-9])+)( )*(:?[KMGTP])?B
// -- remote opts // -- remote opts
/// ### parse_remote_opt
///
/// Parse remote option string. Returns in case of success a RemoteOptions struct /// Parse remote option string. Returns in case of success a RemoteOptions struct
/// For ssh if username is not provided, current user will be used. /// For ssh if username is not provided, current user will be used.
/// In case of error, message is returned /// In case of error, message is returned
@@ -115,8 +113,6 @@ pub fn parse_remote_opt(s: &str) -> Result<FileTransferParams, String> {
} }
} }
/// ### parse_remote_opt_protocol
///
/// Parse protocol from CLI option. In case of success, return the protocol to be used and the remaining arguments /// Parse protocol from CLI option. In case of success, return the protocol to be used and the remaining arguments
fn parse_remote_opt_protocol( fn parse_remote_opt_protocol(
s: &str, s: &str,
@@ -147,8 +143,6 @@ fn parse_remote_opt_protocol(
} }
} }
/// ### parse_generic_remote_opt
///
/// Parse generic remote options /// Parse generic remote options
fn parse_generic_remote_opt( fn parse_generic_remote_opt(
s: &str, s: &str,
@@ -202,8 +196,6 @@ fn parse_generic_remote_opt(
} }
} }
/// ### parse_s3_remote_opt
///
/// Parse remote options for s3 protocol /// Parse remote options for s3 protocol
fn parse_s3_remote_opt(s: &str) -> Result<FileTransferParams, String> { fn parse_s3_remote_opt(s: &str) -> Result<FileTransferParams, String> {
match REMOTE_S3_OPT_REGEX.captures(s) { match REMOTE_S3_OPT_REGEX.captures(s) {
@@ -229,8 +221,6 @@ fn parse_s3_remote_opt(s: &str) -> Result<FileTransferParams, String> {
} }
} }
/// ### parse_semver
///
/// Parse semver string /// Parse semver string
pub fn parse_semver(haystack: &str) -> Option<String> { pub fn parse_semver(haystack: &str) -> Option<String> {
match SEMVER_REGEX.captures(haystack) { match SEMVER_REGEX.captures(haystack) {
@@ -239,8 +229,6 @@ pub fn parse_semver(haystack: &str) -> Option<String> {
} }
} }
/// ### parse_color
///
/// Parse color from string into a `Color` enum. /// Parse color from string into a `Color` enum.
/// ///
/// Color may be in different format: /// Color may be in different format:
@@ -300,8 +288,6 @@ impl FromStr for ByteUnit {
} }
} }
/// ### parse_bytesize
///
/// Parse bytes repr (e.g. `24 MB`) into `ByteSize` /// Parse bytes repr (e.g. `24 MB`) into `ByteSize`
pub fn parse_bytesize<S: AsRef<str>>(bytes: S) -> Option<ByteSize> { pub fn parse_bytesize<S: AsRef<str>>(bytes: S) -> Option<ByteSize> {
match BYTESIZE_REGEX.captures(bytes.as_ref()) { match BYTESIZE_REGEX.captures(bytes.as_ref()) {
+16 -23
View File
@@ -4,8 +4,6 @@
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
/// ### absolutize
///
/// Absolutize target path if relative. /// Absolutize target path if relative.
/// For example: /// For example:
/// ///
@@ -24,8 +22,6 @@ pub fn absolutize(wrkdir: &Path, target: &Path) -> PathBuf {
} }
} }
/// ### diff_paths
///
/// This function will get the difference from path `path` to `base`. Basically will remove `base` from `path` /// This function will get the difference from path `path` to `base`. Basically will remove `base` from `path`
/// ///
/// For example: /// For example:
@@ -127,24 +123,21 @@ mod test {
#[test] #[test]
fn should_tell_whether_path_is_child_of() { fn should_tell_whether_path_is_child_of() {
assert_eq!( assert!(is_child_of(
is_child_of(Path::new("/home/foo/foo.txt"), Path::new("/home"),), Path::new("/home/foo/foo.txt"),
true Path::new("/home"),
); ));
assert_eq!( assert!(is_child_of(
is_child_of(Path::new("/home/foo/foo.txt"), Path::new("/home/foo/"),), Path::new("/home/foo/foo.txt"),
true Path::new("/home/foo/"),
); ));
assert_eq!( assert!(is_child_of(
is_child_of( Path::new("/home/foo/foo.txt"),
Path::new("/home/foo/foo.txt"), Path::new("/home/foo/foo.txt"),
Path::new("/home/foo/foo.txt"), ));
), assert!(!is_child_of(
true Path::new("/home/foo/foo.txt"),
); Path::new("/tmp"),
assert_eq!( ));
is_child_of(Path::new("/home/foo/foo.txt"), Path::new("/tmp"),),
false
);
} }
} }
-6
View File
@@ -33,8 +33,6 @@ pub fn create_sample_file_with_content(content: impl std::fmt::Display) -> Named
tmpfile tmpfile
} }
/// ### make_file_at
///
/// Make a file with `name` at specified path /// Make a file with `name` at specified path
pub fn make_file_at(dir: &Path, filename: &str) -> std::io::Result<PathBuf> { pub fn make_file_at(dir: &Path, filename: &str) -> std::io::Result<PathBuf> {
let mut p: PathBuf = PathBuf::from(dir); let mut p: PathBuf = PathBuf::from(dir);
@@ -47,8 +45,6 @@ pub fn make_file_at(dir: &Path, filename: &str) -> std::io::Result<PathBuf> {
Ok(p) Ok(p)
} }
/// ### make_dir_at
///
/// Make a directory in `dir` /// Make a directory in `dir`
pub fn make_dir_at(dir: &Path, dirname: &str) -> std::io::Result<()> { pub fn make_dir_at(dir: &Path, dirname: &str) -> std::io::Result<()> {
let mut p: PathBuf = PathBuf::from(dir); let mut p: PathBuf = PathBuf::from(dir);
@@ -69,8 +65,6 @@ pub fn make_fsentry<P: AsRef<Path>>(path: P, is_dir: bool) -> File {
} }
} }
/// ### create_file_ioers
///
/// Open a file with two handlers, the first is to read, the second is to write /// Open a file with two handlers, the first is to read, the second is to write
pub fn create_file_ioers(p: &Path) -> (StdFile, StdFile) { pub fn create_file_ioers(p: &Path) -> (StdFile, StdFile) {
( (