Verified Commit df1bde02 authored by Karel Koci's avatar Karel Koci 🤘
Browse files

svupdater/lists: add support for labels

Labels are new generic approach to existing official boolean option.
This removes that option and instead introduces flags that can symbol
anything.

This implementation is just extension of existing one so everything is
till returned all at once. Labels can be matched by name between various
pkglists but that has to be done by user. Here info for labels is
duplicated to every occurrence of that label.
parent 4f7dacaf
......@@ -46,6 +46,8 @@ NOTIFY_MESSAGE_EN = "Your approval is required to apply pending updates." + \
L10N_FILE = "/usr/share/updater/l10n_supported"
# File containing list of known pkglists in json
PKGLISTS_FILE = "/usr/share/updater/pkglists.json"
# File containing list of known pkglists's labels in json
PKGLISTS_LABELS_FILE = "/usr/share/updater/pkglists-labels.json"
# Hooks file containing commands to be run after updater execution finished.
POSTRUN_HOOK_FILE = "/var/run/updater-postrun-hook"
# Copyright (c) 2018, CZ.NIC, z.s.p.o. (http://www.nic.cz/)
# Copyright (c) 2018-2020, CZ.NIC, z.s.p.o. (http://www.nic.cz/)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
......@@ -26,68 +26,103 @@ import os
import json
import gettext
import typing
from euci import EUci, UciExceptionNotFound
from .const import PKGLISTS_FILE
from euci import EUci
from .const import PKGLISTS_FILE, PKGLISTS_LABELS_FILE
from .exceptions import UpdaterNoSuchListError, UpdaterNoSuchListOptionError
__PKGLIST_ENTRIES_LABELS = typing.Dict[str, str]
__PKGLIST_ENTRIES_OPTIONS = typing.Dict[str, typing.Union[str, bool, __PKGLIST_ENTRIES_LABELS]]
__PKGLIST_ENTRIES = typing.Dict[
str, typing.Union[
str, bool, typing.Dict[str, typing.Union[str, bool]]
str, bool, __PKGLIST_ENTRIES_OPTIONS, __PKGLIST_ENTRIES_LABELS
]
]
def _load_lists():
if os.path.isfile(PKGLISTS_FILE): # Just to be sure
with open(PKGLISTS_FILE, 'r') as file:
return json.load(file)
else:
def _load_json_dict(file_path):
if not os.path.isfile(file_path):
return {}
with open(file_path, 'r') as file:
return json.load(file)
def __labels(known_labels, trans, labels):
"""Convert list of label names to label dictionaries with all info.
"""
return {
lbl: {
"title": trans.gettext(known_labels[lbl]['title']),
"description": trans.gettext(known_labels[lbl]['description']),
"severity": known_labels[lbl].get('severity', "primary"),
} for lbl in labels if lbl in known_labels.keys()
}
def __options(pkglist_name, trans, uci, known_labels, options):
"""Convert list of options to option dictionaries with all info.
"""
return {
name: {
"enabled": uci.get('pkglists', pkglist_name, name, dtype=bool, default=option.get('default', False)),
"title": trans.gettext(option['title']),
"description": trans.gettext(option['description']),
"url": option.get('url'),
"labels": __labels(known_labels, trans, option.get('labels', {})),
} for name, option in options.items()
}
def pkglists(lang=None) -> typing.Dict[str, __PKGLIST_ENTRIES]:
"""Returns dict of pkglists.
Argument lang is expected to be a string containing language code. This
code is then used for gettext translations of titles and descriptions of
messages.
Argument lang is expected to be a string containing language code. This code is then used for gettext translations
of titles and descriptions of messages.
Return pkglists are in dictionary where key is name of pkglist and value is
another dictionary with following content:
"enabled": This is boolean value containing info if pkglist is enabled.
"hidden": This is boolean value specifying if pkglist is visible.
"official": This is boolean value specifying if pkglist is supported.
"title": This is title text describing pkglist (human readable name).
"description": This is human readable description of given pkglist.
"url": Optional URL to documentation. This can be None if not provided.
"options": Additional package options
Return pkglists are in dictionary where key is name of pkglist and value is another dictionary with following
content:
"enabled": This is boolean value containing info if pkglist is enabled.
"title": This is title text describing pkglist (human readable name).
"description": This is human readable description of given pkglist.
"url": Optional URL to documentation. This can be None if not provided.
"options": Additional package options stored in dictionary where keys are option names and value another
dictionary with content:
"enabled": Boolean value if option is enabled or not.
"title": Human readable name of option.
"description": Human readable description of given pkglist option.
"url": Optional URL to documentation. This can be None if not provided.
"labels": Labels assigned to option. Value is dictionary same as for pkglists labels.
"labels": Labels assigned to pkglist. Value is dictionary with keys being name of labels and values dictionaries
with following content:
"title": Human readable name of label.
"description": Human readable text describing label's meaning.
"severity": String that is one of following values:
* "danger"
* "warning"
* "info"
* "success"
* "primary"
* "secondary"
* "light"
* "dark"
"""
trans = gettext.translation(
'pkglists',
languages=[lang] if lang is not None else None,
fallback=True)
known_lists = _load_lists()
known_lists = _load_json_dict(PKGLISTS_FILE)
known_labels = _load_json_dict(PKGLISTS_LABELS_FILE)
result = {}
with EUci() as uci:
enabled_lists = uci.get('pkglists', 'pkglists', 'pkglist', list=True, default=[])
for name, lst in known_lists.items():
result[name] = {
return {
name: {
"enabled": name in enabled_lists,
"title": trans.gettext(lst['title']),
"description": trans.gettext(lst['description']),
"official": lst.get('official', False),
"url": lst.get('url'),
"hidden": False, # Obsolete option for backward compatibility
"options": {},
}
for opt_name, option in lst.get('options', {}).items():
result[name]['options'][opt_name] = {
"enabled": uci.get('pkglists', name, opt_name,
dtype=bool, default=option.get('default', False)),
"title": trans.gettext(option['title']),
"description": trans.gettext(option['description']),
}
return result
"options": __options(name, trans, uci, known_labels, lst.get('options', {})),
"labels": __labels(known_labels, trans, lst.get('labels', {})),
} for name, lst in known_lists.items()
}
def update_pkglists(lists: typing.Dict[str, typing.Dict[str, bool]]):
......@@ -96,7 +131,7 @@ def update_pkglists(lists: typing.Dict[str, typing.Dict[str, bool]]):
and sub-dictionary with their options.
Anything omitted will be disabled.
"""
known_lists = _load_lists()
known_lists = _load_json_dict(PKGLISTS_FILE)
for name, options in lists.items():
if name not in known_lists:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment