diff --git a/CHANGES.md b/CHANGES.md index 3b207e6..42df78a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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. diff --git a/Cargo.lock b/Cargo.lock index ebbd248..e6c78f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,10 +269,12 @@ dependencies = [ ] [[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +name = "dotenvs" +version = "0.1.0" +source = "git+https://github.com/jsirois/dotenvs-rs?rev=b2276ef3fd039ed8565b4c1cbedb7a5aeeca734e#b2276ef3fd039ed8565b4c1cbedb7a5aeeca734e" +dependencies = [ + "nom", +] [[package]] name = "either" @@ -436,14 +438,14 @@ dependencies = [ [[package]] name = "jump" -version = "0.13.3" +version = "0.14.0" dependencies = [ "bstr", "byteorder", "bzip2", "ctor", "dirs", - "dotenvy", + "dotenvs", "env_logger", "fd-lock", "flate2", @@ -550,6 +552,12 @@ dependencies = [ "libc", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.5.4" @@ -570,6 +578,16 @@ dependencies = [ "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -781,7 +799,7 @@ dependencies = [ [[package]] name = "scie-jump" -version = "0.13.3" +version = "0.14.0" dependencies = [ "bstr", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index d1f7f6a..c7573c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 ", diff --git a/docs/packaging.md b/docs/packaging.md index b69b2ad..25dc325 100644 --- a/docs/packaging.md +++ b/docs/packaging.md @@ -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 @@ -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. \ No newline at end of file +a zip file entry for each of the files you specified. diff --git a/examples/load/test.sh b/examples/load/test.sh index 20e04ce..8dd2c50 100644 --- a/examples/load/test.sh +++ b/examples/load/test.sh @@ -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 diff --git a/jump/Cargo.toml b/jump/Cargo.toml index 784cf93..bea36fd 100644 --- a/jump/Cargo.toml +++ b/jump/Cargo.toml @@ -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 ", @@ -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"] } @@ -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 } diff --git a/jump/src/lib.rs b/jump/src/lib.rs index e55a851..08ff469 100644 --- a/jump/src/lib.rs +++ b/jump/src/lib.rs @@ -180,20 +180,27 @@ pub fn prepare_boot() -> Result { 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];