section_config: add write - first try
This commit is contained in:
parent
92fb0784d4
commit
e189c93b8c
@ -3,6 +3,9 @@ use failure::*;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::collections::LinkedList;
|
||||||
|
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -27,6 +30,7 @@ pub struct SectionConfig {
|
|||||||
id_schema: Arc<Schema>,
|
id_schema: Arc<Schema>,
|
||||||
parse_section_header: fn(&str) -> Option<(String, String)>,
|
parse_section_header: fn(&str) -> Option<(String, String)>,
|
||||||
parse_section_content: fn(&str) -> Option<(String, String)>,
|
parse_section_content: fn(&str) -> Option<(String, String)>,
|
||||||
|
format_section_header: fn(type_name: &str, section_id: &str, data: &Value) -> String,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ParseState<'a> {
|
enum ParseState<'a> {
|
||||||
@ -36,22 +40,23 @@ enum ParseState<'a> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SectionConfigData {
|
pub struct SectionConfigData {
|
||||||
sections: HashMap<String, Value>,
|
sections: HashMap<String, (String, Value)>,
|
||||||
order: HashMap<String, usize>,
|
order: LinkedList<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SectionConfigData {
|
impl SectionConfigData {
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { sections: HashMap::new(), order: HashMap::new() }
|
Self { sections: HashMap::new(), order: LinkedList::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_data(&mut self, section_id: &str, config: Value) {
|
pub fn set_data(&mut self, section_id: &str, type_name: &str, config: Value) {
|
||||||
self.sections.insert(section_id.to_string(), config);
|
// fixme: verify section_id schema here??
|
||||||
|
self.sections.insert(section_id.to_string(), (type_name.to_string(), config));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_order(&mut self, section_id: &str, pri: usize) {
|
fn record_order(&mut self, section_id: &str) {
|
||||||
self.order.insert(section_id.to_string(), pri);
|
self.order.push_back(section_id.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +68,7 @@ impl SectionConfig {
|
|||||||
id_schema: id_schema,
|
id_schema: id_schema,
|
||||||
parse_section_header: SectionConfig::default_parse_section_header,
|
parse_section_header: SectionConfig::default_parse_section_header,
|
||||||
parse_section_content: SectionConfig::default_parse_section_content,
|
parse_section_content: SectionConfig::default_parse_section_content,
|
||||||
|
format_section_header: SectionConfig::default_format_section_header,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,6 +76,61 @@ impl SectionConfig {
|
|||||||
self.plugins.insert(plugin.type_name.clone(), plugin);
|
self.plugins.insert(plugin.type_name.clone(), plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write(&self, filename: &str, config: &SectionConfigData) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let mut list = LinkedList::new();
|
||||||
|
|
||||||
|
let mut done = HashSet::new();
|
||||||
|
|
||||||
|
for id in &config.order {
|
||||||
|
if config.sections.get(id) == None { continue };
|
||||||
|
list.push_back(id);
|
||||||
|
done.insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id, _) in &config.sections {
|
||||||
|
if done.contains(id) { continue };
|
||||||
|
list.push_back(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut raw = String::new();
|
||||||
|
|
||||||
|
for id in list {
|
||||||
|
let (type_name, section_config) = config.sections.get(id).unwrap();
|
||||||
|
let plugin = self.plugins.get(type_name).unwrap();
|
||||||
|
|
||||||
|
// fixme: verify json data
|
||||||
|
println!("REAL WRITE {} {} {:?}\n", id, type_name, section_config);
|
||||||
|
|
||||||
|
let head = (self.format_section_header)(type_name, id, section_config);
|
||||||
|
|
||||||
|
if !raw.is_empty() { raw += "\n" }
|
||||||
|
|
||||||
|
raw += &head;
|
||||||
|
|
||||||
|
for (key, value) in section_config.as_object().unwrap() {
|
||||||
|
let text = match value {
|
||||||
|
Value::Null => { continue; }, // do nothing ?
|
||||||
|
Value::Bool(bv) => bv.to_string(),
|
||||||
|
Value::String(str) => str.to_string(),
|
||||||
|
Value::Number(num) => num.to_string(),
|
||||||
|
_ => {
|
||||||
|
bail!("file {}: got unsupported type in section {} key {}", filename, id, key);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
raw += "\t";
|
||||||
|
raw += &key;
|
||||||
|
raw += " ";
|
||||||
|
raw += &text;
|
||||||
|
raw += "\n";
|
||||||
|
}
|
||||||
|
println!("CONFIG:\n{}", raw);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse(&self, filename: &str, raw: &str) -> Result<SectionConfigData, Error> {
|
pub fn parse(&self, filename: &str, raw: &str) -> Result<SectionConfigData, Error> {
|
||||||
|
|
||||||
let mut line_no = 0;
|
let mut line_no = 0;
|
||||||
@ -87,18 +148,14 @@ impl SectionConfig {
|
|||||||
|
|
||||||
let mut result = SectionConfigData::new();
|
let mut result = SectionConfigData::new();
|
||||||
|
|
||||||
let mut pri = 1;
|
let mut create_section = |section_id: &str, type_name: &str, config| {
|
||||||
let mut create_section = |section_id: &str, config| {
|
result.set_data(section_id, type_name, config);
|
||||||
result.set_data(section_id, config);
|
result.record_order(section_id);
|
||||||
result.set_order(section_id, pri);
|
|
||||||
pri += 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for line in raw.lines() {
|
for line in raw.lines() {
|
||||||
line_no += 1;
|
line_no += 1;
|
||||||
|
|
||||||
if line.trim().is_empty() { continue; }
|
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
|
|
||||||
ParseState::BeforeHeader => {
|
ParseState::BeforeHeader => {
|
||||||
@ -128,7 +185,7 @@ impl SectionConfig {
|
|||||||
if let Err(err) = test_required_properties(config, &plugin.properties) {
|
if let Err(err) = test_required_properties(config, &plugin.properties) {
|
||||||
bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
|
bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
|
||||||
}
|
}
|
||||||
create_section(section_id, config.take());
|
create_section(section_id, &plugin.type_name, config.take());
|
||||||
state = ParseState::BeforeHeader;
|
state = ParseState::BeforeHeader;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -163,15 +220,20 @@ impl SectionConfig {
|
|||||||
|
|
||||||
if let ParseState::InsideSection(plugin, section_id, config) = state {
|
if let ParseState::InsideSection(plugin, section_id, config) = state {
|
||||||
// finish section
|
// finish section
|
||||||
|
|
||||||
if let Err(err) = test_required_properties(&config, &plugin.properties) {
|
if let Err(err) = test_required_properties(&config, &plugin.properties) {
|
||||||
bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
|
bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
|
||||||
}
|
}
|
||||||
create_section(§ion_id, config);
|
create_section(§ion_id, &plugin.type_name, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_format_section_header(type_name: &str, section_id: &str, data: &Value) -> String {
|
||||||
|
return format!("{}: {}\n", type_name, section_id);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn default_parse_section_content(line: &str) -> Option<(String, String)> {
|
pub fn default_parse_section_content(line: &str) -> Option<(String, String)> {
|
||||||
|
|
||||||
if line.is_empty() { return None; }
|
if line.is_empty() { return None; }
|
||||||
@ -258,9 +320,15 @@ lvmthin: local-lvm
|
|||||||
thinpool data
|
thinpool data
|
||||||
vgname pve5
|
vgname pve5
|
||||||
content rootdir,images
|
content rootdir,images
|
||||||
|
|
||||||
|
lvmthin: local-lvm2
|
||||||
|
thinpool data
|
||||||
|
vgname pve5
|
||||||
|
content rootdir,images
|
||||||
";
|
";
|
||||||
|
|
||||||
let res = config.parse(filename, &raw);
|
let res = config.parse(filename, &raw);
|
||||||
println!("RES: {:?}", res);
|
println!("RES: {:?}", res);
|
||||||
|
config.write(filename, &res.unwrap());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user