diff --git a/calculate/vars/main/cl/__init__.py b/calculate/vars/main/cl/__init__.py index 18213e9..038cf07 100644 --- a/calculate/vars/main/cl/__init__.py +++ b/calculate/vars/main/cl/__init__.py @@ -1,7 +1,7 @@ import os from calculate.utils.fs import readFile from calculate.variables.datavars import Variable, Namespace, Dependence, \ - StringType, BooleanType, Calculate + StringType, BooleanType, HashType, Calculate def get_ebuild_phase(): return os.environ.get("EBUILD_PHASE", "") @@ -31,3 +31,82 @@ Variable("chroot_status", type=BooleanType, source=Calculate(get_chroot_status)) Variable("system_boot_set", type=BooleanType, source=Calculate(is_system_boot)) + +class CmdlineParams(object): + """ + Параметры опции загрузки ядра calculate= + """ + # названия параметров + Calculate = "calculate" + IsoscanFile = "iso-scan/filename" + IOScheduler = "elevator" + + # внутренние параметры calculate + Locale = "lang" + Keymap = "keymap" + Timezone = "timezone" + Resolution = "resolution" + Video = "video" + Composite = "composite" + Domain = "domain" + DomainPassword = "domain_pw" + Audio = "audio" + Clock = "clock" + +def get_cmdline_parameter(paramname): + cmdLine = "/proc/cmdline" + for param in readFile(cmdLine).split(" "): + parname, op, value = param.partition("=") + if parname == paramname: + return value + return None + +def get_calculate_cmdline(): + names = ( + CmdlineParams.Locale, + CmdlineParams.Keymap, + CmdlineParams.Timezone, + CmdlineParams.Resolution, + CmdlineParams.Video, + CmdlineParams.Composite, + CmdlineParams.Domain, + CmdlineParams.DomainPassword, + CmdlineParams.Audio, + CmdlineParams.Clock) + # try get timezone from kernel calculate param + params = {x:"" for x in names} + try: + value = get_cmdline_parameter(CmdlineParams.Calculate) + if value is not None: + for cparam in (x for x in value.split(',') if x): + k, v = cparam.partition(':')[0::2] + if k and v and k in names: + params[k.strip()] = v.strip() + except (IOError, ValueError, IndexError): + pass + return params + +def get_isoscan_filename(): + value = get_cmdline_parameter(CmdlineParams.IsoscanFile) + if value is not None: + return value + return "" + +def get_isoscan_fullpath(base_path, filename): + if filename: + return os.path.join(base_path.value, filename.value.lstrip("/")) + return "" + +with Namespace('cmdline'): + Variable("calculate", type=HashType.fixed, + source=Calculate(get_calculate_cmdline)) + Variable("isoscan_filename", type=StringType, + source=Calculate(get_isoscan_filename)) + +with Namespace('isoscan'): + Variable("base_path", type=StringType, + source="/run/initramfs/isoscan") + Variable("full_path", type=StringType, + source=Calculate(get_isoscan_fullpath, + '.base_path', 'main.cl.cmdline.isoscan_filename' + )) diff --git a/calculate/vars/main/os/x11/__init__.py b/calculate/vars/main/os/x11/__init__.py new file mode 100644 index 0000000..d42d9a8 --- /dev/null +++ b/calculate/vars/main/os/x11/__init__.py @@ -0,0 +1,35 @@ + +import os +from calculate.utils.fs import readFile +from calculate.variables.datavars import Variable, Namespace, Dependence, \ + StringType, BooleanType, Calculate +from calculate.utils.files import Process, FilesError +import re + +def get_resolution_by_xdpyinfo(): + """ + Get resolution by xdpyinfo utility + """ + try: + processXDpy = Process('xdpyinfo') + if processXDpy.failed(): + return "" + except (FilesError, OSError): + return "" + reRes = re.compile(r"dimensions:\s+(\d+)x(\d+)\s+pixels") + for line in processXDpy.read_lines(): + searchRes = reRes.search(line) + if searchRes: + return "%sx%s" % (searchRes.group(1), searchRes.group(2)) + return "" + +def get_resolution_by_xorg(): + pass + +def get_standart_resolution(): + # TODO: заглушка + return "1024x768" + +with Namespace('resolution'): + Variable("standard", type=StringType, + source=Calculate(get_standart_resolution)) diff --git a/pytest.ini b/pytest.ini index 67bda3a..4d95a07 100644 --- a/pytest.ini +++ b/pytest.ini @@ -35,6 +35,7 @@ markers = parameters_processor: marker for running test for TemplateParameters. vars: marker for testing of the datavars module. + calculate_vars: marker for testing of calculate variables. parameters: marker for testing of the parameters module. scripts: marker for testing of the scripts. diff --git a/requirements.txt b/requirements.txt index 74205a6..b8a382c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ pytest jinja2 xattr lxml +mock diff --git a/tests/vars/test_vars.py b/tests/vars/test_vars.py new file mode 100644 index 0000000..348431f --- /dev/null +++ b/tests/vars/test_vars.py @@ -0,0 +1,92 @@ +import pytest +import calculate.vars.main.os.x11 as main_os_x11 +import calculate.vars.main.cl as main_cl +from calculate.vars.main.cl import CmdlineParams +import mock +from itertools import chain + +@pytest.mark.parametrize('case', + [ + { + "name": "failed xdpyinfo", + "failed": True, + "data": "", + "result": "" + }, + { + "name": "worked xdpyinfo", + "failed": False, + "data": open('tests/vars/xdpyinfo.output','r').read(), + "result": "1920x1080" + }, + { + "name": "xdpyinfo not dimenstions info", + "failed": False, + "data": "some trash\ninfo", + "result": "" + }, + ], + ids=lambda x:x["name"]) +@pytest.mark.calculate_vars +def test_main_os_x11_resolution(case): + with mock.patch('calculate.vars.main.os.x11.Process.failed') as failed: + with mock.patch('calculate.vars.main.os.x11.Process.read_lines') as read_lines: + failed.return_value = case["failed"] + read_lines.return_value = case["data"].split("\n") + assert main_os_x11.get_resolution_by_xdpyinfo() == case["result"] + +empty_calculate_cmdhash = { + CmdlineParams.Locale: "", + CmdlineParams.Keymap: "", + CmdlineParams.Timezone: "", + CmdlineParams.Resolution: "", + CmdlineParams.Video: "", + CmdlineParams.Composite: "", + CmdlineParams.Domain: "", + CmdlineParams.DomainPassword: "", + CmdlineParams.Audio: "", + CmdlineParams.Clock: "" +} + +def concat_dict(d1, **d2): + return {x:y for x,y in chain(d1.items(),d2.items())} + +@pytest.mark.parametrize('case', + [ + { + "name": "empty cmdline", + "data": "", + "result": empty_calculate_cmdhash, + }, + { + "name": "cmd has not calculate param", + "data": "BOOT_IMAGE=(loop)/boot/vmlinuz root=live iso-scan/filename=/linux/cld-20201120-x86_64.iso quiet verbose docache", + "result": empty_calculate_cmdhash, + }, + { + "name": "cmd has wrong calculate param", + "data": "BOOT_IMAGE=(loop)/boot/vmlinuz root=live iso-scan/filename=/linux/cld-20201120-x86_64.iso quiet verbose calculate=testingvalue docache", + "result": empty_calculate_cmdhash, + }, + { + "name": "cmd has wrong calculate param name", + "data": "BOOT_IMAGE=(loop)/boot/vmlinuz root=live iso-scan/filename=/linux/cld-20201120-x86_64.iso quiet verbose calculate=testing:value docache", + "result": empty_calculate_cmdhash, + }, + { + "name": "cmd has only video", + "data": "BOOT_IMAGE=(loop)/boot/vmlinuz root=live iso-scan/filename=/linux/cld-20201120-x86_64.iso quiet verbose calculate=video:nvidia docache", + "result": concat_dict(empty_calculate_cmdhash, video="nvidia") + }, + { + "name": "cmd has only video and resolution", + "data": "BOOT_IMAGE=(loop)/boot/vmlinuz root=live iso-scan/filename=/linux/cld-20201120-x86_64.iso quiet verbose calculate=video:nvidia,resolution:1920x1080 docache", + "result": concat_dict(empty_calculate_cmdhash, video="nvidia", resolution="1920x1080") + }, + ], + ids=lambda x:x["name"]) +@pytest.mark.calculate_vars +def test_main_cl_cmdline(case): + with mock.patch('calculate.vars.main.cl.readFile') as readFile: + readFile.return_value = case["data"] + assert main_cl.get_calculate_cmdline() == case["result"] diff --git a/tests/vars/xdpyinfo.output b/tests/vars/xdpyinfo.output new file mode 100644 index 0000000..1e44d55 --- /dev/null +++ b/tests/vars/xdpyinfo.output @@ -0,0 +1,68 @@ +name of display: :0 +version number: 11.0 +vendor string: The X.Org Foundation +vendor release number: 12007000 +X.Org version: 1.20.7 +maximum request size: 16777212 bytes +motion buffer size: 256 +bitmap unit, bit order, padding: 32, LSBFirst, 32 +image byte order: LSBFirst +number of supported pixmap formats: 7 +supported pixmap formats: + depth 1, bits_per_pixel 1, scanline_pad 32 + depth 4, bits_per_pixel 8, scanline_pad 32 + depth 8, bits_per_pixel 8, scanline_pad 32 + depth 15, bits_per_pixel 16, scanline_pad 32 + depth 16, bits_per_pixel 16, scanline_pad 32 + depth 24, bits_per_pixel 32, scanline_pad 32 + depth 32, bits_per_pixel 32, scanline_pad 32 +keycode range: minimum 8, maximum 255 +focus: window 0x8e0001f, revert to Parent +number of extensions: 27 + BIG-REQUESTS + Composite + DAMAGE + DOUBLE-BUFFER + DPMS + DRI2 + DRI3 + GLX + Generic Event Extension + MIT-SCREEN-SAVER + MIT-SHM + Present + RANDR + RECORD + RENDER + SHAPE + SYNC + X-Resource + XC-MISC + XFIXES + XFree86-DGA + XFree86-VidModeExtension + XINERAMA + XInputExtension + XKEYBOARD + XTEST + XVideo +default screen number: 0 +number of screens: 1 + +screen #0: + dimensions: 1920x1080 pixels (508x285 millimeters) + resolution: 96x96 dots per inch + depths (7): 24, 1, 4, 8, 15, 16, 32 + root window id: 0x6bf + depth of root window: 24 planes + number of colormaps: minimum 1, maximum 1 + default colormap: 0x20 + default number of colormap cells: 256 + preallocated pixels: black 0, white 16777215 + options: backing-store WHEN MAPPED, save-unders NO + largest cursor: 128x128 + current input event mask: 0xfa8033 + KeyPressMask KeyReleaseMask EnterWindowMask + LeaveWindowMask ExposureMask StructureNotifyMask + SubstructureNotifyMask SubstructureRedirectMask FocusChangeMask + PropertyChangeMask ColormapChangeMask