Skip to content

feat: allow binaryDestination to accept a full path to the CLI binary#879

Merged
EhabY merged 3 commits intomainfrom
feat/binary-destination-file-path
Apr 10, 2026
Merged

feat: allow binaryDestination to accept a full path to the CLI binary#879
EhabY merged 3 commits intomainfrom
feat/binary-destination-file-path

Conversation

@EhabY
Copy link
Copy Markdown
Collaborator

@EhabY EhabY commented Apr 9, 2026

Summary

The coder.binaryDestination setting (and CODER_BINARY_DESTINATION env var) now accepts a file path in addition to a directory path.

File path (e.g. /usr/bin/coder): the extension checks its version and downloads a replacement if it does not match the server (and downloads are enabled). If downloads are disabled, the existing binary is used with a warning. Downloads always go to the platform-specific name first, then rename to the configured path under the lock.

Directory path (existing behavior): looks for the platform-specific name (coder-linux-amd64) first, then falls back to the simple name (coder / coder.exe). This supports package-manager-installed CLIs (e.g. via apt, brew, winget) that use the simple name.

Changes

  • Add cliUtils.simpleName() and rename name() to fullName() for clarity
  • Add unified resolveBinaryPath() in CliManager returning a ResolvedBinary discriminated union (source: "file-path" | "directory" | "not-found") used by both locateBinary() and fetchBinary()
  • Scope rmOld cleanup to only files prefixed with the binary basename, preventing accidental removal in shared directories like /usr/bin
  • Always download using the platform-specific name for temp files, backups, signatures, and lock files
  • On error recovery, handleAnyBinaryFailure tries candidates in order (download path, user configured path, old backups) and renames the fallback to resolved.binPath so the binary ends up where the user expects
  • Linearize fetchBinary decision tree: version check, lock-wait, and rename logic now use sequential guard clauses instead of nested branches, and a renameToFinalPath helper replaces duplicated rename logic
  • Fix binaryDestination setting description to accurately reflect version-check-then-download behavior
  • Remove flaky lock/progress file assertions from concurrent tests

Test coverage

  • File destination: locate, version match, download+rename, in-place download (platform-specific name matches), downloads disabled, error fallback to configured path, error fallback with rename
  • Simple name fallback: locate, prefer platform-specific, version match, download to platform-specific name, error fallback
  • Old backup restore: simulates EBUSY during replace, verifies .old-* backup is restored to expected path

Resolves #861

@EhabY EhabY self-assigned this Apr 9, 2026
@EhabY EhabY force-pushed the feat/binary-destination-file-path branch 2 times, most recently from d8f1641 to 59f545c Compare April 10, 2026 09:58
EhabY added 2 commits April 10, 2026 19:48
The coder.binaryDestination setting (and CODER_BINARY_DESTINATION env
var) now accepts either a file path or a directory path:

- File path (e.g. /usr/bin/coder): if the file exists, use it directly.
  Version is checked and reported. If the version mismatches and
  downloads are enabled, the binary is re-downloaded to the same path.
  If downloads are disabled, the existing binary is used as-is with a
  warning.

- Directory path (existing behavior): look for the platform-specific
  name (e.g. coder-linux-amd64) first, then fall back to the simple
  name (coder / coder.exe). This supports package-manager-installed
  CLIs that use the simple name.

Adds cliUtils.simpleName() returning "coder" (or "coder.exe" on
Windows) and a unified resolveBinaryPath() method in CliManager used
by both locateBinary() and fetchBinary().

Resolves #861
Always download to the platform-specific binary name (coder-linux-amd64)
for temp files, old backups, signatures, and lock files. After a
successful download, rename the result to the user's configured file
name while still holding the lock to avoid races with other windows.

Scoped rmOld to only clean files prefixed with the binary basename so
it does not accidentally remove unrelated files when the target
directory is shared (e.g. /usr/bin).

Additional improvements:
- Rename cliUtils.name() to fullName() to pair with simpleName()
- Replace ResolvedBinary kind "file"/"dir" with source "file-path"/"directory"
  to clarify that stat always describes the binary, not the directory
- Fix binaryDestination description: file paths are version-checked and
  updated on mismatch, not used without downloading
- Update resolveBinaryPath JSDoc to remove misleading "as-is" language
- Add fallback path to error handler so file-path destinations check
  the user's original binary when the download path has no usable binary
- Simplify handleAnyBinaryFailure with tryCandidate closure and deferred
  findOldBinaries to avoid unnecessary I/O when earlier candidates match
- On error recovery, rename fallback to resolved.binPath so the binary
  always ends up where the user expects
- Add "starting download" back to the no-binary-found log message
- Improve test coverage: file destination error fallback, simple name
  error fallback, platform-specific file destination, old backup restore
- Unify test structure: shared disableSignatureVerification in top-level
  beforeEach, shared withFailedDownload helper, Binary Resolution group
- Remove flaky lock/progress file assertions from concurrent tests
@EhabY EhabY force-pushed the feat/binary-destination-file-path branch from 59f545c to 7cda5ed Compare April 10, 2026 16:48
@EhabY EhabY force-pushed the feat/binary-destination-file-path branch from c3d3903 to 8a691b6 Compare April 10, 2026 19:32
The version check, lock-wait, and rename logic in fetchBinary used
nested if/else-if blocks and a needsDownload flag that made the
control flow hard to follow. This refactors it into sequential guard
clauses (version match, downloads disabled, version mismatch) and
replaces the flag with an early return. The duplicated rename-to-
final-path logic is extracted into a small helper used in both the
lock-wait and download paths.

No behavior changes.
@EhabY EhabY force-pushed the feat/binary-destination-file-path branch from 8a691b6 to e866c3c Compare April 10, 2026 19:35
@EhabY EhabY merged commit c2aa5ca into main Apr 10, 2026
6 checks passed
@EhabY EhabY deleted the feat/binary-destination-file-path branch April 10, 2026 19:37
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.

Allow binaryDirectory setting to accept a full path to the CLI binary

2 participants