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::cell::LazyCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::{BufRead, BufReader, Read, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
@ -121,10 +123,45 @@ impl<'a> Config<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self, _key: &str, _value: ConfigValue, _section: &str) -> Result<(), Error> {
|
/// Write config file with the least modification to the original file, and replace the
|
||||||
// TODO: Copy the file and parse it manually. If the key exists, edit it in place during
|
/// original.
|
||||||
// parsing. If it doesn't, add it at the end of the section. Replace the original file
|
fn write(&self, key: &str, value: ConfigValue, _section: &str) -> Result<(), Error> {
|
||||||
// atomically.
|
// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,13 @@ use crate::config::ConfigValue;
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::num::TryFromIntError;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum Error {
|
pub(crate) enum Error {
|
||||||
IOError(io::Error),
|
IOError(io::Error),
|
||||||
|
IntError(TryFromIntError),
|
||||||
UnableToCreateConfigDir,
|
UnableToCreateConfigDir,
|
||||||
InvalidConfigValueType(ConfigValue),
|
InvalidConfigValueType(ConfigValue),
|
||||||
InvalidValueType(String),
|
InvalidValueType(String),
|
||||||
|
@ -33,6 +35,7 @@ impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Error::IOError(e) => write!(f, "io error: {}", e),
|
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::UnableToCreateConfigDir => write!(f, "Unable to create config dir"),
|
||||||
Error::InvalidConfigValueType(err) => write!(f, "Invalid ConfigValue type: {}", err),
|
Error::InvalidConfigValueType(err) => write!(f, "Invalid ConfigValue type: {}", err),
|
||||||
Error::InvalidValueType(err) => write!(f, "Invalid value type: {}", err),
|
Error::InvalidValueType(err) => write!(f, "Invalid value type: {}", err),
|
||||||
|
@ -50,3 +53,9 @@ impl From<io::Error> for Error {
|
||||||
Error::IOError(err)
|
Error::IOError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<TryFromIntError> for Error {
|
||||||
|
fn from(err: TryFromIntError) -> Error {
|
||||||
|
Error::IntError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue