Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mrnerdhair committed Feb 14, 2021
1 parent 148777c commit c44eee7
Show file tree
Hide file tree
Showing 4 changed files with 347 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
246 changes: 246 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "toml-merge"
version = "0.1.0"
description = "Simple CLI utility which merges TOML files."
authors = ["Reid Rankin <[email protected]>"]
license = "ISC"
repository = "https://github.com/reidrankin/toml-merge"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
json = "0.12.4"
structopt = "0.3.21"
toml = "0.5.8"
85 changes: 85 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use json;
use std::{
fs,
path::PathBuf,
};
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
struct Opt {
/// Output as JSON
#[structopt(short, long)]
json_out: bool,

/// Input files. These will be merged in order, so later files take precedence.
#[structopt(name = "FILE", parse(from_os_str))]
files: Vec<PathBuf>,
}

fn merge(merged: &mut toml::Value, value: &toml::Value) {
match value {
toml::Value::String(_) |
toml::Value::Integer(_) |
toml::Value::Float(_) |
toml::Value::Boolean(_) |
toml::Value::Datetime(_) => *merged = value.clone(),
toml::Value::Array(x) => {
match merged {
toml::Value::Array(merged) => {
for (k, v) in x.iter().enumerate() {
match merged.get_mut(k) {
Some(x) => merge(x, v),
None => {
let _ = merged.insert(k.clone(), v.clone());
},
}
}
},
_ => *merged = value.clone(),
}
},
toml::Value::Table(x) => {
match merged {
toml::Value::Table(merged) => {
for (k, v) in x.iter() {
match merged.get_mut(k) {
Some(x) => merge(x, v),
None => {
let _ = merged.insert(k.clone(), v.clone());
},
}
}
},
_ => *merged = value.clone(),
}
},
}
}

fn toml_to_json(x: toml::Value) -> json::JsonValue {
match x {
toml::Value::String(x) => json::JsonValue::String(x),
toml::Value::Integer(x) => json::JsonValue::Number(x.into()),
toml::Value::Float(x) => json::JsonValue::Number(x.into()),
toml::Value::Boolean(x) => json::JsonValue::Boolean(x),
toml::Value::Datetime(x) => json::JsonValue::String(x.to_string()),
toml::Value::Array(x) => json::JsonValue::Array(x.into_iter().map(toml_to_json).collect()),
toml::Value::Table(x) => json::JsonValue::Object(x.into_iter().map(|(k, v)| (k, toml_to_json(v))).collect()),
}
}

fn main() {
let opt = Opt::from_args();

let mut merged: toml::Value = toml::Value::Table(toml::value::Table::new());
for file in opt.files.iter() {
let value: toml::value::Table = toml::from_slice(&fs::read(file).expect(&format!("Error reading {:?}", file))).expect(&format!("Expected TOML table in {:?}", file));
merge(&mut merged, &toml::Value::Table(value));
}

if opt.json_out {
println!("{}", json::stringify(toml_to_json(merged)));
} else {
println!("{}", merged.to_string());
}
}

0 comments on commit c44eee7

Please sign in to comment.