Skip to content

fix(engine): robust Windows install + ship rocky-lsp alongside rocky#931

Merged
hugocorreia90 merged 2 commits into
mainfrom
fix/install-ps1-locked-binary
Jun 19, 2026
Merged

fix(engine): robust Windows install + ship rocky-lsp alongside rocky#931
hugocorreia90 merged 2 commits into
mainfrom
fix/install-ps1-locked-binary

Conversation

@hugocorreia90

@hugocorreia90 hugocorreia90 commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

The bug

Running the Windows install one-liner while VS Code is open fails:

Copy-Item: The process cannot access the file
'C:\Users\…\AppData\Local\rocky\bin\rocky.exe' because it is being used by another process.

Why

Two things combine:

  1. install.ps1 overwrote rocky.exe in place with Copy-Item -Force. On Windows a running executable is locked, so the overwrite fails.
  2. Neither installer ships the standalone rocky-lsp. The VS Code extension prefers rocky-lsp for the language server but, not finding it, falls back to spawning rocky lsp — so it runs rocky.exe, locking the exact file the installer is replacing.

install.sh (macOS/Linux) didn't hit this because it uses mv (atomic rename, fine over a running binary on Unix). This was Windows-only.

The fix (two complementary changes)

1. Rename-then-replace on Windows. Renaming an in-use binary is allowed on Windows (the running process keeps its handle), so install.ps1 now mirrors install.sh's mv: try a normal copy, and on a locked overwrite move the old binary aside (rocky.exe.old-<rand>) and drop the new one in. Stale .old files are swept on the next run. The install now succeeds while VS Code is open.

2. Ship rocky-lsp alongside rocky (both installers). This removes the root cause: when rocky-lsp is present the extension uses it for the LSP and never runs rocky.exe, so rocky.exe is never locked. Both installers best-effort download rocky-lsp-<target>, verify it against the same checksums.txt, and place it with the same mechanism as rocky. The Windows rename-replace is factored into an Install-RockyBinary helper so both binaries get identical robust install (and rocky-lsp's own future updates are covered too).

Best-effort and non-fatal: if the rocky-lsp archive is missing (older release) or fails verification, it's skipped and the extension falls back to rocky lsp. The core rocky install is unchanged.

No release needed — the one-liners fetch the scripts from main, so this takes effect on merge.

Verification

  • bash -n + shellcheck -S error clean on install.sh.
  • install.ps1 hand-verified (no pwsh on the build host): -ErrorAction Stop makes the lock error terminating so the catch fires; non-lock failures rethrow; the unique .old-<rand> name avoids colliding with a still-locked prior .old; Install-RockyBinary is defined before its call sites; the rocky-lsp block reuses the already-fetched checksums.txt and is wrapped so any failure is non-fatal.

🤖 Generated with Claude Code

On Windows a running executable is locked, so install.ps1's in-place
Copy-Item over rocky.exe failed with 'being used by another process' whenever
something was running the binary — most commonly the VS Code Rocky extension,
which spawns 'rocky lsp' (the installer never ships the standalone rocky-lsp,
so the extension falls back to running rocky.exe itself).

Renaming an in-use binary is allowed on Windows (the running process keeps its
handle to the renamed file), so mirror what install.sh already does with mv:
try a normal copy, and on a locked overwrite move the old binary aside
(rocky.exe.old-<rand>) and drop the new one into place, then tell the user to
restart VS Code. Stale .old files from prior in-use updates are swept on the
next run. The install now succeeds while VS Code is open.
The VS Code extension prefers a sibling rocky-lsp binary for the language
server; when it is present the extension never runs rocky.exe as the LSP, so
rocky.exe is never locked in the first place (the root cause of the Windows
in-place-overwrite failure). Both installers now best-effort install rocky-lsp
next to rocky: download the rocky-lsp-<target> archive, verify it against the
same checksums.txt, and place it with the same mechanism as rocky (mv on Unix;
rename-then-replace on Windows, now factored into an Install-RockyBinary helper
so both binaries get identical robust install).

Best-effort and non-fatal: if the rocky-lsp archive is missing (older release)
or fails verification, it is skipped and the extension falls back to 'rocky lsp'
(which the rename-then-replace install already handles). The core rocky install
is unchanged.
@hugocorreia90 hugocorreia90 changed the title fix(engine/install.ps1): replace an in-use rocky.exe instead of failing the overwrite fix(engine): robust Windows install + ship rocky-lsp alongside rocky Jun 19, 2026
@hugocorreia90 hugocorreia90 merged commit 41e6c86 into main Jun 19, 2026
13 checks passed
@hugocorreia90 hugocorreia90 deleted the fix/install-ps1-locked-binary branch June 19, 2026 16:47
hugocorreia90 added a commit that referenced this pull request Jun 19, 2026
…fix (#936)

- ide-setup.md: the VS Code extension prefers a standalone rocky-lsp binary (now
  installed next to rocky by the install scripts) and falls back to 'rocky lsp'.
- engine CHANGELOG [Unreleased]: record the installer fix (#931) — rocky-lsp
  shipped alongside rocky + Windows rename-then-replace — so it rides the next
  engine release notes. The fix is already live (scripts served from main).
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.

1 participant