Add flags for specifying name and path environment file (#941)
This commit is contained in:
parent
f5689617f4
commit
e72e7dd569
@ -20,7 +20,7 @@ _just() {
|
||||
|
||||
case "${cmd}" in
|
||||
just)
|
||||
opts=" -q -u -v -e -l -h -V -f -d -c -s --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --unstable --verbose --changelog --choose --dump --edit --evaluate --fmt --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show <ARGUMENTS>... "
|
||||
opts=" -q -u -v -e -l -h -V -f -d -c -s --dry-run --highlight --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --unstable --verbose --changelog --choose --dump --edit --evaluate --fmt --init --list --summary --variables --help --version --chooser --color --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show --dotenv-filename --dotenv-path <ARGUMENTS>... "
|
||||
if [[ ${cur} == -* ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
@ -97,6 +97,14 @@ _just() {
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--dotenv-filename)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--dotenv-path)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=()
|
||||
;;
|
||||
|
@ -30,6 +30,8 @@ edit:completion:arg-completer[just] = [@words]{
|
||||
cand --completions 'Print shell completion script for <SHELL>'
|
||||
cand -s 'Show information about <RECIPE>'
|
||||
cand --show 'Show information about <RECIPE>'
|
||||
cand --dotenv-filename 'Search for environment file named <DOTENV-FILENAME> instead of `.env`'
|
||||
cand --dotenv-path 'Load environment file at <DOTENV-PATH> instead of searching for one'
|
||||
cand --dry-run 'Print what just would do without doing it'
|
||||
cand --highlight 'Highlight echoed recipe lines in bold'
|
||||
cand --no-dotenv 'Don''t load `.env` file'
|
||||
|
@ -21,6 +21,8 @@ complete -c just -n "__fish_use_subcommand" -s d -l working-directory -d 'Use <W
|
||||
complete -c just -n "__fish_use_subcommand" -s c -l command -d 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set'
|
||||
complete -c just -n "__fish_use_subcommand" -l completions -d 'Print shell completion script for <SHELL>' -r -f -a "zsh bash fish powershell elvish"
|
||||
complete -c just -n "__fish_use_subcommand" -s s -l show -d 'Show information about <RECIPE>'
|
||||
complete -c just -n "__fish_use_subcommand" -l dotenv-filename -d 'Search for environment file named <DOTENV-FILENAME> instead of `.env`'
|
||||
complete -c just -n "__fish_use_subcommand" -l dotenv-path -d 'Load environment file at <DOTENV-PATH> instead of searching for one'
|
||||
complete -c just -n "__fish_use_subcommand" -l dry-run -d 'Print what just would do without doing it'
|
||||
complete -c just -n "__fish_use_subcommand" -l highlight -d 'Highlight echoed recipe lines in bold'
|
||||
complete -c just -n "__fish_use_subcommand" -l no-dotenv -d 'Don\'t load `.env` file'
|
||||
|
@ -35,6 +35,8 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
|
||||
[CompletionResult]::new('--completions', 'completions', [CompletionResultType]::ParameterName, 'Print shell completion script for <SHELL>')
|
||||
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Show information about <RECIPE>')
|
||||
[CompletionResult]::new('--show', 'show', [CompletionResultType]::ParameterName, 'Show information about <RECIPE>')
|
||||
[CompletionResult]::new('--dotenv-filename', 'dotenv-filename', [CompletionResultType]::ParameterName, 'Search for environment file named <DOTENV-FILENAME> instead of `.env`')
|
||||
[CompletionResult]::new('--dotenv-path', 'dotenv-path', [CompletionResultType]::ParameterName, 'Load environment file at <DOTENV-PATH> instead of searching for one')
|
||||
[CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'Print what just would do without doing it')
|
||||
[CompletionResult]::new('--highlight', 'highlight', [CompletionResultType]::ParameterName, 'Highlight echoed recipe lines in bold')
|
||||
[CompletionResult]::new('--no-dotenv', 'no-dotenv', [CompletionResultType]::ParameterName, 'Don''t load `.env` file')
|
||||
|
@ -31,6 +31,8 @@ _just() {
|
||||
'--completions=[Print shell completion script for <SHELL>]: :(zsh bash fish powershell elvish)' \
|
||||
'-s+[Show information about <RECIPE>]: :_just_commands' \
|
||||
'--show=[Show information about <RECIPE>]: :_just_commands' \
|
||||
'(--dotenv-path)--dotenv-filename=[Search for environment file named <DOTENV-FILENAME> instead of `.env`]' \
|
||||
'--dotenv-path=[Load environment file at <DOTENV-PATH> instead of searching for one]' \
|
||||
'(-q --quiet)--dry-run[Print what just would do without doing it]' \
|
||||
'--highlight[Highlight echoed recipe lines in bold]' \
|
||||
'--no-dotenv[Don'\''t load `.env` file]' \
|
||||
|
@ -29,6 +29,8 @@ pub(crate) struct Config {
|
||||
pub(crate) subcommand: Subcommand,
|
||||
pub(crate) unsorted: bool,
|
||||
pub(crate) unstable: bool,
|
||||
pub(crate) dotenv_filename: Option<String>,
|
||||
pub(crate) dotenv_path: Option<PathBuf>,
|
||||
pub(crate) verbosity: Verbosity,
|
||||
}
|
||||
|
||||
@ -96,6 +98,8 @@ mod arg {
|
||||
pub(crate) const SHELL_COMMAND: &str = "SHELL-COMMAND";
|
||||
pub(crate) const UNSORTED: &str = "UNSORTED";
|
||||
pub(crate) const UNSTABLE: &str = "UNSTABLE";
|
||||
pub(crate) const DOTENV_FILENAME: &str = "DOTENV_FILENAME";
|
||||
pub(crate) const DOTENV_PATH: &str = "DOTENV_PATH";
|
||||
pub(crate) const VERBOSE: &str = "VERBOSE";
|
||||
pub(crate) const WORKING_DIRECTORY: &str = "WORKING-DIRECTORY";
|
||||
|
||||
@ -317,6 +321,19 @@ impl Config {
|
||||
.long("variables")
|
||||
.help("List names of variables"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(arg::DOTENV_FILENAME)
|
||||
.long("dotenv-filename")
|
||||
.takes_value(true)
|
||||
.help("Search for environment file named <DOTENV-FILENAME> instead of `.env`")
|
||||
.conflicts_with(arg::DOTENV_PATH),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(arg::DOTENV_PATH)
|
||||
.long("dotenv-path")
|
||||
.help("Load environment file at <DOTENV-PATH> instead of searching for one")
|
||||
.takes_value(true),
|
||||
)
|
||||
.group(ArgGroup::with_name("SUBCOMMAND").args(cmd::ALL))
|
||||
.arg(
|
||||
Arg::with_name(arg::ARGUMENTS)
|
||||
@ -537,6 +554,8 @@ impl Config {
|
||||
shell_args,
|
||||
shell_present,
|
||||
subcommand,
|
||||
dotenv_filename: matches.value_of(arg::DOTENV_FILENAME).map(str::to_owned),
|
||||
dotenv_path: matches.value_of(arg::DOTENV_PATH).map(PathBuf::from),
|
||||
verbosity,
|
||||
})
|
||||
}
|
||||
@ -616,6 +635,12 @@ OPTIONS:
|
||||
--completions <SHELL>
|
||||
Print shell completion script for <SHELL> [possible values: zsh,
|
||||
bash, fish, powershell, elvish]
|
||||
--dotenv-filename <DOTENV_FILENAME>
|
||||
Search for environment file named <DOTENV-FILENAME> instead of
|
||||
`.env`
|
||||
--dotenv-path <DOTENV_PATH>
|
||||
Load environment file at <DOTENV-PATH> instead of searching for one
|
||||
|
||||
-f, --justfile <JUSTFILE> Use <JUSTFILE> as justfile
|
||||
--list-heading <TEXT> Print <TEXT> before list
|
||||
--list-prefix <TEXT>
|
||||
@ -883,6 +908,11 @@ ARGS:
|
||||
verbosity: Verbosity::Quiet,
|
||||
}
|
||||
|
||||
error! {
|
||||
name: dotenv_both_filename_and_path,
|
||||
args: ["--dotenv-filename", "foo", "--dotenv-path", "bar"],
|
||||
}
|
||||
|
||||
test! {
|
||||
name: set_default,
|
||||
args: [],
|
||||
|
@ -426,7 +426,7 @@ impl<'src> ColorDisplay for Error<'src> {
|
||||
)?;
|
||||
},
|
||||
Dotenv { dotenv_error } => {
|
||||
write!(f, "Failed to load .env: {}", dotenv_error)?;
|
||||
write!(f, "Failed to load environment file: {}", dotenv_error)?;
|
||||
},
|
||||
EditorInvoke { editor, io_error } => {
|
||||
write!(
|
||||
|
@ -1,45 +1,69 @@
|
||||
use crate::common::*;
|
||||
|
||||
const DEFAULT_DOTENV_FILENAME: &str = ".env";
|
||||
|
||||
pub(crate) fn load_dotenv(
|
||||
config: &Config,
|
||||
settings: &Settings,
|
||||
working_directory: &Path,
|
||||
) -> RunResult<'static, BTreeMap<String, String>> {
|
||||
// `dotenv::from_path_iter` should eventually be un-deprecated, see:
|
||||
// https://github.com/dotenv-rs/dotenv/issues/13
|
||||
#![allow(deprecated)]
|
||||
|
||||
if !settings.dotenv_load.unwrap_or(true) {
|
||||
if !settings.dotenv_load.unwrap_or(true)
|
||||
&& config.dotenv_filename.is_none()
|
||||
&& config.dotenv_path.is_none()
|
||||
{
|
||||
return Ok(BTreeMap::new());
|
||||
}
|
||||
|
||||
if let Some(path) = &config.dotenv_path {
|
||||
return load_from_file(config, settings, &path);
|
||||
}
|
||||
|
||||
let filename = config
|
||||
.dotenv_filename
|
||||
.as_deref()
|
||||
.unwrap_or(DEFAULT_DOTENV_FILENAME)
|
||||
.to_owned();
|
||||
|
||||
for directory in working_directory.ancestors() {
|
||||
let path = directory.join(".env");
|
||||
|
||||
let path = directory.join(&filename);
|
||||
if path.is_file() {
|
||||
if settings.dotenv_load.is_none()
|
||||
&& config.verbosity.loud()
|
||||
&& !std::env::var_os("JUST_SUPPRESS_DOTENV_LOAD_WARNING")
|
||||
.map(|val| val.as_os_str().to_str() == Some("1"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
eprintln!(
|
||||
"{}",
|
||||
Warning::DotenvLoad.color_display(config.color.stderr())
|
||||
);
|
||||
}
|
||||
|
||||
let iter = dotenv::from_path_iter(&path)?;
|
||||
let mut dotenv = BTreeMap::new();
|
||||
for result in iter {
|
||||
let (key, value) = result?;
|
||||
if env::var_os(&key).is_none() {
|
||||
dotenv.insert(key, value);
|
||||
}
|
||||
}
|
||||
return Ok(dotenv);
|
||||
return load_from_file(config, settings, &path);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(BTreeMap::new())
|
||||
}
|
||||
|
||||
fn load_from_file(
|
||||
config: &Config,
|
||||
settings: &Settings,
|
||||
path: &Path,
|
||||
) -> RunResult<'static, BTreeMap<String, String>> {
|
||||
// `dotenv::from_path_iter` should eventually be un-deprecated, see:
|
||||
// https://github.com/dotenv-rs/dotenv/issues/13
|
||||
#![allow(deprecated)]
|
||||
|
||||
if config.verbosity.loud()
|
||||
&& settings.dotenv_load.is_none()
|
||||
&& config.dotenv_filename.is_none()
|
||||
&& config.dotenv_path.is_none()
|
||||
&& !std::env::var_os("JUST_SUPPRESS_DOTENV_LOAD_WARNING")
|
||||
.map(|val| val.as_os_str().to_str() == Some("1"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
eprintln!(
|
||||
"{}",
|
||||
Warning::DotenvLoad.color_display(config.color.stderr())
|
||||
);
|
||||
}
|
||||
|
||||
let iter = dotenv::from_path_iter(&path)?;
|
||||
let mut dotenv = BTreeMap::new();
|
||||
for result in iter {
|
||||
let (key, value) = result?;
|
||||
if env::var_os(&key).is_none() {
|
||||
dotenv.insert(key, value);
|
||||
}
|
||||
}
|
||||
Ok(dotenv)
|
||||
}
|
||||
|
100
tests/dotenv.rs
100
tests/dotenv.rs
@ -101,3 +101,103 @@ echo $DOTENV_KEY
|
||||
.suppress_dotenv_load_warning(false)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path_not_found() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
"
|
||||
foo:
|
||||
echo $NAME
|
||||
",
|
||||
)
|
||||
.args(&["--dotenv-path", ".env.prod"])
|
||||
.stderr(if cfg!(windows) {
|
||||
"error: Failed to load environment file: The system cannot find the file specified. (os \
|
||||
error 2)\n"
|
||||
} else {
|
||||
"error: Failed to load environment file: No such file or directory (os error 2)\n"
|
||||
})
|
||||
.status(EXIT_FAILURE)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path_resolves() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
"
|
||||
foo:
|
||||
@echo $NAME
|
||||
",
|
||||
)
|
||||
.tree(tree! {
|
||||
subdir: {
|
||||
".env": "NAME=bar"
|
||||
}
|
||||
})
|
||||
.args(&["--dotenv-path", "subdir/.env"])
|
||||
.stdout("bar\n")
|
||||
.status(EXIT_SUCCESS)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filename_resolves() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
"
|
||||
foo:
|
||||
@echo $NAME
|
||||
",
|
||||
)
|
||||
.tree(tree! {
|
||||
".env.special": "NAME=bar"
|
||||
})
|
||||
.args(&["--dotenv-filename", ".env.special"])
|
||||
.stdout("bar\n")
|
||||
.status(EXIT_SUCCESS)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filename_flag_overwrites_no_load() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
"
|
||||
set dotenv-load := false
|
||||
|
||||
foo:
|
||||
@echo $NAME
|
||||
",
|
||||
)
|
||||
.tree(tree! {
|
||||
".env.special": "NAME=bar"
|
||||
})
|
||||
.args(&["--dotenv-filename", ".env.special"])
|
||||
.stdout("bar\n")
|
||||
.status(EXIT_SUCCESS)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path_flag_overwrites_no_load() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
"
|
||||
set dotenv-load := false
|
||||
|
||||
foo:
|
||||
@echo $NAME
|
||||
",
|
||||
)
|
||||
.tree(tree! {
|
||||
subdir: {
|
||||
".env": "NAME=bar"
|
||||
}
|
||||
})
|
||||
.args(&["--dotenv-path", "subdir/.env"])
|
||||
.stdout("bar\n")
|
||||
.status(EXIT_SUCCESS)
|
||||
.run();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user