core: add new init_script_path option:
`init_script_path` option can be used in `[DEFAULTS]` to run a script at the end of backend initialisation. A new `init_pre_script` method is used to wait for backend to reach this stage (designed to be used mostly by CLI frontend), then the usual `ready_get` method is finished once the script is finished.
This commit is contained in:
parent
258c99b3c5
commit
e14dd9da8b
8 changed files with 83 additions and 10 deletions
|
|
@ -237,6 +237,14 @@ sig_in=
|
|||
sig_out=
|
||||
doc=Return when backend is initialised
|
||||
|
||||
[init_pre_script]
|
||||
async=
|
||||
type=method
|
||||
category=core
|
||||
sig_in=
|
||||
sig_out=
|
||||
doc=Return when backend is nearly initialised, just before init script is run, if any.
|
||||
|
||||
[version_get]
|
||||
type=method
|
||||
category=core
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ class DBusObject(objects.DBusObject):
|
|||
Method('image_convert', arguments='ssss', returns='s'),
|
||||
Method('image_generate_preview', arguments='ss', returns='s'),
|
||||
Method('image_resize', arguments='sii', returns='s'),
|
||||
Method('init_pre_script', arguments='', returns=''),
|
||||
Method('is_connected', arguments='s', returns='b'),
|
||||
Method('main_resource_get', arguments='ss', returns='s'),
|
||||
Method('menu_help_get', arguments='ss', returns='s'),
|
||||
|
|
@ -281,6 +282,9 @@ class DBusObject(objects.DBusObject):
|
|||
def dbus_image_resize(self, image_path, width, height):
|
||||
return self._callback("image_resize", image_path, width, height)
|
||||
|
||||
def dbus_init_pre_script(self, ):
|
||||
return self._callback("init_pre_script", )
|
||||
|
||||
def dbus_is_connected(self, profile_key="@DEFAULT@"):
|
||||
return self._callback("is_connected", profile_key)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import uuid
|
|||
import hashlib
|
||||
import copy
|
||||
from pathlib import Path
|
||||
from typing import Optional, List, Tuple, Dict
|
||||
from typing import Optional, List, Tuple, Dict, cast
|
||||
|
||||
from wokkel.data_form import Option
|
||||
from libervia import backend
|
||||
|
|
@ -49,6 +49,7 @@ from libervia.backend.tools import image
|
|||
from libervia.backend.tools.common import dynamic_import
|
||||
from libervia.backend.tools.common import regex
|
||||
from libervia.backend.tools.common import data_format
|
||||
from libervia.backend.tools.common import async_process
|
||||
from libervia.backend.stdui import ui_contact_list, ui_profile_manager
|
||||
import libervia.backend.plugins
|
||||
|
||||
|
|
@ -66,6 +67,10 @@ class LiberviaBackend(service.Service):
|
|||
self._menus = {}
|
||||
self._menus_paths = {} # path to id. key: (menu_type, lower case tuple of path),
|
||||
# value: menu id
|
||||
|
||||
# like initialised, but launched before init script is done, mainly useful for CLI
|
||||
# frontend, so it can be used in init script, while other frontends are waiting.
|
||||
self.init_pre_script = defer.Deferred()
|
||||
self.initialised = defer.Deferred()
|
||||
self.profiles = {}
|
||||
self.plugins = {}
|
||||
|
|
@ -143,6 +148,7 @@ class LiberviaBackend(service.Service):
|
|||
reactor.callLater(0, self.stop)
|
||||
return
|
||||
|
||||
self.bridge.register_method("init_pre_script", lambda: self.init_pre_script)
|
||||
self.bridge.register_method("ready_get", lambda: self.initialised)
|
||||
self.bridge.register_method("version_get", lambda: self.full_version)
|
||||
self.bridge.register_method("features_get", self.features_get)
|
||||
|
|
@ -239,6 +245,30 @@ class LiberviaBackend(service.Service):
|
|||
sys.exit(1)
|
||||
self._add_base_menus()
|
||||
|
||||
self.init_pre_script.callback(None)
|
||||
|
||||
init_script = self.memory.config_get(None, "init_script_path")
|
||||
if init_script is not None:
|
||||
init_script = cast(str, init_script)
|
||||
script_path = Path(init_script)
|
||||
if not script_path.exists():
|
||||
log.error(f"Init script doesn't exist: {init_script}")
|
||||
sys.exit(C.EXIT_BAD_ARG)
|
||||
elif not script_path.is_file():
|
||||
log.error(f"Init script is not a file: {init_script}")
|
||||
sys.exit(C.EXIT_BAD_ARG)
|
||||
else:
|
||||
log.info(f"Running init script {init_script!r}.")
|
||||
try:
|
||||
await async_process.run(
|
||||
str(init_script),
|
||||
verbose=True
|
||||
)
|
||||
except RuntimeError as e:
|
||||
log.error(f"Init script failed: {e}")
|
||||
self.stopService()
|
||||
sys.exit(C.EXIT_ERROR)
|
||||
|
||||
self.initialised.callback(None)
|
||||
log.info(_("Backend is ready"))
|
||||
|
||||
|
|
|
|||
|
|
@ -380,10 +380,10 @@ class Memory:
|
|||
auth_d.addCallback(do_start_session)
|
||||
return auth_d
|
||||
|
||||
if self.host.initialised.called:
|
||||
if self.host.init_pre_script.called:
|
||||
return defer.succeed(None).addCallback(backend_initialised)
|
||||
else:
|
||||
return self.host.initialised.addCallback(backend_initialised)
|
||||
return self.host.init_pre_script.addCallback(backend_initialised)
|
||||
|
||||
def stop_session(self, profile):
|
||||
"""Delete a profile session
|
||||
|
|
|
|||
|
|
@ -133,7 +133,9 @@ class CommandProtocol(protocol.ProcessProtocol):
|
|||
cmd_args = [command] + args
|
||||
if "env" not in kwargs:
|
||||
# we pass parent environment by default
|
||||
kwargs["env"] = None
|
||||
# FIXME: `None` doesn't seem to work, despite what documentation says, to be
|
||||
# checked and reported upstream if confirmed.
|
||||
kwargs["env"] = os.environ
|
||||
reactor.spawnProcess(prot,
|
||||
command,
|
||||
cmd_args,
|
||||
|
|
|
|||
|
|
@ -713,7 +713,9 @@ class LiberviaCli:
|
|||
)
|
||||
self.quit(C.EXIT_BRIDGE_ERROR, raise_exc=False)
|
||||
return
|
||||
await self.bridge.ready_get()
|
||||
# we wait on init_pre_script instead of ready_get, so the CLI frontend can be used
|
||||
# in init script.
|
||||
await self.bridge.init_pre_script()
|
||||
self.version = await self.bridge.version_get()
|
||||
self._bridge_connected()
|
||||
self.import_plugins()
|
||||
|
|
|
|||
|
|
@ -82,11 +82,7 @@ class bridge:
|
|||
'org.freedesktop.DBus.Error.Spawn.ExecFailed'):
|
||||
errback(BridgeExceptionNoService())
|
||||
elif e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported':
|
||||
log.error(_(
|
||||
'D-Bus is not launched, please see documentation '
|
||||
'(doc/installation.rst, section "Launching D-Bus (on servers)") to '
|
||||
'see instructions on how to launch it.'
|
||||
))
|
||||
log.error(_("D-Bus is not launched, please see README to see instructions on how to launch it"))
|
||||
errback(BridgeInitError)
|
||||
else:
|
||||
errback(e)
|
||||
|
|
@ -446,6 +442,15 @@ class bridge:
|
|||
error_handler = lambda err:errback(dbus_to_bridge_exception(err))
|
||||
return str(self.db_core_iface.image_resize(image_path, width, height, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler))
|
||||
|
||||
def init_pre_script(self, callback=None, errback=None):
|
||||
if callback is None:
|
||||
error_handler = None
|
||||
else:
|
||||
if errback is None:
|
||||
errback = log.error
|
||||
error_handler = lambda err:errback(dbus_to_bridge_exception(err))
|
||||
return self.db_core_iface.init_pre_script(timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)
|
||||
|
||||
def is_connected(self, profile_key="@DEFAULT@", callback=None, errback=None):
|
||||
if callback is None:
|
||||
error_handler = None
|
||||
|
|
@ -1251,6 +1256,14 @@ class AIOBridge(bridge):
|
|||
self.db_core_iface.image_resize(image_path, width, height, timeout=const_TIMEOUT, reply_handler=reply_handler, error_handler=error_handler)
|
||||
return fut
|
||||
|
||||
def init_pre_script(self):
|
||||
loop = asyncio.get_running_loop()
|
||||
fut = loop.create_future()
|
||||
reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret)
|
||||
error_handler = lambda err: loop.call_soon_threadsafe(fut.set_exception, dbus_to_bridge_exception(err))
|
||||
self.db_core_iface.init_pre_script(timeout=const_TIMEOUT, reply_handler=reply_handler, error_handler=error_handler)
|
||||
return fut
|
||||
|
||||
def is_connected(self, profile_key="@DEFAULT@"):
|
||||
loop = asyncio.get_running_loop()
|
||||
fut = loop.create_future()
|
||||
|
|
|
|||
|
|
@ -399,6 +399,15 @@ class bridge(object):
|
|||
else:
|
||||
d.addErrback(self._errback, ori_errback=errback)
|
||||
|
||||
def init_pre_script(self, callback=None, errback=None):
|
||||
d = self.root.callRemote("init_pre_script")
|
||||
if callback is not None:
|
||||
d.addCallback(lambda __: callback())
|
||||
if errback is None:
|
||||
d.addErrback(self._generic_errback)
|
||||
else:
|
||||
d.addErrback(self._errback, ori_errback=errback)
|
||||
|
||||
def is_connected(self, profile_key="@DEFAULT@", callback=None, errback=None):
|
||||
d = self.root.callRemote("is_connected", profile_key)
|
||||
if callback is not None:
|
||||
|
|
@ -955,6 +964,11 @@ class AIOBridge(bridge):
|
|||
d.addErrback(self._errback)
|
||||
return d.asFuture(asyncio.get_event_loop())
|
||||
|
||||
def init_pre_script(self):
|
||||
d = self.root.callRemote("init_pre_script")
|
||||
d.addErrback(self._errback)
|
||||
return d.asFuture(asyncio.get_event_loop())
|
||||
|
||||
def is_connected(self, profile_key="@DEFAULT@"):
|
||||
d = self.root.callRemote("is_connected", profile_key)
|
||||
d.addErrback(self._errback)
|
||||
|
|
|
|||
Loading…
Reference in a new issue