use crate::dirs::WindshDirs; use chrono::prelude::*; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; #[derive(Deserialize, Serialize)] pub struct HistoryItem { datetime: Option, cmd: Option, } #[derive(Clone)] pub struct History { datetime: DateTime, cmd: String, } impl History { pub fn new(cmd: &str) -> Self { Self { datetime: Utc::now(), cmd: String::from(cmd), } } pub fn save(&self, history_file: Option<&str>) { let mut history_file_path = PathBuf::new(); #[cfg(unix)] if history_file == None { history_file_path.push( format!( "{}/history.yml", WindshDirs::load() .config_dir() .to_str() .expect("Cannot convert config_dir path to str") ) .as_str(), ); } else { history_file_path .push(history_file.expect("Cannot get the history file")); } #[cfg(windows)] if history_file == None { history_file_path.push( format!( "{}/history.yml", WindshDirs::load() .config_dir() .to_str() .expect("Cannot convert config_dir path to str") ) .as_str(), ); } else { history_file_path .push(history_file.expect("Cannot get the history file")); } if !history_file_path.exists() { fs::File::create(history_file_path.to_str().unwrap()).unwrap(); let default_content: Vec = vec![HistoryItem { datetime: Some(String::from("DEFAULT")), cmd: Some(String::from("DEFAULT")), }]; fs::write( &history_file_path, serde_yaml::to_string(&default_content).unwrap(), ) .unwrap(); } let content_raw = fs::read_to_string(&history_file_path.to_str().unwrap()).unwrap(); let content_yaml: Vec = serde_yaml::from_str(content_raw.as_str()).unwrap(); let mut history_vec: Vec = Vec::new(); for item in content_yaml { history_vec.push(HistoryItem { datetime: item.datetime, cmd: item.cmd, }) } history_vec.push(HistoryItem { datetime: Some(self.datetime.to_string()), cmd: Some(self.cmd.to_string()), }); let all_history = serde_yaml::to_string(&history_vec).unwrap(); fs::write(history_file_path, all_history).unwrap(); } /// Set the datetime of history /// ```rust /// use windsh_core::history::History; /// use chrono::prelude::*; /// /// let mut my_history = History::new("print Hello, World!"); /// /// my_history.set_datetime(Utc::now()); /// ``` pub fn set_datetime(&mut self, datetime: DateTime) { self.datetime = datetime; } /// Set the cmd of history /// ```rust /// use windsh_core::history::History; /// use chrono::prelude::*; /// /// let mut my_history = History::new("ls -lsa"); /// /// my_history.set_cmd("exec docker run -ti ubuntu:20.04 bash"); /// ``` pub fn set_cmd(&mut self, cmd: &str) { self.cmd = String::from(cmd); } pub fn get_datetime(&self) -> DateTime { self.datetime } pub fn get_cmd(&self) -> String { self.cmd.clone() } } #[cfg(test)] mod tests { use super::*; use std::thread; use std::time; #[test] fn test_history_new() { let my_history = History::new("ls -lsa"); assert_eq!(my_history.cmd, "ls -lsa"); assert_ne!(my_history.cmd, "ls -lsa "); thread::sleep(time::Duration::from_millis(50)); assert_ne!(my_history.datetime, Utc::now()); } #[test] fn test_set_datetime() { let mut my_history = History::new("print Hello, World!"); let datetime = Utc::now(); my_history.set_datetime(datetime); assert_eq!(my_history.datetime, datetime); } #[test] fn test_set_cmd() { let mut my_history = History::new("print Hello, World!"); my_history.set_cmd("print This is awesome"); assert_eq!(my_history.cmd, "print This is awesome"); my_history.set_cmd("ls -lsa \n"); assert_eq!(my_history.cmd, "ls -lsa \n"); } #[test] fn test_get_datetime() { let mut my_history = History::new("ls -lsa"); let datetime = Utc::now(); my_history.datetime = datetime; assert_eq!(my_history.datetime, datetime); thread::sleep(time::Duration::from_millis(50)); assert_ne!(my_history.datetime, Utc::now()); } #[test] fn test_get_cmd() { let mut my_history = History::new("ls -lsa"); assert_eq!(my_history.cmd, "ls -lsa"); my_history.cmd = String::from(""); assert_eq!(my_history.cmd, ""); assert_ne!(my_history.cmd, "\n"); } }