rust-cli / confy

🛋 Zero-boilerplate configuration management in Rust
Other
896 stars 59 forks source link

When config file shrinks it breaks syntax #9

Closed webdesserts closed 5 years ago

webdesserts commented 5 years ago

Confy seems to work fine as long as you're adding information to the config file, but as soon as you remove anything from the config, confy breaks. For example, consider the following code:

extern crate confy;
#[macro_use] extern crate serde_derive;
use std::default::{Default};

#[derive(Serialize, Deserialize)]
struct Config {
    lines: Vec<i32>
}

impl Default for Config {
    fn default() -> Self {
        Self {
            lines: vec![1, 2, 3]
        }
    }
}

fn main() -> Result<(), std::io::Error> {
    let mut config: Config = confy::load("confy-bug")?;
    confy::store("confy-bug", config)
}

If you run the above code you will produce the following output as expected:

lines = [
    1,
    2,
    3,
]

however if you add the following:

 fn main() -> Result<(), std::io::Error> {
     let mut config: Config = confy::load("confy-bug")?;
+    config.lines.clear();
     confy::store("confy-bug", config)
 }

You will instead end up with this syntactically incorrect file:

lines = []
   1,
    2,
    3,
]

It seems that confy is just writing on top of the old file without cleaning up any excess lines left over from the last write.


I was able to fix the issue locally by making the following changes:

diff --git a/src/lib.rs b/src/lib.rs
index f468e89..cb3e03b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -143,7 +143,7 @@ pub fn store<T: Serialize>(name: &str, cfg: T) -> Result<(), IoError> {
     ].iter()
         .collect();

-    let mut f = OpenOptions::new().write(true).create(true).open(path)?;
+    let mut f = OpenOptions::new().write(true).create(true).truncate(true).open(path)?;
     let s = toml::to_string_pretty(&cfg).unwrap();
     f.write_all(s.as_bytes())?;
     Ok(())
tskardal commented 5 years ago

This also applies when saving strings with value that is shorter than the existing one in the file!

Example:

hello = '12345'

Then saving (using confy::store) with hello='1' will result in

hello = '1'
45'

This is also fixed by the suggested change in #10