From 94c0bd2dfeb801087c7a03787a964b15b2a37bd8 Mon Sep 17 00:00:00 2001 From: V3n3RiX Date: Mon, 26 Feb 2024 13:02:07 +0000 Subject: * extend https://bugs.redcorelinux.org/show_bug.cgi?id=143 * improve the UX at package removal stage and orphan removal stage * require double confirmation for a forced, unsafe removal of a package --- src/backend/autormpkgsrc.py | 74 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 11 deletions(-) (limited to 'src/backend/autormpkgsrc.py') diff --git a/src/backend/autormpkgsrc.py b/src/backend/autormpkgsrc.py index 3f0c852..d696757 100644 --- a/src/backend/autormpkgsrc.py +++ b/src/backend/autormpkgsrc.py @@ -1,8 +1,11 @@ #!/usr/bin/python3 import atexit +import fcntl import io +import os import signal +import selectors import subprocess import sys import sisyphus.checkenv @@ -11,6 +14,26 @@ import sisyphus.killemerge import sisyphus.syncdb +def set_nonblocking(fd): + flags = fcntl.fcntl(fd, fcntl.F_GETFL) + fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) + + +def spinner_animation(): + spinner = ['-', '\\', '|', '/'] + sel = selectors.DefaultSelector() + sel.register(sys.stdin, selectors.EVENT_READ) + + for _ in range(10): + for char in spinner: + sys.stdout.write('\b' + char) + sys.stdout.flush() + events = sel.select(timeout=0.1) + if events: + return + sys.stdout.write('\b') + + def sigint_handler(signal, frame): sys.exit(0) @@ -22,17 +45,46 @@ def start(gfx_ui=False): args = ['--quiet', '--depclean'] if sisyphus.checkenv.root() and not gfx_ui: - p_exe = subprocess.Popen(['emerge'] + args + ['--ask']) - try: - p_exe.wait() - sisyphus.syncdb.lcl_tbl() - except KeyboardInterrupt: - p_exe.terminate() - try: - p_exe.wait(1) - except subprocess.TimeoutExpired: - p_exe.kill() - sys.exit() + print("\n" + sisyphus.getclr.bright_white + "Orphaned, no longer needed packages are slated for" + sisyphus.getclr.reset + " " + + sisyphus.getclr.green + "'safe'" + sisyphus.getclr.reset + " " + sisyphus.getclr.bright_white + "removal." + sisyphus.getclr.reset + "\n") + while True: + user_input = input(sisyphus.getclr.bright_white + "Would you like to proceed?" + sisyphus.getclr.reset + " " + + "[" + sisyphus.getclr.bright_green + "Yes" + sisyphus.getclr.reset + "/" + sisyphus.getclr.bright_red + "No" + sisyphus.getclr.reset + "]" + " ") + if user_input.lower() in ['yes', 'y', '']: + p_exe = subprocess.Popen(['emerge'] + args) + try: + set_nonblocking(sys.stdout.fileno()) + spinner_animation() + + sel = selectors.DefaultSelector() + sel.register(sys.stdin, selectors.EVENT_READ) + + while True: + events = sel.select(timeout=0.1) + for key, mask in events: + if key.fileobj == sys.stdin: + line = sys.stdin.readline().strip() + if line.lower() == 'q': + sys.exit() + if p_exe.poll() is not None: + break + except KeyboardInterrupt: + p_exe.terminate() + try: + p_exe.wait(1) + except subprocess.TimeoutExpired: + p_exe.kill() + sys.exit() + finally: + p_exe.wait() + sisyphus.syncdb.lcl_tbl() + break + elif user_input.lower() in ['no', 'n']: + break + else: + print("\nSorry, response" + " " + "'" + + user_input + "'" + " " + "not understood.\n") + continue elif gfx_ui: p_exe = subprocess.Popen( ['emerge'] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -- cgit v1.2.3