Skip to content

Add vastai uninstall command for managed installs - #472

Merged
sammy-vastai merged 3 commits into
masterfrom
feat/uninstall-command
Jul 24, 2026
Merged

Add vastai uninstall command for managed installs#472
sammy-vastai merged 3 commits into
masterfrom
feat/uninstall-command

Conversation

@sammy-vastai

Copy link
Copy Markdown
Contributor

Summary

  • Adds vastai uninstall, mirroring vastai update's structure and same-method discipline: on a managed (curl | bash installer) install it removes the install root and its ~/.local/bin symlinks while leaving ~/.config/vastai (API key), cache, and state untouched; on a pip install it refuses and points at pip uninstall vastai instead of shelling out.
  • Prompts for confirmation unless -y/--yes; refuses in a non-interactive shell without --yes.
  • perform_uninstall() added to selfupdate.py next to the existing perform_update().
  • Both update and uninstall are hidden from --help/tab-completion for now (same hidden=True discoverability gate used for the network-volume commands in Hide unreleased network-volume commands from --help #466) — still fully runnable if typed directly, until they've had more real-world testing.

Test plan

  • poetry run pytest tests/cli/ — 389 passed
  • New tests/cli/test_uninstall_command.py covers: pip-install refusal, --yes skipping the prompt, non-interactive refusal without --yes, confirm/decline/EOF on the prompt, and perform_uninstall()'s filesystem behavior (removes root, removes only symlinks that resolve into the root, leaves foreign same-named binaries and config alone)
  • New hidden-command tests in test_parser.py confirm update/uninstall are excluded from --help but still parse
  • Manually verified end-to-end: built a dev wheel from this branch (scripts/dev-install.sh --from-source), confirmed uninstall is hidden from --help but runs directly, ran vastai uninstall --yes against a real managed install and confirmed the install root was removed and config was left in place, then reinstalled via scripts/install.sh and confirmed the wheel-install progress UX still works

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new vastai uninstall subcommand intended for managed (installer-based) installations, alongside updates to the hidden-command discoverability gate and new test coverage to validate uninstall behavior and help visibility.

Changes:

  • Adds vastai uninstall command with confirmation/--yes behavior and refusal for non-managed installs.
  • Implements managed-uninstall filesystem logic in perform_uninstall() (remove install root + relevant ~/.local/bin symlinks).
  • Extends hidden-command coverage so update/uninstall are excluded from --help while still parsing, plus new uninstall-focused tests.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
vastai/cli/selfupdate.py Adds LOCAL_BIN constant and perform_uninstall() to remove managed install root + symlinks.
vastai/cli/main.py Registers the new uninstall command module so it loads with other CLI commands.
vastai/cli/commands/update.py Marks update as hidden=True to hide it from --help/completion while still runnable.
vastai/cli/commands/uninstall.py Implements vastai uninstall command parsing, confirmation prompt, and managed-install gating.
tests/conftest.py Loads uninstall in the session-scoped CLI parser fixture for tests.
tests/cli/test_uninstall_command.py Adds unit tests for uninstall command behavior and perform_uninstall() filesystem effects.
tests/cli/test_parser.py Adds tests verifying update/uninstall are hidden from help but still parse directly.
Comments suppressed due to low confidence (2)

vastai/cli/selfupdate.py:350

  • perform_uninstall() currently swallows symlink resolution/unlink errors and uses shutil.rmtree(..., ignore_errors=True), so the uninstall command can report success even when binaries/root were not actually removed (e.g., permission errors, symlink loop). It also compares unresolved root against resolved targets, which can fail when VASTAI_INSTALL_DIR is a symlink.
            if link.is_symlink() and root in link.resolve().parents:
                link.unlink()
        except OSError:
            pass
    shutil.rmtree(root, ignore_errors=True)

vastai/cli/commands/uninstall.py:64

  • This message hard-codes "~/.config/vastai" even when XDG_CONFIG_HOME is set. Using $XDG_CONFIG_HOME here avoids telling users to look in the wrong place for their preserved API key/config.
    print("Config in ~/.config/vastai was left untouched.")

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread vastai/cli/selfupdate.py Outdated
Comment on lines +336 to +340
Config (~/.config/vastai), cache (~/.cache/vastai), and state
(~/.local/state/vastai) are left alone — the same guarantee documented
for a manual ``rm -rf`` (docs/install-design.md §3). Safe to call while
running from inside ``root``: like the update swap above, removing the
directory doesn't disturb an already-running interpreter on POSIX.
Comment thread vastai/cli/commands/uninstall.py Outdated
Comment on lines +62 to +65
perform_uninstall()
print(f"vastai {VERSION} uninstalled from {root}.")
print("Config in ~/.config/vastai was left untouched.")
return 0
Comment on lines +30 to +33
({INSTALL_SH_HINT}): the install root and its symlinks in
~/.local/bin. Config in ~/.config/vastai (your API key) is left
untouched, so re-running the installer keeps you logged in.
For pip installs, uninstall with: {PIP_UNINSTALL_HINT}
@sammy-vastai

Copy link
Copy Markdown
Contributor Author

Addressed Copilot's review:

  • perform_uninstall() no longer silently swallows failures: it resolves install_root() before comparing against resolved symlink targets (fixes the mismatch when VASTAI_INSTALL_DIR is itself a symlink) and now raises a new UninstallError with the real OSError detail on any removal failure, instead of ignore_errors=True/bare except: pass.
  • vastai uninstall now treats removal as fallible: it catches UninstallError, prints the real error to stderr, and exits 1 instead of unconditionally printing success. The success message now uses the Path returned by perform_uninstall().
  • Replaced the hardcoded ~/.config/vastai in the command's epilog/messages and the perform_uninstall() docstring with a reference to vastai.cli.util.DIRS (XDG-resolved at runtime), so the text stays correct under $XDG_CONFIG_HOME overrides.
  • Added regression tests: a symlinked VASTAI_INSTALL_DIR, symlink-unlink failure, root-removal failure, and the command surfacing a perform_uninstall() failure as a non-zero exit with the error on stderr.

tests/cli/ — 394 passed.

@sammy-vastai
sammy-vastai merged commit fc29a56 into master Jul 24, 2026
9 checks passed
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.

3 participants