Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update a yaml file with dynamic properties in Rust?

Consider a yaml file with the current content:

namespaces:
  production:

helmRepos:
  stable: "https://kubernetes-charts.storage.googleapis.com"

context: monitoring

apps:
  datadog:
    enabled: true
    namespace: production
    chart: stable/datadog
    version: "1.38.7"
    valuesFile: "values.yaml"

I would like to programatically update the value of the property version in this file. What would be the best way to do that?

What makes it a bit more difficult is that I don't think I can use a struct to deserialize/serialize this file, because for example the keys under helmRepos can be anything.

I have looked at the serde_yaml crate, but I couldn't figure out how to change a value in a file that has unpredictable keys and then serialize it back. I am also quite a beginner in Rust, so I might be missing something obvious because of that.

like image 631
Alex Chirițescu Avatar asked Oct 28 '25 11:10

Alex Chirițescu


1 Answers

If you want to use serde to modify your files, the basic approach is deserialize, modify, reserialize. This will remove all comments and custom formatting like empty lines from your yaml files, so I'm not sure this is the approach you want.

Using serde_yaml, there are different options to achieve this goal. The easiest in my opinion is to use the Value type, which can represent an arbitrary yaml value:

const DOC: &str = r#"namespaces:
  production:

helmRepos:
  stable: "https://kubernetes-charts.storage.googleapis.com"

context: monitoring

apps:
  datadog:
    enabled: true
    namespace: production
    chart: stable/datadog
    version: "1.38.7"
    valuesFile: "values.yaml"
"#;

fn main() {
    let mut value: serde_yaml::Value = serde_yaml::from_str(DOC).unwrap();
    *value
        .get_mut("apps")
        .unwrap()
        .get_mut("datadog")
        .unwrap()
        .get_mut("version")
        .unwrap() = "1.38.8".into();
    serde_yaml::to_writer(std::io::stdout(), &value).unwrap();
}

Playground

You probably want proper error handling instead of using unwrap() everywhere. If you are fine with using unwrap() the above code can be simplified to

let mut value: serde_yaml::Value = serde_yaml::from_str(DOC).unwrap();
value["apps"]["datadog"]["version"] = "1.38.8".into();
serde_yaml::to_writer(std::io::stdout(), &value).unwrap();

If you don't want to lose comments and empty lines, things get a lot more tricky. The proper solution for that goal is to use the yaml_rust crate to parse your files and determine what line to change. However, you can probably get away with some ad-hoc approach for finding the right line if you don't need your code to be robust.

like image 86
Sven Marnach Avatar answered Oct 30 '25 06:10

Sven Marnach