9bf2961d13
test / unit (push) Successful in 57s
test / image-input-builds (push) Successful in 1m2s
Update Quality Badges / update-badges (push) Successful in 1m8s
test / integration-docker (push) Successful in 58s
test / coverage (push) Successful in 15s
lint / lint (push) Failing after 10m9s
The firecracker setup message told users to run
sudo bot-bottle backend setup --backend=firecracker
which fails for exactly the users who followed the documented install. sudo
replaces PATH with sudoers' secure_path — /usr/local/sbin:/usr/local/bin:
/usr/sbin:/usr/bin:/sbin:/bin on Debian and Ubuntu — which deliberately
excludes user-writable directories. Both supported install paths land in one:
pipx uses ~/.local/bin, and install.sh's venv fallback symlinks there. So the
hint works for anyone who installed system-wide and breaks with "command not
found" for everyone else, which is how it survives a read-through.
Add bot_bottle/invocation.py: self_path() resolves the running entry point to
an absolute path, and sudo_command() builds the copy-pasteable form. The one
sudo recommendation in the tree now uses it. Non-sudo hints keep the bare
`bot-bottle`, which is correct — the user reached them by running it.
self_path() falls back to the bare name when argv[0] cannot be resolved (a
`python -m` style invocation), because a slightly wrong hint beats a traceback
raised while reporting some unrelated problem.
Tested behaviourally rather than by scanning source: the first version of the
test grepped the module and failed on the comment explaining why the bare form
is wrong. It now drives _setup_systemd() as non-root and asserts what is
actually printed. Verified the guard bites by restoring the bare form and
watching it fail.
Not verified end to end: this message only prints on the systemd path, so it
is unreachable on macOS, where the rest of this work was tested.
49 lines
1.8 KiB
Python
49 lines
1.8 KiB
Python
"""How to tell a user to re-run this CLI.
|
|
|
|
`bot-bottle …` is the right thing to print for anything the user runs as
|
|
themselves — it is on their PATH, since that is how they got here.
|
|
|
|
Under `sudo` it is not. sudo replaces PATH with sudoers' `secure_path`
|
|
(`/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin` on Debian and
|
|
Ubuntu, similar elsewhere), which deliberately excludes user-writable
|
|
directories. Both supported install paths put the entry point in one of those:
|
|
pipx uses `~/.local/bin`, and `install.sh`'s venv fallback symlinks there too.
|
|
So `sudo bot-bottle …` fails with "command not found" for exactly the users who
|
|
followed the documented install, while working for anyone who happened to
|
|
install system-wide — which is why it survives review so easily.
|
|
|
|
Naming the absolute path sidesteps secure_path entirely.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import shutil
|
|
import sys
|
|
|
|
|
|
def self_path() -> str:
|
|
"""Absolute path to this CLI's entry point.
|
|
|
|
Falls back to the bare name when the entry point cannot be resolved (an
|
|
unusual invocation such as `python -m`), because a slightly wrong hint is
|
|
better than a traceback while reporting an unrelated problem.
|
|
"""
|
|
argv0 = sys.argv[0] or "bot-bottle"
|
|
resolved = shutil.which(argv0) or argv0
|
|
if not os.path.isabs(resolved):
|
|
if os.path.exists(resolved):
|
|
resolved = os.path.abspath(resolved)
|
|
else:
|
|
return "bot-bottle"
|
|
return resolved
|
|
|
|
|
|
def sudo_command(*args: str) -> str:
|
|
"""A copy-pasteable `sudo …` invocation of this CLI.
|
|
|
|
>>> sudo_command("backend", "setup", "--backend=firecracker")
|
|
'sudo /home/u/.local/bin/bot-bottle backend setup --backend=firecracker'
|
|
"""
|
|
return " ".join(["sudo", self_path(), *args])
|