def __init__(self, callback=None, source=None):
        """Class to handle input from the terminal.

        This class is designed to be instantiated on place where it should be used.
        The main method is `get_input()` which is non-blocking asynchronous call. It can be used
        as synchronous call be calling the `wait_on_input` method.

        To get result from this class use the `value` property.

        :param callback: You can specify callback which will be called when user give input.
        :type callback: Callback function with one argument which will be user input.

        :param source: Source of this input. It will be helpful in case of debugging an issue.
        :type source: Class which will process an input from this InputHandler.
        """
        super().__init__()
        self._input = None
        self._input_callback = callback
        self._input_received = False
        self._input_successful = False
        self._skip_concurrency_check = False
        self._source = source

        App.get_event_loop().register_signal_handler(
            InputReadySignal, self._input_received_handler)
    def process_input(self, user_input):
        """Process input from the screens.

        :param user_input: User input string.
        :type user_input: String.

        :raises: ExitMainLoop or any other kind of exception from screen processing.
        """
        # process the input, if it wasn't processed (valid)
        # increment the error counter
        try:
            result = self._process_input(user_input)
        except ExitMainLoop:  # pylint: disable=try-except-raise
            raise
        except Exception:  # pylint: disable=broad-except
            App.get_event_loop().enqueue_signal(ExceptionSignal(self))
            return

        if result.was_successful():
            self._input_error_counter = 0
        else:
            self._input_error_counter += 1

        App.get_scheduler().process_input_result(
            result, self.input_error_threshold_exceeded)
示例#3
0
def start_rescue_mode_ui(anaconda):
    """Start the rescue mode UI."""

    ksdata_rescue = None
    if anaconda.ksdata.rescue.seen:
        ksdata_rescue = anaconda.ksdata.rescue
    scripts = anaconda.ksdata.scripts
    storage = anaconda.storage
    reboot = True
    if conf.target.is_image:
        reboot = False
    if flags.automatedInstall and anaconda.ksdata.reboot.action not in [KS_REBOOT, KS_SHUTDOWN]:
        reboot = False

    rescue = Rescue(storage, ksdata_rescue, reboot, scripts)
    rescue.initialize()

    # We still want to choose from multiple roots, or unlock encrypted devices
    # if needed, so we run UI even for kickstarts (automated install).
    App.initialize()
    loop = App.get_event_loop()
    loop.set_quit_callback(tui_quit_callback)
    spoke = RescueModeSpoke(rescue)
    ScreenHandler.schedule_screen(spoke)
    App.run()
    def test_input_no_prompt(self, mock_stdin, mock_stdout):
        screen = InputWithNoPromptMock()

        App.get_scheduler().schedule_screen(screen)
        App.run()

        self.assertTrue(screen.prompt_entered)
示例#5
0
def exception_msg_handler(signal, data):
    """
    Handler for the ExceptionSignal signal.

    :param signal: event data
    :type signal: (event_type, message_data)
    :param data: additional data
    :type data: any
    """
    global exception_processed
    if exception_processed:
        # get data from the event data structure
        exception_info = signal.exception_info

        stack_trace = "\n" + App.get_scheduler().dump_stack()
        log.error(stack_trace)
        # exception_info is a list
        sys.excepthook(*exception_info)
    else:
        # show only the first exception do not spam user with others
        exception_processed = True
        loop = App.get_event_loop()
        # start new loop for handling the exception
        # this will stop processing all the old signals and prevent raising new exceptions
        loop.execute_new_loop(signal)
示例#6
0
def exception_msg_handler(signal, data):
    """
    Handler for the ExceptionSignal signal.

    :param signal: event data
    :type signal: (event_type, message_data)
    :param data: additional data
    :type data: any
    """
    global exception_processed
    if exception_processed:
        # get data from the event data structure
        exception_info = signal.exception_info

        stack_trace = "\n" + App.get_scheduler().dump_stack()
        log.error(stack_trace)
        # exception_info is a list
        sys.excepthook(*exception_info)
    else:
        # show only the first exception do not spam user with others
        exception_processed = True
        loop = App.get_event_loop()
        # start new loop for handling the exception
        # this will stop processing all the old signals and prevent raising new exceptions
        loop.execute_new_loop(signal)
 def _check_default_password_function(self, password_func=None):
     if password_func:
         self.assertEqual(App.get_configuration().password_function,
                          password_func)
     else:
         self.assertEqual(App.get_configuration().password_function,
                          DEFAULT_PASSWORD_FUNC)
示例#8
0
    def close(self):
        """Emit signal to close this screen.

        Add CloseScreenSignal to the event loop.
        """
        signal = self.create_signal(CloseScreenSignal)
        App.get_event_loop().enqueue_signal(signal)
示例#9
0
    def redraw(self):
        """Emit signal to initiate draw.

        Add RenderScreenSignal to the event loop.
        """
        signal = self.create_signal(RenderScreenSignal)
        App.get_event_loop().enqueue_signal(signal)
    def setUp(self):
        super().setUp()
        self.create_loop()
        App.initialize(event_loop=self.loop)

        self._callback_called = False
        self._callback_input = ""
示例#11
0
def start_rescue_mode_ui(anaconda):
    """Start the rescue mode UI."""

    ksdata_rescue = None
    if anaconda.ksdata.rescue.seen:
        ksdata_rescue = anaconda.ksdata.rescue
    scripts = anaconda.ksdata.scripts
    storage = anaconda.storage
    reboot = True
    if conf.target.is_image:
        reboot = False
    if flags.automatedInstall and anaconda.ksdata.reboot.action not in [
            KS_REBOOT, KS_SHUTDOWN
    ]:
        reboot = False

    rescue = Rescue(storage, ksdata_rescue, reboot, scripts)
    rescue.initialize()

    # We still want to choose from multiple roots, or unlock encrypted devices
    # if needed, so we run UI even for kickstarts (automated install).
    App.initialize()
    loop = App.get_event_loop()
    loop.set_quit_callback(tui_quit_callback)
    spoke = RescueModeSpoke(rescue)
    ScreenHandler.schedule_screen(spoke)
    App.run()
    def test_refresh_input(self, mock_stdin, mock_stdout):
        mock_stdin.return_value = "r"
        screen = RefreshTestScreenMock()

        App.get_scheduler().schedule_screen(screen)
        App.run()

        self.assertTrue(screen.input_processed)
    def test_process_input_and_close(self, input_mock, mock_stdout):
        input_mock.return_value = "a"
        screen = InputStateCloseScreenMock()

        App.get_scheduler().schedule_screen(screen)
        App.run()

        self.assertTrue(screen.input_processed)
示例#14
0
    def test_input_thread_manager_after_initialize(self):
        App.initialize()

        thread_mgr = InputThreadManager.get_instance()

        App.initialize()

        self.assertNotEqual(thread_mgr, InputThreadManager.get_instance())
示例#15
0
    def run(self):
        """Run the `run_input` method and propagate input outside.

        Do not call this method directly. It will be called by InputThreadManager.
        """
        data = self.get_input()

        App.get_event_loop().enqueue_signal(InputReceivedSignal(self, data))
示例#16
0
    def test_process_input_and_redraw(self, input_mock, mock_stdout):
        input_mock.return_value = "a"
        screen = InputStateRedrawScreen()

        App.get_scheduler().schedule_screen(screen)
        App.run()

        self.assertTrue(screen.refreshed)
示例#17
0
    def test_basic_input(self, input_mock, mock_stdout):
        input_mock.return_value = "a"
        screen = InputScreen()

        App.get_scheduler().schedule_screen(screen)
        App.run()

        self.assertTrue(screen.input_processed)
示例#18
0
    def test_create_instance_with_custom_everything(self):
        event_loop = CustomEventLoop()
        App.initialize(event_loop=event_loop,
                       scheduler=CustomScreenScheduler(event_loop),
                       global_configuration=CustomGlobalConfiguration())

        self.assertTrue(isinstance(App.get_event_loop(), CustomEventLoop))
        self.assertTrue(isinstance(App.get_scheduler(), CustomScreenScheduler))
        self.assertTrue(isinstance(App.get_configuration(), CustomGlobalConfiguration))
示例#19
0
    def emit(self, signal):
        """Emit the signal.

        This will add `signal` to the event loop.

        :param signal: signal to emit
        :type signal: instance of class based on `simpleline.event_loop.AbstractSignal`
        """
        App.get_event_loop().enqueue_signal(signal)
    def test_emit(self):
        connect_screen = UIScreen()

        App.initialize(scheduler=MagicMock())
        connect_screen.connect(TestSignal, self._callback)
        connect_screen.emit(TestSignal(self))
        App.get_event_loop().process_signals()

        self.assertTrue(self.callback_called)
    def test_zero_width_no_separator(self, stdout_mock):
        ui_screen = EmptyScreenMock()
        width = 0

        App.get_configuration().width = width
        App.get_scheduler().schedule_screen(ui_screen)
        App.run()

        self.assertEqual("\n\n", stdout_mock.getvalue())
    def test_width(self):
        self._check_default_width()

        App.initialize()
        App.get_configuration().width = 100
        self._check_default_width(100)

        App.initialize()
        self._check_default_width()
    def test_multiple_refresh_on_input_error(self, mock_stdin, mock_stdout):
        mock_stdin.return_value = "q"
        threshold = 12
        screen = InputErrorTestScreenMock(threshold)

        App.get_scheduler().schedule_screen(screen)
        App.run()

        self.assertEqual(screen.render_counter, 3)
        self.assertEqual(screen.error_counter, threshold)
    def test_create_signal(self):
        connect_screen = UIScreen()

        App.initialize(scheduler=MagicMock())
        signal = connect_screen.create_signal(TestSignal, priority=20)

        self.assertEqual(signal.priority, 20)
        self.assertTrue(isinstance(signal, TestSignal))
        # source is set by create_signal
        self.assertEqual(signal.source, connect_screen)
    def test_clear_width(self):
        self._check_default_width()

        test_width = 150

        App.get_configuration().width = test_width
        self._check_default_width(test_width)

        App.get_configuration().clear_width()
        self._check_default_width()
    def test_password_function(self):
        self._check_default_password_function()

        test_mock = MagicMock()
        App.initialize()
        App.get_configuration().password_function = test_mock
        self._check_default_password_function(test_mock)

        App.initialize()
        self._check_default_password_function()
    def test_other_width_separator(self, stdout_mock):
        ui_screen = EmptyScreenMock()
        width = 60

        App.get_configuration().width = width
        App.get_scheduler().schedule_screen(ui_screen)
        App.run()

        self.assertEqual(self.calculate_separator(width),
                         stdout_mock.getvalue())
    def test_custom_getpass(self, mock_stdin, mock_stdout, process_signals):
        prompt = mock.MagicMock()
        ret = "test"
        screen = ScreenWithPassFuncMock(prompt, ret)

        App.get_scheduler().schedule_screen(screen)
        App.run()

        self.assertTrue(screen.pass_called)
        self.assertEqual(screen.pass_prompt.rstrip(), str(prompt))
    def test_clear_password_function(self):
        self._check_default_password_function()

        test_func = MagicMock()

        App.get_configuration().password_function = test_func
        self._check_default_password_function(test_func)

        App.get_configuration().clear_password_function()
        self._check_default_password_function()
示例#30
0
    def emit_failed_input_ready_signal(self):
        """Emit the InputReadySignal with failed state."""
        handler_source = self.source
        signal_source = self._get_request_source()

        new_signal = InputReadySignal(source=signal_source,
                                      input_handler_source=handler_source,
                                      data="",
                                      success=False)
        App.get_event_loop().enqueue_signal(new_signal)
    def tearDown(self):
        super().tearDown()
        self._thread_event_wait_for_outer.set()

        for t in self._threads:
            t.join()

        # process InputReceivedSignal
        App.get_event_loop().process_signals()
        # process InputReadySignal
        App.get_event_loop().process_signals()
    def test_no_refresh_when_prompt_is_none(self, mock_stdin, mock_stdout):
        mock_stdin.return_value = "q"
        threshold = 5
        screen = InputErrorDynamicPromptTestScreenMock(threshold,
                                                       not_return_prompt_on=3)

        App.get_scheduler().schedule_screen(screen)
        App.run()

        # first draw and manual redraw when prompt is None
        self.assertEqual(screen.render_counter, 2)
        self.assertTrue(screen.input_skipped)
        self.assertEqual(screen.error_counter, threshold)
示例#33
0
    def run(self):
        """Run the interface.

        This should do little more than just pass through to something else's run method,
        but is provided here in case more is needed.  This method must be provided by all subclasses.
        """
        return App.run()
示例#34
0
    def setup(self, data):
        """Construct all the objects required to implement this interface.

        This method must be provided by all subclasses.
        """
        # Use GLib event loop for the Simpleline TUI
        loop = GLibEventLoop()
        App.initialize(event_loop=loop)

        loop.set_quit_callback(tui_quit_callback)
        scheduler = App.get_scheduler()
        scheduler.quit_screen = YesNoDialog(self.quitMessage)

        # tell python-meh it should use our raw_input
        meh_io_handler = meh.ui.text.IOHandler(in_func=self._get_meh_input_func)
        self._meh_interface.set_io_handler(meh_io_handler)

        # register handlers for various messages
        loop = App.get_event_loop()
        loop.register_signal_handler(ExceptionSignal, exception_msg_handler)
        loop.register_signal_handler(SendMessageSignal, self._handle_show_message)

        _hubs = self._list_hubs()

        # First, grab a list of all the standalone spokes.
        spokes = self._collectActionClasses(self.paths["spokes"], StandaloneSpoke)
        actionClasses = self._orderActionClasses(spokes, _hubs)

        for klass in actionClasses:
            obj = klass(data, self.storage, self.payload, self.instclass)

            # If we are doing a kickstart install, some standalone spokes
            # could already be filled out.  In that case, we do not want
            # to display them.
            if self._is_standalone(obj) and obj.completed:
                del(obj)
                continue

            if hasattr(obj, "set_path"):
                obj.set_path("spokes", self.paths["spokes"])
                obj.set_path("categories", self.paths["categories"])

            should_schedule = obj.setup(self.ENVIRONMENT)

            if should_schedule:
                scheduler.schedule_screen(obj)
示例#35
0
文件: vnc.py 项目: jaymzh/anaconda
    def changeVNCPasswdWindow(self):
        """ Change the password to a sane parameter.

        We ask user to input a password that (len(password) > 6
        and len(password) <= 8) or password == ''.
        """

        message = _("VNC password must be six to eight characters long.\n"
                    "Please enter a new one, or leave blank for no password.")
        App.initialize()
        loop = App.get_event_loop()
        loop.set_quit_callback(tui_quit_callback)
        spoke = VNCPassSpoke(self.anaconda.ksdata, None, None, None, message)
        ScreenHandler.schedule_screen(spoke)
        App.run()

        self.password = self.anaconda.ksdata.vnc.password
示例#36
0
    def _update_progress(self):
        """Handle progress updates from install thread."""

        from pyanaconda.progress import progressQ
        import queue

        q = progressQ.q

        # Grab all messages may have appeared since last time this method ran.
        while True:
            # Attempt to get a message out of the queue for how we should update
            # the progress bar.  If there's no message, don't error out.
            # Also flush the communication Queue at least once a second and
            # process it's events so we can react to async evens (like a thread
            # throwing an exception)
            while True:
                try:
                    (code, args) = q.get(timeout=1)
                    break
                except queue.Empty:
                    pass
                finally:
                    loop = App.get_event_loop()
                    loop.process_signals()

            if code == progressQ.PROGRESS_CODE_INIT:
                # Text mode doesn't have a finite progress bar
                pass
            elif code == progressQ.PROGRESS_CODE_STEP:
                # Instead of updating a progress bar, we just print a pip
                # but print it without a new line.
                sys.stdout.write('.')
                sys.stdout.flush()
                # Use _stepped as an indication to if we need a newline before
                # the next message
                self._stepped = True
            elif code == progressQ.PROGRESS_CODE_MESSAGE:
                # This should already be translated
                if self._stepped:
                    # Get a new line in case we've done a step before
                    self._stepped = False
                    print('')
                print(args[0])
            elif code == progressQ.PROGRESS_CODE_COMPLETE:
                # There shouldn't be any more progress updates, so return
                q.task_done()

                if self._stepped:
                    print('')
                return True
            elif code == progressQ.PROGRESS_CODE_QUIT:
                sys.exit(args[0])

            q.task_done()
        return True
示例#37
0
def ask_vnc_question(anaconda, vnc_server, message):
    """ Ask the user if TUI or GUI-over-VNC should be started.

    :param anaconda: instance of the Anaconda class
    :param vnc_server: instance of the VNC server object
    :param str message: a message to show to the user together
                        with the question
    """
    App.initialize()
    loop = App.get_event_loop()
    loop.set_quit_callback(tui_quit_callback)
    spoke = AskVNCSpoke(anaconda.ksdata, message)
    ScreenHandler.schedule_screen(spoke)
    App.run()

    if anaconda.ksdata.vnc.enabled:
        if not anaconda.gui_mode:
            log.info("VNC requested via VNC question, switching Anaconda to GUI mode.")
        anaconda.display_mode = constants.DisplayModes.GUI
        flags.usevnc = True
        vnc_server.password = anaconda.ksdata.vnc.password
示例#38
0
    def __init__(self, data, storage=None, payload=None, instclass=None, message=""):
        super().__init__(data, storage, payload, instclass)
        self.input_required = True
        self.initialize_start()
        self._container = None

        # The TUI hasn't been initialized with the message handlers yet. Add an
        # exception message handler so that the TUI exits if anything goes wrong
        # at this stage.
        loop = App.get_event_loop()
        loop.register_signal_handler(ExceptionSignal, exception_msg_handler_and_exit)
        self._message = message
        self._usevnc = False
        self.initialize_done()
示例#39
0
    def _send_show_message(self, msg_fn, args, ret_queue):
        """ Send message requesting to show some message dialog specified by the message function.

        :param msg_fn: message dialog function requested to be called
        :type msg_fn: a function taking the same number of arguments as is the
                      length of the args param
        :param args: arguments to be passed to the message dialog function
        :type args: any
        :param ret_queue: the queue which the return value of the message dialog
                          function should be put
        :type ret_queue: a queue.Queue instance
        """

        signal = SendMessageSignal(self, msg_fn=msg_fn, args=args, ret_queue=ret_queue)
        loop = App.get_event_loop()
        loop.enqueue_signal(signal)
示例#40
0
    def setup(self, args="anaconda"):
        environment = args
        should_schedule = TUIHub.setup(self, environment)
        if not should_schedule:
            return False

        if flags.automatedInstall:
            sys.stdout.write(_("Starting automated install"))
            sys.stdout.flush()
            spokes = self._spokes.values()
            while not all(spoke.ready for spoke in spokes):
                # Catch any asynchronous events (like storage crashing)
                loop = App.get_event_loop()
                loop.process_signals()
                sys.stdout.write('.')
                sys.stdout.flush()
                time.sleep(1)

            print('')
            for spoke in spokes:
                if spoke.changed:
                    spoke.execute()

        return True
示例#41
0
    def handleException(self, dump_info):
        """
        Our own handleException method doing some additional stuff before
        calling the original python-meh's one.

        :type dump_info: an instance of the meh.DumpInfo class
        :see: python-meh's ExceptionHandler.handleException

        """

        log.debug("running handleException")
        exception_lines = traceback.format_exception(*dump_info.exc_info)
        log.critical("\n".join(exception_lines))

        ty = dump_info.exc_info.type
        value = dump_info.exc_info.value

        try:
            gi.require_version("Gtk", "3.0")

            from gi.repository import Gtk

            # XXX: Gtk stopped raising RuntimeError if it fails to
            # initialize. Horay! But will it stay like this? Let's be
            # cautious and raise the exception on our own to work in both
            # cases
            initialized = Gtk.init_check(None)[0]
            if not initialized:
                raise RuntimeError()

            # Attempt to grab the GUI initializing lock, do not block
            if not self._gui_lock.acquire(False):
                # the graphical interface is running, don't crash it by
                # running another one potentially from a different thread
                log.debug("Gtk running, queuing exception handler to the main loop")
                run_in_loop(self._main_loop_handleException, dump_info)
            else:
                log.debug("Gtk not running, starting Gtk and running exception handler in it")
                self._main_loop_handleException(dump_info)

        except (RuntimeError, ImportError, ValueError):
            log.debug("Gtk cannot be initialized")
            # X not running (Gtk cannot be initialized)
            if threadMgr.in_main_thread():
                log.debug("In the main thread, running exception handler")
                if issubclass(ty, NonInteractiveError) or not self._interactive:
                    if issubclass(ty, NonInteractiveError):
                        cmdline_error_msg = _("\nThe installation was stopped due to an "
                                              "error which occurred while running in "
                                              "non-interactive cmdline mode. Since there "
                                              "cannot be any questions in cmdline mode, edit "
                                              "your kickstart file and retry installation. "
                                              "\nThe exact error message is: \n\n%s. \n\nThe "
                                              "installer will now terminate.") % str(value)
                    else:
                        cmdline_error_msg = _("\nRunning in cmdline mode, no interactive "
                                              "debugging allowed.\nThe exact error message is: "
                                              "\n\n%s.\n\nThe installer will now terminate."
                                              ) % str(value)

                    # since there is no UI in cmdline mode and it is completely
                    # non-interactive, we can't show a message window asking the user
                    # to acknowledge the error; instead, print the error out and sleep
                    # for a few seconds before exiting the installer
                    print(cmdline_error_msg)
                    time.sleep(180)
                    sys.exit(1)
                else:
                    print("\nAn unknown error has occured, look at the "
                          "/tmp/anaconda-tb* file(s) for more details")
                    # in the main thread, run exception handler
                    self._main_loop_handleException(dump_info)
            else:
                log.debug("In a non-main thread, sending a message with exception data")
                # not in the main thread, just send message with exception
                # data and let message handler run the exception handler in
                # the main thread
                exc_info = dump_info.exc_info
                # new Simpleline package is now used in TUI. Look if Simpleline is
                # initialized or if this is some fallback from GTK or other stuff.
                if App.is_initialized():
                    # if Simpleline is initialized enqueue exception there
                    loop = App.get_event_loop()
                    loop.enqueue_signal(ExceptionSignal(App.get_scheduler(), exception_info=exc_info))
                else:
                    hubQ.send_exception((exc_info.type,
                                         exc_info.value,
                                         exc_info.stack))