Skip to content

Commit

Permalink
Add support for expanding .env quoted values. (#180)
Browse files Browse the repository at this point in the history
Switch from the dotenvy crate to dotenvs to achieve this. A patched
version is used to ensure we maintain support for hard failure when
invalid `.env` files are read.

Fixes #166
Fixes #167
  • Loading branch information
jsirois authored Dec 22, 2023
1 parent ba7e038 commit f765dc9
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 22 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Release Notes

## 0.14.0

Change `.env` parsing libraries to gain support for double quoted values with variable
substitution; e.g.: the `.env` line `PYTHONPATH="/Users/A. Space:$PYTHONPATH"` now has the
`$PYTHONPATH` portion of the value substituted.

## 0.13.3

Ensure liblzma is statically linked.
Expand Down
32 changes: 25 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ members = [

[package]
name = "scie-jump"
version = "0.13.3"
version = "0.14.0"
description = "The self contained interpreted executable launcher."
authors = [
"John Sirois <[email protected]>",
Expand Down
30 changes: 26 additions & 4 deletions docs/packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,31 @@ In the "lift" manifest, there are 3 required fields:

### Optional fields

A scie "lift" can opt in to loading `.env` files via the "load_dotenv" boolean field. The [dotenv](
https://crates.io/crates/dotenv) crate handles this loading. A lift's files and commands can also
have additional configuration metadata described.
A scie "lift" can opt in to loading `.env` files via the "load_dotenv" boolean field. The [dotenvs](
https://crates.io/crates/dotenvs) crate handles this loading and the following behavior is
guaranteed:

Parsing rules:

- `BASIC=basic` and `export BASIC=basic` both export an environment variable named `BASIC` with
value `basic`.
- Empty lines are skipped.
- Lines beginning with `#` are treated as comments.
- A `#` marks the beginning of a comment (unless the value is wrapped in quotes).
- Empty values become empty strings.
- Inner quotes are maintained.
- Whitespace is removed from both ends of unquoted values.
- Single and double quoted values maintain whitespace from both ends.

Expanding rules:

- `$KEY` or `${KEY}` will expand to the ambient environment value of `KEY` (unless the value is
wrapped in single quotes). If there is no ambient environment value for `KEY`, the expanded value
will be an empty string.
- `${KEY:-default}` will first attempt to expand `KEY` subject to the rules above. If `KEY` is not
defined, then it will return `default`.
- `\$KEY` will escape the `$KEY` rather than expand when not wrapped with quotes or wrapped with
double quotes.

A scie "lift" can also establish a custom `nce` cache directory via the "base" string field. Any
placeholders present in the custom value will be expanded save for the `{scie.lift}` placeholder
Expand Down Expand Up @@ -400,4 +422,4 @@ analyze and measure your use case for applicability when considering making a sc
creates an extra file called the `scie-tote` that is a zip that stores all the files above it inside
as STORED (uncompressed) entries. You need not be aware of this, the scie still functions like you'd
expect. Its only when using a tool like `zipinfo` to inspect your scie executable that you'll notice
a zip file entry for each of the files you specified.
a zip file entry for each of the files you specified.
12 changes: 12 additions & 0 deletions examples/load/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,20 @@ source .env
grep "${GET_CONFIG}" "${GET_LOG_CONFIG}"

# Motivated by: https://github.com/pantsbuild/scie-pants/issues/307
# And ammended by: https://github.com/a-scie/jump/issues/166
# shellcheck disable=SC2016 # We with this text to be included verbatim in the .env file.
echo 'PYTHONPATH="/foo/bar:$PYTHONPATH"' >> .env
./cowsay "Should succeed!"

# See motivating case here: https://github.com/arniu/dotenvs-rs/issues/4
cat << EOF >> .env
A=foo bar
B="notenough
C='toomany''
D=valid
export NOT_SET
E=valid
EOF
if ./cowsay "Should fail!"; then
die "The expected .env file loading failure did not happen."
else
Expand Down
7 changes: 5 additions & 2 deletions jump/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "jump"
version = "0.13.3"
version = "0.14.0"
description = "The bulk of the scie-jump binary logic."
authors = [
"John Sirois <[email protected]>",
Expand All @@ -13,7 +13,6 @@ bstr = { workspace = true }
byteorder = "1.4"
bzip2 = "0.4"
dirs = "4.0"
dotenvy = "0.15"
fd-lock = "3.0"
flate2 = "1.0" # For gz support.
indexmap = { version = "1.9", features = ["serde"] }
Expand All @@ -35,6 +34,10 @@ zip = { workspace = true }
zstd = "0.12"
walkdir = "2.3"

[dependencies.dotenvs]
git = "https://github.com/jsirois/dotenvs-rs"
rev = "b2276ef3fd039ed8565b4c1cbedb7a5aeeca734e"

[dev-dependencies]
ctor = "0.2"
env_logger = { workspace = true }
Expand Down
23 changes: 15 additions & 8 deletions jump/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,20 +180,27 @@ pub fn prepare_boot() -> Result<BootAction, String> {

if lift.load_dotenv {
let _timer = timer!(Level::Debug; "jump::load_dotenv");
match dotenvy::dotenv() {
Ok(dotenv_file) => debug!("Loaded env file from {path}", path = dotenv_file.display()),
Err(err) if err.not_found() => {
match dotenv::from_filename(".env") {
Ok(env) => {
let mut iter = env.iter();
while let Some((key, value)) = iter.try_next().map_err(|err| {
format!(
"This scie requested .env files be loaded but there was an error doing so: \
{err}"
)
})? {
if std::env::var(key).is_err() {
std::env::set_var(key, value);
}
}
}
Err(_) => {
debug!(
"No .env files found for invocation of {current_exe} from cwd of {cwd:?}",
current_exe = current_exe.exe.display(),
cwd = env::current_dir()
)
}
Err(err) => {
return Err(format!(
"This scie requested .env files be loaded but there was an error doing so: {err}"
))
}
}
}
let payload = &data[jump.size..data.len() - lift.size];
Expand Down

0 comments on commit f765dc9

Please sign in to comment.