diff --git a/src/utils.rs b/src/utils.rs index 7f3a1fe..913e420 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -65,7 +65,7 @@ pub fn parse_remote_opt( let tokens: Vec<&str> = wrkstr.split("://").collect(); // If length is > 1, then token[0] is protocol match tokens.len() { - 1 => {}, + 1 => {} 2 => { // Parse protocol match tokens[0] { @@ -92,7 +92,7 @@ pub fn parse_remote_opt( _ => return Err(format!("Unknown protocol '{}'", tokens[0])), } wrkstr = String::from(tokens[1]); // Wrkstr becomes tokens[1] - }, + } _ => return Err(String::from("Bad syntax")), // Too many tokens... } // Set username to default if sftp @@ -109,7 +109,7 @@ pub fn parse_remote_opt( username = Some(String::from(tokens[0])); // Update wrkstr wrkstr = String::from(tokens[1]); - }, + } _ => return Err(String::from("Bad syntax")), // Too many tokens... } // Split wrkstring by ':' @@ -125,16 +125,21 @@ pub fn parse_remote_opt( // Port is second str port = match tokens[1].parse::() { Ok(val) => val, - Err(_) => return Err(format!("Port must be a number in range [0-65535], but is '{}'", tokens[1])) + Err(_) => { + return Err(format!( + "Port must be a number in range [0-65535], but is '{}'", + tokens[1] + )) + } }; - }, + } _ => return Err(String::from("Bad syntax")), // Too many tokens... } Ok((address, port, protocol, username, secure)) } /// ### instant_to_str -/// +/// /// Format a `Instant` into a time string pub fn time_to_str(time: SystemTime, fmt: &str) -> String { let datetime: DateTime = time.into(); @@ -142,30 +147,42 @@ pub fn time_to_str(time: SystemTime, fmt: &str) -> String { } /// ### lstime_to_systime -/// +/// /// 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) -> Result { - let datetime: NaiveDateTime = match NaiveDate::parse_from_str(tm, "%b %d %Y") { - Ok(date) => { // Case 2. +pub fn lstime_to_systime( + tm: &str, + fmt_year: &str, + fmt_hours: &str, +) -> Result { + let datetime: NaiveDateTime = match NaiveDate::parse_from_str(tm, fmt_year) { + Ok(date) => { + // Case 2. // Return NaiveDateTime from NaiveDate with time 00:00:00 date.and_hms(0, 0, 0) } - Err(_) => { // Might be case 1. - // Check if syntax is case 1 - match NaiveDateTime::parse_from_str(tm, "%b %d %H:%M").err().unwrap() { // This will never succeed - ParseError::NotEnough => { // Format is correct - // We need to add Current Year at the end of the string - } - _ => return Err() + Err(_) => { + // Might be case 1. + // We need to add Current Year at the end of the string + let this_year: i32 = Utc::now().year(); + let date_time_str: String = format!("{} {}", tm, this_year); + // Now parse + match NaiveDateTime::parse_from_str( + date_time_str.as_ref(), + format!("{} %Y", fmt_hours).as_ref(), + ) { + Ok(dt) => dt, + Err(err) => return Err(err), } } }; // Convert datetime to system time let mut sys_time: SystemTime = SystemTime::UNIX_EPOCH; - Ok(sys_time.checked_add(Duration::from_secs(datetime.timestamp() as u64)).unwrap_or(SystemTime::UNIX_EPOCH) + Ok(sys_time + .checked_add(Duration::from_secs(datetime.timestamp() as u64)) + .unwrap_or(SystemTime::UNIX_EPOCH)) } #[cfg(test)] @@ -176,49 +193,70 @@ mod tests { #[test] fn test_utils_parse_remote_opt() { // Base case - let result: (String, u16, FileTransferProtocol, Option, bool) = parse_remote_opt(&String::from("172.26.104.1")).ok().unwrap(); + let result: (String, u16, FileTransferProtocol, Option, bool) = + parse_remote_opt(&String::from("172.26.104.1")) + .ok() + .unwrap(); assert_eq!(result.0, String::from("172.26.104.1")); assert_eq!(result.1, 22); assert_eq!(result.2, FileTransferProtocol::Sftp); assert!(result.3.is_some()); assert_eq!(result.4, false); // User case - let result: (String, u16, FileTransferProtocol, Option, bool) = parse_remote_opt(&String::from("root@172.26.104.1")).ok().unwrap(); + let result: (String, u16, FileTransferProtocol, Option, bool) = + parse_remote_opt(&String::from("root@172.26.104.1")) + .ok() + .unwrap(); assert_eq!(result.0, String::from("172.26.104.1")); assert_eq!(result.1, 22); assert_eq!(result.2, FileTransferProtocol::Sftp); assert_eq!(result.3.unwrap(), String::from("root")); assert_eq!(result.4, false); // User + port - let result: (String, u16, FileTransferProtocol, Option, bool) = parse_remote_opt(&String::from("root@172.26.104.1:8022")).ok().unwrap(); + let result: (String, u16, FileTransferProtocol, Option, bool) = + parse_remote_opt(&String::from("root@172.26.104.1:8022")) + .ok() + .unwrap(); assert_eq!(result.0, String::from("172.26.104.1")); assert_eq!(result.1, 8022); assert_eq!(result.2, FileTransferProtocol::Sftp); assert_eq!(result.3.unwrap(), String::from("root")); assert_eq!(result.4, false); // Port only - let result: (String, u16, FileTransferProtocol, Option, bool) = parse_remote_opt(&String::from("172.26.104.1:4022")).ok().unwrap(); + let result: (String, u16, FileTransferProtocol, Option, bool) = + parse_remote_opt(&String::from("172.26.104.1:4022")) + .ok() + .unwrap(); assert_eq!(result.0, String::from("172.26.104.1")); assert_eq!(result.1, 4022); assert_eq!(result.2, FileTransferProtocol::Sftp); assert!(result.3.is_some()); assert_eq!(result.4, false); // Protocol - let result: (String, u16, FileTransferProtocol, Option, bool) = parse_remote_opt(&String::from("ftp://172.26.104.1")).ok().unwrap(); + let result: (String, u16, FileTransferProtocol, Option, bool) = + parse_remote_opt(&String::from("ftp://172.26.104.1")) + .ok() + .unwrap(); assert_eq!(result.0, String::from("172.26.104.1")); assert_eq!(result.1, 21); // Fallback to ftp default assert_eq!(result.2, FileTransferProtocol::Ftp); assert!(result.3.is_none()); // Doesn't fall back assert_eq!(result.4, false); // Protocol + user - let result: (String, u16, FileTransferProtocol, Option, bool) = parse_remote_opt(&String::from("ftps://anon@172.26.104.1")).ok().unwrap(); + let result: (String, u16, FileTransferProtocol, Option, bool) = + parse_remote_opt(&String::from("ftps://anon@172.26.104.1")) + .ok() + .unwrap(); assert_eq!(result.0, String::from("172.26.104.1")); assert_eq!(result.1, 21); // Fallback to ftp default assert_eq!(result.2, FileTransferProtocol::Ftp); assert_eq!(result.3.unwrap(), String::from("anon")); assert_eq!(result.4, true); // All together now - let result: (String, u16, FileTransferProtocol, Option, bool) = parse_remote_opt(&String::from("ftp://anon@172.26.104.1:8021")).ok().unwrap(); + let result: (String, u16, FileTransferProtocol, Option, bool) = + parse_remote_opt(&String::from("ftp://anon@172.26.104.1:8021")) + .ok() + .unwrap(); assert_eq!(result.0, String::from("172.26.104.1")); assert_eq!(result.1, 8021); // Fallback to ftp default assert_eq!(result.2, FileTransferProtocol::Ftp); @@ -234,7 +272,46 @@ mod tests { #[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")); + assert_eq!( + time_to_str(system_time, "%Y-%m-%d"), + String::from("1970-01-01") + ); } + #[test] + fn test_utils_lstime_to_systime() { + // Good cases + assert_eq!( + lstime_to_systime("Nov 5 16:32", "%b %d %Y", "%b %d %H:%M") + .ok() + .unwrap() + .duration_since(SystemTime::UNIX_EPOCH), + Duration::from_secs(1604593920) + ); + assert_eq!( + lstime_to_systime("Dec 2 21:32", "%b %d %Y", "%b %d %H:%M") + .ok() + .unwrap() + .duration_since(SystemTime::UNIX_EPOCH), + Duration::from_secs(1606948320) + ); + assert_eq!( + lstime_to_systime("Nov 5 2018", "%b %d %Y", "%b %d %H:%M") + .ok() + .unwrap() + .duration_since(SystemTime::UNIX_EPOCH), + Duration::from_secs(1541376000) + ); + assert_eq!( + lstime_to_systime("Mar 18 2018", "%b %d %Y", "%b %d %H:%M") + .ok() + .unwrap() + .duration_since(SystemTime::UNIX_EPOCH), + 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()); + } }