improved error handling
All checks were successful
Version Check / check-version (pull_request) Successful in 3s
All checks were successful
Version Check / check-version (pull_request) Successful in 3s
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
use super::{ConfigItem, FormatHandler, ItemStatus, ValueType};
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct EnvHandler;
|
||||
|
||||
impl FormatHandler for EnvHandler {
|
||||
fn parse(&self, path: &Path) -> io::Result<Vec<ConfigItem>> {
|
||||
fn parse(&self, path: &Path) -> anyhow::Result<Vec<ConfigItem>> {
|
||||
let content = fs::read_to_string(path)?;
|
||||
let mut vars = Vec::new();
|
||||
|
||||
@@ -35,7 +35,7 @@ impl FormatHandler for EnvHandler {
|
||||
Ok(vars)
|
||||
}
|
||||
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> io::Result<()> {
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> anyhow::Result<()> {
|
||||
let mut file = fs::File::create(path)?;
|
||||
for var in vars {
|
||||
if !var.is_group {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::{ConfigItem, FormatHandler, FormatType, ItemStatus, ValueType};
|
||||
use serde_json::{Map, Value};
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct HierarchicalHandler {
|
||||
@@ -13,50 +12,40 @@ impl HierarchicalHandler {
|
||||
Self { format_type }
|
||||
}
|
||||
|
||||
fn read_value(&self, path: &Path) -> io::Result<Value> {
|
||||
fn read_value(&self, path: &Path) -> anyhow::Result<Value> {
|
||||
let content = fs::read_to_string(path)?;
|
||||
let value = match self.format_type {
|
||||
FormatType::Json => serde_json::from_str(&content)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?,
|
||||
FormatType::Yaml => serde_yaml::from_str(&content)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?,
|
||||
FormatType::Toml => toml::from_str(&content)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?,
|
||||
FormatType::Xml => xml_to_json(&content)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?,
|
||||
FormatType::Json => serde_json::from_str(&content)?,
|
||||
FormatType::Yaml => serde_yaml::from_str(&content)?,
|
||||
FormatType::Toml => toml::from_str(&content)?,
|
||||
FormatType::Xml => xml_to_json(&content)?,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn write_value(&self, path: &Path, value: &Value) -> io::Result<()> {
|
||||
fn write_value(&self, path: &Path, value: &Value) -> anyhow::Result<()> {
|
||||
let content = match self.format_type {
|
||||
FormatType::Json => serde_json::to_string_pretty(value)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?,
|
||||
FormatType::Yaml => serde_yaml::to_string(value)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?,
|
||||
FormatType::Json => serde_json::to_string_pretty(value)?,
|
||||
FormatType::Yaml => serde_yaml::to_string(value)?,
|
||||
FormatType::Toml => {
|
||||
// toml requires the root to be a table
|
||||
if value.is_object() {
|
||||
let toml_value: toml::Value = serde_json::from_value(value.clone())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
toml::to_string_pretty(&toml_value)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
|
||||
let toml_value: toml::Value = serde_json::from_value(value.clone())?;
|
||||
toml::to_string_pretty(&toml_value)?
|
||||
} else {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"Root of TOML must be an object",
|
||||
));
|
||||
anyhow::bail!("Root of TOML must be an object");
|
||||
}
|
||||
}
|
||||
FormatType::Xml => json_to_xml(value),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
fs::write(path, content)
|
||||
fs::write(path, content)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn xml_to_json(content: &str) -> io::Result<Value> {
|
||||
fn xml_to_json(content: &str) -> anyhow::Result<Value> {
|
||||
use quick_xml::reader::Reader;
|
||||
use quick_xml::events::Event;
|
||||
|
||||
@@ -64,7 +53,7 @@ fn xml_to_json(content: &str) -> io::Result<Value> {
|
||||
reader.config_mut().trim_text(true);
|
||||
let mut buf = Vec::new();
|
||||
|
||||
fn parse_recursive(reader: &mut Reader<&[u8]>) -> io::Result<Value> {
|
||||
fn parse_recursive(reader: &mut Reader<&[u8]>) -> anyhow::Result<Value> {
|
||||
let mut map = Map::new();
|
||||
let mut text = String::new();
|
||||
let mut buf = Vec::new();
|
||||
@@ -276,14 +265,14 @@ fn flatten(value: &Value, prefix: &str, depth: usize, key_name: &str, vars: &mut
|
||||
}
|
||||
|
||||
impl FormatHandler for HierarchicalHandler {
|
||||
fn parse(&self, path: &Path) -> io::Result<Vec<ConfigItem>> {
|
||||
fn parse(&self, path: &Path) -> anyhow::Result<Vec<ConfigItem>> {
|
||||
let value = self.read_value(path)?;
|
||||
let mut vars = Vec::new();
|
||||
flatten(&value, "", 0, "", &mut vars);
|
||||
Ok(vars)
|
||||
}
|
||||
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> io::Result<()> {
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> anyhow::Result<()> {
|
||||
let mut root = Value::Object(Map::new());
|
||||
for var in vars {
|
||||
if !var.is_group {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
use super::{ConfigItem, FormatHandler, ItemStatus, ValueType};
|
||||
use ini::Ini;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct IniHandler;
|
||||
|
||||
impl FormatHandler for IniHandler {
|
||||
fn parse(&self, path: &Path) -> io::Result<Vec<ConfigItem>> {
|
||||
let conf = Ini::load_from_file(path)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
fn parse(&self, path: &Path) -> anyhow::Result<Vec<ConfigItem>> {
|
||||
let conf = Ini::load_from_file(path)?;
|
||||
let mut vars = Vec::new();
|
||||
|
||||
for (section, prop) in &conf {
|
||||
@@ -52,7 +50,7 @@ impl FormatHandler for IniHandler {
|
||||
Ok(vars)
|
||||
}
|
||||
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> io::Result<()> {
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> anyhow::Result<()> {
|
||||
let mut conf = Ini::new();
|
||||
for var in vars {
|
||||
if !var.is_group {
|
||||
@@ -67,8 +65,8 @@ impl FormatHandler for IniHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
conf.write_to_file(path)
|
||||
.map_err(io::Error::other)
|
||||
conf.write_to_file(path)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
pub mod env;
|
||||
@@ -46,8 +45,8 @@ pub enum FormatType {
|
||||
}
|
||||
|
||||
pub trait FormatHandler {
|
||||
fn parse(&self, path: &Path) -> io::Result<Vec<ConfigItem>>;
|
||||
fn merge(&self, path: &Path, vars: &mut Vec<ConfigItem>) -> io::Result<()> {
|
||||
fn parse(&self, path: &Path) -> anyhow::Result<Vec<ConfigItem>>;
|
||||
fn merge(&self, path: &Path, vars: &mut Vec<ConfigItem>) -> anyhow::Result<()> {
|
||||
if !path.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -82,7 +81,7 @@ pub trait FormatHandler {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> io::Result<()>;
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
pub fn detect_format(path: &Path, override_format: Option<String>) -> FormatType {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use super::{ConfigItem, FormatHandler, ItemStatus, ValueType};
|
||||
use java_properties::{LineContent, PropertiesIter, PropertiesWriter};
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufReader, BufWriter};
|
||||
use std::io::{BufReader, BufWriter};
|
||||
use std::path::Path;
|
||||
|
||||
pub struct PropertiesHandler;
|
||||
|
||||
impl FormatHandler for PropertiesHandler {
|
||||
fn parse(&self, path: &Path) -> io::Result<Vec<ConfigItem>> {
|
||||
fn parse(&self, path: &Path) -> anyhow::Result<Vec<ConfigItem>> {
|
||||
let file = File::open(path)?;
|
||||
let reader = BufReader::new(file);
|
||||
let iter = PropertiesIter::new(reader);
|
||||
@@ -16,7 +16,7 @@ impl FormatHandler for PropertiesHandler {
|
||||
let mut groups = std::collections::HashSet::new();
|
||||
|
||||
for line_result in iter {
|
||||
let line = line_result.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let line = line_result?;
|
||||
|
||||
if let LineContent::KVPair(path, value) = line.consume_content() {
|
||||
// Add groups based on dot notation
|
||||
@@ -62,7 +62,7 @@ impl FormatHandler for PropertiesHandler {
|
||||
Ok(vars)
|
||||
}
|
||||
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> io::Result<()> {
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> anyhow::Result<()> {
|
||||
let file = File::create(path)?;
|
||||
let writer = BufWriter::new(file);
|
||||
let mut prop_writer = PropertiesWriter::new(writer);
|
||||
@@ -72,12 +72,12 @@ impl FormatHandler for PropertiesHandler {
|
||||
let val = var.value.as_deref()
|
||||
.or(var.template_value.as_deref())
|
||||
.unwrap_or("");
|
||||
prop_writer.write(&var.path, val)
|
||||
.map_err(io::Error::other)?;
|
||||
prop_writer.write(&var.path, val)?;
|
||||
}
|
||||
}
|
||||
|
||||
prop_writer.finish().map_err(io::Error::other)
|
||||
prop_writer.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user