diff --git a/dak/admin.py b/dak/admin.py index eecb3e91f79fabe7d5be681d110291ec378c7bbc..e2725dd8cbbeda431bfb457a8ff76d967d9f1d99 100755 --- a/dak/admin.py +++ b/dak/admin.py @@ -131,6 +131,14 @@ Perform administrative work on the dak database. s-c rm SUITE COMPONENT remove component from suite (will only work if no packages remain for the component in the suite) + suite-config / s-cfg: + s-cfg list show the names of the configurations + s-cfg list SUITE show the configuration values for SUITE + s-cfg get SUITE NAME ... + show the value for NAME in SUITE + s-cfg set SUITE NAME=VALUE ... + set NAME to VALUE in SUITE + archive: archive list list all archives archive add NAME ROOT DESCRIPTION [primary-mirror=MIRROR] [tainted=1] @@ -719,6 +727,127 @@ def suite_component(command): dispatch['suite-component'] = suite_component dispatch['s-c'] = suite_component + +################################################################################ + +# Sentinal for detecting read-only configurations +SUITE_CONFIG_READ_ONLY = object() + +ALLOWED_SUITE_CONFIGS = { + 'accept_binary_uploads': utils.parse_boolean_from_user, + 'accept_source_uploads': utils.parse_boolean_from_user, + 'allowcsset': utils.parse_boolean_from_user, + 'announce': SUITE_CONFIG_READ_ONLY, + 'butautomaticupgrades': utils.parse_boolean_from_user, + 'byhash': utils.parse_boolean_from_user, + 'changelog': str, + 'changelog_url': str, + # TODO: Create a validator/parser for this + 'checksums': SUITE_CONFIG_READ_ONLY, + 'description': str, + 'include_long_description': utils.parse_boolean_from_user, + 'indices_compression': SUITE_CONFIG_READ_ONLY, + 'label': str, + 'mail_whitelist': str, + 'notautomatic': utils.parse_boolean_from_user, + 'origin': str, + 'priority': int, + 'signingkeys': SUITE_CONFIG_READ_ONLY, + 'untouchable': utils.parse_boolean_from_user, + 'validtime': int, +} + + +def __suite_config_get(d, args): + die_arglen(args, 4, "E: suite-config get needs the name of a configuration") + session = d.session() + suite_name = args[2] + suite = get_suite(suite_name, session) + for arg in args[3:]: + if arg not in ALLOWED_SUITE_CONFIGS: + die("Unknown (or unsupported) suite configuration variable") + value = getattr(suite, arg) + print("%s=%s" % (arg, value)) + + +def __suite_config_set(d, args): + die_arglen(args, 4, "E: suite-config set needs the name of a configuration") + session = d.session() + suite_name = args[2] + suite = get_suite(suite_name, session) + for arg in args[3:]: + if '=' not in arg: + die("Missing value for configuration %s: Use key=value format" % arg) + conf_name, new_value_str = arg.split('=', 1) + converter = ALLOWED_SUITE_CONFIGS.get(conf_name) + if converter is None: + die("Unknown (or unsupported) suite configuration variable") + if converter is SUITE_CONFIG_READ_ONLY: + die("Cannot change %s from the command line" % arg) + try: + new_value = converter(new_value_str) + except RuntimeError as e: + warn("Could not convert value %s for %s" % (conf_name, new_value_str)) + raise e + setattr(suite, conf_name, new_value) + print("%s=%s" % (conf_name, new_value)) + if dryrun: + session.rollback() + print() + print("This was a dryrun; changes have been rolled back") + else: + session.commit() + + +def __suite_config_list(d, args): + suite = None + session = d.session() + if len(args) > 3: + warn("W: Ignoring extra argument after the suite name") + if len(args) == 3: + suite_name = args[2] + suite = get_suite(suite_name, session) + else: + print("Valid suite-config options managable by this command:") + print() + + for arg in sorted(ALLOWED_SUITE_CONFIGS): + mode = 'writable' + if ALLOWED_SUITE_CONFIGS[arg] is SUITE_CONFIG_READ_ONLY: + mode = 'read-ony' + if suite is not None: + value = getattr(suite, arg) + print("%s=%s" % (arg, value)) + else: + print(" * %s (%s)" % (arg, mode)) + + +def suite_config(command): + args = [str(x) for x in command] + Cnf = utils.get_conf() + d = DBConn() + + die_arglen(args, 2, "E: suite-config needs a command") + mode = args[1].lower() + + if mode == 'get': + __suite_config_get(d, args) + elif mode == 'set': + __suite_config_set(d, args) + elif mode == 'list': + __suite_config_list(d, args) + else: + suite = get_suite(mode, d.session()) + if suite is not None: + warn("Did you get the order of the suite and the subcommand wrong?") + warn("Syntax: dak admin %s {get,set,...} " % args[0]) + die("E: suite-config command unknown") + + +dispatch['suite-config'] = suite_config +dispatch['s-cfg'] = suite_config + + ################################################################################ diff --git a/daklib/utils.py b/daklib/utils.py index 7c40ba47d58a48d4061d623543bdd785c2064ae1..74705ac045ba66400cd90a14396b9a25c70cc45e 100644 --- a/daklib/utils.py +++ b/daklib/utils.py @@ -1434,3 +1434,14 @@ def find_possibly_compressed_file(filename): return _file raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), filename) + +################################################################################ + + +def parse_boolean_from_user(value): + value = value.lower() + if value in {'yes', 'true', 'enable', 'enabled'}: + return True + if value in {'no', 'false', 'disable', 'disabled'}: + return False + raise ValueError("Not sure whether %s should be a True or a False" % value) diff --git a/integration-tests/tests/0003-dak-admin-suite-config b/integration-tests/tests/0003-dak-admin-suite-config new file mode 100755 index 0000000000000000000000000000000000000000..a329c92ab6d78127a22348aab4d442a93858f37e --- /dev/null +++ b/integration-tests/tests/0003-dak-admin-suite-config @@ -0,0 +1,101 @@ +#! /bin/bash +# +# © 2019 Niels Thykier +# License: GPL-2+ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set -e +set -u + +. ${DAK_ROOT:?}/integration-tests/common +. ${DAK_ROOT:?}/integration-tests/setup + +# add a unstable suite with amd64 +dak admin architecture add amd64 AMD64 + +for suite in testing stable; do + dak admin suite add "${suite}" "" + dak admin suite-architecture add "${suite}" source all amd64 + dak admin suite-component add "${suite}" main contrib non-free +done + +echo "---- testing ----" + +# Play a bit with testing +( + dak admin suite-config set testing allowcsset=yes accept_source_uploads=no \ + accept_binary_uploads=no changelog="dists/testing/ChangeLog" \ + changelog_url="http://metadata.ftp-master.debian.org/changelogs/@CHANGEPATH@_changelog" +) + +# Verify that the values match our changes +( + expected="$(cat <