roezio/config: implement Config.write. Untested
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
bae5bdae98
commit
47530a5506
2 changed files with 50 additions and 4 deletions
|
@ -18,6 +18,8 @@ use crate::error::Error;
|
|||
use std::cell::LazyCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::io::{BufRead, BufReader, Read, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
|
@ -121,10 +123,45 @@ impl<'a> Config<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&self, _key: &str, _value: ConfigValue, _section: &str) -> Result<(), Error> {
|
||||
// TODO: Copy the file and parse it manually. If the key exists, edit it in place during
|
||||
// parsing. If it doesn't, add it at the end of the section. Replace the original file
|
||||
// atomically.
|
||||
/// Write config file with the least modification to the original file, and replace the
|
||||
/// original.
|
||||
fn write(&self, key: &str, value: ConfigValue, _section: &str) -> Result<(), Error> {
|
||||
// Copy the file
|
||||
let tempfile = self.filename.clone().with_extension("tmp");
|
||||
fs::copy(self.filename.clone(), tempfile.clone())?;
|
||||
|
||||
{
|
||||
// Parse the file, get seek offset
|
||||
let mut file = fs::File::open(tempfile.clone())?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut line = String::new();
|
||||
let mut clear_offset: u64 = 0;
|
||||
|
||||
let linestart = format!("{} ", key);
|
||||
loop {
|
||||
let len = reader.read_line(&mut line)?;
|
||||
if line.trim().starts_with(linestart.as_str()) {
|
||||
// Found offset
|
||||
break;
|
||||
}
|
||||
clear_offset = clear_offset + u64::try_from(len)?; // This can fail?
|
||||
}
|
||||
|
||||
// Keep remainder of the file in memory
|
||||
let mut remainder = String::new();
|
||||
reader.read_to_string(&mut remainder);
|
||||
|
||||
let mut file = reader.into_inner();
|
||||
|
||||
// Clear file after the found offset. If not offset was found, clears after EOF, and
|
||||
// the remainder is empty.
|
||||
file.set_len(clear_offset);
|
||||
file.write(format!("{} = {}\n", key, value).as_bytes());
|
||||
file.write(remainder.as_bytes());
|
||||
}
|
||||
|
||||
fs::rename(tempfile, self.filename.clone());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,13 @@ use crate::config::ConfigValue;
|
|||
use std::error::Error as StdError;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::num::TryFromIntError;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Error {
|
||||
IOError(io::Error),
|
||||
IntError(TryFromIntError),
|
||||
UnableToCreateConfigDir,
|
||||
InvalidConfigValueType(ConfigValue),
|
||||
InvalidValueType(String),
|
||||
|
@ -33,6 +35,7 @@ impl fmt::Display for Error {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::IOError(e) => write!(f, "io error: {}", e),
|
||||
Error::IntError(e) => write!(f, "int error: {}", e),
|
||||
Error::UnableToCreateConfigDir => write!(f, "Unable to create config dir"),
|
||||
Error::InvalidConfigValueType(err) => write!(f, "Invalid ConfigValue type: {}", err),
|
||||
Error::InvalidValueType(err) => write!(f, "Invalid value type: {}", err),
|
||||
|
@ -50,3 +53,9 @@ impl From<io::Error> for Error {
|
|||
Error::IOError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TryFromIntError> for Error {
|
||||
fn from(err: TryFromIntError) -> Error {
|
||||
Error::IntError(err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue