anaconda/anaconda-40.22.3.13/pyanaconda/core/glib.py
2024-11-14 21:39:56 -08:00

160 lines
5.4 KiB
Python

# 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