[enh] support config_panel in TOML format

This commit is contained in:
Laurent Peuch 2019-06-01 01:44:33 +02:00
parent f6f73c23b1
commit 4084bddb54
2 changed files with 131 additions and 10 deletions

1
debian/control vendored
View file

@ -14,6 +14,7 @@ Depends: ${python:Depends}, ${misc:Depends}
, moulinette (>= 2.7.1), ssowat (>= 2.7.1) , moulinette (>= 2.7.1), ssowat (>= 2.7.1)
, python-psutil, python-requests, python-dnspython, python-openssl , python-psutil, python-requests, python-dnspython, python-openssl
, python-apt, python-miniupnpc, python-dbus, python-jinja2 , python-apt, python-miniupnpc, python-dbus, python-jinja2
, python-toml
, glances, apt-transport-https , glances, apt-transport-https
, dnsutils, bind9utils, unzip, git, curl, cron, wget, jq , dnsutils, bind9utils, unzip, git, curl, cron, wget, jq
, ca-certificates, netcat-openbsd, iproute , ca-certificates, netcat-openbsd, iproute

View file

@ -24,6 +24,7 @@
Manage apps Manage apps
""" """
import os import os
import toml
import json import json
import shutil import shutil
import yaml import yaml
@ -680,7 +681,7 @@ def app_upgrade(app=[], url=None, file=None):
os.system('rm -rf "%s/scripts" "%s/manifest.json %s/conf"' % (app_setting_path, app_setting_path, app_setting_path)) os.system('rm -rf "%s/scripts" "%s/manifest.json %s/conf"' % (app_setting_path, app_setting_path, app_setting_path))
os.system('mv "%s/manifest.json" "%s/scripts" %s' % (extracted_app_folder, extracted_app_folder, app_setting_path)) os.system('mv "%s/manifest.json" "%s/scripts" %s' % (extracted_app_folder, extracted_app_folder, app_setting_path))
for file_to_copy in ["actions.json", "config_panel.json", "conf"]: for file_to_copy in ["actions.json", "config_panel.json", "config_panel.toml", "conf"]:
if os.path.exists(os.path.join(extracted_app_folder, file_to_copy)): if os.path.exists(os.path.join(extracted_app_folder, file_to_copy)):
os.system('cp -R %s/%s %s' % (extracted_app_folder, file_to_copy, app_setting_path)) os.system('cp -R %s/%s %s' % (extracted_app_folder, file_to_copy, app_setting_path))
@ -835,7 +836,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
os.system('cp %s/manifest.json %s' % (extracted_app_folder, app_setting_path)) os.system('cp %s/manifest.json %s' % (extracted_app_folder, app_setting_path))
os.system('cp -R %s/scripts %s' % (extracted_app_folder, app_setting_path)) os.system('cp -R %s/scripts %s' % (extracted_app_folder, app_setting_path))
for file_to_copy in ["actions.json", "config_panel.json", "conf"]: for file_to_copy in ["actions.json", "config_panel.json", "config_panel.toml", "conf"]:
if os.path.exists(os.path.join(extracted_app_folder, file_to_copy)): if os.path.exists(os.path.join(extracted_app_folder, file_to_copy)):
os.system('cp -R %s/%s %s' % (extracted_app_folder, file_to_copy, app_setting_path)) os.system('cp -R %s/%s %s' % (extracted_app_folder, file_to_copy, app_setting_path))
@ -1581,12 +1582,12 @@ def app_config_show_panel(app):
# this will take care of checking if the app is installed # this will take care of checking if the app is installed
app_info_dict = app_info(app) app_info_dict = app_info(app)
config_panel = os.path.join(APPS_SETTING_PATH, app, 'config_panel.json') config_panel = _get_app_config_panel(app)
config_script = os.path.join(APPS_SETTING_PATH, app, 'scripts', 'config') config_script = os.path.join(APPS_SETTING_PATH, app, 'scripts', 'config')
app_id, app_instance_nb = _parse_app_instance_name(app) app_id, app_instance_nb = _parse_app_instance_name(app)
if not os.path.exists(config_panel) or not os.path.exists(config_script): if not config_panel or not os.path.exists(config_script):
return { return {
"app_id": app_id, "app_id": app_id,
"app": app, "app": app,
@ -1594,8 +1595,6 @@ def app_config_show_panel(app):
"config_panel": [], "config_panel": [],
} }
config_panel = read_json(config_panel)
env = { env = {
"YNH_APP_ID": app_id, "YNH_APP_ID": app_id,
"YNH_APP_INSTANCE_NAME": app, "YNH_APP_INSTANCE_NAME": app,
@ -1672,15 +1671,13 @@ def app_config_apply(app, args):
if not installed: if not installed:
raise YunohostError('app_not_installed', app=app) raise YunohostError('app_not_installed', app=app)
config_panel = os.path.join(APPS_SETTING_PATH, app, 'config_panel.json') config_panel = _get_app_config_panel(app)
config_script = os.path.join(APPS_SETTING_PATH, app, 'scripts', 'config') config_script = os.path.join(APPS_SETTING_PATH, app, 'scripts', 'config')
if not os.path.exists(config_panel) or not os.path.exists(config_script): if not config_panel or not os.path.exists(config_script):
# XXX real exception # XXX real exception
raise Exception("Not config-panel.json nor scripts/config") raise Exception("Not config-panel.json nor scripts/config")
config_panel = read_json(config_panel)
app_id, app_instance_nb = _parse_app_instance_name(app) app_id, app_instance_nb = _parse_app_instance_name(app)
env = { env = {
"YNH_APP_ID": app_id, "YNH_APP_ID": app_id,
@ -1719,6 +1716,129 @@ def app_config_apply(app, args):
logger.success("Config updated as expected") logger.success("Config updated as expected")
def _get_app_config_panel(app_id):
"Get app config panel stored in json or in toml"
config_panel_toml_path = os.path.join(APPS_SETTING_PATH, app_id, 'config_panel.toml')
config_panel_json_path = os.path.join(APPS_SETTING_PATH, app_id, 'config_panel.json')
# sample data to get an idea of what is going on
# this toml extract:
#
# version = "0.1"
# name = "Unattended-upgrades configuration panel"
#
# [main]
# name = "Unattended-upgrades configuration"
#
# [main.unattended_configuration]
# name = "50unattended-upgrades configuration file"
#
# [main.unattended_configuration.upgrade_level]
# name = "Choose the sources of packages to automatically upgrade."
# default = "Security only"
# type = "text"
# help = "We can't use a choices field for now. In the meantime please choose between one of this values:<br>Security only, Security and updates."
# # choices = ["Security only", "Security and updates"]
# [main.unattended_configuration.ynh_update]
# name = "Would you like to update YunoHost packages automatically ?"
# type = "bool"
# default = true
#
# will be parsed into this:
#
# OrderedDict([(u'version', u'0.1'),
# (u'name', u'Unattended-upgrades configuration panel'),
# (u'main',
# OrderedDict([(u'name', u'Unattended-upgrades configuration'),
# (u'unattended_configuration',
# OrderedDict([(u'name',
# u'50unattended-upgrades configuration file'),
# (u'upgrade_level',
# OrderedDict([(u'name',
# u'Choose the sources of packages to automatically upgrade.'),
# (u'default',
# u'Security only'),
# (u'type', u'text'),
# (u'help',
# u"We can't use a choices field for now. In the meantime please choose between one of this values:<br>Security only, Security and updates.")])),
# (u'ynh_update',
# OrderedDict([(u'name',
# u'Would you like to update YunoHost packages automatically ?'),
# (u'type', u'bool'),
# (u'default', True)])),
#
# and needs to be converted into this:
#
# {u'name': u'Unattended-upgrades configuration panel',
# u'panel': [{u'id': u'main',
# u'name': u'Unattended-upgrades configuration',
# u'sections': [{u'id': u'unattended_configuration',
# u'name': u'50unattended-upgrades configuration file',
# u'options': [{u'//': u'"choices" : ["Security only", "Security and updates"]',
# u'default': u'Security only',
# u'help': u"We can't use a choices field for now. In the meantime please choose between one of this values:<br>Security only, Security and updates.",
# u'id': u'upgrade_level',
# u'name': u'Choose the sources of packages to automatically upgrade.',
# u'type': u'text'},
# {u'default': True,
# u'id': u'ynh_update',
# u'name': u'Would you like to update YunoHost packages automatically ?',
# u'type': u'bool'},
if os.path.exists(config_panel_toml_path):
toml_config_panel = toml.load(open(config_panel_toml_path, "r"), _dict=OrderedDict)
# transform toml format into json format
config_panel = {
"name": toml_config_panel["name"],
"version": toml_config_panel["version"],
"panel": [],
}
panels = filter(lambda (key, value): key not in ("name", "version")
and isinstance(value, OrderedDict),
toml_config_panel.items())
for key, value in panels:
panel = {
"id": key,
"name": value["name"],
"sections": [],
}
sections = filter(lambda (k, v): k not in ("name",)
and isinstance(v, OrderedDict),
value.items())
for section_key, section_value in sections:
section = {
"id": section_key,
"name": section_value["name"],
"options": [],
}
options = filter(lambda (k, v): k not in ("name",)
and isinstance(v, OrderedDict),
section_value.items())
for option_key, option_value in options:
option = dict(option_value)
option["id"] = option_key
section["options"].append(option)
panel["sections"].append(section)
config_panel["panel"].append(panel)
return config_panel
elif os.path.exists(config_panel_json_path):
return json.load(open(config_panel_json_path))
return None
def _get_app_settings(app_id): def _get_app_settings(app_id):
""" """
Get settings of an installed app Get settings of an installed app