Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1748-dotenv-files #2022

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
18 changes: 17 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub(crate) struct Config {
pub(crate) color: Color,
pub(crate) command_color: Option<ansi_term::Color>,
pub(crate) dotenv_filename: Option<String>,
pub(crate) dotenv_files: Option<Vec<PathBuf>>,
pub(crate) dotenv_path: Option<PathBuf>,
pub(crate) dry_run: bool,
pub(crate) dump_format: DumpFormat,
Expand Down Expand Up @@ -98,6 +99,7 @@ mod arg {
pub(crate) const COMMAND_COLOR: &str = "COMMAND-COLOR";
pub(crate) const DOTENV_FILENAME: &str = "DOTENV-FILENAME";
pub(crate) const DOTENV_PATH: &str = "DOTENV-PATH";
pub(crate) const DOTENV_FILES: &str = "DOTENV-FILES";
pub(crate) const DRY_RUN: &str = "DRY-RUN";
pub(crate) const DUMP_FORMAT: &str = "DUMP-FORMAT";
pub(crate) const HIGHLIGHT: &str = "HIGHLIGHT";
Expand Down Expand Up @@ -398,7 +400,18 @@ impl Config {
.long("dotenv-filename")
.takes_value(true)
.help("Search for environment file named <DOTENV-FILENAME> instead of `.env`")
.conflicts_with(arg::DOTENV_PATH),
.conflicts_with(arg::DOTENV_PATH)
.conflicts_with(arg::DOTENV_FILES),
)
.arg(
Arg::with_name(arg::DOTENV_FILES)
.long("dotenv-files")
.takes_value(true)
.multiple(true)
.number_of_values(1)
.help("Search for environment list of files.")
.conflicts_with(arg::DOTENV_PATH)
.conflicts_with(arg::DOTENV_FILENAME),
)
.arg(
Arg::with_name(arg::DOTENV_PATH)
Expand Down Expand Up @@ -653,6 +666,9 @@ impl Config {
command_color,
dotenv_filename: matches.value_of(arg::DOTENV_FILENAME).map(str::to_owned),
dotenv_path: matches.value_of(arg::DOTENV_PATH).map(PathBuf::from),
dotenv_files: matches
.values_of(arg::DOTENV_FILES)
.map(|value| value.map(PathBuf::from).collect()),
dry_run: matches.is_present(arg::DRY_RUN),
dump_format: Self::dump_format_from_matches(matches)?,
highlight: !matches.is_present(arg::NO_HIGHLIGHT),
Expand Down
1 change: 1 addition & 0 deletions src/keyword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub(crate) enum Keyword {
DotenvFilename,
DotenvLoad,
DotenvPath,
DotenvFiles,
Else,
Export,
Fallback,
Expand Down
24 changes: 13 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ pub(crate) use {
fragment::Fragment, function::Function, function_context::FunctionContext,
interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item,
justfile::Justfile, keyed::Keyed, keyword::Keyword, lexer::Lexer, line::Line, list::List,
load_dotenv::load_dotenv, loader::Loader, name::Name, namepath::Namepath, ordinal::Ordinal,
output::output, output_error::OutputError, parameter::Parameter, parameter_kind::ParameterKind,
parser::Parser, platform::Platform, platform_interface::PlatformInterface, position::Position,
positional::Positional, ran::Ran, range_ext::RangeExt, recipe::Recipe,
recipe_context::RecipeContext, recipe_resolver::RecipeResolver, scope::Scope, search::Search,
search_config::SearchConfig, search_error::SearchError, set::Set, setting::Setting,
settings::Settings, shebang::Shebang, shell::Shell, show_whitespace::ShowWhitespace,
source::Source, string_kind::StringKind, string_literal::StringLiteral, subcommand::Subcommand,
suggestion::Suggestion, table::Table, thunk::Thunk, token::Token, token_kind::TokenKind,
unresolved_dependency::UnresolvedDependency, unresolved_recipe::UnresolvedRecipe,
use_color::UseColor, variables::Variables, verbosity::Verbosity, warning::Warning,
load_dotenv::load_dotenv, loader::Loader, name::Name, namepath::Namepath,
ordered_list::OrderedList, ordinal::Ordinal, output::output, output_error::OutputError,
parameter::Parameter, parameter_kind::ParameterKind, parser::Parser, platform::Platform,
platform_interface::PlatformInterface, position::Position, positional::Positional, ran::Ran,
range_ext::RangeExt, recipe::Recipe, recipe_context::RecipeContext,
recipe_resolver::RecipeResolver, scope::Scope, search::Search, search_config::SearchConfig,
search_error::SearchError, set::Set, setting::Setting, settings::Settings, shebang::Shebang,
shell::Shell, show_whitespace::ShowWhitespace, source::Source, string_kind::StringKind,
string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table,
thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency,
unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
verbosity::Verbosity, warning::Warning,
},
std::{
cmp,
Expand Down Expand Up @@ -151,6 +152,7 @@ mod load_dotenv;
mod loader;
mod name;
mod namepath;
mod ordered_list;
mod ordinal;
mod output;
mod output_error;
Expand Down
24 changes: 22 additions & 2 deletions src/load_dotenv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,18 @@ pub(crate) fn load_dotenv(
.as_ref()
.or(settings.dotenv_path.as_ref());

if !settings.dotenv_load.unwrap_or_default() && dotenv_filename.is_none() && dotenv_path.is_none()
let dotenv_files = config.dotenv_files.as_ref().or_else(|| {
if settings.dotenv_files.is_empty() {
None
} else {
Some(settings.dotenv_files.as_ref())
}
});

if !settings.dotenv_load.unwrap_or_default()
&& dotenv_filename.is_none()
&& dotenv_path.is_none()
&& dotenv_files.is_none()
{
return Ok(BTreeMap::new());
}
Expand All @@ -35,7 +46,16 @@ pub(crate) fn load_dotenv(
}
}

Ok(BTreeMap::new())
let mut return_tree = BTreeMap::new();
if let Some(dotenv_files) = dotenv_files {
for path in dotenv_files.iter() {
match load_from_file(&path) {
Ok(mut env_tree) => return_tree.append(&mut env_tree),
Err(error) => return Err(error),
}
}
}
Ok(return_tree)
}

fn load_from_file(path: &Path) -> RunResult<'static, BTreeMap<String, String>> {
Expand Down
5 changes: 5 additions & 0 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@ impl<'src> Node<'src> for Set<'src> {
Setting::DotenvFilename(value) | Setting::DotenvPath(value) | Setting::Tempdir(value) => {
set.push_mut(Tree::string(value));
}
Setting::DotenvFiles(ordered_list) => {
for item in ordered_list.list.iter() {
set.push_mut(Tree::string(&item.cooked));
}
}
}

set
Expand Down
23 changes: 23 additions & 0 deletions src/ordered_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use super::*;

#[derive(Debug, Clone, PartialEq, Serialize)]
pub(crate) struct OrderedList<'src> {
pub(crate) list: Vec<StringLiteral<'src>>,
}

impl<'src> Display for OrderedList<'src> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "[")?;
write!(
f,
"{}",
self
.list
.iter()
.map(|v| v.cooked.as_ref())
.collect::<Vec<&str>>()
.join(", ")
)?;
write!(f, "]")
}
}
25 changes: 24 additions & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use {super::*, TokenKind::*};
use {self::ordered_list::OrderedList, super::*, TokenKind::*};

/// Just language parser
///
Expand Down Expand Up @@ -866,6 +866,7 @@ impl<'run, 'src> Parser<'run, 'src> {
let set_value = match keyword {
Keyword::DotenvFilename => Some(Setting::DotenvFilename(self.parse_string_literal()?.cooked)),
Keyword::DotenvPath => Some(Setting::DotenvPath(self.parse_string_literal()?.cooked)),
Keyword::DotenvFiles => Some(Setting::DotenvFiles(self.parse_ordered_list()?)),
Keyword::Shell => Some(Setting::Shell(self.parse_shell()?)),
Keyword::Tempdir => Some(Setting::Tempdir(self.parse_string_literal()?.cooked)),
Keyword::WindowsShell => Some(Setting::WindowsShell(self.parse_shell()?)),
Expand All @@ -881,6 +882,28 @@ impl<'run, 'src> Parser<'run, 'src> {
}))
}

/// Parse a shell setting value
fn parse_ordered_list(&mut self) -> CompileResult<'src, OrderedList<'src>> {
let mut list = Vec::new();
self.expect(BracketL)?;

list.push(self.parse_string_literal()?);

if self.accepted(Comma)? {
while !self.next_is(BracketR) {
list.push(self.parse_string_literal()?);

if !self.accepted(Comma)? {
break;
}
}
}

self.expect(BracketR)?;

Ok(OrderedList { list })
}

/// Parse a shell setting value
fn parse_shell(&mut self) -> CompileResult<'src, Shell<'src>> {
self.expect(BracketL)?;
Expand Down
4 changes: 4 additions & 0 deletions src/setting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub(crate) enum Setting<'src> {
DotenvFilename(String),
DotenvLoad(bool),
DotenvPath(String),
DotenvFiles(OrderedList<'src>),
Export(bool),
Fallback(bool),
IgnoreComments(bool),
Expand All @@ -29,6 +30,9 @@ impl<'src> Display for Setting<'src> {
| Setting::Quiet(value)
| Setting::WindowsPowerShell(value) => write!(f, "{value}"),
Setting::Shell(shell) | Setting::WindowsShell(shell) => write!(f, "{shell}"),
Setting::DotenvFiles(value) => {
write!(f, "{value}")
}
Setting::DotenvFilename(value) | Setting::DotenvPath(value) | Setting::Tempdir(value) => {
write!(f, "{value:?}")
}
Expand Down
8 changes: 8 additions & 0 deletions src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub(crate) const WINDOWS_POWERSHELL_ARGS: &[&str] = &["-NoLogo", "-Command"];
pub(crate) struct Settings<'src> {
pub(crate) allow_duplicate_recipes: bool,
pub(crate) dotenv_filename: Option<String>,
pub(crate) dotenv_files: Vec<PathBuf>,
pub(crate) dotenv_load: Option<bool>,
pub(crate) dotenv_path: Option<PathBuf>,
pub(crate) export: bool,
Expand Down Expand Up @@ -67,6 +68,13 @@ impl<'src> Settings<'src> {
Setting::Tempdir(tempdir) => {
settings.tempdir = Some(tempdir);
}
Setting::DotenvFiles(ordered_list) => {
settings.dotenv_files = ordered_list
.list
.iter()
.map(|path| PathBuf::from(&path.cooked))
.collect();
}
}
}

Expand Down
18 changes: 18 additions & 0 deletions tests/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ fn alias() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -81,6 +82,7 @@ fn assignment() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -132,6 +134,7 @@ fn body() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -195,6 +198,7 @@ fn dependencies() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -295,6 +299,7 @@ fn dependency_argument() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -358,6 +363,7 @@ fn duplicate_recipes() {
"settings": {
"allow_duplicate_recipes": true,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -402,6 +408,7 @@ fn doc_comment() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -432,6 +439,7 @@ fn empty_justfile() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -583,6 +591,7 @@ fn parameters() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -667,6 +676,7 @@ fn priors() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -711,6 +721,7 @@ fn private() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -755,6 +766,7 @@ fn quiet() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -811,6 +823,7 @@ fn settings() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": "filename",
"dotenv_files": [],
"dotenv_load": true,
"dotenv_path": "path",
"export": true,
Expand Down Expand Up @@ -861,6 +874,7 @@ fn shebang() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -905,6 +919,7 @@ fn simple() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -952,6 +967,7 @@ fn attribute() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down Expand Up @@ -1012,6 +1028,7 @@ fn module() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand All @@ -1031,6 +1048,7 @@ fn module() {
"settings": {
"allow_duplicate_recipes": false,
"dotenv_filename": null,
"dotenv_files": [],
"dotenv_load": null,
"dotenv_path": null,
"export": false,
Expand Down