Repository: a-scie/jump
Pull request #66 (2022-12-20 18:36:28)

Add opt-in support for .env loading.
This adds ~15KB to the Linux x86_64 binary.

jsirois: The scie-pants will enable this. In particular, this is one way to enable https://github.com/pantsbuild/scie-pants/pull/43 more ergonomically. No special launcher script to set env vars is needed, just a corporate `.env` in your home dir, etc.

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 3bee871..df192e2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -187,6 +187,12 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "dotenv"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
+
 [[package]]
 name = "either"
 version = "1.8.0"
@@ -370,6 +376,7 @@ dependencies = [
  "byteorder",
  "bzip2",
  "dirs",
+ "dotenv",
  "fd-lock",
  "flate2",
  "itertools",
diff --git a/examples/load/lift.linux-aarch64.json b/examples/load/lift.linux-aarch64.json
index 534a17c..3393a19 100644
--- a/examples/load/lift.linux-aarch64.json
+++ b/examples/load/lift.linux-aarch64.json
@@ -2,6 +2,7 @@
   "scie": {
     "lift": {
       "name": "cowsay",
+      "load_dotenv": true,
       "files": [
         {
           "name": "get.sh"
diff --git a/examples/load/lift.linux-x86_64.json b/examples/load/lift.linux-x86_64.json
index 89c57aa..6ed3d91 100644
--- a/examples/load/lift.linux-x86_64.json
+++ b/examples/load/lift.linux-x86_64.json
@@ -2,6 +2,7 @@
   "scie": {
     "lift": {
       "name": "cowsay",
+      "load_dotenv": true,
       "files": [
         {
           "name": "get.sh"
diff --git a/examples/load/lift.macos-aarch64.json b/examples/load/lift.macos-aarch64.json
index 4d7fd35..50674c5 100644
--- a/examples/load/lift.macos-aarch64.json
+++ b/examples/load/lift.macos-aarch64.json
@@ -2,6 +2,7 @@
   "scie": {
     "lift": {
       "name": "cowsay",
+      "load_dotenv": true,
       "files": [
         {
           "name": "get.sh"
diff --git a/examples/load/lift.macos-x86_64.json b/examples/load/lift.macos-x86_64.json
index 572a31a..5d16b02 100644
--- a/examples/load/lift.macos-x86_64.json
+++ b/examples/load/lift.macos-x86_64.json
@@ -2,6 +2,7 @@
   "scie": {
     "lift": {
       "name": "cowsay",
+      "load_dotenv": true,
       "files": [
         {
           "name": "get.sh"
diff --git a/examples/load/lift.windows-x86_64.json b/examples/load/lift.windows-x86_64.json
index e82913b..b8bd2ba 100644
--- a/examples/load/lift.windows-x86_64.json
+++ b/examples/load/lift.windows-x86_64.json
@@ -2,6 +2,7 @@
   "scie": {
     "lift": {
       "name": "cowsay",
+      "load_dotenv": true,
       "files": [
         {
           "name": "get.sh"
diff --git a/jump/Cargo.toml b/jump/Cargo.toml
index 2705e85..0bc829c 100644
--- a/jump/Cargo.toml
+++ b/jump/Cargo.toml
@@ -13,6 +13,7 @@ bstr = { workspace = true }
 byteorder = "1.4"
 bzip2 = "0.4"
 dirs = "4.0"
+dotenv = "0.15"
 fd-lock = "3.0"
 flate2 = "1.0"  # For gz support.
 itertools = "0.10"
diff --git a/jump/src/config.rs b/jump/src/config.rs
index b788cda..e0f7c46 100644
--- a/jump/src/config.rs
+++ b/jump/src/config.rs
@@ -243,6 +243,9 @@ pub struct Lift {
     pub base: Option<PathBuf>,
     pub files: Vec<File>,
     pub boot: Boot,
+    #[serde(default)]
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub load_dotenv: Option<bool>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
@@ -433,7 +436,8 @@ mod tests {
                         bindings: Default::default()
                     },
                     name: "test".to_string(),
-                    description: None
+                    description: None,
+                    load_dotenv: Some(false)
                 },
                 None,
             ))
diff --git a/jump/src/context.rs b/jump/src/context.rs
index 75348ba..9205689 100644
--- a/jump/src/context.rs
+++ b/jump/src/context.rs
@@ -608,6 +608,7 @@ mod tests {
             name: "test".to_string(),
             description: None,
             base: Some(tempdir.path().to_path_buf()),
+            load_dotenv: true,
             size: 137,
             hash: "abc".to_string(),
             boot: Boot {
diff --git a/jump/src/lib.rs b/jump/src/lib.rs
index 2cd06df..11e0417 100644
--- a/jump/src/lib.rs
+++ b/jump/src/lib.rs
@@ -24,7 +24,8 @@ use std::env;
 use std::env::current_exe;
 use std::path::PathBuf;
 
-use logging_timer::time;
+use log::Level;
+use logging_timer::{time, timer};
 
 pub use crate::archive::create_options;
 use crate::config::Config;
@@ -148,6 +149,12 @@ pub fn prepare_boot() -> Result<BootAction, String> {
         }
     }
 
+    if lift.load_dotenv {
+        let _timer = timer!(Level::Debug; "jump::load_dotenv");
+        if let Ok(dotenv_file) = dotenv::dotenv() {
+            debug!("Loaded env file from {path}", path = dotenv_file.display());
+        }
+    }
     let payload = &data[jump.size..data.len() - lift.size];
     let installer = Installer::new(payload);
     let result = context::select_command(&current_exe, &jump, &lift, &installer);
diff --git a/jump/src/lift.rs b/jump/src/lift.rs
index 1de88ed..8cae7d8 100644
--- a/jump/src/lift.rs
+++ b/jump/src/lift.rs
@@ -53,6 +53,7 @@ pub struct Lift {
     pub name: String,
     pub description: Option<String>,
     pub base: Option<PathBuf>,
+    pub(crate) load_dotenv: bool,
     pub size: usize,
     pub hash: String,
     pub boot: Boot,
@@ -95,6 +96,7 @@ impl From<Lift> for crate::config::Lift {
             name: value.name,
             description: value.description,
             base: value.base,
+            load_dotenv: if value.load_dotenv { Some(true) } else { None },
             boot: value.boot,
             files: value
                 .files
@@ -276,6 +278,7 @@ fn load(
             name: lift.name,
             description: lift.description,
             base: lift.base,
+            load_dotenv: lift.load_dotenv.unwrap_or(false),
             boot: lift.boot,
             size: data.len(),
             hash: fingerprint::digest(data),
diff --git a/src/boot/split.rs b/src/boot/split.rs
index 49e031b..88e7c33 100644
--- a/src/boot/split.rs
+++ b/src/boot/split.rs
@@ -7,7 +7,7 @@ use std::io::Read;
 use std::path::{Path, PathBuf};
 
 use jump::config::{FileType, Fmt};
-use jump::{File, Jump, Lift};
+use jump::{File, Jump, Lift, Source};
 use log::debug;
 use proc_exit::{Code, Exit, ExitResult};
 use zip::ZipArchive;
@@ -88,7 +88,9 @@ pub(crate) fn split(jump: Jump, mut lift: Lift, scie_path: PathBuf) -> ExitResul
     let mut scie_tote = vec![];
     let scie_tote_index = lift.files.len() - 1;
     for (index, file) in lift.files.iter().enumerate() {
-        if file.size == 0 {
+        if file.source != Source::Scie {
+            continue;
+        } else if file.size == 0 {
             scie_tote.push(file);
         } else if file.file_type == FileType::Directory
             || (index == scie_tote_index && !scie_tote.is_empty())
@@ -154,13 +156,15 @@ pub(crate) fn split(jump: Jump, mut lift: Lift, scie_path: PathBuf) -> ExitResul
     if !scie_tote.is_empty() {
         lift.files.remove(lift.files.len() - 1);
         for mut file in lift.files.iter_mut() {
-            let metadata = base.join(&file.name).metadata().map_err(|e| {
-                Code::FAILURE.with_message(format!(
-                    "Failed to determine size of {file}: {e}",
-                    file = file.name
-                ))
-            })?;
-            file.size = metadata.len() as usize;
+            if file.source == Source::Scie {
+                let metadata = base.join(&file.name).metadata().map_err(|e| {
+                    Code::FAILURE.with_message(format!(
+                        "Failed to determine size of {file}: {e}",
+                        file = file.name
+                    ))
+                })?;
+                file.size = metadata.len() as usize;
+            }
         }
     }
 


Test patch:
diff --git a/examples/load/test.sh b/examples/load/test.sh
index 7606fb9..2b45a1a 100644
--- a/examples/load/test.sh
+++ b/examples/load/test.sh
@@ -27,7 +27,10 @@ GET_LOG_CONFIG="$(mktemp)"
 gc "${GET_LOG_CONFIG}"
 export GET_LOG_CONFIG
 
-export GET_CONFIG="alt-metadata.json"
+# Specify an alternate URL database via load_dotenv capability.
+gc "${PWD}/.env"
+echo GET_CONFIG=alt-metadata.json > .env
 ./cowsay "Alt Curl!"
 
+source .env
 grep "${GET_CONFIG}" "${GET_LOG_CONFIG}"
diff --git a/examples/ptex/test.sh b/examples/ptex/test.sh
index 1837a6b..8629caa 100644
--- a/examples/ptex/test.sh
+++ b/examples/ptex/test.sh
@@ -10,6 +10,16 @@ check_cmd mktemp
 gc "${PWD}/cowsay"
 "${SCIE_JUMP}" "${LIFT}"
 
+# Verify byte-wise identical pack -> split -> pack round tripping.
+gc "${PWD}/split"
+SCIE="split" ./cowsay split
+
+sha256 cowsay* > split/cowsay.sha256
+cd split && ./scie-jump
+sha256 --check cowsay.sha256
+sha256 cowsay* ../cowsay*
+cd .. && rm -rf split
+
 # Force downloads to occur to exercise the load functionality even if nce cache has the JDK and the
 # cowsay jars already from other examples.
 SCIE_BASE="$(mktemp -d)"