Skip to content

Commit

Permalink
feat: Show diff of entire file after inserting or deleting vars
Browse files Browse the repository at this point in the history
  • Loading branch information
schpet committed Sep 22, 2024
1 parent 0e219e9 commit 2e67ebb
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 131 deletions.
7 changes: 7 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 @@ -25,6 +25,7 @@ serde_json = "1.0.128"
serde = { version = "1.0.210", features = ["derive"] }
peg = "0.8.4"
chumsky = "0.9.3"
similar = "2.6.0"

[dev-dependencies]
strip-ansi-escapes = "0.2.0"
Expand Down
82 changes: 31 additions & 51 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod parser;

use chumsky::Parser;
use colored::Colorize;
use serde_json::{self, json};
use serde_json::json;
use std::collections::HashMap;
use std::fs;
use std::io::{self, Read, Write};
Expand Down Expand Up @@ -53,9 +53,15 @@ pub fn print_env_vars_as_json<W: Write>(file_path: &str, writer: &mut W) {
}
}

pub fn print_env_file(file_path: &str, env_vars: &HashMap<String, String>) -> std::io::Result<()> {
let content = fs::read_to_string(file_path).unwrap_or_default();
let mut lines = parser::parser().parse(&*content).map_err(|e| {
pub fn read_env_file_contents(file_path: &str) -> std::io::Result<String> {
fs::read_to_string(file_path)
}

pub fn add_env_vars(
content: &str,
env_vars: &HashMap<String, String>,
) -> Result<Vec<parser::Line>, std::io::Error> {
let mut lines = parser::parser().parse(content).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Error parsing .env file: {:?}", e),
Expand Down Expand Up @@ -90,9 +96,22 @@ pub fn print_env_file(file_path: &str, env_vars: &HashMap<String, String>) -> st
}
}

let mut buffer = Vec::new();
print_lines(&lines, &mut buffer, false);
Ok(lines)
}

pub fn print_env_file_contents<W: Write>(
lines: &[parser::Line],
writer: &mut W,
) -> std::io::Result<()> {
print_lines(lines, writer, false);
Ok(())
}

pub fn update_env_file(file_path: &str, env_vars: &HashMap<String, String>) -> std::io::Result<()> {
let content = read_env_file_contents(file_path).unwrap_or_default();
let lines = add_env_vars(&content, env_vars)?;
let mut buffer = Vec::new();
print_env_file_contents(&lines, &mut buffer)?;
fs::write(file_path, buffer)
}

Expand Down Expand Up @@ -206,48 +225,17 @@ pub fn print_env_keys_to_writer<W: Write>(file_path: &str, writer: &mut W) {
}
}

pub fn print_diff<W: Write>(
original: &HashMap<String, String>,
updated: &HashMap<String, String>,
writer: &mut W,
) {
for key in updated.keys() {
let updated_value = updated.get(key).unwrap();
match original.get(key) {
Some(original_value) if original_value != updated_value => {
writeln!(writer, "{}", format!("-{}={}", key, original_value).red()).unwrap();
writeln!(writer, "{}", format!("+{}={}", key, updated_value).green()).unwrap();
}
None => {
writeln!(writer, "{}", format!("+{}={}", key, updated_value).green()).unwrap();
}
_ => {}
}
}

for key in original.keys() {
if !updated.contains_key(key) {
writeln!(
writer,
"{}",
format!("-{}={}", key, original.get(key).unwrap()).red()
)
.unwrap();
}
}
}

pub fn delete_keys(file_path: &str, keys: &[String]) -> std::io::Result<()> {
let content = fs::read_to_string(file_path)?;
let lines = parser::parser().parse(&*content).map_err(|e| {
pub fn delete_env_vars(
content: &str,
keys: &[String],
) -> Result<Vec<parser::Line>, std::io::Error> {
let lines = parser::parser().parse(content).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Error parsing .env file: {:?}", e),
)
})?;

let original_env = parse_env_content(&content);

let updated_lines: Vec<parser::Line> = lines
.into_iter()
.filter(|line| {
Expand All @@ -259,15 +247,7 @@ pub fn delete_keys(file_path: &str, keys: &[String]) -> std::io::Result<()> {
})
.collect();

let mut buffer = Vec::new();
print_lines(&updated_lines, &mut buffer, false);

fs::write(file_path, &buffer)?;

let updated_env = parse_env_content(&String::from_utf8_lossy(&buffer));
print_diff(&original_env, &updated_env, &mut std::io::stdout());

Ok(())
Ok(updated_lines)
}

fn needs_quoting(value: &str) -> bool {
Expand Down
104 changes: 91 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,41 @@
use atty::Stream;
use clap::Parser;
use colored::Colorize;
use similar::{ChangeTag, TextDiff};
use std::collections::HashMap;
use std::process;

use envset::{
parse_args, parse_stdin, print_diff, print_env_file, print_env_keys_to_writer, print_env_vars,
print_env_vars_as_json, print_parse_tree, read_env_vars,
add_env_vars, parse_args, parse_stdin, print_env_file_contents, print_env_keys_to_writer,
print_env_vars, print_env_vars_as_json, print_parse_tree, read_env_file_contents,
read_env_vars,
};

fn print_diff(old_content: &str, new_content: &str, use_color: bool) {
let diff = TextDiff::from_lines(old_content, new_content);

for change in diff.iter_all_changes() {
if use_color {
match change.tag() {
ChangeTag::Delete => print!("{}", change.to_string().trim_end().on_bright_red()),
ChangeTag::Insert => print!("{}", change.to_string().trim_end().on_bright_green()),
ChangeTag::Equal => print!("{}", change),
}
// Print a newline after each colored line
if change.tag() != ChangeTag::Equal {
println!();
}
} else {
let sign = match change.tag() {
ChangeTag::Delete => "-",
ChangeTag::Insert => "+",
ChangeTag::Equal => " ",
};
print!("{}{}", sign, change);
}
}
}

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -86,12 +114,42 @@ fn main() {
Some(Commands::Keys) => {
print_env_keys_to_writer(&cli.file, &mut std::io::stdout());
}
Some(Commands::Delete { keys }) => {
if let Err(e) = envset::delete_keys(&cli.file, keys) {
eprintln!("Error deleting environment variables: {}", e);
Some(Commands::Delete { keys }) => match read_env_file_contents(&cli.file) {
Ok(old_content) => match envset::delete_env_vars(&old_content, keys) {
Ok(updated_lines) => {
let mut buffer = Vec::new();
if let Err(e) = print_env_file_contents(&updated_lines, &mut buffer) {
eprintln!("Error writing .env file contents: {}", e);
process::exit(1);
}
let new_content = String::from_utf8_lossy(&buffer);

if old_content == new_content {
eprintln!(
"No environment variables found to delete. Attempted to delete: {}",
keys.join(", ")
);
process::exit(1);
}

let use_color = atty::is(Stream::Stdout);
print_diff(&old_content, &new_content, use_color);

if let Err(e) = std::fs::write(&cli.file, buffer) {
eprintln!("Error writing .env file: {}", e);
process::exit(1);
}
}
Err(e) => {
eprintln!("Error deleting environment variables: {}", e);
process::exit(1);
}
},
Err(e) => {
eprintln!("Error reading .env file: {}", e);
process::exit(1);
}
}
},
None => {}
}

Expand Down Expand Up @@ -120,20 +178,40 @@ fn main() {
}
};

let original_env = env_vars.clone();

for (key, value) in &new_vars {
if !env_vars.contains_key(key as &str) || !no_overwrite {
env_vars.insert(key.clone(), value.clone());
}
}

if let Err(e) = print_env_file(&cli.file, &env_vars) {
eprintln!("Error writing .env file: {}", e);
process::exit(1);
match read_env_file_contents(&cli.file) {
Ok(old_content) => match add_env_vars(&old_content, &env_vars) {
Ok(updated_lines) => {
let mut buffer = Vec::new();
if let Err(e) = print_env_file_contents(&updated_lines, &mut buffer) {
eprintln!("Error writing .env file contents: {}", e);
process::exit(1);
}
let new_content = String::from_utf8_lossy(&buffer);

let use_color = atty::is(Stream::Stdout);
print_diff(&old_content, &new_content, use_color);

if let Err(e) = std::fs::write(&cli.file, buffer) {
eprintln!("Error writing .env file: {}", e);
process::exit(1);
}
}
Err(e) => {
eprintln!("Error updating .env file contents: {}", e);
process::exit(1);
}
},
Err(e) => {
eprintln!("Error reading .env file: {}", e);
process::exit(1);
}
}

print_diff(&original_env, &env_vars, &mut std::io::stdout());
}

if should_print {
Expand Down
Loading

0 comments on commit 2e67ebb

Please sign in to comment.