diff --git a/.gitignore b/.gitignore index 96ef6c0..8f819b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /target Cargo.lock +*.log +*.yaml +*.yml diff --git a/src/lib.rs b/src/lib.rs index 65ef47a..bdde25a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ use simplelog::*; #[cfg(test)] mod tests; -mod settings; +pub mod settings; use settings::utils; #[allow(dead_code)] @@ -39,7 +39,6 @@ pub fn init() -> std::result::Result<(), log::SetLoggerError> { } } -#[allow(dead_code)] -fn import_words(path: PathBuf) -> Result { +pub fn import_input(path: PathBuf) -> Result { utils::read_file(&path) } diff --git a/src/settings/mod.rs b/src/settings/mod.rs index ec8a19c..66c72dd 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -1,23 +1,19 @@ extern crate serde; extern crate serde_json; extern crate serde_yaml; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; extern crate log; use log::warn; // mod utils; pub mod utils; +use utils::SettingsType; #[allow(dead_code)] const RULESET_CURRENT_VERSION: &'static str = "1"; -pub enum SettingsType { - Yaml, - Json, -} - -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct Settings { #[serde(default = "Settings::get_ruleset_version")] version: String, @@ -28,7 +24,6 @@ pub struct Settings { } impl Settings { - #[allow(dead_code)] pub fn new() -> Self { Self { version: Self::get_ruleset_version(), @@ -41,23 +36,39 @@ impl Settings { String::from(RULESET_CURRENT_VERSION) } + pub fn export(&self, path: &std::path::Path) -> std::io::Result<()> { + let filetype = utils::get_file_type(&path).unwrap(); + let content = match filetype { + SettingsType::Yaml => match serde_yaml::to_string(&self) { + Err(e) => { + warn!("Could not serialize settings: {}", e.to_string()); + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + e, + )); + } + Ok(val) => val, + }, + SettingsType::Json => match serde_json::to_string(&self) { + Err(e) => { + warn!("Could not serialize settings: {}", e.to_string()); + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + e, + )); + } + Ok(val) => val, + }, + }; + + utils::write_file(&path, content) + } + #[allow(dead_code)] - pub fn import(path: &std::path::PathBuf) -> std::io::Result { + pub fn import(path: &std::path::Path) -> std::io::Result { use SettingsType::*; let display = path.display(); - let extension = path.extension().unwrap(); - let extension = extension.to_str().unwrap(); - let method = match extension { - "yaml" => Yaml, - "json" => Json, - _ => { - use std::io::{Error, ErrorKind}; - return Err(Error::new( - ErrorKind::InvalidInput, - "File must have \"yaml\" or \"json\" extension", - )); - } - }; + let file_type = utils::get_file_type(&path).unwrap(); let content = match utils::read_file(&path) { Err(e) => { warn!("Could not read file {}: {}", display, e.to_string()); @@ -66,7 +77,7 @@ impl Settings { Ok(content) => content, }; - let settings: Settings = match method { + let settings: Settings = match file_type { Yaml => match serde_yaml::from_str(&content) { Err(e) => { warn!("Could not import settings: {}", e.to_string()); @@ -92,3 +103,26 @@ impl Settings { Ok(settings) } } + +impl PartialEq for Settings { + fn eq(&self, other: &Self) -> bool { + self.version == other.version + && self.categories == other.categories + && self.rules == other.rules + } +} + +impl Eq for Settings {} + +#[test] +fn write_settings() { + let s = Settings::new(); + let path = std::path::Path::new("test.yaml"); + let settings = r#"--- +version: "1" +categories: [] +rules: []"#; + utils::write_file(&path, serde_yaml::to_string(&s).unwrap()).unwrap(); + assert_eq!(settings, utils::read_file(&path).unwrap()); +} + diff --git a/src/settings/utils.rs b/src/settings/utils.rs index ec67075..d22460c 100644 --- a/src/settings/utils.rs +++ b/src/settings/utils.rs @@ -3,9 +3,14 @@ use log::{info, warn}; use std::fs::File; use std::io::{Read, Result}; -use std::path::PathBuf; +use std::path::Path; -pub fn read_file(path: &PathBuf) -> Result { +pub enum SettingsType { + Yaml, + Json, +} + +pub fn read_file(path: &Path) -> Result { let display = path.display(); let mut file = match File::open(&path) { Err(why) => { @@ -26,3 +31,52 @@ pub fn read_file(path: &PathBuf) -> Result { } } } + +pub fn write_file(path: &Path, content: String) -> Result<()> { + use std::io::prelude::*; + let mut file = match File::create(&path) { + Err(e) => { + warn!("Could not open file {}: {}", path.display(), e.to_string()); + return Err(e); + } + Ok(file) => file, + }; + match file.write_all(content.as_bytes()) { + Err(e) => { + warn!( + "Could not write settings to file {}: {}", + path.display(), + e.to_string() + ); + return Err(e); + } + Ok(_) => { + info!("Wrote settings to file {}", path.display()); + } + }; + Ok(()) +} + +pub fn get_file_type(path: &Path) -> Result { + let extension = match path.extension() { + None => { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "File has no extension", + )); + } + Some(val) => val, + }; + let extension = extension + .to_str() + .expect("Could not get String out of extension") + .to_lowercase(); + match extension.as_str() { + "yml" | "yaml" => Ok(SettingsType::Yaml), + "json" => Ok(SettingsType::Json), + _ => Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Invalid extension", + )), + } +}