section_config: improve parser
This commit is contained in:
parent
1fa897cfed
commit
bdb631da88
|
@ -391,7 +391,7 @@ fn parse_property_string(value_str: &str, schema: &Schema) -> Result<Value, Erro
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_simple_value(value_str: &str, schema: &Schema) -> Result<Value, Error> {
|
pub fn parse_simple_value(value_str: &str, schema: &Schema) -> Result<Value, Error> {
|
||||||
|
|
||||||
let value = match schema {
|
let value = match schema {
|
||||||
Schema::Null => {
|
Schema::Null => {
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub struct SectionConfig {
|
||||||
|
|
||||||
enum ParseState<'a> {
|
enum ParseState<'a> {
|
||||||
BeforeHeader,
|
BeforeHeader,
|
||||||
InsideSection(&'a SectionConfigPlugin),
|
InsideSection(&'a SectionConfigPlugin, Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SectionConfig {
|
impl SectionConfig {
|
||||||
|
@ -53,6 +53,15 @@ impl SectionConfig {
|
||||||
|
|
||||||
let mut state = ParseState::BeforeHeader;
|
let mut state = ParseState::BeforeHeader;
|
||||||
|
|
||||||
|
let test_required_properties = |value: &Value, schema: &ObjectSchema| -> Result<(), Error> {
|
||||||
|
for (name, (optional, _prop_schema)) in &schema.properties {
|
||||||
|
if *optional == false && value[name] == Value::Null {
|
||||||
|
return Err(format_err!("property '{}' is missing and it is not optional.", name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
for line in raw.lines() {
|
for line in raw.lines() {
|
||||||
line_no += 1;
|
line_no += 1;
|
||||||
|
|
||||||
|
@ -67,7 +76,7 @@ impl SectionConfig {
|
||||||
if let Some((section_type, section_id)) = (self.parse_section_header)(line) {
|
if let Some((section_type, section_id)) = (self.parse_section_header)(line) {
|
||||||
println!("OKLINE: type: {} ID: {}", section_type, section_id);
|
println!("OKLINE: type: {} ID: {}", section_type, section_id);
|
||||||
if let Some(ref plugin) = self.plugins.get(§ion_type) {
|
if let Some(ref plugin) = self.plugins.get(§ion_type) {
|
||||||
state = ParseState::InsideSection(plugin);
|
state = ParseState::InsideSection(plugin, json!({}));
|
||||||
} else {
|
} else {
|
||||||
bail!("file '{}' line {} - unknown section type '{}'",
|
bail!("file '{}' line {} - unknown section type '{}'",
|
||||||
filename, line_no, section_type);
|
filename, line_no, section_type);
|
||||||
|
@ -76,16 +85,38 @@ impl SectionConfig {
|
||||||
bail!("file '{}' line {} - syntax error (expected header)", filename, line_no);
|
bail!("file '{}' line {} - syntax error (expected header)", filename, line_no);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParseState::InsideSection(plugin) => {
|
ParseState::InsideSection(plugin, ref mut config) => {
|
||||||
|
|
||||||
if line.trim().is_empty() {
|
if line.trim().is_empty() {
|
||||||
// finish section
|
// finish section
|
||||||
|
if let Err(err) = test_required_properties(config, &plugin.properties) {
|
||||||
|
bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
|
||||||
|
}
|
||||||
state = ParseState::BeforeHeader;
|
state = ParseState::BeforeHeader;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
println!("CONTENT: {}", line);
|
println!("CONTENT: {}", line);
|
||||||
if let Some((key, value)) = (self.parse_section_content)(line) {
|
if let Some((key, value)) = (self.parse_section_content)(line) {
|
||||||
println!("CONTENT: key: {} value: {}", key, value);
|
println!("CONTENT: key: {} value: {}", key, value);
|
||||||
|
|
||||||
|
if let Some((_optional, prop_schema)) = plugin.properties.properties.get::<str>(&key) {
|
||||||
|
match parse_simple_value(&value, prop_schema) {
|
||||||
|
Ok(value) => {
|
||||||
|
if config[&key] == Value::Null {
|
||||||
|
config[key] = value;
|
||||||
|
} else {
|
||||||
|
bail!("file '{}' line {} - duplicate property '{}'",
|
||||||
|
filename, line_no, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
bail!("file '{}' line {} - property '{}': {}",
|
||||||
|
filename, line_no, key, err.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bail!("file '{}' line {} - unknown property '{}'", filename, line_no, key)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bail!("file '{}' line {} - syntax error (expected section properties)", filename, line_no);
|
bail!("file '{}' line {} - syntax error (expected section properties)", filename, line_no);
|
||||||
}
|
}
|
||||||
|
@ -93,8 +124,11 @@ impl SectionConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ParseState::InsideSection(plugin) = state {
|
if let ParseState::InsideSection(plugin, ref config) = state {
|
||||||
// finish section
|
// finish section
|
||||||
|
if let Err(err) = test_required_properties(config, &plugin.properties) {
|
||||||
|
bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -170,6 +204,7 @@ fn test_section_config1() {
|
||||||
ObjectSchema::new("lvmthin properties")
|
ObjectSchema::new("lvmthin properties")
|
||||||
.required("thinpool", StringSchema::new("LVM thin pool name."))
|
.required("thinpool", StringSchema::new("LVM thin pool name."))
|
||||||
.required("vgname", StringSchema::new("LVM volume group name."))
|
.required("vgname", StringSchema::new("LVM volume group name."))
|
||||||
|
.optional("content", StringSchema::new("Storage content types."))
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut config = SectionConfig::new();
|
let mut config = SectionConfig::new();
|
||||||
|
|
Loading…
Reference in New Issue