simple replacement for urwid signals wrapper as used in server
I think this removes all use of urwid from the server code.
This commit is contained in:
parent
ddf9baf19c
commit
dab04bcb3a
|
@ -57,8 +57,8 @@ subiquitycore/models/network.py
|
||||||
subiquitycore/netplan.py
|
subiquitycore/netplan.py
|
||||||
subiquitycore/palette.py
|
subiquitycore/palette.py
|
||||||
subiquitycore/prober.py
|
subiquitycore/prober.py
|
||||||
|
subiquitycore/pubsub.py
|
||||||
subiquitycore/screen.py
|
subiquitycore/screen.py
|
||||||
subiquitycore/signals.py
|
|
||||||
subiquitycore/snapd.py
|
subiquitycore/snapd.py
|
||||||
subiquitycore/ssh.py
|
subiquitycore/ssh.py
|
||||||
subiquitycore/testing/__init__.py
|
subiquitycore/testing/__init__.py
|
||||||
|
@ -111,6 +111,7 @@ subiquity/models/tests/__init__.py
|
||||||
subiquity/models/tests/test_filesystem.py
|
subiquity/models/tests/test_filesystem.py
|
||||||
subiquity/models/tests/test_mirror.py
|
subiquity/models/tests/test_mirror.py
|
||||||
subiquity/models/tests/test_subiquity.py
|
subiquity/models/tests/test_subiquity.py
|
||||||
|
subiquity/models/updates.py
|
||||||
subiquity/server/controller.py
|
subiquity/server/controller.py
|
||||||
subiquity/server/controllers/cmdlist.py
|
subiquity/server/controllers/cmdlist.py
|
||||||
subiquity/server/controllers/debconf.py
|
subiquity/server/controllers/debconf.py
|
||||||
|
@ -130,6 +131,7 @@ subiquity/server/controllers/reporting.py
|
||||||
subiquity/server/controllers/snaplist.py
|
subiquity/server/controllers/snaplist.py
|
||||||
subiquity/server/controllers/ssh.py
|
subiquity/server/controllers/ssh.py
|
||||||
subiquity/server/controllers/tests/test_keyboard.py
|
subiquity/server/controllers/tests/test_keyboard.py
|
||||||
|
subiquity/server/controllers/updates.py
|
||||||
subiquity/server/controllers/userdata.py
|
subiquity/server/controllers/userdata.py
|
||||||
subiquity/server/controllers/zdev.py
|
subiquity/server/controllers/zdev.py
|
||||||
subiquity/server/dryrun.py
|
subiquity/server/dryrun.py
|
||||||
|
|
|
@ -55,15 +55,14 @@ class MirrorController(SubiquityController):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
model_name = "mirror"
|
model_name = "mirror"
|
||||||
signals = [
|
|
||||||
('snapd-network-change', 'snapd_network_changed'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
self.geoip_enabled = True
|
self.geoip_enabled = True
|
||||||
self.check_state = CheckState.NOT_STARTED
|
self.check_state = CheckState.NOT_STARTED
|
||||||
self.lookup_task = SingleInstanceTask(self.lookup)
|
self.lookup_task = SingleInstanceTask(self.lookup)
|
||||||
|
self.app.hub.subscribe(
|
||||||
|
'snapd-network-change', self.snapd_network_changed)
|
||||||
|
|
||||||
def load_autoinstall_data(self, data):
|
def load_autoinstall_data(self, data):
|
||||||
if data is None:
|
if data is None:
|
||||||
|
|
|
@ -42,7 +42,7 @@ class ProxyController(SubiquityController):
|
||||||
if self.model.proxy:
|
if self.model.proxy:
|
||||||
os.environ['http_proxy'] = os.environ['https_proxy'] = \
|
os.environ['http_proxy'] = os.environ['https_proxy'] = \
|
||||||
self.model.proxy
|
self.model.proxy
|
||||||
self.signal.emit_signal('network-proxy-set')
|
self.app.hub.broadcast('network-proxy-set')
|
||||||
|
|
||||||
@with_context()
|
@with_context()
|
||||||
async def apply_autoinstall_config(self, context=None):
|
async def apply_autoinstall_config(self, context=None):
|
||||||
|
@ -64,5 +64,5 @@ class ProxyController(SubiquityController):
|
||||||
|
|
||||||
async def POST(self, data: str):
|
async def POST(self, data: str):
|
||||||
self.model.proxy = data
|
self.model.proxy = data
|
||||||
self.signal.emit_signal('network-proxy-set')
|
self.app.hub.broadcast('network-proxy-set')
|
||||||
self.configured()
|
self.configured()
|
||||||
|
|
|
@ -52,10 +52,6 @@ class RefreshController(SubiquityController):
|
||||||
'additionalProperties': False,
|
'additionalProperties': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
signals = [
|
|
||||||
('snapd-network-change', 'snapd_network_changed'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
self.ai_data = {}
|
self.ai_data = {}
|
||||||
|
@ -63,6 +59,8 @@ class RefreshController(SubiquityController):
|
||||||
self.configure_task = None
|
self.configure_task = None
|
||||||
self.check_task = None
|
self.check_task = None
|
||||||
self.status = RefreshStatus(availability=RefreshCheckState.UNKNOWN)
|
self.status = RefreshStatus(availability=RefreshCheckState.UNKNOWN)
|
||||||
|
self.app.hub.subscribe(
|
||||||
|
'snapd-network-change', self.snapd_network_changed)
|
||||||
|
|
||||||
def load_autoinstall_data(self, data):
|
def load_autoinstall_data(self, data):
|
||||||
if data is not None:
|
if data is not None:
|
||||||
|
|
|
@ -129,9 +129,6 @@ class SnapListController(SubiquityController):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
model_name = "snaplist"
|
model_name = "snaplist"
|
||||||
signals = [
|
|
||||||
('snapd-network-change', 'snapd_network_changed'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def _make_loader(self):
|
def _make_loader(self):
|
||||||
return SnapdSnapInfoLoader(
|
return SnapdSnapInfoLoader(
|
||||||
|
@ -141,6 +138,8 @@ class SnapListController(SubiquityController):
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
self.loader = self._make_loader()
|
self.loader = self._make_loader()
|
||||||
|
self.app.hub.subscribe(
|
||||||
|
'snapd-network-change', self.snapd_network_changed)
|
||||||
|
|
||||||
def load_autoinstall_data(self, ai_data):
|
def load_autoinstall_data(self, ai_data):
|
||||||
to_install = []
|
to_install = []
|
||||||
|
|
|
@ -235,10 +235,10 @@ class SubiquityServer(Application):
|
||||||
self.note_data_for_apport("SnapUpdated", str(self.updated))
|
self.note_data_for_apport("SnapUpdated", str(self.updated))
|
||||||
self.event_listeners = []
|
self.event_listeners = []
|
||||||
self.autoinstall_config = None
|
self.autoinstall_config = None
|
||||||
self.signal.connect_signals([
|
self.hub.subscribe(
|
||||||
('network-proxy-set', lambda: schedule_task(self._proxy_set())),
|
'network-up', self._network_change)
|
||||||
('network-change', self._network_change),
|
self.hub.subscribe(
|
||||||
])
|
'network-proxy-set', lambda: schedule_task(self._proxy_set()))
|
||||||
|
|
||||||
def load_serialized_state(self):
|
def load_serialized_state(self):
|
||||||
for controller in self.controllers.instances:
|
for controller in self.controllers.instances:
|
||||||
|
@ -523,12 +523,12 @@ class SubiquityServer(Application):
|
||||||
await self.apply_autoinstall_config()
|
await self.apply_autoinstall_config()
|
||||||
|
|
||||||
def _network_change(self):
|
def _network_change(self):
|
||||||
self.signal.emit_signal('snapd-network-change')
|
self.hub.broadcast('snapd-network-change')
|
||||||
|
|
||||||
async def _proxy_set(self):
|
async def _proxy_set(self):
|
||||||
await run_in_thread(
|
await run_in_thread(
|
||||||
self.snapd.connection.configure_proxy, self.base_model.proxy)
|
self.snapd.connection.configure_proxy, self.base_model.proxy)
|
||||||
self.signal.emit_signal('snapd-network-change')
|
self.hub.broadcast('snapd-network-change')
|
||||||
|
|
||||||
def restart(self):
|
def restart(self):
|
||||||
cmdline = ['snap', 'run', 'subiquity.subiquity-server']
|
cmdline = ['snap', 'run', 'subiquity.subiquity-server']
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from subiquitycore.signals import Signal
|
|
||||||
from subiquitycore.testing import view_helpers
|
from subiquitycore.testing import view_helpers
|
||||||
|
|
||||||
from subiquity.client.controllers.identity import IdentityController
|
from subiquity.client.controllers.identity import IdentityController
|
||||||
|
@ -22,7 +21,6 @@ class IdentityViewTests(unittest.TestCase):
|
||||||
|
|
||||||
def make_view(self):
|
def make_view(self):
|
||||||
controller = mock.create_autospec(spec=IdentityController)
|
controller = mock.create_autospec(spec=IdentityController)
|
||||||
controller.signal = mock.create_autospec(spec=Signal)
|
|
||||||
return IdentityView(controller, IdentityData())
|
return IdentityView(controller, IdentityData())
|
||||||
|
|
||||||
def test_initial_focus(self):
|
def test_initial_focus(self):
|
||||||
|
|
|
@ -22,25 +22,16 @@ log = logging.getLogger("subiquitycore.controller")
|
||||||
class BaseController(ABC):
|
class BaseController(ABC):
|
||||||
"""Base class for controllers."""
|
"""Base class for controllers."""
|
||||||
|
|
||||||
signals = []
|
|
||||||
model_name = None
|
model_name = None
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.name = type(self).__name__[:-len("Controller")]
|
self.name = type(self).__name__[:-len("Controller")]
|
||||||
self.signal = app.signal
|
|
||||||
self.opts = app.opts
|
self.opts = app.opts
|
||||||
self.app = app
|
self.app = app
|
||||||
self.context = self.app.context.child(self.name, childlevel="DEBUG")
|
self.context = self.app.context.child(self.name, childlevel="DEBUG")
|
||||||
if self.model_name is not None:
|
if self.model_name is not None:
|
||||||
self.model = getattr(self.app.base_model, self.model_name)
|
self.model = getattr(self.app.base_model, self.model_name)
|
||||||
|
|
||||||
def register_signals(self):
|
|
||||||
"""Defines signals associated with controller from model."""
|
|
||||||
signals = []
|
|
||||||
for sig, cb in self.signals:
|
|
||||||
signals.append((sig, getattr(self, cb)))
|
|
||||||
self.signal.connect_signals(signals)
|
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Called just before the main loop is started.
|
"""Called just before the main loop is started.
|
||||||
|
|
||||||
|
|
|
@ -470,7 +470,7 @@ class BaseNetworkController(BaseController):
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def update_default_routes(self, routes):
|
def update_default_routes(self, routes):
|
||||||
if routes:
|
if routes:
|
||||||
self.signal.emit_signal('network-change')
|
self.app.hub.broadcast('network-up')
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def new_link(self, netdev):
|
def new_link(self, netdev):
|
||||||
|
|
|
@ -22,7 +22,7 @@ from subiquitycore.context import (
|
||||||
Context,
|
Context,
|
||||||
)
|
)
|
||||||
from subiquitycore.controllerset import ControllerSet
|
from subiquitycore.controllerset import ControllerSet
|
||||||
from subiquitycore.signals import Signal
|
from subiquitycore.pubsub import MessageHub
|
||||||
|
|
||||||
log = logging.getLogger('subiquitycore.core')
|
log = logging.getLogger('subiquitycore.core')
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class Application:
|
||||||
self.scale_factor = float(
|
self.scale_factor = float(
|
||||||
os.environ.get('SUBIQUITY_REPLAY_TIMESCALE', "1"))
|
os.environ.get('SUBIQUITY_REPLAY_TIMESCALE', "1"))
|
||||||
self.updated = os.path.exists(self.state_path('updating'))
|
self.updated = os.path.exists(self.state_path('updating'))
|
||||||
self.signal = Signal()
|
self.hub = MessageHub()
|
||||||
self.aio_loop = asyncio.get_event_loop()
|
self.aio_loop = asyncio.get_event_loop()
|
||||||
self.aio_loop.set_exception_handler(self._exception_handler)
|
self.aio_loop.set_exception_handler(self._exception_handler)
|
||||||
self.controllers = ControllerSet(
|
self.controllers = ControllerSet(
|
||||||
|
@ -84,13 +84,6 @@ class Application:
|
||||||
else:
|
else:
|
||||||
loop.default_exception_handler(context)
|
loop.default_exception_handler(context)
|
||||||
|
|
||||||
def _connect_base_signals(self):
|
|
||||||
"""Connect signals used in the core controller."""
|
|
||||||
# Registers signals from each controller
|
|
||||||
for controller in self.controllers.instances:
|
|
||||||
controller.register_signals()
|
|
||||||
log.debug("known signals: %s", self.signal.known_signals)
|
|
||||||
|
|
||||||
def state_path(self, *parts):
|
def state_path(self, *parts):
|
||||||
return os.path.join(self.state_dir, *parts)
|
return os.path.join(self.state_dir, *parts)
|
||||||
|
|
||||||
|
@ -124,7 +117,6 @@ class Application:
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
self.controllers.load_all()
|
self.controllers.load_all()
|
||||||
self._connect_base_signals()
|
|
||||||
self.start_controllers()
|
self.start_controllers()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Copyright 2021 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
class MessageHub:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.subscriptions = {}
|
||||||
|
|
||||||
|
def subscribe(self, channel, method, *args):
|
||||||
|
self.subscriptions.setdefault(channel, []).append((method, args))
|
||||||
|
|
||||||
|
def broadcast(self, channel):
|
||||||
|
for m, args in self.subscriptions.get(channel, []):
|
||||||
|
m(*args)
|
|
@ -1,64 +0,0 @@
|
||||||
# Copyright 2015 Canonical, Ltd.
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
""" Registers all known signal emitters
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
import types
|
|
||||||
|
|
||||||
import urwid
|
|
||||||
|
|
||||||
log = logging.getLogger('subiquity.signals')
|
|
||||||
|
|
||||||
|
|
||||||
class SignalException(Exception):
|
|
||||||
"Problem with a signal"
|
|
||||||
|
|
||||||
|
|
||||||
class Signal:
|
|
||||||
known_signals = []
|
|
||||||
|
|
||||||
def register_signals(self, signals):
|
|
||||||
if type(signals) is list:
|
|
||||||
self.known_signals.extend(signals)
|
|
||||||
else:
|
|
||||||
self.known_signals.append(signals)
|
|
||||||
urwid.register_signal(Signal, self.known_signals)
|
|
||||||
|
|
||||||
def emit_signal(self, name, *args, **kwargs):
|
|
||||||
urwid.emit_signal(self, name, *args, **kwargs)
|
|
||||||
|
|
||||||
def connect_signal(self, name, cb):
|
|
||||||
if isinstance(cb, types.MethodType):
|
|
||||||
scb = "{}.{}".format(
|
|
||||||
cb.__self__.__class__.__name__, cb.__func__.__name__)
|
|
||||||
else:
|
|
||||||
scb = str(cb)
|
|
||||||
log.debug("connect_signal: %s -> %s", name, scb)
|
|
||||||
urwid.connect_signal(self, name, cb)
|
|
||||||
|
|
||||||
def connect_signals(self, signal_callback):
|
|
||||||
""" Connects a batch of signals
|
|
||||||
|
|
||||||
:param list signal_callback: List of tuples eg. ('signame', self.cb)
|
|
||||||
"""
|
|
||||||
if not type(signal_callback) is list:
|
|
||||||
raise SignalException(
|
|
||||||
"Passed something other than a required list.")
|
|
||||||
for sig, cb in signal_callback:
|
|
||||||
if sig not in self.known_signals:
|
|
||||||
self.register_signals(sig)
|
|
||||||
self.connect_signal(sig, cb)
|
|
|
@ -98,9 +98,6 @@ class RepeatedController(BaseController):
|
||||||
self.index = index
|
self.index = index
|
||||||
self.context = orig.context
|
self.context = orig.context
|
||||||
|
|
||||||
def register_signals(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def make_ui(self):
|
def make_ui(self):
|
||||||
return self.orig.make_ui(self.index)
|
return self.orig.make_ui(self.index)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue