Merge pull request #1578 from dbungert/lp-2008271-validate-kbd-layout
keyboard: validate layout and variant
This commit is contained in:
commit
359a5caa7d
|
@ -20,7 +20,11 @@ import os
|
|||
import yaml
|
||||
|
||||
from subiquity.common.resources import resource_path
|
||||
from subiquity.common.types import KeyboardSetting
|
||||
from subiquity.common.serialize import Serializer
|
||||
from subiquity.common.types import (
|
||||
KeyboardLayout,
|
||||
KeyboardSetting,
|
||||
)
|
||||
|
||||
log = logging.getLogger("subiquity.models.keyboard")
|
||||
|
||||
|
@ -71,6 +75,8 @@ class KeyboardModel:
|
|||
self.default_setting = from_config_file(self.config_path)
|
||||
else:
|
||||
self.default_setting = self.layout_for_lang['en_US.UTF-8']
|
||||
self.keyboard_list = KeyboardList()
|
||||
self.keyboard_list.load_language('C')
|
||||
self._setting = None
|
||||
|
||||
@property
|
||||
|
@ -81,8 +87,18 @@ class KeyboardModel:
|
|||
|
||||
@setting.setter
|
||||
def setting(self, value):
|
||||
self.validate_setting(value)
|
||||
self._setting = value
|
||||
|
||||
def validate_setting(self, setting: KeyboardSetting) -> None:
|
||||
kbd_layout = self.keyboard_list.layout_map.get(setting.layout)
|
||||
if kbd_layout is None:
|
||||
raise ValueError(f'Unknown keyboard layout "{setting.layout}"')
|
||||
if not any(variant.code == setting.variant
|
||||
for variant in kbd_layout.variants):
|
||||
raise ValueError(f'Unknown keyboard variant "{setting.variant}" '
|
||||
f'for layout "{setting.layout}"')
|
||||
|
||||
def render_config_file(self):
|
||||
options = ""
|
||||
if self.setting.toggle:
|
||||
|
@ -130,3 +146,44 @@ class KeyboardModel:
|
|||
for k, v in data.items():
|
||||
ret[k] = KeyboardSetting(**v)
|
||||
return ret
|
||||
|
||||
|
||||
class KeyboardList:
|
||||
|
||||
def __init__(self):
|
||||
self._kbnames_dir = resource_path('kbds')
|
||||
self.serializer = Serializer(compact=True)
|
||||
self._clear()
|
||||
|
||||
def _file_for_lang(self, code):
|
||||
return os.path.join(self._kbnames_dir, code + '.jsonl')
|
||||
|
||||
def _has_language(self, code):
|
||||
return os.path.exists(self._file_for_lang(code))
|
||||
|
||||
def load_language(self, code):
|
||||
if '.' in code:
|
||||
code = code.split('.')[0]
|
||||
if not self._has_language(code):
|
||||
code = code.split('_')[0]
|
||||
if not self._has_language(code):
|
||||
code = 'C'
|
||||
|
||||
if code == self.current_lang:
|
||||
return
|
||||
|
||||
self._clear()
|
||||
|
||||
with open(self._file_for_lang(code)) as kbdnames:
|
||||
self.layouts = []
|
||||
self.layout_map = {}
|
||||
for line in kbdnames:
|
||||
kbd_layout = self.serializer.from_json(KeyboardLayout, line)
|
||||
self.layouts.append(kbd_layout)
|
||||
self.layout_map[kbd_layout.code] = kbd_layout
|
||||
self.current_lang = code
|
||||
|
||||
def _clear(self):
|
||||
self.current_lang = None
|
||||
self.layouts = []
|
||||
self.layout_map = {}
|
||||
|
|
|
@ -29,11 +29,21 @@ class TestKeyboardModel(SubiTestCase):
|
|||
self.assertIsNone(self.model._setting)
|
||||
self.assertEqual('us', self.model.setting.layout)
|
||||
|
||||
def testSetToZZ(self):
|
||||
val = KeyboardSetting(layout='zz')
|
||||
self.model.setting = val
|
||||
self.assertEqual(val, self.model.setting)
|
||||
self.assertEqual(val, self.model._setting)
|
||||
@parameterized.expand((['zz'], ['en']))
|
||||
def testSetToInvalidLayout(self, layout):
|
||||
initial = self.model.setting
|
||||
val = KeyboardSetting(layout=layout)
|
||||
with self.assertRaises(ValueError):
|
||||
self.model.setting = val
|
||||
self.assertEqual(initial, self.model.setting)
|
||||
|
||||
@parameterized.expand((['zz']))
|
||||
def testSetToInvalidVariant(self, variant):
|
||||
initial = self.model.setting
|
||||
val = KeyboardSetting(layout='us', variant=variant)
|
||||
with self.assertRaises(ValueError):
|
||||
self.model.setting = val
|
||||
self.assertEqual(initial, self.model.setting)
|
||||
|
||||
@parameterized.expand([
|
||||
['ast_ES.UTF-8', 'es', 'ast'],
|
||||
|
|
|
@ -28,7 +28,6 @@ from subiquity.common.resources import resource_path
|
|||
from subiquity.common.serialize import Serializer
|
||||
from subiquity.common.types import (
|
||||
AnyStep,
|
||||
KeyboardLayout,
|
||||
KeyboardSetting,
|
||||
KeyboardSetup,
|
||||
)
|
||||
|
@ -118,44 +117,6 @@ def for_ui(setting):
|
|||
layout=layout, variant=variant, toggle=setting.toggle)
|
||||
|
||||
|
||||
class KeyboardList:
|
||||
|
||||
def __init__(self):
|
||||
self._kbnames_dir = resource_path('kbds')
|
||||
self.serializer = Serializer(compact=True)
|
||||
self._clear()
|
||||
|
||||
def _file_for_lang(self, code):
|
||||
return os.path.join(self._kbnames_dir, code + '.jsonl')
|
||||
|
||||
def _has_language(self, code):
|
||||
return os.path.exists(self._file_for_lang(code))
|
||||
|
||||
def load_language(self, code):
|
||||
if '.' in code:
|
||||
code = code.split('.')[0]
|
||||
if not self._has_language(code):
|
||||
code = code.split('_')[0]
|
||||
if not self._has_language(code):
|
||||
code = 'C'
|
||||
|
||||
if code == self.current_lang:
|
||||
return
|
||||
|
||||
self._clear()
|
||||
|
||||
with open(self._file_for_lang(code)) as kbdnames:
|
||||
self.layouts = [
|
||||
self.serializer.from_json(KeyboardLayout, line)
|
||||
for line in kbdnames
|
||||
]
|
||||
self.current_lang = code
|
||||
|
||||
def _clear(self):
|
||||
self.current_lang = None
|
||||
self.layouts = []
|
||||
|
||||
|
||||
class KeyboardController(SubiquityController):
|
||||
|
||||
endpoint = API.keyboard
|
||||
|
@ -177,7 +138,6 @@ class KeyboardController(SubiquityController):
|
|||
self.serializer = Serializer(compact=True)
|
||||
self.pc105_steps = None
|
||||
self.needs_set_keyboard = False
|
||||
self.keyboard_list = KeyboardList()
|
||||
super().__init__(app)
|
||||
|
||||
def load_autoinstall_data(self, data):
|
||||
|
@ -213,10 +173,10 @@ class KeyboardController(SubiquityController):
|
|||
|
||||
async def GET(self) -> KeyboardSetup:
|
||||
lang = self.app.base_model.locale.selected_language
|
||||
self.keyboard_list.load_language(lang)
|
||||
self.model.keyboard_list.load_language(lang)
|
||||
return KeyboardSetup(
|
||||
setting=for_ui(self.model.setting_for_lang(lang)),
|
||||
layouts=self.keyboard_list.layouts)
|
||||
layouts=self.model.keyboard_list.layouts)
|
||||
|
||||
async def POST(self, data: KeyboardSetting):
|
||||
log.debug(data)
|
||||
|
|
Loading…
Reference in New Issue