section_config.rs: simplify parser by using new try_block macro

This commit is contained in:
Dietmar Maurer 2019-02-15 12:13:15 +01:00
parent fe651dd6e5
commit 9b50c16103
2 changed files with 71 additions and 77 deletions

View File

@ -37,18 +37,12 @@ const DATASTORE_CFG_FILENAME: &str = "/etc/proxmox-backup/datastore.cfg";
pub fn config() -> Result<SectionConfigData, Error> { pub fn config() -> Result<SectionConfigData, Error> {
let mut file = match OpenOptions::new()
.create(true)
.read(true)
.write(true)
.open(DATASTORE_CFG_FILENAME) {
Ok(file) => file,
Err(err) => bail!("Unable to open '{}' - {}",
DATASTORE_CFG_FILENAME, err),
};
let mut contents = String::new(); let mut contents = String::new();
file.read_to_string(&mut contents)?;
try_block!({
let mut file = std::fs::File::open(DATASTORE_CFG_FILENAME)?;
file.read_to_string(&mut contents)
}).map_err(|e| format_err!("unable to read '{}' - {}", DATASTORE_CFG_FILENAME, e))?;
CONFIG.parse(DATASTORE_CFG_FILENAME, &contents) CONFIG.parse(DATASTORE_CFG_FILENAME, &contents)
} }

View File

@ -145,8 +145,6 @@ impl SectionConfig {
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 state = ParseState::BeforeHeader; let mut state = ParseState::BeforeHeader;
let test_required_properties = |value: &Value, schema: &ObjectSchema| -> Result<(), Error> { let test_required_properties = |value: &Value, schema: &ObjectSchema| -> Result<(), Error> {
@ -158,87 +156,89 @@ impl SectionConfig {
Ok(()) Ok(())
}; };
let mut result = SectionConfigData::new(); let mut line_no = 0;
let mut create_section = |section_id: &str, type_name: &str, config| { try_block!({
result.set_data(section_id, type_name, config);
result.record_order(section_id);
};
for line in raw.lines() { let mut result = SectionConfigData::new();
line_no += 1;
match state { let mut create_section = |section_id: &str, type_name: &str, config| {
result.set_data(section_id, type_name, config);
result.record_order(section_id);
};
ParseState::BeforeHeader => { try_block!({
for line in raw.lines() {
line_no += 1;
if line.trim().is_empty() { continue; } match state {
if let Some((section_type, section_id)) = (self.parse_section_header)(line) { ParseState::BeforeHeader => {
//println!("OKLINE: type: {} ID: {}", section_type, section_id);
if let Some(ref plugin) = self.plugins.get(&section_type) {
if let Err(err) = parse_simple_value(&section_id, &self.id_schema) {
bail!("file '{}' line {} - syntax error in section identifier: {}",
filename, line_no, err.to_string());
}
state = ParseState::InsideSection(plugin, section_id, json!({}));
} else {
bail!("file '{}' line {} - unknown section type '{}'",
filename, line_no, section_type);
}
} else {
bail!("file '{}' line {} - syntax error (expected header)", filename, line_no);
}
}
ParseState::InsideSection(plugin, ref mut section_id, ref mut config) => {
if line.trim().is_empty() { if line.trim().is_empty() { continue; }
// finish section
if let Err(err) = test_required_properties(config, &plugin.properties) {
bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
}
create_section(section_id, &plugin.type_name, config.take());
state = ParseState::BeforeHeader;
continue;
}
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) { if let Some((section_type, section_id)) = (self.parse_section_header)(line) {
match parse_simple_value(&value, prop_schema) { //println!("OKLINE: type: {} ID: {}", section_type, section_id);
Ok(value) => { if let Some(ref plugin) = self.plugins.get(&section_type) {
if config[&key] == Value::Null { if let Err(err) = parse_simple_value(&section_id, &self.id_schema) {
config[key] = value; bail!("syntax error in section identifier: {}", err.to_string());
} else {
bail!("file '{}' line {} - duplicate property '{}'",
filename, line_no, key);
} }
state = ParseState::InsideSection(plugin, section_id, json!({}));
} else {
bail!("unknown section type '{}'", section_type);
} }
Err(err) => { } else {
bail!("file '{}' line {} - property '{}': {}", bail!("syntax error (expected header)");
filename, line_no, key, err.to_string()); }
} }
ParseState::InsideSection(plugin, ref mut section_id, ref mut config) => {
if line.trim().is_empty() {
// finish section
test_required_properties(config, &plugin.properties)?;
create_section(section_id, &plugin.type_name, config.take());
state = ParseState::BeforeHeader;
continue;
}
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!("duplicate property '{}'", key);
}
}
Err(err) => {
bail!("property '{}': {}", key, err.to_string());
}
}
} else {
bail!("unknown property '{}'", key)
}
} else {
bail!("syntax error (expected section properties)");
} }
} else {
bail!("file '{}' line {} - unknown property '{}'", filename, line_no, key)
} }
} else {
bail!("file '{}' line {} - syntax error (expected section properties)", filename, line_no);
} }
} }
}
}
if let ParseState::InsideSection(plugin, section_id, config) = state { if let ParseState::InsideSection(plugin, section_id, config) = state {
// finish section // finish section
test_required_properties(&config, &plugin.properties)?;
create_section(&section_id, &plugin.type_name, config);
}
if let Err(err) = test_required_properties(&config, &plugin.properties) { Ok(())
bail!("file '{}' line {} - {}", filename, line_no, err.to_string());
}
create_section(&section_id, &plugin.type_name, config);
}
Ok(result) }).map_err(|e| format_err!("line {} - {}", line_no, e))?;
Ok(result)
}).map_err(|e: Error| format_err!("parsing '{}' failed: {}", filename, e))
} }
pub fn default_format_section_header(type_name: &str, section_id: &str, _data: &Value) -> String { pub fn default_format_section_header(type_name: &str, section_id: &str, _data: &Value) -> String {