From cf98ca9209a5cfbd3c7ee7eafe1ee27082f73c5a Mon Sep 17 00:00:00 2001 From: Laurent Fourrier Date: Tue, 10 Oct 2023 17:52:24 +0200 Subject: [PATCH 1/7] Added two new settings to `justfile`s. - `dotenv-filename` can be used to change the name of the `.env` file to look for. - `dotenv-path` can be used to change the path (and thus the name!) of the `.env` file to look for. --- src/keyword.rs | 2 ++ src/load_dotenv.rs | 24 +++++++------ src/node.rs | 2 +- src/parser.rs | 34 ++++++++++--------- src/setting.rs | 6 ++-- src/settings.rs | 8 +++++ tests/dotenv.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++ tests/json.rs | 34 +++++++++++++++++++ 8 files changed, 164 insertions(+), 30 deletions(-) diff --git a/src/keyword.rs b/src/keyword.rs index bff1b6c288..db2ba95155 100644 --- a/src/keyword.rs +++ b/src/keyword.rs @@ -5,7 +5,9 @@ use super::*; pub(crate) enum Keyword { Alias, AllowDuplicateRecipes, + DotenvFilename, DotenvLoad, + DotenvPath, Else, Export, Fallback, diff --git a/src/load_dotenv.rs b/src/load_dotenv.rs index b1fbe868a4..41f9eb9c6f 100644 --- a/src/load_dotenv.rs +++ b/src/load_dotenv.rs @@ -7,25 +7,27 @@ pub(crate) fn load_dotenv( settings: &Settings, working_directory: &Path, ) -> RunResult<'static, BTreeMap> { - if !settings.dotenv_load.unwrap_or(false) - && config.dotenv_filename.is_none() - && config.dotenv_path.is_none() - { + let dotenv_filename = config + .dotenv_filename + .as_ref() + .or(settings.dotenv_filename.as_ref()); + let dotenv_path = config + .dotenv_path + .as_ref() + .or(settings.dotenv_path.as_ref()); + + if !settings.dotenv_load.unwrap_or(false) && dotenv_filename.is_none() && dotenv_path.is_none() { return Ok(BTreeMap::new()); } - if let Some(path) = &config.dotenv_path { + if let Some(path) = dotenv_path { return load_from_file(path); } - let filename = config - .dotenv_filename - .as_deref() - .unwrap_or(DEFAULT_DOTENV_FILENAME) - .to_owned(); + let filename = dotenv_filename.map_or(DEFAULT_DOTENV_FILENAME, |s| s.as_str()); for directory in working_directory.ancestors() { - let path = directory.join(filename.as_str()); + let path = directory.join(filename); if path.is_file() { return load_from_file(&path); } diff --git a/src/node.rs b/src/node.rs index e231c2484e..924bcf348e 100644 --- a/src/node.rs +++ b/src/node.rs @@ -249,7 +249,7 @@ impl<'src> Node<'src> for Set<'src> { set.push_mut(Tree::string(&argument.cooked)); } } - Setting::Tempdir(value) => { + Setting::DotenvFilename(value) | Setting::DotenvPath(value) | Setting::Tempdir(value) => { set.push_mut(Tree::string(value)); } } diff --git a/src/parser.rs b/src/parser.rs index 04c4a9d1c5..e7c2ea0d52 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -780,8 +780,9 @@ impl<'tokens, 'src> Parser<'tokens, 'src> { self.presume_keyword(Keyword::Set)?; let name = Name::from_identifier(self.presume(Identifier)?); let lexeme = name.lexeme(); + let keyword = Keyword::from_lexeme(lexeme); - let set_bool: Option = match Keyword::from_lexeme(lexeme) { + let set_bool: Option = match keyword { Some(kw) => match kw { Keyword::AllowDuplicateRecipes => { Some(Setting::AllowDuplicateRecipes(self.parse_set_bool()?)) @@ -803,21 +804,22 @@ impl<'tokens, 'src> Parser<'tokens, 'src> { self.expect(ColonEquals)?; - if name.lexeme() == Keyword::Shell.lexeme() { - Ok(Set { - value: Setting::Shell(self.parse_shell()?), - name, - }) - } else if name.lexeme() == Keyword::WindowsShell.lexeme() { - Ok(Set { - value: Setting::WindowsShell(self.parse_shell()?), - name, - }) - } else if name.lexeme() == Keyword::Tempdir.lexeme() { - Ok(Set { - value: Setting::Tempdir(self.parse_string_literal()?.cooked), - name, - }) + let set_value: Option = match keyword { + Some(kw) => match kw { + Keyword::DotenvFilename => { + Some(Setting::DotenvFilename(self.parse_string_literal()?.cooked)) + } + Keyword::DotenvPath => Some(Setting::DotenvPath(self.parse_string_literal()?.cooked)), + 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()?)), + _ => None, + }, + None => None, + }; + + if let Some(value) = set_value { + Ok(Set { name, value }) } else { Err(name.error(CompileErrorKind::UnknownSetting { setting: name.lexeme(), diff --git a/src/setting.rs b/src/setting.rs index 7278760a21..9b2a9fe6f9 100644 --- a/src/setting.rs +++ b/src/setting.rs @@ -3,7 +3,9 @@ use super::*; #[derive(Debug, Clone)] pub(crate) enum Setting<'src> { AllowDuplicateRecipes(bool), + DotenvFilename(String), DotenvLoad(bool), + DotenvPath(String), Export(bool), Fallback(bool), IgnoreComments(bool), @@ -25,8 +27,8 @@ impl<'src> Display for Setting<'src> { | Setting::PositionalArguments(value) | Setting::WindowsPowerShell(value) => write!(f, "{value}"), Setting::Shell(shell) | Setting::WindowsShell(shell) => write!(f, "{shell}"), - Setting::Tempdir(tempdir) => { - write!(f, "{tempdir:?}") + Setting::DotenvFilename(value) | Setting::DotenvPath(value) | Setting::Tempdir(value) => { + write!(f, "{value:?}") } } } diff --git a/src/settings.rs b/src/settings.rs index 508cfb022e..26765e0f8f 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -9,7 +9,9 @@ pub(crate) const WINDOWS_POWERSHELL_ARGS: &[&str] = &["-NoLogo", "-Command"]; #[allow(clippy::struct_excessive_bools)] pub(crate) struct Settings<'src> { pub(crate) allow_duplicate_recipes: bool, + pub(crate) dotenv_filename: Option, pub(crate) dotenv_load: Option, + pub(crate) dotenv_path: Option, pub(crate) export: bool, pub(crate) fallback: bool, pub(crate) ignore_comments: bool, @@ -29,9 +31,15 @@ impl<'src> Settings<'src> { Setting::AllowDuplicateRecipes(allow_duplicate_recipes) => { settings.allow_duplicate_recipes = allow_duplicate_recipes; } + Setting::DotenvFilename(filename) => { + settings.dotenv_filename = Some(filename); + } Setting::DotenvLoad(dotenv_load) => { settings.dotenv_load = Some(dotenv_load); } + Setting::DotenvPath(path) => { + settings.dotenv_path = Some(PathBuf::from(path)); + } Setting::Export(export) => { settings.export = export; } diff --git a/tests/dotenv.rs b/tests/dotenv.rs index a1182f608a..3814e892f4 100644 --- a/tests/dotenv.rs +++ b/tests/dotenv.rs @@ -161,3 +161,87 @@ fn path_flag_overwrites_no_load() { .status(EXIT_SUCCESS) .run(); } + +#[test] +fn can_set_dotenv_filename_from_justfile() { + Test::new() + .justfile( + r#" + set dotenv-filename := ".env.special" + + foo: + @echo $NAME + "#, + ) + .tree(tree! { + ".env.special": "NAME=bar" + }) + .stdout("bar\n") + .status(EXIT_SUCCESS) + .run(); +} + +#[test] +fn can_set_dotenv_path_from_justfile() { + Test::new() + .justfile( + r#" + set dotenv-path:= "subdir/.env" + + foo: + @echo $NAME + "#, + ) + .tree(tree! { + subdir: { + ".env": "NAME=bar" + } + }) + .stdout("bar\n") + .status(EXIT_SUCCESS) + .run(); +} + +#[test] +fn program_argument_has_priority_for_dotenv_filename() { + Test::new() + .justfile( + r#" + set dotenv-filename := ".env.special" + + foo: + @echo $NAME + "#, + ) + .tree(tree! { + ".env.special": "NAME=bar", + ".env.superspecial": "NAME=baz" + }) + .args(["--dotenv-filename", ".env.superspecial"]) + .stdout("baz\n") + .status(EXIT_SUCCESS) + .run(); +} + +#[test] +fn program_argument_has_priority_for_dotenv_path() { + Test::new() + .justfile( + r#" + set dotenv-path:= "subdir/.env" + + foo: + @echo $NAME + "#, + ) + .tree(tree! { + subdir: { + ".env": "NAME=bar", + ".env.special": "NAME=baz" + } + }) + .args(["--dotenv-path", "subdir/.env.special"]) + .stdout("baz\n") + .status(EXIT_SUCCESS) + .run(); +} diff --git a/tests/json.rs b/tests/json.rs index 4e4afb1b15..39e04b68e3 100644 --- a/tests/json.rs +++ b/tests/json.rs @@ -42,7 +42,9 @@ fn alias() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "positional_arguments": false, @@ -74,7 +76,9 @@ fn assignment() { "recipes": {}, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -120,7 +124,9 @@ fn body() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -177,7 +183,9 @@ fn dependencies() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -271,7 +279,9 @@ fn dependency_argument() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -329,7 +339,9 @@ fn duplicate_recipes() { }, "settings": { "allow_duplicate_recipes": true, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -368,7 +380,9 @@ fn doc_comment() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -394,7 +408,9 @@ fn empty_justfile() { "recipes": {}, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -535,7 +551,9 @@ fn parameters() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -612,7 +630,9 @@ fn priors() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -651,7 +671,9 @@ fn private() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -690,7 +712,9 @@ fn quiet() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -710,6 +734,8 @@ fn settings() { test( " set dotenv-load + set dotenv-filename := \"filename\" + set dotenv-path := \"path\" set export set fallback set positional-arguments @@ -738,7 +764,9 @@ fn settings() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": "filename", "dotenv_load": true, + "dotenv_path": "path", "export": true, "fallback": true, "ignore_comments": true, @@ -783,7 +811,9 @@ fn shebang() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -822,7 +852,9 @@ fn simple() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "ignore_comments": false, @@ -864,7 +896,9 @@ fn attribute() { }, "settings": { "allow_duplicate_recipes": false, + "dotenv_filename": null, "dotenv_load": null, + "dotenv_path": null, "export": false, "fallback": false, "positional_arguments": false, From 5a1b900f6def786c45a5c01cf74bcf73d476957b Mon Sep 17 00:00:00 2001 From: Laurent Fourrier Date: Tue, 10 Oct 2023 18:13:49 +0200 Subject: [PATCH 2/7] Updated documentation (EN). --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7145ab3ee5..33bbaa8be8 100644 --- a/README.md +++ b/README.md @@ -669,7 +669,9 @@ foo: | Name | Value | Default | Description | | ------------------------- | ------------------ | ------- |---------------------------------------------------------------------------------------------- | | `allow-duplicate-recipes` | boolean | `false` | Allow recipes appearing later in a `justfile` to override earlier recipes with the same name. | +| `dotenv-filename` | string | - | Load a `.env` file with a custom name, if present. | | `dotenv-load` | boolean | `false` | Load a `.env` file, if present. | +| `dotenv-path` | string | - | Load a `.env` file from a custom path, if present. Overrides `dotenv-filename`. | | `export` | boolean | `false` | Export all variables as environment variables. | | `fallback` | boolean | `false` | Search `justfile` in parent directory if the first recipe on the command line is not found. | | `ignore-comments` | boolean | `false` | Ignore recipe lines beginning with `#`. | @@ -710,10 +712,15 @@ $ just foo bar ``` -#### Dotenv Load +#### Dotenv Settings If `dotenv-load` is `true`, a `.env` file will be loaded if present. Defaults to `false`. +`dotenv-filename` and `dotenv-path` can also be used to load a `.env` file: + +- `dotenv-filename` will look for a file with the given name in the current directory and all of its parents. +- `dotenv-path` will directly load the file at the given path. + #### Export The `export` setting causes all `just` variables to be exported as environment variables. Defaults to `false`. @@ -880,7 +887,11 @@ Available recipes: ### Dotenv Integration -If [`dotenv-load`](#dotenv-load) is set, `just` will load environment variables from a file named `.env`. This file can be located in the same directory as your `justfile` or in a parent directory. These variables are environment variables, not `just` variables, and so must be accessed using `$VARIABLE_NAME` in recipes and backticks. +If one of [`dotenv-load`, `dotenv-filename` or `dotenv-path`](#dotenv-settings) is set, `just` will load environment variables from a file. + +This file is named `.env` by default, unless `dotenv-filename` is used to change the name of the file that `just` will look for. +This file can be located in the same directory as your `justfile` or in a parent directory, unless this behavior is changed to point to a file in an arbitrary directory using `dotenv-path`. +These variables are environment variables, not `just` variables, and so must be accessed using `$VARIABLE_NAME` in recipes and backticks. For example, if your `.env` file contains: From 7c96dc3c04bc2c4a4feae08821398d3a86a3748e Mon Sep 17 00:00:00 2001 From: Laurent Fourrier Date: Wed, 11 Oct 2023 10:27:24 +0200 Subject: [PATCH 3/7] Added grammar for new `dotenv-*` settings. --- GRAMMAR.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GRAMMAR.md b/GRAMMAR.md index c19b24e87c..d99e7f89b4 100644 --- a/GRAMMAR.md +++ b/GRAMMAR.md @@ -60,7 +60,9 @@ assignment : NAME ':=' expression eol export : 'export' assignment setting : 'set' 'allow-duplicate-recipes' boolean? + | 'set' 'dotenv-filename' ':=' string | 'set' 'dotenv-load' boolean? + | 'set' 'dotenv-path' ':=' string | 'set' 'export' boolean? | 'set' 'fallback' boolean? | 'set' 'ignore-comments' boolean? From 5c0d3649f8449642c7347ab1decf2bbeca3b6ef5 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Wed, 11 Oct 2023 21:46:03 -0700 Subject: [PATCH 4/7] Refactor and add test --- src/load_dotenv.rs | 1 + src/parser.rs | 52 +++++++++++++++++++++------------------------- tests/misc.rs | 18 ++++++++++++++-- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/load_dotenv.rs b/src/load_dotenv.rs index 41f9eb9c6f..1ccb4b9bfb 100644 --- a/src/load_dotenv.rs +++ b/src/load_dotenv.rs @@ -11,6 +11,7 @@ pub(crate) fn load_dotenv( .dotenv_filename .as_ref() .or(settings.dotenv_filename.as_ref()); + let dotenv_path = config .dotenv_path .as_ref() diff --git a/src/parser.rs b/src/parser.rs index e7c2ea0d52..7928d6594e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -780,22 +780,23 @@ impl<'tokens, 'src> Parser<'tokens, 'src> { self.presume_keyword(Keyword::Set)?; let name = Name::from_identifier(self.presume(Identifier)?); let lexeme = name.lexeme(); - let keyword = Keyword::from_lexeme(lexeme); + let Some(keyword) = Keyword::from_lexeme(lexeme) else { + return Err(name.error(CompileErrorKind::UnknownSetting { + setting: name.lexeme(), + })); + }; - let set_bool: Option = match keyword { - Some(kw) => match kw { - Keyword::AllowDuplicateRecipes => { - Some(Setting::AllowDuplicateRecipes(self.parse_set_bool()?)) - } - Keyword::DotenvLoad => Some(Setting::DotenvLoad(self.parse_set_bool()?)), - Keyword::Export => Some(Setting::Export(self.parse_set_bool()?)), - Keyword::Fallback => Some(Setting::Fallback(self.parse_set_bool()?)), - Keyword::IgnoreComments => Some(Setting::IgnoreComments(self.parse_set_bool()?)), - Keyword::PositionalArguments => Some(Setting::PositionalArguments(self.parse_set_bool()?)), - Keyword::WindowsPowershell => Some(Setting::WindowsPowerShell(self.parse_set_bool()?)), - _ => None, - }, - None => None, + let set_bool = match keyword { + Keyword::AllowDuplicateRecipes => { + Some(Setting::AllowDuplicateRecipes(self.parse_set_bool()?)) + } + Keyword::DotenvLoad => Some(Setting::DotenvLoad(self.parse_set_bool()?)), + Keyword::Export => Some(Setting::Export(self.parse_set_bool()?)), + Keyword::Fallback => Some(Setting::Fallback(self.parse_set_bool()?)), + Keyword::IgnoreComments => Some(Setting::IgnoreComments(self.parse_set_bool()?)), + Keyword::PositionalArguments => Some(Setting::PositionalArguments(self.parse_set_bool()?)), + Keyword::WindowsPowershell => Some(Setting::WindowsPowerShell(self.parse_set_bool()?)), + _ => None, }; if let Some(value) = set_bool { @@ -804,22 +805,17 @@ impl<'tokens, 'src> Parser<'tokens, 'src> { self.expect(ColonEquals)?; - let set_value: Option = match keyword { - Some(kw) => match kw { - Keyword::DotenvFilename => { - Some(Setting::DotenvFilename(self.parse_string_literal()?.cooked)) - } - Keyword::DotenvPath => Some(Setting::DotenvPath(self.parse_string_literal()?.cooked)), - 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()?)), - _ => None, - }, - None => None, + 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::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()?)), + _ => None, }; if let Some(value) = set_value { - Ok(Set { name, value }) + return Ok(Set { name, value }); } else { Err(name.error(CompileErrorKind::UnknownSetting { setting: name.lexeme(), diff --git a/tests/misc.rs b/tests/misc.rs index 2c64d5d2fd..7d8ff0f2c4 100644 --- a/tests/misc.rs +++ b/tests/misc.rs @@ -71,10 +71,24 @@ test! { set foo ", stderr: " - error: Expected ':=', but found end of line + error: Unknown setting `foo` | 1 | set foo - | ^ + | ^^^ + ", + status: EXIT_FAILURE, +} + +test! { + name: bad_setting_with_keyword_name, + justfile: " + set if := 'foo' + ", + stderr: " + error: Unknown setting `if` + | + 1 | set if := 'foo' + | ^^ ", status: EXIT_FAILURE, } From 303929cefc2a5726312a16a7fd508a189311a33d Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Wed, 11 Oct 2023 21:51:05 -0700 Subject: [PATCH 5/7] Unwrap lines --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 33bbaa8be8..8fb7f98047 100644 --- a/README.md +++ b/README.md @@ -889,9 +889,7 @@ Available recipes: If one of [`dotenv-load`, `dotenv-filename` or `dotenv-path`](#dotenv-settings) is set, `just` will load environment variables from a file. -This file is named `.env` by default, unless `dotenv-filename` is used to change the name of the file that `just` will look for. -This file can be located in the same directory as your `justfile` or in a parent directory, unless this behavior is changed to point to a file in an arbitrary directory using `dotenv-path`. -These variables are environment variables, not `just` variables, and so must be accessed using `$VARIABLE_NAME` in recipes and backticks. +This file is named `.env` by default, unless `dotenv-filename` is used to change the name of the file that `just` will look for. This file can be located in the same directory as your `justfile` or in a parent directory, unless this behavior is changed to point to a file in an arbitrary directory using `dotenv-path`. These variables are environment variables, not `just` variables, and so must be accessed using `$VARIABLE_NAME` in recipes and backticks. For example, if your `.env` file contains: From 09ededdb8f1687029533667539f654bb03545748 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Wed, 11 Oct 2023 21:58:11 -0700 Subject: [PATCH 6/7] Combine dotenv settings and dotenv integration --- README.md | 69 ++++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index f2bd2dd20a..3efe0b9910 100644 --- a/README.md +++ b/README.md @@ -712,14 +712,41 @@ $ just foo bar ``` -#### Dotenv Settings +#### Dotenv -If `dotenv-load` is `true`, a `.env` file will be loaded if present. Defaults to `false`. +If `dotenv-load`, `dotenv-filename` or `dotenv-path` is set, `just` will load environment variables from a file. -`dotenv-filename` and `dotenv-path` can also be used to load a `.env` file: +If `dotenv-path` is set, `just` will look for a file at the given path. -- `dotenv-filename` will look for a file with the given name in the current directory and all of its parents. -- `dotenv-path` will directly load the file at the given path. +Otherwise, `just` looks for a file named `.env` by default, unless `dotenv-filename` set, in which case the value of `dotenv-filename` is used. This file can be located in the same directory as your `justfile` or in a parent directory. + +The loaded variables are environment variables, not `just` variables, and so must be accessed using `$VARIABLE_NAME` in recipes and backticks. + +For example, if your `.env` file contains: + +```sh +# a comment, will be ignored +DATABASE_ADDRESS=localhost:6379 +SERVER_PORT=1337 +``` + +And your `justfile` contains: + +```just +set dotenv-load + +serve: + @echo "Starting server with database $DATABASE_ADDRESS on port $SERVER_PORT…" + ./server --database $DATABASE_ADDRESS --port $SERVER_PORT +``` + +`just serve` will output: + +```sh +$ just serve +Starting server with database localhost:6379 on port 1337… +./server --database $DATABASE_ADDRESS --port $SERVER_PORT +``` #### Export @@ -885,38 +912,6 @@ Available recipes: test # test stuff ``` -### Dotenv Integration - -If one of [`dotenv-load`, `dotenv-filename` or `dotenv-path`](#dotenv-settings) is set, `just` will load environment variables from a file. - -This file is named `.env` by default, unless `dotenv-filename` is used to change the name of the file that `just` will look for. This file can be located in the same directory as your `justfile` or in a parent directory, unless this behavior is changed to point to a file in an arbitrary directory using `dotenv-path`. These variables are environment variables, not `just` variables, and so must be accessed using `$VARIABLE_NAME` in recipes and backticks. - -For example, if your `.env` file contains: - -```sh -# a comment, will be ignored -DATABASE_ADDRESS=localhost:6379 -SERVER_PORT=1337 -``` - -And your `justfile` contains: - -```just -set dotenv-load - -serve: - @echo "Starting server with database $DATABASE_ADDRESS on port $SERVER_PORT…" - ./server --database $DATABASE_ADDRESS --port $SERVER_PORT -``` - -`just serve` will output: - -```sh -$ just serve -Starting server with database localhost:6379 on port 1337… -./server --database $DATABASE_ADDRESS --port $SERVER_PORT -``` - ### Variables and Substitution Variables, strings, concatenation, path joining, and substitution using `{{…}}` are supported: From caf1dd151a87b517eb39dce6f875b829fcc1a009 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Wed, 11 Oct 2023 22:01:58 -0700 Subject: [PATCH 7/7] Placate clippy --- README.md | 7 ++----- justfile | 4 ---- src/parser.rs | 8 ++++---- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3efe0b9910..65e7aa4a43 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Yay, all your tests passed! - Wherever possible, errors are resolved statically. Unknown recipes and circular dependencies are reported before anything runs. -- `just` [loads `.env` files](#dotenv-integration), making it easy to populate environment variables. +- `just` [loads `.env` files](#dotenv-settings), making it easy to populate environment variables. - Recipes can be [listed from the command line](#listing-available-recipes). @@ -712,7 +712,7 @@ $ just foo bar ``` -#### Dotenv +#### Dotenv Settings If `dotenv-load`, `dotenv-filename` or `dotenv-path` is set, `just` will load environment variables from a file. @@ -1532,9 +1532,6 @@ print_home_folder: $ just HOME is '/home/myuser' ``` -#### Loading Environment Variables from a `.env` File - -`just` will load environment variables from a `.env` file if [dotenv-load](#dotenv-load) is set. The variables in the file will be available as environment variables to the recipes. See [dotenv-integration](#dotenv-integration) for more information. #### Setting `just` Variables from Environment Variables diff --git a/justfile b/justfile index 52b4ee1fa0..f25e719cb3 100755 --- a/justfile +++ b/justfile @@ -6,10 +6,6 @@ alias t := test alias c := check -bt := '0' - -export RUST_BACKTRACE := bt - log := "warn" export JUST_LOG := log diff --git a/src/parser.rs b/src/parser.rs index 7928d6594e..81ae3c19df 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -816,11 +816,11 @@ impl<'tokens, 'src> Parser<'tokens, 'src> { if let Some(value) = set_value { return Ok(Set { name, value }); - } else { - Err(name.error(CompileErrorKind::UnknownSetting { - setting: name.lexeme(), - })) } + + Err(name.error(CompileErrorKind::UnknownSetting { + setting: name.lexeme(), + })) } /// Parse a shell setting value