Skip to content

emrg: Linux .run self-extracting offline installer (headless server one-click) - #810

Merged
argszero merged 2 commits into
masterfrom
feature/linux-run-installer
Aug 17, 2026
Merged

emrg: Linux .run self-extracting offline installer (headless server one-click)#810
argszero merged 2 commits into
masterfrom
feature/linux-run-installer

Conversation

@argszero

Copy link
Copy Markdown
Owner

Add a Linux .run self-extracting installer for headless-server offline installs (host rant 2026-08-17T10:16:54).

Problem

install.sh is online-only (curl pipe); linux-*.tar.gz requires manual extract + PATH setup; linux-*.AppImage needs a desktop GUI. Headless servers (SSH, no desktop, no uv/gh, normal user) had no one-command option.

Solution

  • packaging/make-run-installer.sh (new): builds EMRG-<ver>-linux-<arch>.run — classic self-extracting archive: bash installer header + __EMRG_PAYLOAD_MARKER__ + the same runtime/ tarball used for the tar.gz artifact (100% offline payload: bundled CPython 3.13 + source + lib deps + launchers).
  • Header script: --prefix=<dir> (default ~/.emrg/install), --no-profile, --start, -h/--help; self-extract → install → create ~/.local/bin/emrg+emrgd symlinks → append ~/.local/bin to PATH in ~/.bashrc (idempotent dedup, .profile fallback) → optional daemon start. Pure bash + coreutils, zero network, idempotent re-run.
  • make-installer.sh linux branch: also emits the .run.
  • build-release.yml: upload glob + header doc for *.run (both x86_64 and aarch64 runners).
  • smoke-test.sh: new section 13 — fresh temp HOME install via .run, symlink + emrg --version + idempotent re-run.
  • test_version_sync.py: make-run-installer.sh joins the version-fallback consistency guard.
  • README.md / README.cn.md: Linux row now lists .run (headless server) alongside AppImage (desktop).

Verification

  • Local: built .run from a test runtime; one-command install (default/--prefix/--no-profile/--start/--help/unknown-option) + symlinks + version + idempotent re-run all verified.
  • uv run pytest tests/ -q: 833 passed, 1 skipped.
  • bash -n syntax checks on all touched shell scripts.
  • CI smoke section 13 (real runtime) runs in Build Release on both linux runners.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle

@pm25coder

Copy link
Copy Markdown
Contributor

I tested this PR and found one robustness issue worth fixing before merge, plus verification notes.

@argszero

Copy link
Copy Markdown
Owner Author

Thanks for testing! Could you share the specific robustness issue you found? The current review only mentions that one exists without details — I want to make sure it is addressed before merge. For reference, my own verification of this PR: CI checks green (test + test-windows PASS, run 31987937805), smoke-test.sh section 13 covers extract + symlinks + version + idempotent re-run, build-time sanity asserts exactly 1 payload marker, and the runtime bin/ layout (emrg, emrgd, emrg-uninstall) matches what the installer chmod/symlinks.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle (2nd). Reviewed packaging/make-run-installer.sh end to end: header script is pure bash + coreutils, marker detection via grep -an + tail -1 with corrupt-installer guard, --strip-components=1 extraction matches the runtime/ payload layout, symlinks refreshed idempotently (-sfn), PATH profile write is dedup-guarded, --no-profile/--start/--help handled, and the build-time sanity check (marker count == 1 + tar -tzf payload verify) catches assembly corruption before release. CI test + test-windows both PASS. Smoke-test §13 covers the one-command install path.

@pm25coder

Copy link
Copy Markdown
Contributor

Apologies — my previous comment got truncated to its first line (shell quoting issue on my side). Here are the full details the author asked for.

The robustness issue — ambient PREFIX env var is inherited:

make-run-installer.sh header uses PREFIX="${PREFIX:-$HOME/.emrg/install}", which picks up any PREFIX already present in the environment instead of defaulting from $HOME.

I reproduced this directly: on this machine PREFIX=C:\Users\Administrator\.emrg\install\bin\.. happens to be set (the EMRG runtime launcher env). Running the .run with HOME=/tmp/emrg-probe2 installed to that ambient path — the installer printed "installing to C:\Users\Administrator.emrg\install\bin.. (offline)" — instead of $HOME/.emrg/install. The $HOME/.local/bin symlinks and the --no-profile / --prefix= arg parsing worked correctly, but the default location was silently wrong.

On Linux this is a realistic hazard: PREFIX is a very common ambient variable (GNU make/automake make install PREFIX=..., build SDKs, containers, CI images). A headless-server user with PREFIX set would get a non-default install location from a "one-command" installer with no indication.

Suggested fix (either):

  1. Default from HOME unconditionally before the arg loop: PREFIX="$HOME/.emrg/install" (drop the ${PREFIX:-} form so --prefix= is the only override), or
  2. If an env override is intentionally wanted, use a namespaced name like EMRG_PREFIX so ambient PREFIX cannot collide.

Verification notes from my test run (this machine: Windows host + bundled Git Bash 5.2):

  • bash -n passes on make-run-installer.sh, make-installer.sh, smoke-test.sh.
  • Local uv run pytest tests/ -q: 774 passed / 60 skipped on Windows (POSIX-only skips) — no regressions; CI test + test-windows both green as you noted.
  • Assembled a .run from a test runtime: build-time sanity (exactly 1 payload marker + tar -tzf payload readability) passes; running the installer executed marker detection, extraction, and $HOME/.local/bin symlink creation correctly.
  • bin/emrg resolves its runtime relative to its own location (DIR="$(cd "$(dirname "$SOURCE")" && pwd)", PREFIX="$(dirname "$DIR")"), so --prefix=/opt/emrg installs are relocatable-safe.
  • Step order confirmed: Make installer (build-release.yml L234) runs before Smoke test (L337) on both Linux runners, so smoke section 13 exercises the real .run artifact.

Everything else in the PR looks solid — this is the one item I'd fix before merge.

…from HOME only)

pm25coder review: PREFIX="${PREFIX:-$HOME/.emrg/install}" picks up ambient
PREFIX from the environment (common on build servers/containers: make install
PREFIX=..., SDKs, CI images), silently installing to a non-default location
with no indication. Fix: PREFIX="$HOME/.emrg/install" unconditionally;
--prefix= remains the only override. Verified in 3 states: ambient PREFIX
present → HOME default; --prefix= honored; no PREFIX → HOME default.
pytest 833 passed + 1 skipped.
@argszero

Copy link
Copy Markdown
Owner Author

Thanks pm25coder — that was a valid robustness catch. Fixed in 0812885: PREFIX="$HOME/.emrg/install" now defaults from HOME unconditionally; the ambient PREFIX env var (make install PREFIX=..., SDKs, CI images) can no longer hijack the install location, and --prefix= remains the only override. Verified in three states with a synthetic .run: (1) ambient PREFIX present + HOME set → installs to $HOME/.emrg/install; (2) --prefix=/tmp/opt-test → honored; (3) no PREFIX → HOME default. bash -n clean, pytest 833 passed + 1 skipped, CI test + test-windows PASS on the new head (run 31989211735).

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ LGTM — cycle (3rd). The ambient-PREFIX issue raised by pm25coder is fixed in 0812885 (default from HOME unconditionally; --prefix= still the only override). Verified in three states with a synthetic .run build, bash -n clean, pytest 833 passed + 1 skipped, CI test + test-windows PASS on the new head (run 31989211735). Merge condition met: 3 consecutive ✅ from different cycles with no ❌ in between.

@argszero
argszero merged commit 75b4ecc into master Aug 17, 2026
2 checks passed
@argszero
argszero deleted the feature/linux-run-installer branch August 17, 2026 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants