Mini Shell

Direktori : /usr/lib64/python3.6/site-packages/pyanaconda/core/
Upload File :
Current File : //usr/lib64/python3.6/site-packages/pyanaconda/core/glib.py

# Wrappers for GLib functions.
#
# Use these only if there is no other abstraction above the low level glib
# functions.
#
# Copyright (C) 2018 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.  You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
#  Author(s):  Jiri Konecny <jkonecny@redhat.com>
#

import gi
gi.require_version("GLib", "2.0")
gi.require_version("Gio", "2.0")

from gi.repository.GLib import markup_escape_text, format_size_full, \
                               timeout_add_seconds, timeout_add, idle_add, \
                               io_add_watch, child_watch_add, \
                               source_remove, timeout_source_new, \
                               spawn_close_pid, spawn_async_with_pipes, \
                               MainLoop, MainContext, \
                               GError, Variant, VariantType, Bytes, \
                               IOCondition, IOChannel, SpawnFlags, \
                               MAXUINT
from gi.repository.Gio import Cancellable

from pyanaconda.anaconda_loggers import get_module_logger
log = get_module_logger(__name__)


__all__ = ["create_main_loop", "create_new_context",
           "markup_escape_text", "format_size_full",
           "timeout_add_seconds", "timeout_add", "idle_add",
           "io_add_watch", "child_watch_add",
           "source_remove", "timeout_source_new",
           "spawn_close_pid", "spawn_async_with_pipes",
           "GError", "Variant", "VariantType", "Bytes",
           "IOCondition", "IOChannel", "SpawnFlags",
           "MAXUINT", "Cancellable"]


def create_main_loop(main_context=None):
    """Create GLib main loop.

    :param main_context: main context to be used for the loop
    :type main_context: GLib.MainContext
    :returns: GLib.MainLoop instance.
    """
    return MainLoop(main_context)


def create_new_context():
    """Create GLib context.

    :returns: GLib.MainContext."""
    return MainContext.new()


class GLibCallResult():
    """Result of GLib async finish callback."""
    def __init__(self):
        self.received_data = None
        self.error_message = ""
        self.timeout = False

    @property
    def succeeded(self):
        """The async call has succeeded."""
        return not self.failed

    @property
    def failed(self):
        """The async call has failed."""
        return bool(self.error_message) or self.timeout


def sync_call_glib(context, async_call, async_call_finish, timeout, *call_args):
    """Call GLib asynchronous method synchronously with timeout.

    :param context: context for the new loop in which the method will be called
    :type context: GMainContext
    :param async_call: asynchronous GLib method to be called
    :type async_call: GLib method
    :param async_call_finish: finish method of the asynchronous call
    :type async_call_finish: GLib method
    :param timeout: timeout for the loop in seconds (0 == no timeout)
    :type timeout: int

    *call_args should hold all positional arguments preceding the cancellable argument
    """

    info = async_call.get_symbol()
    result = GLibCallResult()

    loop = create_main_loop(context)
    callbacks = [loop.quit]

    def _stop_loop():
        log.debug("sync_call_glib[%s]: quit", info)
        while callbacks:
            callback = callbacks.pop()
            callback()

    def _cancellable_cb():
        log.debug("sync_call_glib[%s]: cancelled", info)

    cancellable = Cancellable()
    cancellable_id = cancellable.connect(_cancellable_cb)
    callbacks.append(lambda: cancellable.disconnect(cancellable_id))

    def _timeout_cb(user_data):
        log.debug("sync_call_glib[%s]: timeout", info)
        result.timeout = True
        cancellable.cancel()
        return False

    timeout_source = timeout_source_new(int(timeout * 1000))
    timeout_source.set_callback(_timeout_cb)
    timeout_source.attach(context)
    callbacks.append(timeout_source.destroy)

    def _finish_cb(source_object, async_result):
        log.debug("sync_call_glib[%s]: call %s",
                  info,
                  async_call_finish.get_symbol())
        try:
            result.received_data = async_call_finish(async_result)
        except Exception as e:  # pylint: disable=broad-except
            result.error_message = str(e)
        finally:
            _stop_loop()

    context.push_thread_default()

    log.debug("sync_call_glib[%s]: call", info)
    try:
        async_call(
            *call_args,
            cancellable=cancellable,
            callback=_finish_cb
        )
        loop.run()
    finally:
        _stop_loop()
        context.pop_thread_default()

    return result