Skip to content

fix: preserve freshly-installed v2 binary during v1 legacy cleanup#309

Merged
nimish-ks merged 2 commits into
mainfrom
fix/install-legacy-cleanup
Jul 7, 2026
Merged

fix: preserve freshly-installed v2 binary during v1 legacy cleanup#309
nimish-ks merged 2 commits into
mainfrom
fix/install-legacy-cleanup

Conversation

@nimish-ks

Copy link
Copy Markdown
Member

Problem

The v1 (Python/PyInstaller) binary-zip install laid down phase and an _internal/ directory side by side in /usr/local/bin. A v2 binary install lands in that same directory, but cleanup_legacy() deleted ${dir}/phase whenever ${dir}/_internal existed — removing the v2 binary it had just installed.

The installer still printed installed successfully and exited 0, so the machine was silently left with no phase command at all.

This only affected distros that fall through to the binary install path — Arch, and any OS/distro without a matching deb/rpm/apk package. Package installs put v2 in /usr/bin and were unaffected.

Reproduced (Arch, real v1.21.3 → v2.3.0 artifacts), old script

Installing to /usr/local/bin/phase...          # v2 written
Removing legacy /usr/local/bin/_internal/...
Removing old v1 binary /usr/local/bin/phase...  # deletes the v2 binary!
Phase CLI v2.3.0 installed successfully.        # exit 0
$ phase --version  → command not found

Fix

cleanup_legacy() now takes the absolute path of the just-installed binary (keep) and never deletes it — guarding both the _internal removal loop and the stale-symlink branch. Also removes the old package-manager advisory blocks, which were misleading (they fired even right after a successful v2 install).

Verification

Tested in containers against real v1.21.3 and v2.3.0 release artifacts:

Path Prior state Result
binary (Arch) v1 binary-zip leftover ✅ v2 preserved, _internal removed
deb / rpm / apk v1 binary-zip leftover in /usr/local/bin ✅ leftover removed, v2 at /usr/bin
deb / apk / rpm real v1 package upgrade ✅ clean upgrade to 2.3.0
binary v1 pkg symlink present ✅ stale /usr/bin/phase symlink removed, v2 kept
binary existing v2.0.0 ✅ idempotent re-run → 2.3.0
binary (Arch), old script v1 binary-zip leftover 🔴 reproduced the bug (v2 deleted)

sh -n clean.

The v1 (Python/PyInstaller) binary-zip layout installed `phase` alongside an
`_internal/` directory in /usr/local/bin. A v2 *binary* install lands in that
same directory, but cleanup_legacy() removed `${dir}/phase` whenever
`${dir}/_internal` was present — deleting the v2 binary it had just installed.
The installer still printed "installed successfully" and exited 0, leaving the
machine with no `phase` at all.

This only bit distros that fall through to the binary install path (Arch, and
any OS/distro without a matching deb/rpm/apk package); package installs put v2
in /usr/bin and were unaffected.

cleanup_legacy() now takes the absolute path of the just-installed binary and
never deletes it — guarding both the _internal removal loop and the
stale-symlink branch. Also drops the old, misleading package-manager advisory
blocks (they fired even after a successful v2 install).

Verified against real v1.21.3 and v2.3.0 release artifacts across binary,
deb, rpm and apk installs, real v1->v2 package upgrades, the stale-symlink
path, and idempotent re-runs.
Follow-up to the keep-guard fix, addressing review of #309:

- Compare inodes (-ef) instead of paths when deciding whether ${dir}/phase
  is the just-installed binary. On the (exotic) topology where a loop dir is
  a symlink onto another (e.g. /usr/local/bin -> /usr/bin), a v1 leftover and
  the fresh v2 binary are the same physical file under two paths; the old
  string compare missed that and deleted v2 on the package path. Verified on
  dash and busybox.

- Add a safety net: if $keep no longer exists after cleanup, die loudly
  instead of printing "installed successfully" over a broken install. This
  fails closed for any future regression in this class.

- Drop the non-load-bearing string guard on the stale-symlink branch (a
  successful package install has already replaced the symlink with a regular
  file, so [ -L ] is false there); the -ef check now covers it.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 6, 2026

Copy link
Copy Markdown

Deploying phase-cli-install-script with  Cloudflare Pages  Cloudflare Pages

Latest commit: f60eff3
Status: ✅  Deploy successful!
Preview URL: https://77d51908.phase-cli-install-script.pages.dev
Branch Preview URL: https://fix-install-legacy-cleanup.phase-cli-install-script.pages.dev

View logs

@nimish-ks nimish-ks merged commit e2c7e41 into main Jul 7, 2026
5 checks passed
@nimish-ks nimish-ks deleted the fix/install-legacy-cleanup branch July 7, 2026 10:31
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