diff --git a/.env.example b/.env.example index e69de29..50d500b 100644 --- a/.env.example +++ b/.env.example @@ -0,0 +1,5 @@ +HELLO=string +TAYLOR=string +AGE=int +SCORE=float +ACTIVE=bool diff --git a/Cargo.lock b/Cargo.lock index 8eeb4d4..286d0b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,6 +50,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + [[package]] name = "clap" version = "4.4.14" @@ -110,6 +116,7 @@ dependencies = [ name = "envy" version = "0.3.0" dependencies = [ + "anyhow", "clap", "colored", "indexmap", diff --git a/Cargo.toml b/Cargo.toml index 196fb8f..52ec9a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] + clap = { version = "4.4.14", features = ["derive"] } colored = "2.1.0" indexmap = "2.1.0" +anyhow = "1.0.79" diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..1a89b3d --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,12 @@ +pre-commit: + commands: + format: + glob: "*.rs" + run: cargo fmt + + check: + run: "cargo check" + + test: + run: "cargo test" + diff --git a/src/common.rs b/src/common.rs new file mode 100644 index 0000000..ca6bb2d --- /dev/null +++ b/src/common.rs @@ -0,0 +1,27 @@ +#[derive(Debug, PartialEq)] +pub enum SupportedFormats { + ENV, + TOML, + YAML, + INVALID, +} + +impl SupportedFormats { + pub fn to_string(&self) -> String { + match self { + SupportedFormats::ENV => "env", + SupportedFormats::TOML => "toml", + SupportedFormats::YAML => "yaml", + _ => "invalid", + } + .to_string() + } + + pub fn supported_formats() -> Vec { + return vec![ + SupportedFormats::ENV.to_string(), + SupportedFormats::TOML.to_string(), + SupportedFormats::YAML.to_string(), + ]; + } +} diff --git a/src/io_manager.rs b/src/dotenv_handler.rs similarity index 74% rename from src/io_manager.rs rename to src/dotenv_handler.rs index f6915f0..7737c58 100644 --- a/src/io_manager.rs +++ b/src/dotenv_handler.rs @@ -1,32 +1,13 @@ -use colored::*; use indexmap::IndexMap; use std::fs::File; use std::io::prelude::*; use std::io::{BufRead, BufReader, Error}; -static SUPPORTED_FORMATS: [&str; 1] = ["env"]; +use anyhow::Result; #[allow(dead_code)] -fn read_dot_env(path: &str) -> Result, Error> { +fn read_dotenv(path: &str) -> Result, Error> { let mut env = IndexMap::new(); - if std::path::Path::new(path).exists() == false { - println!("{} {}", "❌ Error:".red(), "File not found".bold()); - std::process::exit(1); - } - let format = path.split('.').last().unwrap(); - if SUPPORTED_FORMATS.contains(&format) == false { - println!( - "{} {}", - "❌ Error:".red(), - "Unsupported file format".bold() - ); - println!( - "{} {}", - "Supported formats:".bold(), - SUPPORTED_FORMATS.join(", ").bold() - ); - std::process::exit(1); - } let file = File::open(path)?; let reader = BufReader::new(file); for line in reader.lines() { @@ -65,17 +46,6 @@ fn get_type(value: &str) -> &str { } } -#[allow(dead_code)] -fn generate_dot_env_string(env: IndexMap) -> String { - let mut env_string = String::new(); - for (key, val) in env { - let val_type = get_type(&val); - env_string.push_str(&format!("{}={}\n", key, val_type)); - } - env_string = env_string.strip_suffix("\n").unwrap().to_string(); - env_string -} - fn remove_comments(text: &str) -> String { let mut text = text.to_string(); // From: # This is a comment, To: "" @@ -86,9 +56,20 @@ fn remove_comments(text: &str) -> String { text } -pub fn generate_dot_env_file(dry_run: bool, path: &str) -> Result<(), Error> { - let env = read_dot_env(path)?; - let mut env_string = generate_dot_env_string(env); +#[allow(dead_code)] +fn generate_dotenv_string(env: IndexMap) -> Result { + let mut env_string = String::new(); + for (key, val) in env { + let val_type = get_type(&val); + env_string.push_str(&format!("{}={}\n", key, val_type)); + } + env_string = env_string.strip_suffix("\n").unwrap().to_string(); + Ok(env_string) +} + +pub fn generate_dotenv_file(dry_run: bool, path: &str) -> Result<()> { + let env = read_dotenv(path)?; + let mut env_string = generate_dotenv_string(env)?; env_string.push_str("\n"); let mut file = File::create(".env.example")?; if dry_run { @@ -105,7 +86,7 @@ mod tests { #[test] fn test_read_env() { - let env = read_dot_env("test.env").unwrap(); + let env = read_dotenv("test.env").unwrap(); assert_eq!(env.get("HELLO").unwrap(), "ADELE"); assert_eq!(env.get("TAYLOR").unwrap(), "SWIFT"); } @@ -123,11 +104,11 @@ mod tests { } #[test] - fn test_generate_dot_env_string() { + fn test_generate_dotenv_string() { let mut env = IndexMap::new(); env.insert("HELLO".to_string(), "ADELE".to_string()); env.insert("WORLD".to_string(), "21".to_string()); - let env_string = generate_dot_env_string(env); + let env_string = generate_dotenv_string(env).unwrap(); assert_eq!(env_string, "HELLO=string\nWORLD=int"); } @@ -145,14 +126,14 @@ mod tests { } #[test] - fn test_generate_dot_env_file() { - generate_dot_env_file(false, "test.env").unwrap(); + fn test_generate_dotenv_file() { + generate_dotenv_file(false, "test.env").unwrap(); let mut file = File::open(".env.example").unwrap(); let mut contents = String::new(); file.read_to_string(&mut contents).unwrap(); assert_eq!( contents, - "HELLO=string\nTAYLOR=string\nAGE=int\nSCORE=float\nACTIVE=bool" + "HELLO=string\nTAYLOR=string\nAGE=int\nSCORE=float\nACTIVE=bool\n" ); } } diff --git a/src/main.rs b/src/main.rs index c3d03dd..ce275c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,35 @@ -mod io_manager; +mod common; +mod dotenv_handler; +mod utils; use clap::{ArgAction, Command}; use colored::*; -use io_manager::generate_dot_env_file; +use common::SupportedFormats; +use dotenv_handler::generate_dotenv_file; +use utils::validate_file; fn generate(val: &clap::ArgMatches) { let path = val.get_one::("path").unwrap(); + let format = validate_file(&path); let dry_run: bool = val.get_flag("dry-run"); - generate_dot_env_file(dry_run, &path).unwrap(); + match format { + SupportedFormats::ENV => { + let _ = generate_dotenv_file(dry_run, &path); + } + _ => { + println!( + "{} {}", + "❌ Error:".red(), + "Unsupported file format".bold() + ); + println!( + "{} {}", + "Supported formats:".bold(), + SupportedFormats::supported_formats().join(", ").bold() + ); + std::process::exit(1); + } + } if !dry_run { println!( "{} {}", diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..09cf27e --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,42 @@ +use crate::common::SupportedFormats; +use colored::*; + +fn _extract_file_format(path: &str) -> SupportedFormats { + let file_extension = path.split('.').last().unwrap(); + match file_extension { + "env" => SupportedFormats::ENV, + "toml" => SupportedFormats::TOML, + "yaml" => SupportedFormats::YAML, + _ => SupportedFormats::INVALID, + } +} + +fn _check_file_format(path: &str) -> SupportedFormats { + let format = _extract_file_format(path); + if format == SupportedFormats::INVALID { + println!( + "{} {}", + "❌ Error:".red(), + "Unsupported file format".bold() + ); + println!( + "{} {}", + "Supported formats:".bold(), + SupportedFormats::supported_formats().join(", ").bold() + ); + std::process::exit(1); + } + return format; +} + +fn _check_path_exists(path: &str) { + if std::path::Path::new(path).exists() == false { + println!("{} {}", "❌ Error:".red(), "File not found".bold()); + std::process::exit(1); + } +} + +pub fn validate_file(path: &str) -> SupportedFormats { + _check_path_exists(path); + _check_file_format(path) +} diff --git a/test.env b/test.env index 5667fe0..ea438dd 100644 --- a/test.env +++ b/test.env @@ -7,3 +7,5 @@ AGE=25 ACTIVE =true # + + \ No newline at end of file