Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2024"

[dependencies]
chrono = "0.4.44"
clap = { version = "4", features = ["derive"] }
dotenvy = "0.15"
regex = "1"
Expand Down
19 changes: 19 additions & 0 deletions src/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,25 @@ impl TryFrom<RawEntryKind> for EntryKind {
pub fn generate_env(schema: &Schema, existing_env: &HashMap<String, String>) -> String {
let mut output = String::new();

// Add header comments and metadata
let version = option_env!("CENV_VERSION").unwrap_or("unknown");
output.push_str("# This file is auto-generated by cenv. Do not edit directly.\n");
output.push_str("# To update this file, edit the schema and run `cenv fix`.\n");
output.push_str(format!("#schema-version={}\n", version).as_str());
output.push_str(format!("#generated-at={}\n\n", chrono::Utc::now().to_rfc3339()).as_str());

// Add the key=value pairs for each entry in the schema,
// using existing env values or defaults as needed.
let env_content = generate_env_vars(schema, existing_env);
output.push_str(&env_content);

output
}

// Generates the key=value lines for the .env file based on the schema and existing env values.
fn generate_env_vars(schema: &Schema, existing_env: &HashMap<String, String>) -> String {
let mut output = String::new();

for entry in &schema.entries {
// Determine the value to use:
// 1. Use existing value from .env if present and non-empty
Expand Down
22 changes: 11 additions & 11 deletions src/schema/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn default_options() -> Entry {
default_entry()
}

// ==================== generate_env Tests ====================
// ==================== generate_env_vars Tests ====================

mod generate_env_tests {
use super::*;
Expand All @@ -40,15 +40,15 @@ mod generate_env_tests {
fn empty_schema_produces_empty_output() {
let schema = create_schema(vec![]);
let existing = HashMap::new();
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "");
}

#[test]
fn single_entry_no_existing_no_default() {
let schema = create_schema(vec![create_entry("FOO", default_options())]);
let existing = HashMap::new();
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "FOO=\n");
}

Expand All @@ -58,7 +58,7 @@ mod generate_env_tests {
opts.default = Some("bar".to_string());
let schema = create_schema(vec![create_entry("FOO", opts)]);
let existing = HashMap::new();
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "FOO=bar\n");
}

Expand All @@ -69,7 +69,7 @@ mod generate_env_tests {
let schema = create_schema(vec![create_entry("FOO", opts)]);
let mut existing = HashMap::new();
existing.insert("FOO".to_string(), "existing_value".to_string());
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "FOO=existing_value\n");
}

Expand All @@ -80,7 +80,7 @@ mod generate_env_tests {
let schema = create_schema(vec![create_entry("FOO", opts)]);
let mut existing = HashMap::new();
existing.insert("FOO".to_string(), "".to_string());
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "FOO=default_value\n");
}

Expand All @@ -89,7 +89,7 @@ mod generate_env_tests {
let schema = create_schema(vec![create_entry("FOO", default_options())]);
let mut existing = HashMap::new();
existing.insert("FOO".to_string(), "".to_string());
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "FOO=\n");
}

Expand All @@ -101,7 +101,7 @@ mod generate_env_tests {
create_entry("CCC", default_options()),
]);
let existing = HashMap::new();
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "AAA=\nBBB=\nCCC=\n");
}

Expand All @@ -118,7 +118,7 @@ mod generate_env_tests {
let mut existing = HashMap::new();
existing.insert("AAA".to_string(), "value_a".to_string());
existing.insert("CCC".to_string(), "value_c".to_string());
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "AAA=value_a\nBBB=default_b\nCCC=value_c\n");
}

Expand All @@ -129,7 +129,7 @@ mod generate_env_tests {
existing.insert("FOO".to_string(), "foo_value".to_string());
existing.insert("BAR".to_string(), "bar_value".to_string());
existing.insert("BAZ".to_string(), "baz_value".to_string());
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "FOO=foo_value\n");
}

Expand All @@ -141,7 +141,7 @@ mod generate_env_tests {
"FOO".to_string(),
"value with spaces & special=chars!".to_string(),
);
let output = generate_env(&schema, &existing);
let output = generate_env_vars(&schema, &existing);
assert_eq!(output, "FOO=value with spaces & special=chars!\n");
}
}
Expand Down