install.sh, setup.sh: apply the no-tty consent fix to the remaining sites (#7470)
Follow-up to #7435, which fixed _smart_apt_install. Three sites were left. studio/setup.sh: the WSL GGUF build-deps block is the pre-#7435 install.sh pattern verbatim. It probes with 'test -r /dev/tty', assumes REPLY=y when that fails, and then runs the elevated apt-get with stdin open. Its own guard comment says a password is needed on WSL, so this is exactly the scenario from issue #7307, and install.sh runs setup.sh in the same install. Give it the same treatment: a real open probe, -n -k with stdin closed on the headless path, and the manual command plus the existing _SKIP_GGUF_BUILD degradation on failure. The helper is defined locally because setup.sh runs as its own process. install.sh autostart prompt: still used 'test -r /dev/tty' and printed the question before checking, leaving a dangling prompt in container logs. Reuse _can_read_tty and move the printf inside the branch. install.sh interactive escalation: a sudoers denial, a wrong password or an apt error aborted on the bare message while the headless branch printed what to run by hand. Make both symmetric. Co-authored-by: danielhanchen <unslothai@gmail.com>
This commit is contained in:
parent
d7cdc96051
commit
dc24bba43e
3 changed files with 77 additions and 21 deletions
22
install.sh
22
install.sh
|
|
@ -718,8 +718,20 @@ _smart_apt_install() {
|
|||
exit 1
|
||||
;;
|
||||
esac
|
||||
sudo apt-get update -y </dev/null
|
||||
sudo apt-get install -y $_STILL_MISSING </dev/null
|
||||
# Mirror the headless branch: on a sudoers denial, a wrong password
|
||||
# or an apt error, say what to run by hand instead of letting set -e
|
||||
# abort on a bare sudo/apt message.
|
||||
if sudo apt-get update -y </dev/null &&
|
||||
sudo apt-get install -y $_STILL_MISSING </dev/null; then
|
||||
:
|
||||
else
|
||||
echo ""
|
||||
echo " Could not install these packages: $_STILL_MISSING"
|
||||
echo " See the error above."
|
||||
echo " Please install them first, then re-run Unsloth Studio setup:"
|
||||
echo " sudo apt-get update -y && sudo apt-get install -y $_STILL_MISSING"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Nobody can answer a prompt or type a password here. -n makes sudo
|
||||
# refuse rather than prompt into a closed stdin, which is how #7307
|
||||
|
|
@ -4091,9 +4103,11 @@ echo ""
|
|||
# In non-interactive environments (Docker, CI, cloud-init) just print instructions.
|
||||
if [ "$_SKIP_AUTOSTART" != true ] && [ -t 1 ]; then
|
||||
echo ""
|
||||
printf " Start Unsloth Studio now? [Y/n] "
|
||||
# No readable answer (closed/EOF tty) defaults to no; Enter is still yes.
|
||||
if [ -r /dev/tty ]; then
|
||||
# Prompt only when something can answer: `test -r` passes on the unopenable
|
||||
# /dev/tty found in containers, leaving a dangling question in the log.
|
||||
if _can_read_tty; then
|
||||
printf " Start Unsloth Studio now? [Y/n] "
|
||||
read -r _reply </dev/tty || _reply="n"
|
||||
else
|
||||
_reply="n"
|
||||
|
|
|
|||
|
|
@ -67,6 +67,15 @@ fi
|
|||
step() { printf " ${C_DIM}%-15.15s${C_RST}${3:-$C_OK}%s${C_RST}\n" "$1" "$2"; }
|
||||
substep() { printf " %-15s${2:-$C_DIM}%s${C_RST}\n" "" "$1"; }
|
||||
|
||||
# ── Helper: can the controlling terminal actually be opened for reading? ──
|
||||
# `test -r` only checks permission bits, which look fine in containers and
|
||||
# systemd units where open() then fails with ENXIO. Probe with a real open.
|
||||
# Mirrors install.sh's _can_read_tty; defined here too because setup.sh runs
|
||||
# as its own process (install.sh invokes it, it does not source it).
|
||||
_can_read_tty() {
|
||||
( : </dev/tty ) >/dev/null 2>&1
|
||||
}
|
||||
|
||||
_is_verbose() {
|
||||
[ "${UNSLOTH_VERBOSE:-0}" = "1" ]
|
||||
}
|
||||
|
|
@ -1510,25 +1519,46 @@ if [ "$_NEED_LLAMA_SOURCE_BUILD" = true ] && grep -qi microsoft /proc/version 2>
|
|||
step "gguf deps" "installed"
|
||||
elif command -v sudo >/dev/null 2>&1; then
|
||||
step "gguf deps" "sudo required for: $_STILL_MISSING" "$C_WARN"
|
||||
printf " %-15s" ""
|
||||
printf "accept? [Y/n] "
|
||||
if [ -r /dev/tty ]; then
|
||||
read -r REPLY </dev/tty || REPLY="y"
|
||||
if _can_read_tty; then
|
||||
printf " %-15s" ""
|
||||
printf "accept? [Y/n] "
|
||||
# The device opened, so a failed read is EOF, not consent: decline.
|
||||
read -r REPLY </dev/tty || REPLY="n"
|
||||
case "$REPLY" in
|
||||
[nN]*)
|
||||
substep "skipped -- run manually:"
|
||||
substep "sudo apt-get install -y $_STILL_MISSING"
|
||||
_SKIP_GGUF_BUILD=true
|
||||
;;
|
||||
*)
|
||||
# Degrade like the no-sudo branch below rather than letting
|
||||
# set -e abort setup on a bare apt error: missing GGUF build
|
||||
# deps are recoverable, not fatal.
|
||||
if sudo apt-get update -y </dev/null &&
|
||||
sudo apt-get install -y $_STILL_MISSING </dev/null; then
|
||||
step "gguf deps" "installed"
|
||||
else
|
||||
step "gguf deps" "install failed -- run manually:" "$C_WARN"
|
||||
substep "sudo apt-get update -y && sudo apt-get install -y $_STILL_MISSING"
|
||||
_SKIP_GGUF_BUILD=true
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
else
|
||||
REPLY="y"
|
||||
fi
|
||||
case "$REPLY" in
|
||||
[nN]*)
|
||||
substep "skipped -- run manually:"
|
||||
substep "sudo apt-get install -y $_STILL_MISSING"
|
||||
# Nobody can answer a prompt or type a password here, so -n makes
|
||||
# sudo refuse rather than prompt into a closed stdin, and -k ignores
|
||||
# any cached timestamp so only a real NOPASSWD rule gets through.
|
||||
# Same treatment as install.sh's _smart_apt_install. This is the WSL
|
||||
# GGUF-export case noted above, where sudo does want a password.
|
||||
if sudo -n -k apt-get update -y </dev/null &&
|
||||
sudo -n -k apt-get install -y $_STILL_MISSING </dev/null; then
|
||||
step "gguf deps" "installed (non-interactive sudo)"
|
||||
else
|
||||
step "gguf deps" "needs sudo, no terminal -- run manually:" "$C_WARN"
|
||||
substep "sudo apt-get update -y && sudo apt-get install -y $_STILL_MISSING"
|
||||
_SKIP_GGUF_BUILD=true
|
||||
;;
|
||||
*)
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y $_STILL_MISSING
|
||||
step "gguf deps" "installed"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
else
|
||||
step "gguf deps" "missing (no sudo) -- install manually:" "$C_WARN"
|
||||
substep "apt-get install -y $_STILL_MISSING"
|
||||
|
|
|
|||
|
|
@ -163,6 +163,11 @@ run_smart() {
|
|||
*) return 1 ;;
|
||||
esac
|
||||
fi
|
||||
# Sudoers refuses the command outright, with or without -n.
|
||||
if [ "$_sudo_mode" = denied ]; then
|
||||
echo "sudo: user is not allowed to execute that" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "SUDO_RAN: $*"
|
||||
}
|
||||
# shellcheck disable=SC1090
|
||||
|
|
@ -199,6 +204,13 @@ _out=$(run_smart tty needspasswd)
|
|||
assert_contains "tty present: still prompts" "$_out" "Accept? [Y/n]"
|
||||
assert_contains "tty present: accepts and installs" "$_out" "SUDO_RAN: apt-get install -y cmake"
|
||||
|
||||
# Consent given at a real tty, but the elevated apt-get fails anyway (sudoers
|
||||
# denial, wrong password, apt error). The interactive branch must say what to
|
||||
# run by hand, like the headless branch does, not die on the bare sudo error.
|
||||
_out=$(run_smart tty denied)
|
||||
assert_contains "tty + denied sudo: gives the manual command" \
|
||||
"$_out" "sudo apt-get update -y && sudo apt-get install -y cmake"
|
||||
|
||||
# No sudo at all keeps its own message.
|
||||
_out=$(run_smart notty absent)
|
||||
assert_contains "no sudo binary: unchanged message" "$_out" "sudo is not available on this system"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue