From 16489d26df9f6f68a240ec073836bfb1a604ee32 Mon Sep 17 00:00:00 2001 From: Matt Carlotta Date: Wed, 18 Sep 2024 11:40:19 -0700 Subject: [PATCH] feat: update GitHub actions and fix code formatting --- .github/ISSUE_TEMPLATE/bug_report.md | 3 +- .github/workflows/release.yml | 64 ++++---- clippy.toml | 1 + docs/README.md | 34 ++-- docs/nvi.1 | 234 --------------------------- examples/rust/src/main.rs | 4 +- rustfmt.toml | 3 + src/api.rs | 42 ++--- src/arg/arg.rs | 62 +++---- src/arg/arg_parser.rs | 90 +++++------ src/arg/mod.rs | 2 +- src/generator.rs | 25 ++- src/globals.rs | 46 +++--- src/lexer/lexer.rs | 21 ++- src/lexer/lexer_token.rs | 27 ++-- src/logger.rs | 10 +- src/options.rs | 18 +-- src/parser.rs | 8 +- 18 files changed, 231 insertions(+), 463 deletions(-) create mode 100644 clippy.toml delete mode 100644 docs/nvi.1 create mode 100644 rustfmt.toml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5bcf2b20..45e3904e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,7 +11,6 @@ Feature requests should be opened using the feature request template. Please complete the following information: - Binary Version [e.g. 0.0.1] - OS and Version: [e.g. Linux Mint 21.2] -- Compiler and Version [e.g. g++ v11.3.0+] ## Describe the bug A clear and concise description of what the bug is. @@ -24,7 +23,7 @@ A clear and concise description of what the bug is. 5. See error ## Debug logs -Run the binary with the `-de` or `--debug` flag and please provide any applicable debug logs. +Run the binary with the `--debug` flag and please provide any applicable debug logs. ## Expected behavior A clear and concise description of what you expected to happen. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ad0a25e4..2f39084f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,42 +16,55 @@ jobs: fail-fast: true matrix: toolchain: - - {runs_on: ubuntu-latest, name: "Linux x86_64", archive_name: "linux-x86_64", cpus: "$(nproc --all)"} - - {runs_on: macos-11, name: "macOS x86_64", archive_name: "macos-x86_64", cpus: "$(sysctl -n hw.ncpu)"} - - {runs_on: macos-14, name: "macOS AArch64", archive_name: "macos-aarch64", cpus: "$(sysctl -n hw.ncpu)"} + - {runs_on: ubuntu-latest, name: "Linux x86_64", archive_name: "linux-x86_64"} + - {runs_on: macos-11, name: "macOS x86_64", archive_name: "macos-x86_64"} + - {runs_on: macos-14, name: "macOS AArch64", archive_name: "macos-aarch64"} steps: - - uses: actions/checkout@v4 + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup Rust Toolchain + uses: actions-rs/toolchain@v1 with: - submodules: "recursive" - fetch-depth: 0 + toolchain: stable + components: rustfmt, clippy - - name: install dependencies + - name: Install Dependencies if: ${{ matrix.toolchain.archive_name == 'linux-x86_64' }} run: | sudo apt-get -y update - sudo apt-get -y install libcurl4-openssl-dev + sudo apt-get -y install pandoc - - name: build - run: | - cmake -DCOMPILE_SRC=ON -DCOMPILE_TESTS=ON -DUSE_LOCALHOST_API=OFF . - cmake --build . -j ${{ matrix.toolchain.cpus }} + - name: Install Dependencies + if: ${{ matrix.toolchain.archive_name != 'linux-x86_64' }} + run: brew install pandoc + + - name: format Assets + run: cargo fmt --verbose --all --check - - name: test + - name: Lint Assets + run: cargo clippy -- -Dwarnings + + - name: Build Assets run: | - cd tests - ./tests - cd ../ + cargo build --release + cd docs + pandoc --standalone --to man nvi.1.md -o nvi.1 + + - name: Run Tests + run: cargo test - - name: compress + - name: Compress Assets run: | mkdir -p nvi/bin mkdir -p nvi/man - cp ./src/nvi nvi/bin/ + cp ./target/release/nvi nvi/bin/ cp ./docs/nvi.1 nvi/man/ tar -zcvf ./nvi-${{ matrix.toolchain.archive_name }}.tar.gz nvi - - uses: actions/upload-artifact@v4 + - name: Upload Assets + uses: actions/upload-artifact@v4 with: if-no-files-found: error name: nvi-${{ matrix.toolchain.archive_name }} @@ -73,13 +86,8 @@ jobs: - uses: actions/download-artifact@v4 - - if: github.event_name == 'push' - run: | - TAG_NAME=${{ github.ref }} - echo "TAG_NAME=${TAG_NAME#refs/tags/}" >> $GITHUB_ENV + - name: Set Tag Name + run: TAG_NAME=${{ github.ref }} - - name: publish release - env: - DEBUG: api - run: | - gh release create $TAG_NAME --generate-notes --title "$TAG_NAME" --target $GITHUB_SHA nvi-macos-x86_64/* nvi-macos-aarch64/* nvi-linux-x86_64/* + - name: Publish Release + run: gh release create $TAG_NAME --generate-notes --title "$TAG_NAME" --target $GITHUB_SHA nvi-macos-x86_64/* nvi-macos-aarch64/* nvi-linux-x86_64/* diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000..787620d8 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +allow-private-module-inception = true diff --git a/docs/README.md b/docs/README.md index 8dc8fbf9..00dc9531 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,30 +1,36 @@ # NVI Man Documentation -This documentation has been pre-built and exists [here](nvi.1). +Man documentation nvi CLI tool. -# Usage +## Requirements +- pandoc v3.1.6+ (click [here](https://pandoc.org/MANUAL.html) for documentation) + +## Manually Build +```bash +git clone git@github.com:mattcarlotta/nvi.git +cd docs +pandoc --standalone --to man nvi.1.md -o nvi.1 +``` +Man from local directory: ```bash man ./nvi.1 ``` -# System Installation +## System Installation Locate directory paths that `man` searches within by running one of the commands below (directories are separated by colons `:`): -GNU/Linux: +GNU/LINUX (typically installed in `/usr/share/man`) ```bash man --path ``` -MAC OS: +Mac OS (typically installed in `/usr/local/share/man`) ```bash cat /private/etc/manpaths ``` -Select a directory path, add `man1` to the end of the path, and run the following command below (must be located within this `/docs` directory): - -GNU/LINUX (typically installed in `/usr/share/man/man1`) -MAC OS (typically installed in `/usr/local/share/man/man1`) +Select a directory path, add `man1` to the end of the path, and then run the following command below (must be located within this `/docs` directory): ```bash sudo cp nvi.1 ``` @@ -34,17 +40,9 @@ To view installed documentation: man nvi ``` -# Uninstallation +## System Uninstallation ```bash sudo rm /nvi.1 ``` -# Build -### Requirements -- pandoc v3.1.6+ (click [here](https://pandoc.org/MANUAL.html) for documentation) - -To manually generate the man documentation, run the following command: -```bash -pandoc --standalone --to man nvi.1.md -o nvi.1 -``` diff --git a/docs/nvi.1 b/docs/nvi.1 deleted file mode 100644 index 3f418a3c..00000000 --- a/docs/nvi.1 +++ /dev/null @@ -1,234 +0,0 @@ -.\" Automatically generated by Pandoc 3.1.6 -.\" -.\" Define V font for inline verbatim, using C font in formats -.\" that render this, and otherwise B font. -.ie "\f[CB]x\f[]"x" \{\ -. ftr V B -. ftr VI BI -. ftr VB B -. ftr VBI BI -.\} -.el \{\ -. ftr V CR -. ftr VI CI -. ftr VB CB -. ftr VBI CBI -.\} -.TH "nvi" "1" "08-28-2024" "CLI Documentation v0.3.0" "" -.hy -.SH NAME -.PP -\f[B]nvi\f[R] \[em] a stand-alone .env file parser for interpolating and -assigning multiple .env files into a process. -.SH SYNOPSIS -.PP -nvi [\f[B]options\f[R]] -.SH DESCRIPTION -.PP -A stand-alone binary that can parse, interpolate and assign ENVs into a -process locally or remotely. -It will either print ENVs as ENVs, flags or JSON to standard output or -it will assign them to a child process. -All options below are optional. -Only long form (--) flags are supported. -.SH OPTIONS -.TP ---api -Specifies whether or not to retrieve ENVs from the nvi API. -.TP ---config \f[I]environment\f[R] -Specifies which environment config to load from a nvi.toml file. -.TP ---debug -Specifies whether or not to log debug details. -.TP ---directory \f[I]path\f[R] -Specifies which directory path the .env files are located within. -The \f[I]path\f[R] will be relative to the current directory. -.TP ---environment \f[I]environment\f[R] -Specifies which environment config to use within a nvi API project. -Remote environments are created via the front-facing web application. -.TP ---files \f[I]file1.env\f[R] \f[I]file2.env\f[R] \f[I]file3.env\f[R] \&...etc -A list of .env files to parse. -Each specified \f[I]file\f[R] needs to be separated by a space. -.TP ---help -Prints condensed documentation for flag usage. -.TP ---project \f[I]project\f[R] -Specifies which remote project to select from the nvi API. -Remote projects are created via the front-facing web application. -.TP ---print \f[I]envs|ENVs\f[R] or \f[I]flags\f[R] or \f[I]json|JSON\f[R] -Specifies whether or not to print ENVs as ENVs, flags, or JSON to -standard out after parsing. -This flag will be ignored if a system command is defined. -.TP ---required \f[I]KEY_1\f[R] \f[I]KEY_2\f[R] \f[I]KEY_3\f[R] \&...etc -A list of ENV keys that are required to be defined after parsing. -Each specified \f[I]KEY\f[R] needs to be separated by a space. -.TP ---save -Specifies whether or not to save nvi API ENVs to disk with the selected -environment name. -.TP ---version -Prints the current version number. -.TP --- \f[I]command\f[R] -A system command to run in a child process that has been assigned with -the parsed ENVs. -This should be last flag defined, therefore anything placed after it -will be consumed as part of the system command. -.SH EXIT STATUS -.PP -nvi exits\ with a 0 on success and\ 1 if there\[cq]s an error. -.SH FILES -.TP -\f[I]*/nvi.toml\f[R] -Global project environment configuration file. -.TP -\f[I]*/*.env.*\f[R] -One or many files containing ENVs to be parsed and interpolated. -.SH EXAMPLES -.PP -Parsing a local \f[V]example.env\f[R] file from a custom directory with -debug logging: -.IP -.nf -\f[C] -$ nvi --files example.env --directory dist/client --debug -\f[R] -.fi -.PP -Parsing one or many local \f[V].env\f[R] files from a nvi.toml -configuration file typically located at a project\[cq]s root directory: -.IP -.nf -\f[C] -$ nvi --config standard -\f[R] -.fi -.PP -Parsing a local \f[V].env\f[R] file, checking the parsed ENVs for -required keys, and then, if good, applying those ENVs to a spawned -\[lq]npm\[rq] child process: -.IP -.nf -\f[C] -$ nvi --files .env --required KEY1 KEY2 -- npm run dev -\f[R] -.fi -.PP -To retrieve remote ENVs from the nvi API, you must first register and -verify your email using the front-facing -application (https://github.com/mattcarlotta/nvi-app). -.IP "1." 3 -Once registered and verified, create a project, an environment and at -least 1 ENV secret within the environment -.IP "2." 3 -Navigate to your account settings page, locate your unique API key and -click the copy to clipboard button -.IP "3." 3 -Using the nvi CLI tool, input the following: -.RS 4 -.IP "a." 3 -\[lq]--api\[rq] flag followed by a space -.IP "b." 3 -optional \[lq]--project\[rq] flag followed by a space and then the name -of the project you\[cq]ve created -.IP "c." 3 -optional \[lq]--environment\[rq] flag followed by a space and then the -name of the environment you\[cq]ve created -.IP "d." 3 -a \[lq]--print\[rq] flag or a --\[rq] flag followed by a space and then -a system command to run -.RE -.IP "4." 3 -Press the \[lq]Enter\[rq] key and nvi will prompt you for your unique -API key‡ -.IP "5." 3 -Input the API key and nvi will attempt to retrieve and assign remote -ENVs from the selected project and environment to the command (if no -command is provided then nvi will just print the parsed and interpolated -envs to standard out) -.PP -‡ You can bypass this step by creating a \f[V].nvi-key\f[R] file at the -project root directory that includes your unique API key. -Be mindful, that this file \f[B]MUST\f[R] be added to your -\f[V].gitignore\f[R]! -.PP -Retrieving remote ENVs: -.IP -.nf -\f[C] -$ nvi --api --project my_project --environment development -- cargo run -\f[R] -.fi -.PP -Then, you\[cq]ll be asked for your API key. -Input your API key and press the \[lq]Enter\[rq] key: -.IP -.nf -\f[C] -$ [nvi] Please enter your unique API key: -\f[R] -.fi -.PP -If no error is displayed in the terminal, then a child process should be -spawned with the command OR ENVs will be printed to standard out as -stringified JSON. -.PP -The following represents an example \f[V]nvi.toml\f[R] configuration: -.IP -.nf -\f[C] -[dev] -debug = true -directory = \[dq]path/to/custom/dir\[dq] -files = [ \[dq].env\[dq], \[dq]base.env\[dq], \[dq]reference.env\[dq] ] -execute = [\[dq]echo\[dq], \[dq]Hello\[dq]] -required = [ \[dq]TEST1\[dq], \[dq]TEST2\[dq], \[dq]TEST3\[dq] ] - -[staging] -files = [ \[dq].env\[dq] ] -required = [ \[dq]TEST1\[dq] ] - -[remote_dev] -api = true -debug = true -environment = \[dq]development\[dq] -execute = [\[dq]echo\[dq], \[dq]Hello\[dq]] -project = \[dq]my_project\[dq] -required = [ \[dq]TEST1\[dq], \[dq]TEST2\[dq], \[dq]TEST3\[dq] ] -save = true -\f[R] -.fi -.PP -To target a configuration within the nvi.toml config file, simply use -the \f[V]--config\f[R] flag followed by the config name: -.IP -.nf -\f[C] -$ nvi --config dev -\f[R] -.fi -.PP -Please read -this (https://github.com/mattcarlotta/nvi#what-are-the-nvi-configuration-file-specs) -for config file specs. -.SH SEE ALSO -.PP -Source (https://github.com/mattcarlotta/nvi) -.PP -Issues (https://github.com/mattcarlotta/nvi/issues) -.PP -Documentation (https://github.com/mattcarlotta/nvi#README) -.SH LICENSE -.PP -Copyright 2024 (C) Matt Carlotta. -GPL-3.0 licensed. -.SH AUTHORS -Matt Carlotta. diff --git a/examples/rust/src/main.rs b/examples/rust/src/main.rs index a547eb8d..630e025d 100644 --- a/examples/rust/src/main.rs +++ b/examples/rust/src/main.rs @@ -1,8 +1,8 @@ fn get_env(key: &str) -> String { - return match std::env::var(key) { + match std::env::var(key) { Ok(val) => val, Err(_) => String::new(), - }; + } } fn main() { diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..130a070b --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,3 @@ +# use empty config file to ensure that `rustfmt` will always use +# the default configuration when formatting code +# even if there is a `rustfmt.toml` file in parent directories diff --git a/src/api.rs b/src/api.rs index 1ef7d0cd..ced68ab7 100644 --- a/src/api.rs +++ b/src/api.rs @@ -34,7 +34,7 @@ impl<'a> Api<'a> { let mut headers = HeaderMap::new(); headers.insert(CONTENT_TYPE, HeaderValue::from_static("text/plain")); - return Api { + Api { request: Client::new(), headers, options, @@ -43,7 +43,7 @@ impl<'a> Api<'a> { api_key: String::new(), status_code: StatusCode::OK, logger, - }; + } } fn fetch_data( @@ -81,7 +81,7 @@ impl<'a> Api<'a> { self.logger.fatal(format!("failed to retrieve {req_type} from the nvi API. Excepted the response content-type to be text/plain instead received {content_type}.")); } - self.data = res.text().unwrap_or(String::new()); + self.data = res.text().unwrap_or_default(); if !self.status_code.is_success() || self.data.is_empty() { self.logger.fatal(format!("failed to retrieve {req_type} from the nvi API. Either the API key was invalid or you haven't created any {req_type} yet!")); @@ -110,9 +110,10 @@ impl<'a> Api<'a> { index += 1; } - self.logger.print(format!( + self.logger.print( "Please select one of the options above using the corresponding [number]... " - )); + .to_string(), + ); io::stdout().flush().expect("Failed to flush stdout"); } @@ -130,7 +131,7 @@ impl<'a> Api<'a> { .read_line(&mut selection) .expect("Failed to read line"); - selection.retain(|c| c.is_digit(10)); + selection.retain(|c| c.is_ascii_digit()); } let index_option = selection.parse::().unwrap_or(0); @@ -141,11 +142,11 @@ impl<'a> Api<'a> { )); return option.to_string(); - } else { - self.logger.fatal(format!( - "was provided a(n) invalid {req_type} selection. Aborting.", - )); - }; + } + + self.logger.fatal(format!( + "was provided a(n) invalid {req_type} selection. Aborting.", + )); } fn save_envs_to_disk(&mut self) { @@ -163,9 +164,8 @@ impl<'a> Api<'a> { self.save_file_path.display() )); - self.logger.print(format!( - "Are you sure you want to save and overwrite it? (y|N) " - )); + self.logger + .print("Are you sure you want to save and overwrite it? (y|N) ".to_string()); io::stdout().flush().expect("Failed to flush stdout"); let mut selection = String::new(); @@ -233,13 +233,13 @@ impl<'a> Api<'a> { "successfully parsed the API key found within \"{}\"!", api_key_file.display() )); - } else { - if let Ok(mut ak) = - prompt_password(format!("[nvi] Please enter your unique API key: ").cyan()) - { - ak.retain(|c| c.is_alphanumeric()); - self.api_key.push_str(ak.as_str()); - } + } else if let Ok(mut ak) = prompt_password( + "[nvi] Please enter your unique API key: " + .to_string() + .cyan(), + ) { + ak.retain(|c| c.is_alphanumeric()); + self.api_key.push_str(ak.as_str()); } if self.api_key.is_empty() { diff --git a/src/arg/arg.rs b/src/arg/arg.rs index 5cac3f98..b56f87b7 100644 --- a/src/arg/arg.rs +++ b/src/arg/arg.rs @@ -1,44 +1,44 @@ use std::fmt::{Display, Formatter, Result as FmtResult}; -pub enum ARG { - API, - CONFIG, - DEBUG, - DIRECTORY, - ENVIRONMENT, - EXECUTE, - FILES, - HELP, - PRINT, - PROJECT, - REQUIRED, - SAVE, - VERSION, - UNKNOWN, +pub enum Arg { + Api, + Config, + Debug, + Directory, + Environment, + Execute, + Files, + Help, + Print, + Project, + Required, + Save, + Version, + Unknown, } -impl ARG { +impl Arg { pub fn as_str(&self) -> &'static str { match self { - ARG::API => "--api", - ARG::CONFIG => "--config", - ARG::DEBUG => "--debug", - ARG::DIRECTORY => "--directory", - ARG::ENVIRONMENT => "--environment", - ARG::EXECUTE => "--", - ARG::FILES => "--files", - ARG::HELP => "--help", - ARG::PRINT => "--print", - ARG::PROJECT => "--project", - ARG::REQUIRED => "--required", - ARG::SAVE => "--save", - ARG::VERSION => "--version", - ARG::UNKNOWN => "", + Arg::Api => "--api", + Arg::Config => "--config", + Arg::Debug => "--debug", + Arg::Directory => "--directory", + Arg::Environment => "--environment", + Arg::Execute => "--", + Arg::Files => "--files", + Arg::Help => "--help", + Arg::Print => "--print", + Arg::Project => "--project", + Arg::Required => "--required", + Arg::Save => "--save", + Arg::Version => "--version", + Arg::Unknown => "", } } } -impl Display for ARG { +impl Display for Arg { fn fmt(&self, f: &mut Formatter) -> FmtResult { write!(f, "{}", self.as_str()) } diff --git a/src/arg/arg_parser.rs b/src/arg/arg_parser.rs index f5723b40..2c6905b2 100644 --- a/src/arg/arg_parser.rs +++ b/src/arg/arg_parser.rs @@ -1,4 +1,4 @@ -use super::ARG; +use super::Arg; use crate::globals; use crate::logger::Logger; use crate::options::{OptionsType, PrintOptions}; @@ -21,7 +21,7 @@ impl<'a> ArgParser<'a> { let mut logger = Logger::new("ArgParser"); logger.set_debug(&options.debug); - return ArgParser { + ArgParser { argc: argv.len(), argv, file: globals::current_dir().clone(), @@ -29,7 +29,7 @@ impl<'a> ArgParser<'a> { options, index: 1, logger, - }; + } } fn get_vec_str_opt(&self, config: &Value, prop: &str) -> Option> { @@ -57,7 +57,7 @@ impl<'a> ArgParser<'a> { return Some(opts); }; - return None; + None } fn get_str_opt(&self, config: &Value, prop: &str) -> Option { @@ -71,7 +71,7 @@ impl<'a> ArgParser<'a> { }; }; - return None; + None } fn get_bool_opt(&self, config: &Value, prop: &str) -> Option { @@ -85,7 +85,7 @@ impl<'a> ArgParser<'a> { }; }; - return None; + None } fn parse_config(&mut self) -> &mut Self { @@ -179,7 +179,7 @@ impl<'a> ArgParser<'a> { self.options.save = save; } - return self; + self } fn next_arg(&mut self) { @@ -191,13 +191,13 @@ impl<'a> ArgParser<'a> { } fn get_arg(&'a self) -> &'a str { - return match self.argv.get(self.index) { + match self.argv.get(self.index) { Some(a) => a, None => "", - }; + } } - fn parse_single_arg(&mut self, flag: ARG) -> String { + fn parse_single_arg(&mut self, flag: Arg) -> String { self.next_arg(); let arg = self.get_arg(); @@ -205,21 +205,21 @@ impl<'a> ArgParser<'a> { if arg.is_empty() || arg.contains("-") { let mut error = String::new(); match flag { - ARG::CONFIG => { + Arg::Config => { error.push_str("The \"--config\" flag must contain an environment name from the nvi.toml configuration file"); } - ARG::DIRECTORY => { + Arg::Directory => { error.push_str("The \"--directory\" flag must contain a valid directory path"); } - ARG::ENVIRONMENT => { + Arg::Environment => { error.push_str( "The \"--environment\" flag must contain a valid environment name", ); } - ARG::PROJECT => { + Arg::Project => { error.push_str("The \"--project\" flag must contain a valid project name"); } - ARG::PRINT => { + Arg::Print => { error.push_str( "The \"--print\" flag must contain a valid format: envs|ENVs, flags, or json|JSON", ); @@ -231,10 +231,10 @@ impl<'a> ArgParser<'a> { )); } - return arg.to_owned(); + arg.to_owned() } - fn parse_multi_arg(&mut self, flag: ARG, delimiter_stop: bool) -> Vec { + fn parse_multi_arg(&mut self, flag: Arg, delimiter_stop: bool) -> Vec { let mut args = vec![]; while self.index < self.argc { @@ -257,15 +257,15 @@ impl<'a> ArgParser<'a> { if args.is_empty() { let mut error = String::new(); match flag { - ARG::EXECUTE => { + Arg::Execute => { error.push_str( "The \"--\" (execute) flag must contain at least 1 system command", ); } - ARG::FILES => { + Arg::Files => { error.push_str("The \"--files\" flag must contain at least 1 .env file"); } - ARG::REQUIRED => { + Arg::Required => { error.push_str("The \"--required\" flag must contain at least 1 ENV key"); } _ => (), @@ -275,54 +275,54 @@ impl<'a> ArgParser<'a> { )); } - return args; + args } pub fn parse(&mut self) { while self.index < self.argc { self.curr_flag = match self.argv.get(self.index) { Some(f) => f.to_owned(), - None => ARG::UNKNOWN.to_string(), + None => Arg::Unknown.to_string(), }; match globals::args().get(self.curr_flag.as_str()) { - Some(ARG::API) => self.options.api = true, - Some(ARG::CONFIG) => { - self.options.config = self.parse_single_arg(ARG::CONFIG); + Some(Arg::Api) => self.options.api = true, + Some(Arg::Config) => { + self.options.config = self.parse_single_arg(Arg::Config); } - Some(ARG::DEBUG) => { + Some(Arg::Debug) => { self.options.debug = true; self.logger.set_debug(&self.options.debug); } - Some(ARG::DIRECTORY) => { - self.options.dir = self.parse_single_arg(ARG::DIRECTORY); + Some(Arg::Directory) => { + self.options.dir = self.parse_single_arg(Arg::Directory); } - Some(ARG::ENVIRONMENT) => { - self.options.environment = self.parse_single_arg(ARG::ENVIRONMENT); + Some(Arg::Environment) => { + self.options.environment = self.parse_single_arg(Arg::Environment); } - Some(ARG::EXECUTE) => { - self.options.commands = self.parse_multi_arg(ARG::EXECUTE, false); + Some(Arg::Execute) => { + self.options.commands = self.parse_multi_arg(Arg::Execute, false); } - Some(ARG::FILES) => { - self.options.files = self.parse_multi_arg(ARG::FILES, true); + Some(Arg::Files) => { + self.options.files = self.parse_multi_arg(Arg::Files, true); } - Some(ARG::HELP) => self.logger.print_help_and_exit(), - Some(ARG::PRINT) => { - match PrintOptions::to_option(self.parse_single_arg(ARG::PRINT)) { + Some(Arg::Help) => self.logger.print_help_and_exit(), + Some(Arg::Print) => { + match PrintOptions::to_option(self.parse_single_arg(Arg::Print)) { Ok(print) => self.options.print = print, Err(_) => { - self.logger.fatal(format!("encountered an error: The \"--print\" option must be a valid format: envs|ENVs, flags, or json|JSON. Use flag \"--help\" for more information.")); + self.logger.fatal("encountered an error: The \"--print\" option must be a valid format: envs|ENVs, flags, or json|JSON. Use flag \"--help\" for more information.".to_string()); } } } - Some(ARG::PROJECT) => { - self.options.project = self.parse_single_arg(ARG::PROJECT); + Some(Arg::Project) => { + self.options.project = self.parse_single_arg(Arg::Project); } - Some(ARG::REQUIRED) => { - self.options.required_envs = self.parse_multi_arg(ARG::REQUIRED, true); + Some(Arg::Required) => { + self.options.required_envs = self.parse_multi_arg(Arg::Required, true); } - Some(ARG::SAVE) => self.options.save = true, - Some(ARG::VERSION) => self.logger.print_version_and_exit(), + Some(Arg::Save) => self.options.save = true, + Some(Arg::Version) => self.logger.print_version_and_exit(), _ => { let mut invalid_args = String::new(); @@ -337,7 +337,7 @@ impl<'a> ArgParser<'a> { } if !invalid_args.is_empty() { - invalid_args.push_str(" "); + invalid_args.push(' '); } invalid_args.push_str(arg); diff --git a/src/arg/mod.rs b/src/arg/mod.rs index 12271841..e9bd5535 100644 --- a/src/arg/mod.rs +++ b/src/arg/mod.rs @@ -1,4 +1,4 @@ -pub use arg::ARG; +pub use arg::Arg; pub use arg_parser::ArgParser; mod arg; diff --git a/src/generator.rs b/src/generator.rs index 3dee33ee..52d2761f 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -14,11 +14,11 @@ impl<'a> Generator<'a> { let mut logger = Logger::new("Generator"); logger.set_debug(&options.debug); - return Generator { + Generator { options, output: String::new(), logger, - }; + } } pub fn run(&mut self, envs: HashMap) { @@ -32,23 +32,22 @@ impl<'a> Generator<'a> { child_process.wait().expect("Failed to read command output"); } else if self.options.print != PrintOptions::Unknown { let mut env_count = 1; - if self.options.print == PrintOptions::JSON { - self.output.push_str("{"); + if self.options.print == PrintOptions::Json { + self.output.push('{'); } for (key, value) in &envs { - let kv: String; - match self.options.print { - PrintOptions::JSON => { - kv = format!("{:?}:{:?},", key, value); + let kv = match self.options.print { + PrintOptions::Json => { + format!("{:?}:{:?},", key, value) } PrintOptions::Flags => { - kv = format!("--{} {} ", key, value); + format!("--{} {} ", key, value) } _ => { - kv = format!("{}={}\n", key, value); + format!("{}={}\n", key, value) } - } + }; let mut kvl = kv.len(); if env_count == envs.len() { kvl -= 1; @@ -57,8 +56,8 @@ impl<'a> Generator<'a> { env_count += 1; } - if self.options.print == PrintOptions::JSON { - self.output.push_str("}"); + if self.options.print == PrintOptions::Json { + self.output.push('}'); } println!("{}", self.output); } else if !self.options.api && !self.options.save { diff --git a/src/globals.rs b/src/globals.rs index 4d79271f..98f203ed 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -1,4 +1,4 @@ -use crate::arg::ARG; +use crate::arg::Arg; use std::collections::HashMap; use std::env; use std::path::PathBuf; @@ -19,36 +19,34 @@ pub const CLOSE_BRACE: char = '}'; // 0x7d pub const NULL_CHAR: char = '\0'; // 0x0 #[cfg(debug_assertions)] -pub const API_URL: &'static str = "http://127.0.0.1:4000"; +pub const API_URL: &str = "http://127.0.0.1:4000"; #[cfg(not(debug_assertions))] -pub const API_URL: &'static str = "http://nvi.sh/api"; +pub const API_URL: &str = "http://nvi.sh/api"; pub fn current_dir() -> &'static PathBuf { static CURRENT_DIR: OnceLock = OnceLock::new(); - CURRENT_DIR.get_or_init(|| { - return env::current_dir().expect("Failed to retrieve current directory."); - }) + CURRENT_DIR.get_or_init(|| env::current_dir().expect("Failed to retrieve current directory.")) } -pub fn args() -> &'static HashMap<&'static str, ARG> { - static HASHMAP: OnceLock> = OnceLock::new(); +pub fn args() -> &'static HashMap<&'static str, Arg> { + static HASHMAP: OnceLock> = OnceLock::new(); HASHMAP.get_or_init(|| { - return HashMap::from([ - (ARG::API.as_str(), ARG::API), - (ARG::CONFIG.as_str(), ARG::CONFIG), - (ARG::DEBUG.as_str(), ARG::DEBUG), - (ARG::DIRECTORY.as_str(), ARG::DIRECTORY), - (ARG::ENVIRONMENT.as_str(), ARG::ENVIRONMENT), - (ARG::EXECUTE.as_str(), ARG::EXECUTE), - (ARG::FILES.as_str(), ARG::FILES), - (ARG::HELP.as_str(), ARG::HELP), - (ARG::PRINT.as_str(), ARG::PRINT), - (ARG::PROJECT.as_str(), ARG::PROJECT), - (ARG::REQUIRED.as_str(), ARG::REQUIRED), - (ARG::SAVE.as_str(), ARG::SAVE), - (ARG::VERSION.as_str(), ARG::VERSION), - (ARG::UNKNOWN.as_str(), ARG::UNKNOWN), - ]); + HashMap::from([ + (Arg::Api.as_str(), Arg::Api), + (Arg::Config.as_str(), Arg::Config), + (Arg::Debug.as_str(), Arg::Debug), + (Arg::Directory.as_str(), Arg::Directory), + (Arg::Environment.as_str(), Arg::Environment), + (Arg::Execute.as_str(), Arg::Execute), + (Arg::Files.as_str(), Arg::Files), + (Arg::Help.as_str(), Arg::Help), + (Arg::Print.as_str(), Arg::Print), + (Arg::Project.as_str(), Arg::Project), + (Arg::Required.as_str(), Arg::Required), + (Arg::Save.as_str(), Arg::Save), + (Arg::Version.as_str(), Arg::Version), + (Arg::Unknown.as_str(), Arg::Unknown), + ]) }) } diff --git a/src/lexer/lexer.rs b/src/lexer/lexer.rs index d0b98a2a..059cf0cc 100644 --- a/src/lexer/lexer.rs +++ b/src/lexer/lexer.rs @@ -22,7 +22,7 @@ impl<'a> Lexer<'a> { let mut logger = Logger::new("Lexer"); logger.set_debug(&options.debug); - return Lexer { + Lexer { options, index: 0, byte: 1, @@ -32,11 +32,11 @@ impl<'a> Lexer<'a> { file_path: globals::current_dir().clone(), tokens: vec![], logger, - }; + } } pub fn get_tokens(self) -> Vec { - return self.tokens; + self.tokens } fn reset_byte(&mut self) { @@ -57,10 +57,7 @@ impl<'a> Lexer<'a> { return None; } - match self.file.chars().nth(index) { - Some(c) => return Some(c), - None => return None, - } + self.file.chars().nth(index) } fn skip(&mut self, offset: Option) { @@ -70,10 +67,10 @@ impl<'a> Lexer<'a> { } fn get_char(&self, offset: Option) -> char { - return match self.peek(offset) { + match self.peek(offset) { Some(c) => c, None => globals::NULL_CHAR, - }; + } } fn parse(&mut self) { @@ -170,7 +167,7 @@ impl<'a> Lexer<'a> { self.logger.fatal( format!( "found an error in {}:{}:{}. The key {:?} contains an interpolated \"{{\" operator, but appears to be missing a closing \"}}\" operator.", - self.file_name, self.line, self.byte, token.key.unwrap_or(String::new()) + self.file_name, self.line, self.byte, token.key.unwrap_or_default() ) ); } @@ -392,14 +389,14 @@ mod tests { let mut lexer = Lexer::new(&options); lexer.tokenize(); - return lexer.get_tokens(); + lexer.get_tokens() }) } fn get_token(index: usize) -> LexerToken { let tokens = get_tokens(); - return tokens[index].to_owned(); + tokens[index].to_owned() } #[test] diff --git a/src/lexer/lexer_token.rs b/src/lexer/lexer_token.rs index 9095bb38..dbcd04c5 100644 --- a/src/lexer/lexer_token.rs +++ b/src/lexer/lexer_token.rs @@ -16,7 +16,7 @@ impl Display for LexerValue { LexerValue::Comment => "COMMENT", LexerValue::Multiline => "MULTILINE", }; - return write!(f, "{}", val); + write!(f, "{}", val) } } @@ -29,12 +29,12 @@ pub struct LexerValueToken { impl Clone for LexerValueToken { fn clone(&self) -> Self { - return LexerValueToken { + LexerValueToken { token_type: self.token_type.clone(), value: self.value.clone(), byte: self.byte, line: self.line, - }; + } } } @@ -44,22 +44,22 @@ impl Debug for LexerValueToken { Some(v) => format!("Some({v})"), None => String::from("None"), }; - return write!( + write!( f, "token_type: {}, value: {}, line: {}, byte: {}", &self.token_type, value, &self.line, &self.byte - ); + ) } } impl LexerValueToken { pub fn new(token_type: LexerValue, value: &String, line: usize, byte: usize) -> Self { - return LexerValueToken { + LexerValueToken { token_type, value: Some(value.to_owned()), line, byte, - }; + } } } @@ -71,31 +71,30 @@ pub struct LexerToken { impl Clone for LexerToken { fn clone(&self) -> Self { - return LexerToken { + LexerToken { key: self.key.clone(), values: self.values.clone(), file: self.file.clone(), - }; + } } } impl Debug for LexerToken { fn fmt(&self, f: &mut Formatter) -> FmtResult { - return f - .debug_struct("LexerToken") + f.debug_struct("LexerToken") .field("key", &self.key) .field("values", &self.values) .field("file", &self.file) - .finish(); + .finish() } } impl LexerToken { pub fn new() -> Self { - return LexerToken { + LexerToken { key: None, values: vec![], file: String::new(), - }; + } } } diff --git a/src/logger.rs b/src/logger.rs index 1bb1fcdc..f8b8e042 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -11,10 +11,10 @@ pub struct Logger<'a> { impl<'a> Logger<'a> { pub fn new(log_type: &'a str) -> Self { - return Logger { + Logger { log_type, debug: false, - }; + } } pub fn set_debug(&mut self, debug: &bool) { @@ -73,7 +73,7 @@ impl<'a> Logger<'a> { } pub fn print_help_and_exit(&self) -> ! { - println!("{}", format!( + println!("{}", r#"┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ nvi documentation │ ├───────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -91,8 +91,8 @@ impl<'a> Logger<'a> { │ --save │ specifies whether or not to save nvi API ENVs to disk with the selected environment name. (ex: --save) │ │ --version │ prints out app version. (ex: --version) │ │ -- │ specifies which system command to run in a child process with parsed ENVs. (ex: -- cargo run) │ -└───────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘"#, - ).green()); +└───────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘"# + .to_string().green()); exit(0); } } diff --git a/src/options.rs b/src/options.rs index f9ac2595..a66d4433 100644 --- a/src/options.rs +++ b/src/options.rs @@ -6,7 +6,7 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; pub enum PrintOptions { Envs, Flags, - JSON, + Json, Unknown, } @@ -15,24 +15,24 @@ impl PrintOptions { match self { PrintOptions::Envs => "envs", PrintOptions::Flags => "flags", - PrintOptions::JSON => "json", + PrintOptions::Json => "json", PrintOptions::Unknown => "", } } pub fn to_option(input: String) -> Result { - return match input.as_str() { - "json" | "JSON" => Ok(PrintOptions::JSON), + match input.as_str() { + "json" | "JSON" => Ok(PrintOptions::Json), "flags" => Ok(PrintOptions::Flags), "envs" | "ENVs" => Ok(PrintOptions::Envs), _ => Err(input), - }; + } } } impl Debug for PrintOptions { fn fmt(&self, f: &mut Formatter) -> FmtResult { - return write!(f, "{:?}", self.as_str()); + write!(f, "{:?}", self.as_str()) } } @@ -55,7 +55,7 @@ pub type OptionsType = Options; impl Debug for Options { fn fmt(&self, f: &mut Formatter) -> FmtResult { - return write!( + write!( f, "{{\n \"api\": {},\n \"command\": {:?},\n \"config\": {:?},\n \"debug\": {},\n \"directory\": {:?},\n \"environment\": {:?},\n \"files\": {:?},\n \"print\": {:?},\n \"project\": {:?},\n \"required_envs\": {:?},\n \"save\": {}\n}}", self.api, @@ -69,7 +69,7 @@ impl Debug for Options { self.project, self.required_envs, self.save - ); + ) } } @@ -103,7 +103,7 @@ impl Options { } } - return options; + options } } diff --git a/src/parser.rs b/src/parser.rs index 4f4e0fc8..70a9f8d7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -17,17 +17,17 @@ impl<'a> Parser<'a> { let mut logger = Logger::new("Parser"); logger.set_debug(&options.debug); - return Parser { + Parser { envs: HashMap::new(), options, tokens, undefined_keys: options.required_envs.clone(), logger, - }; + } } pub fn get_envs(self) -> HashMap { - return self.envs; + self.envs } pub fn parse_tokens(&mut self) { @@ -136,7 +136,7 @@ mod tests { let mut parser = Parser::new(&options, lexer.get_tokens()); parser.parse_tokens(); - return parser.get_envs(); + parser.get_envs() }) }