Prefer pipx over pip3 --break-system-packages for Python tools

The previous fallback chain (pip3 install → pip3 install
--break-system-packages) silently writes into the distro Python's
site-packages on PEP 668 systems (Debian 12+, Ubuntu 23.04+). The warn
message fires after the damage is done. Since the target audience is
engineers SSH-ing into Linux servers, the PEP 668 hit rate is high.

New order:
  1. pipx install   (isolated per-tool venvs)
  2. pip3 --user    (works on pre-PEP-668 Python)
  3. --break-system-packages  (gated behind CHOPSTICKS_ALLOW_BREAK_SYSTEM=1)
  4. fail with a remediation hint

Also:
- Bootstrap pipx via the system package manager if it's missing.
- Warn if $HOME/.local/bin is absent from PATH (pipx and pip --user
  both install there).

Closes #66
This commit is contained in:
m1ngsama 2026-05-16 22:42:56 +08:00
parent d6df4fee3e
commit db68caee11
2 changed files with 37 additions and 7 deletions

View file

@ -26,6 +26,10 @@
- `install.sh` no longer silently `PlugClean!`s user-added plugins from - `install.sh` no longer silently `PlugClean!`s user-added plugins from
`~/.vim/plugged`; it now lists undeclared plugin directories first and `~/.vim/plugged`; it now lists undeclared plugin directories first and
asks before removing them (`--yes` skips the removal entirely) asks before removing them (`--yes` skips the removal entirely)
- `install.sh` Python tools now prefer `pipx` and `pip3 --user` over
`pip3 install --break-system-packages`; the break-system path is gated
behind `CHOPSTICKS_ALLOW_BREAK_SYSTEM=1` so PEP 668 distros are no
longer silently polluted
- `g:loaded_logipat` typo → `g:loaded_logiPat` — logiPat was loading fully (0.478ms wasted) - `g:loaded_logipat` typo → `g:loaded_logiPat` — logiPat was loading fully (0.478ms wasted)
- `get.sh` now refuses to update an existing `~/.vim` git repo unless its - `get.sh` now refuses to update an existing `~/.vim` git repo unless its
origin is chopsticks origin is chopsticks

View file

@ -1015,19 +1015,45 @@ elif [[ $_I_PYTHON -lt 0 ]] || ! _selected "$_I_PYTHON"; then
skip "Python tool suite (skipped by user)" skip "Python tool suite (skipped by user)"
SKIPPED+=("black" "isort" "flake8" "pylint" "yamllint" "sqlfluff") SKIPPED+=("black" "isort" "flake8" "pylint" "yamllint" "sqlfluff")
else else
# Prefer pipx (isolated per-tool venvs, the recommended path on PEP 668
# distros like Debian 12+/Ubuntu 23.04+). Bootstrap pipx via the system
# package manager if missing. Only fall back to --break-system-packages
# if the user explicitly opts in.
if ! command -v pipx >/dev/null 2>&1; then
if pkg_install pipx pipx python-pipx pipx 2>/dev/null; then
ok "pipx (recommended Python CLI installer)"
else
warn "pipx not available — falling back to pip3 --user"
fi
fi
case ":$PATH:" in
*":$HOME/.local/bin:"*) ;;
*) warn "\$HOME/.local/bin is not on PATH — pipx/pip --user tools will not be found"
info "Add to your shell rc: export PATH=\"\$HOME/.local/bin:\$PATH\"" ;;
esac
pip_install() { pip_install() {
local pkg="$1" check="${2:-$1}" local pkg="$1" check="${2:-$1}"
if command -v "$check" >/dev/null 2>&1; then if command -v "$check" >/dev/null 2>&1; then
ok "$pkg (already installed)"; return ok "$pkg (already installed)"; return
fi fi
if pip3 install --quiet "$pkg" 2>/dev/null; then if command -v pipx >/dev/null 2>&1 && pipx install --quiet "$pkg" 2>/dev/null; then
ok "$pkg"; INSTALLED+=("$pkg") ok "$pkg (via pipx)"; INSTALLED+=("$pkg")
elif pip3 install --quiet --break-system-packages "$pkg" 2>/dev/null; then return
warn "$pkg installed with --break-system-packages (consider using a virtualenv)"
ok "$pkg"; INSTALLED+=("$pkg")
else
fail "$pkg"; FAILED+=("$pkg")
fi fi
if pip3 install --quiet --user "$pkg" 2>/dev/null; then
ok "$pkg (via pip --user)"; INSTALLED+=("$pkg")
return
fi
if [[ "${CHOPSTICKS_ALLOW_BREAK_SYSTEM:-0}" == "1" ]] && \
pip3 install --quiet --break-system-packages "$pkg" 2>/dev/null; then
warn "$pkg installed with --break-system-packages (CHOPSTICKS_ALLOW_BREAK_SYSTEM=1)"
INSTALLED+=("$pkg")
return
fi
fail "$pkg — install pipx, or set CHOPSTICKS_ALLOW_BREAK_SYSTEM=1 to bypass PEP 668"
FAILED+=("$pkg")
} }
pip_install black pip_install black
pip_install isort pip_install isort