153 lines
5.0 KiB
Rust
153 lines
5.0 KiB
Rust
use std::io::Write;
|
|
|
|
#[derive(Clone, Copy)]
|
|
pub enum EnvFileType {
|
|
DotEnv,
|
|
Yaml,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct EnvFile {
|
|
pub file_type: EnvFileType,
|
|
//
|
|
buffer: serde_json::Value,
|
|
}
|
|
|
|
impl EnvFile {
|
|
pub fn new(file_type: EnvFileType) -> Self {
|
|
EnvFile {
|
|
file_type,
|
|
buffer: serde_json::Value::Object(serde_json::Map::new()),
|
|
}
|
|
}
|
|
|
|
pub fn write_line(&mut self, key: &str, value: &str) {
|
|
self._write_line_buffer(key, value);
|
|
}
|
|
|
|
pub fn write(&mut self, stream: &mut dyn Write, with_prefix: bool) {
|
|
self._write_buffer(stream, with_prefix);
|
|
}
|
|
|
|
fn key_into_buffer_key(&self, key: &str) -> Vec<String> {
|
|
key.split("__").map(String::from).collect()
|
|
}
|
|
|
|
fn _write_line_buffer(&mut self, key: &str, value: &str) {
|
|
let buffer_key = self.key_into_buffer_key(key);
|
|
let mut current = &mut self.buffer;
|
|
for k in &buffer_key[0..(buffer_key.len() - 1)] {
|
|
if current.get(k).is_none() {
|
|
current[k] = serde_json::Value::Object(serde_json::Map::new());
|
|
}
|
|
current = &mut current[k];
|
|
}
|
|
current[buffer_key.last().unwrap()] = serde_json::Value::String(value.to_string());
|
|
}
|
|
|
|
fn _write_buffer(&self, file: &mut dyn Write, with_prefix: bool) {
|
|
match self.file_type {
|
|
EnvFileType::DotEnv => self._write_buffer_env(file, with_prefix),
|
|
EnvFileType::Yaml => self._write_buffer_yaml(file),
|
|
}
|
|
}
|
|
|
|
fn _write_buffer_env(&self, file: &mut dyn Write, with_prefix: bool) {
|
|
fn _write_buffer_env_layer(
|
|
file: &mut dyn Write,
|
|
buffer: &serde_json::Value,
|
|
prefix: String,
|
|
with_root_prefix: bool,
|
|
) {
|
|
if let serde_json::Value::Object(map) = buffer {
|
|
for (key, value) in map {
|
|
let current_key = if prefix.is_empty() {
|
|
if with_root_prefix {
|
|
format!("YANPM__{}", key)
|
|
} else {
|
|
key.to_string()
|
|
}
|
|
} else {
|
|
format!("{}__{}", prefix, key)
|
|
};
|
|
match value {
|
|
serde_json::Value::Object(_) => {
|
|
_write_buffer_env_layer(file, value, current_key, with_root_prefix);
|
|
}
|
|
_ => {
|
|
writeln!(file, "{}={}", current_key, value).unwrap();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_write_buffer_env_layer(file, &self.buffer, String::new(), with_prefix);
|
|
}
|
|
|
|
fn _write_buffer_yaml(&self, file: &mut dyn Write) {
|
|
let mut layer = 0;
|
|
fn _write_buffer_yaml_layer(
|
|
file: &mut dyn Write,
|
|
buffer: &serde_json::Value,
|
|
layer: &mut usize,
|
|
) {
|
|
if let serde_json::Value::Object(map) = buffer {
|
|
for (key, value) in map {
|
|
let indent = " ".repeat(*layer);
|
|
match value {
|
|
serde_json::Value::Object(_) => {
|
|
writeln!(file, "{}{}:", indent, key).unwrap();
|
|
*layer += 1;
|
|
_write_buffer_yaml_layer(file, value, layer);
|
|
*layer -= 1;
|
|
}
|
|
_ => {
|
|
writeln!(file, "{}{}: {}", indent, key, value).unwrap();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_write_buffer_yaml_layer(file, &self.buffer, &mut layer);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_env_file_write_yaml() {
|
|
let mut env_file_nested = EnvFile::new(EnvFileType::Yaml);
|
|
|
|
env_file_nested.write_line("DATABASE__TYPE", "SQLite");
|
|
env_file_nested.write_line("DATABASE__URL", "mysql://user:pass@localhost/db");
|
|
let mut output_stream = Vec::new();
|
|
env_file_nested.write(&mut output_stream, false);
|
|
let output_string = String::from_utf8(output_stream).unwrap();
|
|
let expected_output = "\
|
|
DATABASE:
|
|
TYPE: \"SQLite\"
|
|
URL: \"mysql://user:pass@localhost/db\"
|
|
";
|
|
assert_eq!(output_string, expected_output);
|
|
}
|
|
|
|
#[test]
|
|
fn test_env_file_write_env() {
|
|
let mut env_file_nested = EnvFile::new(EnvFileType::DotEnv);
|
|
env_file_nested.write_line("DATABASE__TYPE", "PostgreSQL");
|
|
env_file_nested.write_line("DATABASE__URL", "postgres://user:pass@localhost/db");
|
|
let mut output_stream = Vec::new();
|
|
env_file_nested.write(&mut output_stream, true);
|
|
let output_string = String::from_utf8(output_stream).unwrap();
|
|
let expected_output = "\
|
|
YANPM__DATABASE__TYPE=\"PostgreSQL\"
|
|
YANPM__DATABASE__URL=\"postgres://user:pass@localhost/db\"
|
|
";
|
|
assert_eq!(output_string, expected_output);
|
|
}
|
|
}
|