mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
Utils into multiple files
This commit is contained in:
@@ -30,7 +30,7 @@ extern crate regex;
|
||||
|
||||
use super::{FileTransfer, FileTransferError, FileTransferErrorType};
|
||||
use crate::fs::{FsDirectory, FsEntry, FsFile};
|
||||
use crate::utils::lstime_to_systime;
|
||||
use crate::utils::parser::parse_lstime;
|
||||
|
||||
// Includes
|
||||
use ftp4::native_tls::TlsConnector;
|
||||
@@ -142,7 +142,7 @@ impl FtpFileTransfer {
|
||||
(owner_pex, group_pex, others_pex)
|
||||
};
|
||||
// Parse mtime and convert to SystemTime
|
||||
let mtime: SystemTime = match lstime_to_systime(
|
||||
let mtime: SystemTime = match parse_lstime(
|
||||
metadata.get(7).unwrap().as_str(),
|
||||
"%b %d %Y",
|
||||
"%b %d %H:%M",
|
||||
|
||||
@@ -30,7 +30,7 @@ extern crate ssh2;
|
||||
// Locals
|
||||
use super::{FileTransfer, FileTransferError, FileTransferErrorType};
|
||||
use crate::fs::{FsDirectory, FsEntry, FsFile};
|
||||
use crate::utils::lstime_to_systime;
|
||||
use crate::utils::parser::parse_lstime;
|
||||
|
||||
// Includes
|
||||
use regex::Regex;
|
||||
@@ -151,7 +151,7 @@ impl ScpFileTransfer {
|
||||
(owner_pex, group_pex, others_pex)
|
||||
};
|
||||
// Parse mtime and convert to SystemTime
|
||||
let mtime: SystemTime = match lstime_to_systime(
|
||||
let mtime: SystemTime = match parse_lstime(
|
||||
metadata.get(7).unwrap().as_str(),
|
||||
"%b %d %Y",
|
||||
"%b %d %H:%M",
|
||||
|
||||
@@ -27,7 +27,7 @@ extern crate bytesize;
|
||||
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
||||
extern crate users;
|
||||
|
||||
use crate::utils::{fmt_pex, time_to_str};
|
||||
use crate::utils::fmt::{fmt_pex, fmt_time};
|
||||
|
||||
use bytesize::ByteSize;
|
||||
use std::path::PathBuf;
|
||||
@@ -271,7 +271,7 @@ impl std::fmt::Display for FsEntry {
|
||||
// Get byte size
|
||||
let size: ByteSize = ByteSize(self.get_size() as u64);
|
||||
// Get date
|
||||
let datetime: String = time_to_str(self.get_last_change_time(), "%b %d %Y %H:%M");
|
||||
let datetime: String = fmt_time(self.get_last_change_time(), "%b %d %Y %H:%M");
|
||||
// Set file name (or elide if too long)
|
||||
let name: String = self.get_name();
|
||||
let name: String = match name.len() >= 24 {
|
||||
@@ -467,7 +467,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"bar.txt \t-rw-r--r-- \troot \t8.2 KB \t{}",
|
||||
time_to_str(t, "%b %d %Y %H:%M")
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -475,7 +475,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"bar.txt \t-rw-r--r-- \t0 \t8.2 KB \t{}",
|
||||
time_to_str(t, "%b %d %Y %H:%M")
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
// Elide name
|
||||
@@ -498,7 +498,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"piroparoporoperoperu... \t-rw-r--r-- \troot \t8.2 KB \t{}",
|
||||
time_to_str(t, "%b %d %Y %H:%M")
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -506,7 +506,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"piroparoporoperoperu... \t-rw-r--r-- \t0 \t8.2 KB \t{}",
|
||||
time_to_str(t, "%b %d %Y %H:%M")
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
// No pex
|
||||
@@ -529,7 +529,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"bar.txt \t-????????? \troot \t8.2 KB \t{}",
|
||||
time_to_str(t, "%b %d %Y %H:%M")
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -537,7 +537,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"bar.txt \t-????????? \t0 \t8.2 KB \t{}",
|
||||
time_to_str(t, "%b %d %Y %H:%M")
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
// No user
|
||||
@@ -560,7 +560,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"bar.txt \t-????????? \t0 \t8.2 KB \t{}",
|
||||
time_to_str(t, "%b %d %Y %H:%M")
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -568,7 +568,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"bar.txt \t-????????? \t0 \t8.2 KB \t{}",
|
||||
time_to_str(t, "%b %d %Y %H:%M")
|
||||
fmt_time(t, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -593,7 +593,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"projects \tdrwxr-xr-x \troot \t4.1 KB \t{}",
|
||||
time_to_str(t_now, "%b %d %Y %H:%M")
|
||||
fmt_time(t_now, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -601,7 +601,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"projects \tdrwxr-xr-x \t0 \t4.1 KB \t{}",
|
||||
time_to_str(t_now, "%b %d %Y %H:%M")
|
||||
fmt_time(t_now, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
// No pex, no user
|
||||
@@ -622,7 +622,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"projects \td????????? \t0 \t4.1 KB \t{}",
|
||||
time_to_str(t_now, "%b %d %Y %H:%M")
|
||||
fmt_time(t_now, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -630,7 +630,7 @@ mod tests {
|
||||
format!("{}", entry),
|
||||
format!(
|
||||
"projects \td????????? \t0 \t4.1 KB \t{}",
|
||||
time_to_str(t_now, "%b %d %Y %H:%M")
|
||||
fmt_time(t_now, "%b %d %Y %H:%M")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ fn main() {
|
||||
let extra_args: Vec<String> = matches.free;
|
||||
if let Some(remote) = extra_args.get(0) {
|
||||
// Parse address
|
||||
match utils::parse_remote_opt(remote) {
|
||||
match utils::parser::parse_remote_opt(remote) {
|
||||
Ok((addr, portn, proto, user)) => {
|
||||
// Set params
|
||||
address = Some(addr);
|
||||
|
||||
@@ -31,7 +31,7 @@ extern crate rand;
|
||||
use crate::bookmarks::serializer::BookmarkSerializer;
|
||||
use crate::bookmarks::{Bookmark, SerializerError, SerializerErrorKind, UserHosts};
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
use crate::utils::time_to_str;
|
||||
use crate::utils::fmt::fmt_time;
|
||||
// Ext
|
||||
use magic_crypt::MagicCryptTrait;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
@@ -220,7 +220,7 @@ impl BookmarksClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
let name: String = time_to_str(SystemTime::now(), "ISO%Y%m%dT%H%M%S");
|
||||
let name: String = fmt_time(SystemTime::now(), "ISO%Y%m%dT%H%M%S");
|
||||
self.hosts.recents.insert(name, host);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ use super::{
|
||||
AuthActivity, Context, DialogYesNoOption, FileTransferProtocol, InputField, InputForm,
|
||||
InputMode, PopupType,
|
||||
};
|
||||
use crate::utils::align_text_center;
|
||||
use crate::utils::fmt::align_text_center;
|
||||
|
||||
use tui::{
|
||||
layout::{Constraint, Corner, Direction, Layout, Rect},
|
||||
|
||||
@@ -28,7 +28,7 @@ use super::{
|
||||
Context, DialogYesNoOption, FileExplorerTab, FileTransferActivity, FsEntry, InputField,
|
||||
InputMode, LogLevel, LogRecord, PopupType,
|
||||
};
|
||||
use crate::utils::{align_text_center, time_to_str};
|
||||
use crate::utils::fmt::{align_text_center, fmt_time};
|
||||
|
||||
use bytesize::ByteSize;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -484,10 +484,10 @@ impl FileTransferActivity {
|
||||
// Get name and path
|
||||
let abs_path: PathBuf = fsentry.get_abs_path();
|
||||
let name: String = fsentry.get_name();
|
||||
let ctime: String = time_to_str(fsentry.get_creation_time(), "%b %d %Y %H:%M:%S");
|
||||
let ctime: String = fmt_time(fsentry.get_creation_time(), "%b %d %Y %H:%M:%S");
|
||||
let atime: String =
|
||||
time_to_str(fsentry.get_last_access_time(), "%b %d %Y %H:%M:%S");
|
||||
let mtime: String = time_to_str(fsentry.get_creation_time(), "%b %d %Y %H:%M:%S");
|
||||
fmt_time(fsentry.get_last_access_time(), "%b %d %Y %H:%M:%S");
|
||||
let mtime: String = fmt_time(fsentry.get_creation_time(), "%b %d %Y %H:%M:%S");
|
||||
let (bsize, size): (ByteSize, usize) =
|
||||
(ByteSize(fsentry.get_size() as u64), fsentry.get_size());
|
||||
let user: Option<u32> = fsentry.get_user();
|
||||
|
||||
@@ -28,7 +28,8 @@ extern crate tempfile;
|
||||
// Locals
|
||||
use super::{FileTransferActivity, InputMode, LogLevel, PopupType};
|
||||
use crate::fs::{FsEntry, FsFile};
|
||||
use crate::utils::{fmt_millis, hash_sha256_file};
|
||||
use crate::utils::fmt::fmt_millis;
|
||||
use crate::utils::hash::hash_sha256_file;
|
||||
|
||||
// Ext
|
||||
use bytesize::ByteSize;
|
||||
|
||||
172
src/utils/fmt.rs
Normal file
172
src/utils/fmt.rs
Normal file
@@ -0,0 +1,172 @@
|
||||
//! ## Fmt
|
||||
//!
|
||||
//! `fmt` is the module which provides utilities for formatting
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
|
||||
*
|
||||
* This file is part of "TermSCP"
|
||||
*
|
||||
* TermSCP 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.
|
||||
*
|
||||
* TermSCP 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 TermSCP. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
extern crate chrono;
|
||||
extern crate textwrap;
|
||||
|
||||
use chrono::prelude::*;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
/// ### fmt_pex
|
||||
///
|
||||
/// Convert 3 bytes of permissions value into ls notation (e.g. rwx-wx--x)
|
||||
pub fn fmt_pex(owner: u8, group: u8, others: u8) -> String {
|
||||
let mut mode: String = String::with_capacity(9);
|
||||
let read: u8 = (owner >> 2) & 0x1;
|
||||
let write: u8 = (owner >> 1) & 0x1;
|
||||
let exec: u8 = owner & 0x1;
|
||||
mode.push_str(match read {
|
||||
1 => "r",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match write {
|
||||
1 => "w",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match exec {
|
||||
1 => "x",
|
||||
_ => "-",
|
||||
});
|
||||
let read: u8 = (group >> 2) & 0x1;
|
||||
let write: u8 = (group >> 1) & 0x1;
|
||||
let exec: u8 = group & 0x1;
|
||||
mode.push_str(match read {
|
||||
1 => "r",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match write {
|
||||
1 => "w",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match exec {
|
||||
1 => "x",
|
||||
_ => "-",
|
||||
});
|
||||
let read: u8 = (others >> 2) & 0x1;
|
||||
let write: u8 = (others >> 1) & 0x1;
|
||||
let exec: u8 = others & 0x1;
|
||||
mode.push_str(match read {
|
||||
1 => "r",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match write {
|
||||
1 => "w",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match exec {
|
||||
1 => "x",
|
||||
_ => "-",
|
||||
});
|
||||
mode
|
||||
}
|
||||
|
||||
/// ### instant_to_str
|
||||
///
|
||||
/// Format a `Instant` into a time string
|
||||
pub fn fmt_time(time: SystemTime, fmt: &str) -> String {
|
||||
let datetime: DateTime<Local> = time.into();
|
||||
format!("{}", datetime.format(fmt))
|
||||
}
|
||||
|
||||
/// ### fmt_millis
|
||||
///
|
||||
/// Format duration as {secs}.{millis}
|
||||
pub fn fmt_millis(duration: Duration) -> String {
|
||||
let seconds: u128 = duration.as_millis() / 1000;
|
||||
let millis: u128 = duration.as_millis() % 1000;
|
||||
format!("{}.{:0width$}", seconds, millis, width = 3)
|
||||
}
|
||||
|
||||
/// align_text_center
|
||||
///
|
||||
/// Align text to center for a given width
|
||||
pub fn align_text_center(text: &str, width: u16) -> String {
|
||||
let indent_size: usize = match (width as usize) >= text.len() {
|
||||
// NOTE: The check prevents underflow
|
||||
true => (width as usize - text.len()) / 2,
|
||||
false => 0,
|
||||
};
|
||||
textwrap::indent(
|
||||
text,
|
||||
(0..indent_size).map(|_| " ").collect::<String>().as_str(),
|
||||
)
|
||||
.trim_end()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_utils_fmt_pex() {
|
||||
assert_eq!(fmt_pex(7, 7, 7), String::from("rwxrwxrwx"));
|
||||
assert_eq!(fmt_pex(7, 5, 5), String::from("rwxr-xr-x"));
|
||||
assert_eq!(fmt_pex(6, 6, 6), String::from("rw-rw-rw-"));
|
||||
assert_eq!(fmt_pex(6, 4, 4), String::from("rw-r--r--"));
|
||||
assert_eq!(fmt_pex(6, 0, 0), String::from("rw-------"));
|
||||
assert_eq!(fmt_pex(0, 0, 0), String::from("---------"));
|
||||
assert_eq!(fmt_pex(4, 4, 4), String::from("r--r--r--"));
|
||||
assert_eq!(fmt_pex(1, 2, 1), String::from("--x-w---x"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utils_fmt_time() {
|
||||
let system_time: SystemTime = SystemTime::from(SystemTime::UNIX_EPOCH);
|
||||
assert_eq!(
|
||||
fmt_time(system_time, "%Y-%m-%d"),
|
||||
String::from("1970-01-01")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utils_align_text_center() {
|
||||
assert_eq!(
|
||||
align_text_center("hello world!", 24),
|
||||
String::from(" hello world!")
|
||||
);
|
||||
// Bad case
|
||||
assert_eq!(
|
||||
align_text_center("hello world!", 8),
|
||||
String::from("hello world!")
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_utils_fmt_millis() {
|
||||
assert_eq!(
|
||||
fmt_millis(Duration::from_millis(2048)),
|
||||
String::from("2.048")
|
||||
);
|
||||
assert_eq!(
|
||||
fmt_millis(Duration::from_millis(8192)),
|
||||
String::from("8.192")
|
||||
);
|
||||
assert_eq!(
|
||||
fmt_millis(Duration::from_millis(18192)),
|
||||
String::from("18.192")
|
||||
);
|
||||
}
|
||||
}
|
||||
75
src/utils/hash.rs
Normal file
75
src/utils/hash.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
//! ## Hash
|
||||
//!
|
||||
//! `hash` is the module which provides utilities for calculating digests
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
|
||||
*
|
||||
* This file is part of "TermSCP"
|
||||
*
|
||||
* TermSCP 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.
|
||||
*
|
||||
* TermSCP 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 TermSCP. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
extern crate data_encoding;
|
||||
extern crate ring;
|
||||
|
||||
use data_encoding::HEXLOWER;
|
||||
use ring::digest::{Context, Digest, SHA256};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
|
||||
/// ### hash_sha256_file
|
||||
///
|
||||
/// Get SHA256 of provided path
|
||||
pub fn hash_sha256_file(file: &Path) -> Result<String, std::io::Error> {
|
||||
// Open file
|
||||
let mut reader: File = File::open(file)?;
|
||||
let mut context = Context::new(&SHA256);
|
||||
let mut buffer = [0; 8192];
|
||||
loop {
|
||||
let count = reader.read(&mut buffer)?;
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
context.update(&buffer[..count]);
|
||||
}
|
||||
// Finish context
|
||||
let digest: Digest = context.finish();
|
||||
Ok(HEXLOWER.encode(digest.as_ref()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
#[test]
|
||||
fn test_utils_hash_sha256() {
|
||||
let tmp: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap();
|
||||
// Write
|
||||
let mut fhnd: File = File::create(tmp.path()).unwrap();
|
||||
assert!(fhnd.write_all(b"Hello world!\n").is_ok());
|
||||
assert_eq!(
|
||||
*hash_sha256_file(tmp.path()).ok().as_ref().unwrap(),
|
||||
String::from("0ba904eae8773b70c75333db4de2f3ac45a8ad4ddba1b242f0b3cfc199391dd8")
|
||||
);
|
||||
// Bad file
|
||||
assert!(hash_sha256_file(Path::new("/tmp/oiojjt5ig/aiehgoiwg")).is_err());
|
||||
}
|
||||
}
|
||||
29
src/utils/mod.rs
Normal file
29
src/utils/mod.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
//! ## Utils
|
||||
//!
|
||||
//! `utils` is the module which provides utilities of different kind
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
|
||||
*
|
||||
* This file is part of "TermSCP"
|
||||
*
|
||||
* TermSCP 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.
|
||||
*
|
||||
* TermSCP 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 TermSCP. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// modules
|
||||
pub mod fmt;
|
||||
pub mod hash;
|
||||
pub mod parser;
|
||||
@@ -1,6 +1,6 @@
|
||||
//! ## Utils
|
||||
//! ## Parser
|
||||
//!
|
||||
//! `utils` is the module which provides utilities of different kind
|
||||
//! `parser` is the module which provides utilities for parsing different kind of stuff
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -25,20 +25,12 @@
|
||||
|
||||
// Dependencies
|
||||
extern crate chrono;
|
||||
extern crate data_encoding;
|
||||
extern crate ring;
|
||||
extern crate textwrap;
|
||||
extern crate whoami;
|
||||
|
||||
use crate::filetransfer::FileTransferProtocol;
|
||||
|
||||
use chrono::format::ParseError;
|
||||
use chrono::prelude::*;
|
||||
use data_encoding::HEXLOWER;
|
||||
use ring::digest::{Context, Digest, SHA256};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
/// ### parse_remote_opt
|
||||
@@ -152,87 +144,13 @@ pub fn parse_remote_opt(
|
||||
Ok((address, port, protocol, username))
|
||||
}
|
||||
|
||||
/// ### fmt_pex
|
||||
///
|
||||
/// Convert 3 bytes of permissions value into ls notation (e.g. rwx-wx--x)
|
||||
pub fn fmt_pex(owner: u8, group: u8, others: u8) -> String {
|
||||
let mut mode: String = String::with_capacity(9);
|
||||
let read: u8 = (owner >> 2) & 0x1;
|
||||
let write: u8 = (owner >> 1) & 0x1;
|
||||
let exec: u8 = owner & 0x1;
|
||||
mode.push_str(match read {
|
||||
1 => "r",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match write {
|
||||
1 => "w",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match exec {
|
||||
1 => "x",
|
||||
_ => "-",
|
||||
});
|
||||
let read: u8 = (group >> 2) & 0x1;
|
||||
let write: u8 = (group >> 1) & 0x1;
|
||||
let exec: u8 = group & 0x1;
|
||||
mode.push_str(match read {
|
||||
1 => "r",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match write {
|
||||
1 => "w",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match exec {
|
||||
1 => "x",
|
||||
_ => "-",
|
||||
});
|
||||
let read: u8 = (others >> 2) & 0x1;
|
||||
let write: u8 = (others >> 1) & 0x1;
|
||||
let exec: u8 = others & 0x1;
|
||||
mode.push_str(match read {
|
||||
1 => "r",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match write {
|
||||
1 => "w",
|
||||
_ => "-",
|
||||
});
|
||||
mode.push_str(match exec {
|
||||
1 => "x",
|
||||
_ => "-",
|
||||
});
|
||||
mode
|
||||
}
|
||||
|
||||
/// ### instant_to_str
|
||||
///
|
||||
/// Format a `Instant` into a time string
|
||||
pub fn time_to_str(time: SystemTime, fmt: &str) -> String {
|
||||
let datetime: DateTime<Local> = time.into();
|
||||
format!("{}", datetime.format(fmt))
|
||||
}
|
||||
|
||||
/// ### fmt_millis
|
||||
///
|
||||
/// Format duration as {secs}.{millis}
|
||||
pub fn fmt_millis(duration: Duration) -> String {
|
||||
let seconds: u128 = duration.as_millis() / 1000;
|
||||
let millis: u128 = duration.as_millis() % 1000;
|
||||
format!("{}.{:0width$}", seconds, millis, width = 3)
|
||||
}
|
||||
|
||||
/// ### lstime_to_systime
|
||||
/// ### parse_lstime
|
||||
///
|
||||
/// Convert ls syntax time to System Time
|
||||
/// ls time has two possible syntax:
|
||||
/// 1. if year is current: %b %d %H:%M (e.g. Nov 5 13:46)
|
||||
/// 2. else: %b %d %Y (e.g. Nov 5 2019)
|
||||
pub fn lstime_to_systime(
|
||||
tm: &str,
|
||||
fmt_year: &str,
|
||||
fmt_hours: &str,
|
||||
) -> Result<SystemTime, ParseError> {
|
||||
pub fn parse_lstime(tm: &str, fmt_year: &str, fmt_hours: &str) -> Result<SystemTime, ParseError> {
|
||||
let datetime: NaiveDateTime = match NaiveDate::parse_from_str(tm, fmt_year) {
|
||||
Ok(date) => {
|
||||
// Case 2.
|
||||
@@ -261,50 +179,11 @@ pub fn lstime_to_systime(
|
||||
.unwrap_or(SystemTime::UNIX_EPOCH))
|
||||
}
|
||||
|
||||
/// align_text_center
|
||||
///
|
||||
/// Align text to center for a given width
|
||||
pub fn align_text_center(text: &str, width: u16) -> String {
|
||||
let indent_size: usize = match (width as usize) >= text.len() {
|
||||
// NOTE: The check prevents underflow
|
||||
true => (width as usize - text.len()) / 2,
|
||||
false => 0,
|
||||
};
|
||||
textwrap::indent(
|
||||
text,
|
||||
(0..indent_size).map(|_| " ").collect::<String>().as_str(),
|
||||
)
|
||||
.trim_end()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// ### hash_sha256_file
|
||||
///
|
||||
/// Get SHA256 of provided path
|
||||
pub fn hash_sha256_file(file: &Path) -> Result<String, std::io::Error> {
|
||||
// Open file
|
||||
let mut reader: File = File::open(file)?;
|
||||
let mut context = Context::new(&SHA256);
|
||||
let mut buffer = [0; 8192];
|
||||
loop {
|
||||
let count = reader.read(&mut buffer)?;
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
context.update(&buffer[..count]);
|
||||
}
|
||||
// Finish context
|
||||
let digest: Digest = context.finish();
|
||||
Ok(HEXLOWER.encode(digest.as_ref()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
#[test]
|
||||
fn test_utils_parse_remote_opt() {
|
||||
// Base case
|
||||
@@ -395,31 +274,10 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utils_fmt_pex() {
|
||||
assert_eq!(fmt_pex(7, 7, 7), String::from("rwxrwxrwx"));
|
||||
assert_eq!(fmt_pex(7, 5, 5), String::from("rwxr-xr-x"));
|
||||
assert_eq!(fmt_pex(6, 6, 6), String::from("rw-rw-rw-"));
|
||||
assert_eq!(fmt_pex(6, 4, 4), String::from("rw-r--r--"));
|
||||
assert_eq!(fmt_pex(6, 0, 0), String::from("rw-------"));
|
||||
assert_eq!(fmt_pex(0, 0, 0), String::from("---------"));
|
||||
assert_eq!(fmt_pex(4, 4, 4), String::from("r--r--r--"));
|
||||
assert_eq!(fmt_pex(1, 2, 1), String::from("--x-w---x"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utils_time_to_str() {
|
||||
let system_time: SystemTime = SystemTime::from(SystemTime::UNIX_EPOCH);
|
||||
assert_eq!(
|
||||
time_to_str(system_time, "%Y-%m-%d"),
|
||||
String::from("1970-01-01")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utils_lstime_to_systime() {
|
||||
fn test_utils_parse_lstime() {
|
||||
// Good cases
|
||||
assert_eq!(
|
||||
lstime_to_systime("Nov 5 16:32", "%b %d %Y", "%b %d %H:%M")
|
||||
parse_lstime("Nov 5 16:32", "%b %d %Y", "%b %d %H:%M")
|
||||
.ok()
|
||||
.unwrap()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
@@ -428,7 +286,7 @@ mod tests {
|
||||
Duration::from_secs(1604593920)
|
||||
);
|
||||
assert_eq!(
|
||||
lstime_to_systime("Dec 2 21:32", "%b %d %Y", "%b %d %H:%M")
|
||||
parse_lstime("Dec 2 21:32", "%b %d %Y", "%b %d %H:%M")
|
||||
.ok()
|
||||
.unwrap()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
@@ -437,7 +295,7 @@ mod tests {
|
||||
Duration::from_secs(1606944720)
|
||||
);
|
||||
assert_eq!(
|
||||
lstime_to_systime("Nov 5 2018", "%b %d %Y", "%b %d %H:%M")
|
||||
parse_lstime("Nov 5 2018", "%b %d %Y", "%b %d %H:%M")
|
||||
.ok()
|
||||
.unwrap()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
@@ -446,7 +304,7 @@ mod tests {
|
||||
Duration::from_secs(1541376000)
|
||||
);
|
||||
assert_eq!(
|
||||
lstime_to_systime("Mar 18 2018", "%b %d %Y", "%b %d %H:%M")
|
||||
parse_lstime("Mar 18 2018", "%b %d %Y", "%b %d %H:%M")
|
||||
.ok()
|
||||
.unwrap()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
@@ -455,50 +313,8 @@ mod tests {
|
||||
Duration::from_secs(1521331200)
|
||||
);
|
||||
// bad cases
|
||||
assert!(lstime_to_systime("Oma 31 2018", "%b %d %Y", "%b %d %H:%M").is_err());
|
||||
assert!(lstime_to_systime("Feb 31 2018", "%b %d %Y", "%b %d %H:%M").is_err());
|
||||
assert!(lstime_to_systime("Feb 15 25:32", "%b %d %Y", "%b %d %H:%M").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utils_align_text_center() {
|
||||
assert_eq!(
|
||||
align_text_center("hello world!", 24),
|
||||
String::from(" hello world!")
|
||||
);
|
||||
// Bad case
|
||||
assert_eq!(
|
||||
align_text_center("hello world!", 8),
|
||||
String::from("hello world!")
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_utils_fmt_millis() {
|
||||
assert_eq!(
|
||||
fmt_millis(Duration::from_millis(2048)),
|
||||
String::from("2.048")
|
||||
);
|
||||
assert_eq!(
|
||||
fmt_millis(Duration::from_millis(8192)),
|
||||
String::from("8.192")
|
||||
);
|
||||
assert_eq!(
|
||||
fmt_millis(Duration::from_millis(18192)),
|
||||
String::from("18.192")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utils_hash_sha256() {
|
||||
let tmp: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap();
|
||||
// Write
|
||||
let mut fhnd: File = File::create(tmp.path()).unwrap();
|
||||
assert!(fhnd.write_all(b"Hello world!\n").is_ok());
|
||||
assert_eq!(
|
||||
*hash_sha256_file(tmp.path()).ok().as_ref().unwrap(),
|
||||
String::from("0ba904eae8773b70c75333db4de2f3ac45a8ad4ddba1b242f0b3cfc199391dd8")
|
||||
);
|
||||
// Bad file
|
||||
assert!(hash_sha256_file(Path::new("/tmp/oiojjt5ig/aiehgoiwg")).is_err());
|
||||
assert!(parse_lstime("Oma 31 2018", "%b %d %Y", "%b %d %H:%M").is_err());
|
||||
assert!(parse_lstime("Feb 31 2018", "%b %d %Y", "%b %d %H:%M").is_err());
|
||||
assert!(parse_lstime("Feb 15 25:32", "%b %d %Y", "%b %d %H:%M").is_err());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user