move code aroud now only the server calls set_keyboard
This commit is contained in:
parent
449de0f374
commit
697949c1d2
|
@ -34,11 +34,9 @@ subiquity/common/api/tests/test_server.py
|
||||||
subiquity/common/errorreport.py
|
subiquity/common/errorreport.py
|
||||||
subiquity/common/filesystem.py
|
subiquity/common/filesystem.py
|
||||||
subiquity/common/__init__.py
|
subiquity/common/__init__.py
|
||||||
subiquity/common/keyboard.py
|
|
||||||
subiquity/common/serialize.py
|
subiquity/common/serialize.py
|
||||||
subiquity/common/tests/__init__.py
|
subiquity/common/tests/__init__.py
|
||||||
subiquity/common/tests/test_filesystem.py
|
subiquity/common/tests/test_filesystem.py
|
||||||
subiquity/common/tests/test_keyboard.py
|
|
||||||
subiquity/common/tests/test_serialization.py
|
subiquity/common/tests/test_serialization.py
|
||||||
subiquity/common/types.py
|
subiquity/common/types.py
|
||||||
subiquitycore/async_helpers.py
|
subiquitycore/async_helpers.py
|
||||||
|
@ -132,6 +130,7 @@ subiquity/server/controllers/refresh.py
|
||||||
subiquity/server/controllers/reporting.py
|
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/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
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
# Copyright 2020 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/>.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
|
|
||||||
from subiquitycore.utils import arun_command
|
|
||||||
|
|
||||||
from subiquity.common.types import KeyboardSetting
|
|
||||||
|
|
||||||
|
|
||||||
etc_default_keyboard_template = """\
|
|
||||||
# KEYBOARD CONFIGURATION FILE
|
|
||||||
|
|
||||||
# Consult the keyboard(5) manual page.
|
|
||||||
|
|
||||||
XKBMODEL="pc105"
|
|
||||||
XKBLAYOUT="{layout}"
|
|
||||||
XKBVARIANT="{variant}"
|
|
||||||
XKBOPTIONS="{options}"
|
|
||||||
|
|
||||||
BACKSPACE="guess"
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def from_config_file(config_file):
|
|
||||||
with open(config_file) as fp:
|
|
||||||
content = fp.read()
|
|
||||||
|
|
||||||
def optval(opt, default):
|
|
||||||
match = re.search(r'(?m)^\s*%s=(.*)$' % (opt,), content)
|
|
||||||
if match:
|
|
||||||
r = match.group(1).strip('"')
|
|
||||||
if r != '':
|
|
||||||
return r
|
|
||||||
return default
|
|
||||||
|
|
||||||
XKBLAYOUT = optval("XKBLAYOUT", "us")
|
|
||||||
XKBVARIANT = optval("XKBVARIANT", "")
|
|
||||||
XKBOPTIONS = optval("XKBOPTIONS", "")
|
|
||||||
toggle = None
|
|
||||||
for option in XKBOPTIONS.split(','):
|
|
||||||
if option.startswith('grp:'):
|
|
||||||
toggle = option[4:]
|
|
||||||
return KeyboardSetting(layout=XKBLAYOUT, variant=XKBVARIANT, toggle=toggle)
|
|
||||||
|
|
||||||
|
|
||||||
def render(setting):
|
|
||||||
options = ""
|
|
||||||
if setting.toggle:
|
|
||||||
options = "grp:" + setting.toggle
|
|
||||||
return etc_default_keyboard_template.format(
|
|
||||||
layout=setting.layout,
|
|
||||||
variant=setting.variant,
|
|
||||||
options=options)
|
|
||||||
|
|
||||||
|
|
||||||
async def set_keyboard(root, setting, dry_run):
|
|
||||||
path = os.path.join(root, 'etc', 'default', 'keyboard')
|
|
||||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
||||||
with open(path, 'w') as fp:
|
|
||||||
fp.write(render(setting))
|
|
||||||
cmds = [
|
|
||||||
['setupcon', '--save', '--force', '--keyboard-only'],
|
|
||||||
['/snap/bin/subiquity.subiquity-loadkeys'],
|
|
||||||
]
|
|
||||||
if dry_run:
|
|
||||||
scale = os.environ.get('SUBIQUITY_REPLAY_TIMESCALE', "1")
|
|
||||||
cmds = [['sleep', str(1/float(scale))]]
|
|
||||||
for cmd in cmds:
|
|
||||||
await arun_command(cmd)
|
|
|
@ -14,30 +14,75 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from subiquity.common.keyboard import from_config_file, render
|
|
||||||
from subiquity.common.types import KeyboardSetting
|
from subiquity.common.types import KeyboardSetting
|
||||||
|
|
||||||
log = logging.getLogger("subiquity.models.keyboard")
|
log = logging.getLogger("subiquity.models.keyboard")
|
||||||
|
|
||||||
|
|
||||||
|
etc_default_keyboard_template = """\
|
||||||
|
# KEYBOARD CONFIGURATION FILE
|
||||||
|
|
||||||
|
# Consult the keyboard(5) manual page.
|
||||||
|
|
||||||
|
XKBMODEL="pc105"
|
||||||
|
XKBLAYOUT="{layout}"
|
||||||
|
XKBVARIANT="{variant}"
|
||||||
|
XKBOPTIONS="{options}"
|
||||||
|
|
||||||
|
BACKSPACE="guess"
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def from_config_file(config_file):
|
||||||
|
with open(config_file) as fp:
|
||||||
|
content = fp.read()
|
||||||
|
|
||||||
|
def optval(opt, default):
|
||||||
|
match = re.search(r'(?m)^\s*%s=(.*)$' % (opt,), content)
|
||||||
|
if match:
|
||||||
|
r = match.group(1).strip('"')
|
||||||
|
if r != '':
|
||||||
|
return r
|
||||||
|
return default
|
||||||
|
|
||||||
|
XKBLAYOUT = optval("XKBLAYOUT", "us")
|
||||||
|
XKBVARIANT = optval("XKBVARIANT", "")
|
||||||
|
XKBOPTIONS = optval("XKBOPTIONS", "")
|
||||||
|
toggle = None
|
||||||
|
for option in XKBOPTIONS.split(','):
|
||||||
|
if option.startswith('grp:'):
|
||||||
|
toggle = option[4:]
|
||||||
|
return KeyboardSetting(layout=XKBLAYOUT, variant=XKBVARIANT, toggle=toggle)
|
||||||
|
|
||||||
|
|
||||||
class KeyboardModel:
|
class KeyboardModel:
|
||||||
|
|
||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
self.root = root
|
self.config_path = os.path.join(
|
||||||
config_path = os.path.join(self.root, 'etc', 'default', 'keyboard')
|
root, 'etc', 'default', 'keyboard')
|
||||||
if os.path.exists(config_path):
|
if os.path.exists(self.config_path):
|
||||||
self.setting = from_config_file(config_path)
|
self.setting = from_config_file(self.config_path)
|
||||||
else:
|
else:
|
||||||
self.setting = KeyboardSetting(layout='us')
|
self.setting = KeyboardSetting(layout='us')
|
||||||
|
|
||||||
|
def render_config_file(self):
|
||||||
|
options = ""
|
||||||
|
if self.setting.toggle:
|
||||||
|
options = "grp:" + self.setting.toggle
|
||||||
|
return etc_default_keyboard_template.format(
|
||||||
|
layout=self.setting.layout,
|
||||||
|
variant=self.setting.variant,
|
||||||
|
options=options)
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
return {
|
return {
|
||||||
'write_files': {
|
'write_files': {
|
||||||
'etc_default_keyboard': {
|
'etc_default_keyboard': {
|
||||||
'path': 'etc/default/keyboard',
|
'path': 'etc/default/keyboard',
|
||||||
'content': render(self.setting),
|
'content': self.render_config_file(),
|
||||||
'permissions': 0o644,
|
'permissions': 0o644,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,9 +20,9 @@ import os
|
||||||
import attr
|
import attr
|
||||||
|
|
||||||
from subiquitycore.context import with_context
|
from subiquitycore.context import with_context
|
||||||
|
from subiquitycore.utils import arun_command
|
||||||
|
|
||||||
from subiquity.common.apidef import API
|
from subiquity.common.apidef import API
|
||||||
from subiquity.common.keyboard import set_keyboard
|
|
||||||
from subiquity.common.serialize import Serializer
|
from subiquity.common.serialize import Serializer
|
||||||
from subiquity.common.types import (
|
from subiquity.common.types import (
|
||||||
AnyStep,
|
AnyStep,
|
||||||
|
@ -146,12 +146,26 @@ class KeyboardController(SubiquityController):
|
||||||
@with_context()
|
@with_context()
|
||||||
async def apply_autoinstall_config(self, context):
|
async def apply_autoinstall_config(self, context):
|
||||||
if self.needs_set_keyboard:
|
if self.needs_set_keyboard:
|
||||||
await set_keyboard(
|
await self.set_keyboard()
|
||||||
self.app.root, self.model.setting, self.opts.dry_run)
|
|
||||||
|
|
||||||
def make_autoinstall(self):
|
def make_autoinstall(self):
|
||||||
return attr.asdict(self.model.setting)
|
return attr.asdict(self.model.setting)
|
||||||
|
|
||||||
|
async def set_keyboard(self):
|
||||||
|
path = self.model.config_path
|
||||||
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||||
|
with open(path, 'w') as fp:
|
||||||
|
fp.write(self.model.render_config_file())
|
||||||
|
cmds = [
|
||||||
|
['setupcon', '--save', '--force', '--keyboard-only'],
|
||||||
|
['/snap/bin/subiquity.subiquity-loadkeys'],
|
||||||
|
]
|
||||||
|
if self.opts.dry_run:
|
||||||
|
scale = os.environ.get('SUBIQUITY_REPLAY_TIMESCALE', "1")
|
||||||
|
cmds = [['sleep', str(1/float(scale))]]
|
||||||
|
for cmd in cmds:
|
||||||
|
await arun_command(cmd)
|
||||||
|
|
||||||
async def GET(self) -> KeyboardSetting:
|
async def GET(self) -> KeyboardSetting:
|
||||||
return for_ui(self.model.setting)
|
return for_ui(self.model.setting)
|
||||||
|
|
||||||
|
@ -160,9 +174,8 @@ class KeyboardController(SubiquityController):
|
||||||
if new is not None:
|
if new is not None:
|
||||||
data = KeyboardSetting(new[0], new[1], data.toggle)
|
data = KeyboardSetting(new[0], new[1], data.toggle)
|
||||||
if data != self.model.setting:
|
if data != self.model.setting:
|
||||||
await set_keyboard(
|
|
||||||
self.app.root, data, self.opts.dry_run)
|
|
||||||
self.model.setting = data
|
self.model.setting = data
|
||||||
|
await self.set_keyboard()
|
||||||
self.configured()
|
self.configured()
|
||||||
|
|
||||||
async def needs_toggle_GET(self, layout_code: str,
|
async def needs_toggle_GET(self, layout_code: str,
|
||||||
|
|
|
@ -18,13 +18,19 @@ import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from subiquity.common.keyboard import (
|
from subiquity.models.keyboard import (
|
||||||
from_config_file,
|
KeyboardModel,
|
||||||
set_keyboard,
|
)
|
||||||
|
from subiquity.server.controllers.keyboard import (
|
||||||
|
KeyboardController,
|
||||||
)
|
)
|
||||||
from subiquity.common.types import KeyboardSetting
|
from subiquity.common.types import KeyboardSetting
|
||||||
|
|
||||||
|
|
||||||
|
class opts:
|
||||||
|
dry_run = True
|
||||||
|
|
||||||
|
|
||||||
class TestSubiquityModel(unittest.TestCase):
|
class TestSubiquityModel(unittest.TestCase):
|
||||||
|
|
||||||
def test_write_config(self):
|
def test_write_config(self):
|
||||||
|
@ -38,9 +44,13 @@ class TestSubiquityModel(unittest.TestCase):
|
||||||
os.environ['SUBIQUITY_REPLAY_TIMESCALE'] = '100'
|
os.environ['SUBIQUITY_REPLAY_TIMESCALE'] = '100'
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
new_setting = KeyboardSetting('fr', 'azerty')
|
new_setting = KeyboardSetting('fr', 'azerty')
|
||||||
await set_keyboard(tmpdir, new_setting, True)
|
model = KeyboardModel(tmpdir)
|
||||||
read_setting = from_config_file(
|
model.setting = new_setting
|
||||||
os.path.join(tmpdir, 'etc', 'default', 'keyboard'))
|
c = object.__new__(KeyboardController)
|
||||||
|
c.opts = opts
|
||||||
|
c.model = model
|
||||||
|
await c.set_keyboard()
|
||||||
|
read_setting = KeyboardModel(tmpdir).setting
|
||||||
self.assertEqual(new_setting, read_setting)
|
self.assertEqual(new_setting, read_setting)
|
||||||
loop.run_until_complete(t())
|
loop.run_until_complete(t())
|
||||||
loop.close()
|
loop.close()
|
Loading…
Reference in New Issue