mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-02 10:52:22 +00:00
fix(update): confirm with Yes focused and keep the package list aligned
This commit is contained in:
@@ -167,7 +167,7 @@ class UpdateCliTests(unittest.TestCase):
|
|||||||
with tempfile.TemporaryDirectory(prefix='pbs-update-i18n-') as folder:
|
with tempfile.TemporaryDirectory(prefix='pbs-update-i18n-') as folder:
|
||||||
body=function('scripts/global/update-pbs.sh','update_pbs')
|
body=function('scripts/global/update-pbs.sh','update_pbs')
|
||||||
for old,new in [('/var/log/',folder+'/log/'),('/tmp/proxmenux_screen_capture_',folder+'/tmp/proxmenux_screen_capture_'),('/var/run/',folder+'/run/'),('/boot/',folder+'/boot/')]: body=body.replace(old,new)
|
for old,new in [('/var/log/',folder+'/log/'),('/tmp/proxmenux_screen_capture_',folder+'/tmp/proxmenux_screen_capture_'),('/var/run/',folder+'/run/'),('/boot/',folder+'/boot/')]: body=body.replace(old,new)
|
||||||
script=UPDATE_HARNESS+function('scripts/utils.sh','translate')+body+'\nupdate_pbs\n'
|
script=UPDATE_HARNESS+function('scripts/utils.sh','translate')+function('scripts/global/common-functions.sh','pmx_confirm_update')+body+'\nupdate_pbs\n'
|
||||||
result=subprocess.run(['bash','-c',script],capture_output=True,text=True,timeout=15,
|
result=subprocess.run(['bash','-c',script],capture_output=True,text=True,timeout=15,
|
||||||
env={**os.environ,'REPO':str(ROOT),'FIXTURE':folder,'CASE':case,'LANGUAGE':language,'SUITE':suite})
|
env={**os.environ,'REPO':str(ROOT),'FIXTURE':folder,'CASE':case,'LANGUAGE':language,'SUITE':suite})
|
||||||
files={str(p.relative_to(folder)):p.read_text() for p in Path(folder).rglob('*') if p.is_file()}
|
files={str(p.relative_to(folder)):p.read_text() for p in Path(folder).rglob('*') if p.is_file()}
|
||||||
|
|||||||
@@ -8601,6 +8601,7 @@
|
|||||||
"missing": "fehlt",
|
"missing": "fehlt",
|
||||||
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs nicht gefunden. Installieren Sie btrfs-progs und versuchen Sie es erneut.",
|
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs nicht gefunden. Installieren Sie btrfs-progs und versuchen Sie es erneut.",
|
||||||
"more": "mehr",
|
"more": "mehr",
|
||||||
|
"more packages; the full list is in the update log": "weitere Pakete; die vollständige Liste steht im Update-Protokoll",
|
||||||
"motionEye web interface": "motionEye Web-Schnittstelle",
|
"motionEye web interface": "motionEye Web-Schnittstelle",
|
||||||
"mount.cifs command not found after installation.": "Der Befehl mount.cifs wurde nach der Installation nicht gefunden.",
|
"mount.cifs command not found after installation.": "Der Befehl mount.cifs wurde nach der Installation nicht gefunden.",
|
||||||
"mount.nfs command not found after installation.": "Der Befehl mount.nfs wurde nach der Installation nicht gefunden.",
|
"mount.nfs command not found after installation.": "Der Befehl mount.nfs wurde nach der Installation nicht gefunden.",
|
||||||
|
|||||||
@@ -8574,6 +8574,7 @@
|
|||||||
"missing": "faltan",
|
"missing": "faltan",
|
||||||
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs no encontrado. Instala btrfs-progs y vuelve a intentarlo.",
|
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs no encontrado. Instala btrfs-progs y vuelve a intentarlo.",
|
||||||
"more": "más",
|
"more": "más",
|
||||||
|
"more packages; the full list is in the update log": "paquetes más; la lista completa está en el registro de la actualización",
|
||||||
"motionEye web interface": "Interfaz web de motionEye",
|
"motionEye web interface": "Interfaz web de motionEye",
|
||||||
"mount.cifs command not found after installation.": "El comando mount.cifs no se encuentra después de la instalación.",
|
"mount.cifs command not found after installation.": "El comando mount.cifs no se encuentra después de la instalación.",
|
||||||
"mount.nfs command not found after installation.": "El comando mount.nfs no se encuentra después de la instalación.",
|
"mount.nfs command not found after installation.": "El comando mount.nfs no se encuentra después de la instalación.",
|
||||||
|
|||||||
@@ -8600,6 +8600,7 @@
|
|||||||
"missing": "manquant",
|
"missing": "manquant",
|
||||||
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs introuvable. Installez btrfs-progs et réessayez.",
|
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs introuvable. Installez btrfs-progs et réessayez.",
|
||||||
"more": "plus",
|
"more": "plus",
|
||||||
|
"more packages; the full list is in the update log": "paquets de plus ; la liste complète se trouve dans le journal de la mise à jour",
|
||||||
"motionEye web interface": "Interface web motionEye",
|
"motionEye web interface": "Interface web motionEye",
|
||||||
"mount.cifs command not found after installation.": "Commande mount.cifs introuvable après l'installation.",
|
"mount.cifs command not found after installation.": "Commande mount.cifs introuvable après l'installation.",
|
||||||
"mount.nfs command not found after installation.": "Commande mount.nfs introuvable après l'installation.",
|
"mount.nfs command not found after installation.": "Commande mount.nfs introuvable après l'installation.",
|
||||||
|
|||||||
@@ -8601,6 +8601,7 @@
|
|||||||
"missing": "mancanti",
|
"missing": "mancanti",
|
||||||
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs non trovato. Installare btrfs-progs e riprovare.",
|
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs non trovato. Installare btrfs-progs e riprovare.",
|
||||||
"more": "in più",
|
"more": "in più",
|
||||||
|
"more packages; the full list is in the update log": "pacchetti in più; l'elenco completo è nel log dell'aggiornamento",
|
||||||
"motionEye web interface": "Interfaccia web motionEye",
|
"motionEye web interface": "Interfaccia web motionEye",
|
||||||
"mount.cifs command not found after installation.": "Comando mount.cifs non trovato dopo l'installazione.",
|
"mount.cifs command not found after installation.": "Comando mount.cifs non trovato dopo l'installazione.",
|
||||||
"mount.nfs command not found after installation.": "Comando mount.nfs non trovato dopo l'installazione.",
|
"mount.nfs command not found after installation.": "Comando mount.nfs non trovato dopo l'installazione.",
|
||||||
|
|||||||
@@ -8601,6 +8601,7 @@
|
|||||||
"missing": "faltando",
|
"missing": "faltando",
|
||||||
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs não encontrado. Instale o btrfs-progs e tente novamente.",
|
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs não encontrado. Instale o btrfs-progs e tente novamente.",
|
||||||
"more": "mais",
|
"more": "mais",
|
||||||
|
"more packages; the full list is in the update log": "pacotes a mais; a lista completa está no registo da atualização",
|
||||||
"motionEye web interface": "Interface Web motionEye",
|
"motionEye web interface": "Interface Web motionEye",
|
||||||
"mount.cifs command not found after installation.": "Comando mount.cifs não encontrado após a instalação.",
|
"mount.cifs command not found after installation.": "Comando mount.cifs não encontrado após a instalação.",
|
||||||
"mount.nfs command not found after installation.": "Comando mount.nfs não encontrado após a instalação.",
|
"mount.nfs command not found after installation.": "Comando mount.nfs não encontrado após a instalação.",
|
||||||
|
|||||||
@@ -8602,6 +8602,7 @@
|
|||||||
"missing": "chýba",
|
"missing": "chýba",
|
||||||
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs sa nenašiel. Nainštalujte btrfs-progs a skúste to znova.",
|
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs sa nenašiel. Nainštalujte btrfs-progs a skúste to znova.",
|
||||||
"more": "ďalších",
|
"more": "ďalších",
|
||||||
|
"more packages; the full list is in the update log": "ďalších balíkov; úplný zoznam je v zázname aktualizácie",
|
||||||
"motionEye web interface": "Webové rozhranie motionEye",
|
"motionEye web interface": "Webové rozhranie motionEye",
|
||||||
"mount.cifs command not found after installation.": "Príkaz mount.cifs sa po inštalácii nenašiel.",
|
"mount.cifs command not found after installation.": "Príkaz mount.cifs sa po inštalácii nenašiel.",
|
||||||
"mount.nfs command not found after installation.": "Príkaz mount.nfs sa po inštalácii nenašiel.",
|
"mount.nfs command not found after installation.": "Príkaz mount.nfs sa po inštalácii nenašiel.",
|
||||||
|
|||||||
@@ -8601,6 +8601,7 @@
|
|||||||
"missing": "saknad",
|
"missing": "saknad",
|
||||||
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs hittades inte. Installera btrfs-progs och försök igen.",
|
"mkfs.btrfs not found. Install btrfs-progs and retry.": "mkfs.btrfs hittades inte. Installera btrfs-progs och försök igen.",
|
||||||
"more": "mer",
|
"more": "mer",
|
||||||
|
"more packages; the full list is in the update log": "paket till; hela listan finns i uppdateringsloggen",
|
||||||
"motionEye web interface": "motionEye webbgränssnitt",
|
"motionEye web interface": "motionEye webbgränssnitt",
|
||||||
"mount.cifs command not found after installation.": "mount.cifs-kommandot hittades inte efter installationen.",
|
"mount.cifs command not found after installation.": "mount.cifs-kommandot hittades inte efter installationen.",
|
||||||
"mount.nfs command not found after installation.": "mount.nfs-kommandot hittades inte efter installationen.",
|
"mount.nfs command not found after installation.": "mount.nfs-kommandot hittades inte efter installationen.",
|
||||||
|
|||||||
@@ -445,19 +445,68 @@ cleanup_duplicate_repos() {
|
|||||||
# an operator reads the log days later to find out what moved.
|
# an operator reads the log days later to find out what moved.
|
||||||
|
|
||||||
# Reads `apt list --upgradable` on stdin and writes one aligned
|
# Reads `apt list --upgradable` on stdin and writes one aligned
|
||||||
# `name old → new` line per package. Lines that do not carry the
|
# `name old → new` line per package, never wider than the dialog that
|
||||||
|
# shows it (70 columns by default): a package whose versions do not fit
|
||||||
|
# continues on indented lines. Lines that do not carry the
|
||||||
# "[upgradable from: …]" part are passed through as they came.
|
# "[upgradable from: …]" part are passed through as they came.
|
||||||
pmx_format_upgradable() {
|
pmx_format_upgradable() {
|
||||||
awk 'NF == 0 { next }
|
awk -v width="${1:-70}" 'NF == 0 { next }
|
||||||
$0 ~ /\[upgradable from: / {
|
$0 ~ /\[upgradable from: / {
|
||||||
name = $1; sub(/\/.*/, "", name)
|
name = $1; sub(/\/.*/, "", name)
|
||||||
from = $6; sub(/\]$/, "", from)
|
from = $6; sub(/\]$/, "", from)
|
||||||
printf " %-30s %s → %s\n", name, from, $2
|
# Widths are counted by hand: " → " is three columns but more
|
||||||
|
# bytes, and mawk measures bytes.
|
||||||
|
if (2 + 30 + 1 + length(from) + 3 + length($2) <= width && length(name) <= 30)
|
||||||
|
printf " %-30s %s → %s\n", name, from, $2
|
||||||
|
else if (6 + length(from) + 3 + length($2) <= width)
|
||||||
|
printf " %s\n %s → %s\n", name, from, $2
|
||||||
|
else
|
||||||
|
printf " %s\n %s\n → %s\n", name, from, $2
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
{ print " " $0 }'
|
{ print " " $0 }'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Asks whether to go ahead with an update, with Yes focused so Enter
|
||||||
|
# confirms. whiptail cannot focus a button while its text scrolls, so the
|
||||||
|
# box takes the height of the terminal and a list that does not fit ends
|
||||||
|
# with a line counting the packages left out; the update log keeps them all.
|
||||||
|
#
|
||||||
|
# pmx_confirm_update TITLE TEXT LIST QUESTION
|
||||||
|
pmx_confirm_update() {
|
||||||
|
local title="$1" text="$2" list="$3" question="$4"
|
||||||
|
local rows height room shown more
|
||||||
|
rows=$(tput lines 2>/dev/null)
|
||||||
|
[[ "$rows" =~ ^[0-9]+$ ]] || rows=24
|
||||||
|
height=$(( rows > 50 ? 48 : rows - 2 ))
|
||||||
|
(( height < 16 )) && height=16
|
||||||
|
# Frame, padding, the heading, the question and the buttons.
|
||||||
|
room=$(( height - 9 - $(printf '%b' "$text" | grep -c '') ))
|
||||||
|
(( room < 3 )) && room=3
|
||||||
|
|
||||||
|
# A package that spans several lines is shown whole or counted.
|
||||||
|
shown=$(printf '%s\n' "$list" | awk -v room="$room" '
|
||||||
|
/^ [^ ]/ { package++ }
|
||||||
|
{ lines[NR] = $0; owner[NR] = package }
|
||||||
|
END {
|
||||||
|
if (NR <= room) { for (i = 1; i <= NR; i++) print lines[i]; exit }
|
||||||
|
# One line is kept for the count of the packages left out.
|
||||||
|
cap = room - 1
|
||||||
|
last = owner[cap]
|
||||||
|
if (owner[cap + 1] == last) last--
|
||||||
|
for (i = 1; i <= NR && owner[i] <= last; i++) print lines[i]
|
||||||
|
printf "\n%d\n", package - last
|
||||||
|
}')
|
||||||
|
more="${shown##*$'\n'}"
|
||||||
|
if [[ "$shown" == *$'\n\n'"$more" && "$more" =~ ^[0-9]+$ ]]; then
|
||||||
|
shown="${shown%$'\n\n'"$more"}"
|
||||||
|
shown+="\n … ${more} $(translate "more packages; the full list is in the update log")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
whiptail --title "$title" --yesno \
|
||||||
|
"${text}$(translate "Packages to be upgraded"):\n${shown}\n\n${question}" "$height" 78
|
||||||
|
}
|
||||||
|
|
||||||
# Writes what dpkg actually did since `$1` (a "YYYY-MM-DD HH:MM:SS"
|
# Writes what dpkg actually did since `$1` (a "YYYY-MM-DD HH:MM:SS"
|
||||||
# stamp taken before the upgrade). dpkg's own log is the authoritative
|
# stamp taken before the upgrade). dpkg's own log is the authoritative
|
||||||
# record of the transaction — it carries both versions of every package
|
# record of the transaction — it carries both versions of every package
|
||||||
|
|||||||
@@ -110,10 +110,9 @@ update_pbs() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
menu_text+="$(translate "Packages to be upgraded"):\n$upgradable_list\n\n"
|
|
||||||
menu_text+="$(translate "Do you want to proceed with the system update?")"
|
|
||||||
local proceed=0
|
local proceed=0
|
||||||
whiptail --title "$(translate "Proxmox Backup Server Update")" --scrolltext --yesno "$menu_text" 24 78 || proceed=1
|
pmx_confirm_update "$(translate "Proxmox Backup Server Update")" "$menu_text" "$upgradable_list" \
|
||||||
|
"$(translate "Do you want to proceed with the system update?")" || proceed=1
|
||||||
|
|
||||||
clear
|
clear
|
||||||
show_proxmenux_logo
|
show_proxmenux_logo
|
||||||
|
|||||||
@@ -205,12 +205,9 @@ update_pve_safe() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# The package list rides in the same dialog as the summary, so the
|
# The package list rides in the same dialog as the summary, so the
|
||||||
# decision is taken knowing what is about to be replaced. Keep Yes focused
|
# decision is taken knowing what is about to be replaced.
|
||||||
# while the list remains scrollable; --keep-tite restores the execution screen.
|
if ! pmx_confirm_update "$(translate "Proxmox Update")" "$menu_text" "$upgradable_list" \
|
||||||
menu_text+="$(translate "Packages to be upgraded"):\n$upgradable_list\n\n"
|
"$(translate "Do you want to proceed with the system update?")"; then
|
||||||
menu_text+="$(translate "Do you want to proceed with the system update?")"
|
|
||||||
if ! dialog --keep-tite --title "$(translate "Proxmox Update")" \
|
|
||||||
--default-button yes --no-collapse --scrollbar --yesno "$menu_text" 24 78; then
|
|
||||||
msg_info2 "$(translate "Update cancelled by user")"
|
msg_info2 "$(translate "Update cancelled by user")"
|
||||||
apt-get -y autoremove >/dev/null 2>&1 || true
|
apt-get -y autoremove >/dev/null 2>&1 || true
|
||||||
apt-get -y autoclean >/dev/null 2>&1 || true
|
apt-get -y autoclean >/dev/null 2>&1 || true
|
||||||
|
|||||||
@@ -169,12 +169,8 @@ EOF
|
|||||||
else
|
else
|
||||||
# The package list rides in the same dialog as the summary, so
|
# The package list rides in the same dialog as the summary, so
|
||||||
# the decision is taken knowing what is about to be replaced.
|
# the decision is taken knowing what is about to be replaced.
|
||||||
# Keep Yes focused while the full package list remains scrollable.
|
if pmx_confirm_update "$(translate "Proxmox Update")" "$menu_text" "$upgradable_list" \
|
||||||
# --keep-tite restores the execution screen after confirmation.
|
"$(translate "Do you want to proceed with the system update?")"; then
|
||||||
menu_text+="$(translate "Packages to be upgraded"):\n$upgradable_list\n\n"
|
|
||||||
menu_text+="$(translate "Do you want to proceed with the system update?")"
|
|
||||||
if dialog --keep-tite --title "$(translate "Proxmox Update")" \
|
|
||||||
--default-button yes --no-collapse --scrollbar --yesno "$menu_text" 24 78; then
|
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -272,12 +272,8 @@ EOF
|
|||||||
else
|
else
|
||||||
# The package list rides in the same dialog as the summary, so
|
# The package list rides in the same dialog as the summary, so
|
||||||
# the decision is taken knowing what is about to be replaced.
|
# the decision is taken knowing what is about to be replaced.
|
||||||
# Keep Yes focused while the full package list remains scrollable.
|
if pmx_confirm_update "$(translate "Proxmox Update")" "$menu_text" "$upgradable_list" \
|
||||||
# --keep-tite restores the execution screen after confirmation.
|
"$(translate "Do you want to proceed with the system update?")"; then
|
||||||
menu_text+="$(translate "Packages to be upgraded"):\n$upgradable_list\n\n"
|
|
||||||
menu_text+="$(translate "Do you want to proceed with the system update?")"
|
|
||||||
if dialog --keep-tite --title "$(translate "Proxmox Update")" \
|
|
||||||
--default-button yes --no-collapse --scrollbar --yesno "$menu_text" 24 78; then
|
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Exercise only the update confirmation widget in a disposable terminal.
|
"""Exercise only the update confirmation widget in a disposable terminal.
|
||||||
|
|
||||||
No update script is sourced or executed: the isolated UI command receives
|
No update script is sourced or executed: the shared confirmation function
|
||||||
synthetic package names. Requires dialog; skips on systems without it.
|
receives synthetic package names. Requires whiptail; skips without it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
@@ -27,17 +27,23 @@ UPDATERS = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def confirmation_command(name):
|
COMMON = ROOT / "scripts/global/common-functions.sh"
|
||||||
source = (ROOT / "scripts/global" / name).read_text()
|
|
||||||
match = re.search(
|
|
||||||
r'^\s*if (?:! )?((?:dialog|whiptail) --(?:keep-tite --)?title '
|
def confirmation_function():
|
||||||
r'"\$\(translate "Proxmox Update"\)"[^;]+); then',
|
match = re.search(r"^pmx_confirm_update\(\) \{\n.*?^\}\n", COMMON.read_text(),
|
||||||
source,
|
re.MULTILINE | re.DOTALL)
|
||||||
re.MULTILINE,
|
|
||||||
)
|
|
||||||
if not match:
|
if not match:
|
||||||
raise AssertionError("Update confirmation not found: " + name)
|
raise AssertionError("pmx_confirm_update not found")
|
||||||
return match.group(1)
|
return match.group(0)
|
||||||
|
|
||||||
|
|
||||||
|
def confirmation_command():
|
||||||
|
"""The shared confirmation as an updater calls it; the package list comes
|
||||||
|
from UPDATE_CONFIRMATION_TEXT, formatted as pmx_format_upgradable writes it."""
|
||||||
|
return (confirmation_function() + 'pmx_confirm_update "Proxmox Update" '
|
||||||
|
'"System Update Information\\n\\n" "$UPDATE_CONFIRMATION_TEXT" '
|
||||||
|
'"Do you want to proceed with the system update?"')
|
||||||
|
|
||||||
|
|
||||||
def run_widget(command, text, keys):
|
def run_widget(command, text, keys):
|
||||||
@@ -50,8 +56,7 @@ def run_widget(command, text, keys):
|
|||||||
for key in list(environment):
|
for key in list(environment):
|
||||||
if key.startswith("DIALOG_"):
|
if key.startswith("DIALOG_"):
|
||||||
environment.pop(key)
|
environment.pop(key)
|
||||||
script = ('translate() { printf "%s" "$1"; }\n'
|
script = 'translate() { printf "%s" "$1"; }\n' + command
|
||||||
'menu_text=$UPDATE_CONFIRMATION_TEXT\n' + command)
|
|
||||||
os.execve("/bin/bash", ["bash", "-c", script], environment)
|
os.execve("/bin/bash", ["bash", "-c", script], environment)
|
||||||
|
|
||||||
output = bytearray()
|
output = bytearray()
|
||||||
@@ -90,36 +95,47 @@ def run_widget(command, text, keys):
|
|||||||
os.close(terminal)
|
os.close(terminal)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(shutil.which("dialog"), "dialog is not installed")
|
def packages(count, long_every=0):
|
||||||
|
"""Formatted list lines; every `long_every`-th package spans three lines."""
|
||||||
|
lines = []
|
||||||
|
for i in range(count):
|
||||||
|
if long_every and i % long_every == 0:
|
||||||
|
lines += [" libsamba-{:03d}".format(i), " 2:2.11.0+samba4.22.10+dfsg-0+deb13u1",
|
||||||
|
" → 2:2.11.0+samba4.22.11+dfsg-0+deb13u1"]
|
||||||
|
else:
|
||||||
|
lines.append(" package-{:03d} 1.0 → 2.0".format(i))
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(shutil.which("whiptail"), "whiptail is not installed")
|
||||||
class UpdateConfirmationTest(unittest.TestCase):
|
class UpdateConfirmationTest(unittest.TestCase):
|
||||||
def test_enter_confirms_yes_without_tab_for_short_and_long_lists(self):
|
def test_enter_confirms_yes_without_tab_for_short_and_long_lists(self):
|
||||||
for updater in UPDATERS:
|
for count in (1, 80, 200):
|
||||||
for count in (1, 80):
|
with self.subTest(packages=count):
|
||||||
with self.subTest(updater=updater, packages=count):
|
status, output = run_widget(confirmation_command(), packages(count, 7), b"\r")
|
||||||
text = "System Update Information\\n\\n" + "\\n".join(
|
self.assertEqual(status, 0, output)
|
||||||
" package-{:02d} 1.0 -> 2.0".format(i)
|
|
||||||
for i in range(count)
|
|
||||||
) + "\\n\\nDo you want to proceed with the system update?"
|
|
||||||
status, output = run_widget(confirmation_command(updater), text, b"\r")
|
|
||||||
self.assertEqual(status, 0, output)
|
|
||||||
|
|
||||||
def test_tab_can_select_no_and_escape_can_cancel(self):
|
def test_tab_can_select_no_and_escape_can_cancel(self):
|
||||||
for updater in UPDATERS:
|
for keys, expected in ((b"\t\r", 1), (b"\x1b", 255)):
|
||||||
for keys, expected in ((b"\t\r", 1), (b"\x1b", 255)):
|
with self.subTest(keys=keys):
|
||||||
with self.subTest(updater=updater, keys=keys):
|
status, output = run_widget(confirmation_command(), packages(80), keys)
|
||||||
status, output = run_widget(confirmation_command(updater), "Confirm update?", keys)
|
self.assertEqual(status, expected, output)
|
||||||
self.assertEqual(status, expected, output)
|
|
||||||
|
|
||||||
def test_full_list_remains_scrollable_with_yes_focused(self):
|
def test_a_long_list_fits_and_counts_the_packages_left_out(self):
|
||||||
text = "\\n".join("package-{:03d}".format(i) for i in range(80))
|
status, output = run_widget(confirmation_command(), packages(200, 7), b"\r")
|
||||||
for updater in UPDATERS:
|
self.assertEqual(status, 0, output)
|
||||||
|
plain = re.sub(rb"\x1b(?:\[[0-?]*[ -/]*[@-~]|[()][A-Za-z0-9]|.)", b"", output)
|
||||||
|
self.assertIn(b"more packages; the full list is in the update log", plain)
|
||||||
|
# A package is shown whole or counted, never cut after its name.
|
||||||
|
self.assertNotRegex(plain, rb"libsamba-\d{3}\s+\.\.\.")
|
||||||
|
|
||||||
|
def test_every_updater_asks_through_the_shared_confirmation(self):
|
||||||
|
for updater in UPDATERS + ("update-pbs.sh",):
|
||||||
with self.subTest(updater=updater):
|
with self.subTest(updater=updater):
|
||||||
# G scrolls to the end of the yes/no text without moving focus.
|
source = (ROOT / "scripts/global" / updater).read_text()
|
||||||
status, output = run_widget(confirmation_command(updater), text, b"G\r")
|
self.assertIn("pmx_confirm_update ", source)
|
||||||
self.assertEqual(status, 0, output)
|
self.assertNotIn("--scrolltext --yesno", source)
|
||||||
# Curses may repaint only changed digits rather than emit a
|
self.assertNotIn("dialog --keep-tite", source)
|
||||||
# complete final line. Its 100% indicator confirms the end.
|
|
||||||
self.assertIn(b"100%", output)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user