section_config: improve parser
This commit is contained in:
		@ -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 {
 | 
			
		||||
        Schema::Null => {
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ pub struct SectionConfig {
 | 
			
		||||
 | 
			
		||||
enum ParseState<'a> {
 | 
			
		||||
    BeforeHeader,
 | 
			
		||||
    InsideSection(&'a SectionConfigPlugin),
 | 
			
		||||
    InsideSection(&'a SectionConfigPlugin, Value),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SectionConfig {
 | 
			
		||||
@ -53,6 +53,15 @@ impl SectionConfig {
 | 
			
		||||
 | 
			
		||||
        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() {
 | 
			
		||||
            line_no += 1;
 | 
			
		||||
 | 
			
		||||
@ -67,7 +76,7 @@ impl SectionConfig {
 | 
			
		||||
                    if let Some((section_type, section_id)) = (self.parse_section_header)(line) {
 | 
			
		||||
                        println!("OKLINE: type: {} ID: {}", section_type, section_id);
 | 
			
		||||
                        if let Some(ref plugin) = self.plugins.get(§ion_type) {
 | 
			
		||||
                            state = ParseState::InsideSection(plugin);
 | 
			
		||||
                            state = ParseState::InsideSection(plugin, json!({}));
 | 
			
		||||
                        } else {
 | 
			
		||||
                            bail!("file '{}' line {} - unknown section type '{}'",
 | 
			
		||||
                                  filename, line_no, section_type);
 | 
			
		||||
@ -76,16 +85,38 @@ impl SectionConfig {
 | 
			
		||||
                        bail!("file '{}' line {} - syntax error (expected header)", filename, line_no);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                ParseState::InsideSection(plugin) => {
 | 
			
		||||
                ParseState::InsideSection(plugin, ref mut config) => {
 | 
			
		||||
 | 
			
		||||
                    if line.trim().is_empty() {
 | 
			
		||||
                        // finish section
 | 
			
		||||
                        if let Err(err) = test_required_properties(config, &plugin.properties) {
 | 
			
		||||
                            bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
 | 
			
		||||
                        }
 | 
			
		||||
                        state = ParseState::BeforeHeader;
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                    println!("CONTENT: {}", line);
 | 
			
		||||
                    if let Some((key, value)) = (self.parse_section_content)(line) {
 | 
			
		||||
                        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 {
 | 
			
		||||
                        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
 | 
			
		||||
            if let Err(err) = test_required_properties(config, &plugin.properties) {
 | 
			
		||||
                bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
@ -170,6 +204,7 @@ fn test_section_config1() {
 | 
			
		||||
        ObjectSchema::new("lvmthin properties")
 | 
			
		||||
            .required("thinpool", StringSchema::new("LVM thin pool name."))
 | 
			
		||||
            .required("vgname", StringSchema::new("LVM volume group name."))
 | 
			
		||||
            .optional("content", StringSchema::new("Storage content types."))
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let mut config = SectionConfig::new();
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user