From 459d9bfcce481b0da71e9493e644488c83e0e9ba Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Wed, 2 Apr 2014 22:13:46 +0200 Subject: config: add decorator to add_option_* functions This allows us to build an internal list of valid options and print these. --- docs/manpages/gbp-config.sgml | 14 ++++++-- gbp/config.py | 48 +++++++++++++++++++++------- gbp/scripts/buildpackage.py | 29 ++++++++++------- gbp/scripts/clone.py | 14 +++++--- gbp/scripts/config.py | 64 ++++++++++++++++++++++++++++++------- gbp/scripts/create_remote_repo.py | 61 ++++++++++++++++++++--------------- gbp/scripts/dch.py | 35 ++++++++++++++------ gbp/scripts/import_dsc.py | 15 ++++++--- gbp/scripts/import_orig.py | 13 ++++++-- gbp/scripts/pq.py | 13 ++++++-- gbp/scripts/pull.py | 14 ++++++-- tests/18_test_Config.py | 16 +++++++++- tests/19_test_gbp_scripts_config.py | 60 +++++++++++++++++++++++++--------- 13 files changed, 291 insertions(+), 105 deletions(-) diff --git a/docs/manpages/gbp-config.sgml b/docs/manpages/gbp-config.sgml index c07d758..d68ac64 100644 --- a/docs/manpages/gbp-config.sgml +++ b/docs/manpages/gbp-config.sgml @@ -23,7 +23,10 @@ [auto|on|off] - command.option + + command.option + command + @@ -85,7 +88,14 @@ would use: $ gbp config buildpackage.upstream-branch - upstream + buildpackage.upstream-branch=upstream + + Print the values of all of &gbp-buildpackage;s options + + $ gbp config buildpackage + buildpackage.upstream-branch=upstream + buildpackage.debian-branch=master + ... diff --git a/gbp/config.py b/gbp/config.py index 710eddf..fc31076 100644 --- a/gbp/config.py +++ b/gbp/config.py @@ -45,6 +45,27 @@ def check_tristate(option, opt, value): else: return val + +def safe_option(f): + def _decorator(self, *args, **kwargs): + obj = self + option_name = kwargs.get('option_name') + if not option_name and len(args): + option_name = args[0] + + # We're decorating GbpOption not GbpOptionParser + if not hasattr(obj, 'valid_options'): + if not hasattr(obj, 'parser'): + raise ValueError("Can only decorete GbpOptionParser and GbpOptionGroup not %s" % obj) + else: + obj = obj.parser + + if option_name and not option_name.startswith('no-'): + obj.valid_options.append(option_name) + return f(self, *args, **kwargs) + return _decorator + + class GbpOption(Option): TYPES = Option.TYPES + ('path', 'tristate') TYPE_CHECKER = copy(Option.TYPE_CHECKER) @@ -373,6 +394,7 @@ class GbpOptionParser(OptionParser): self.config = {} self.config_files = self.get_config_files() self.parse_config_files() + self.valid_options = [] if self.command.startswith('git-') or self.command.startswith('gbp-'): prog = self.command @@ -426,15 +448,16 @@ class GbpOptionParser(OptionParser): default = self.config[option_name] return default + @safe_option def add_config_file_option(self, option_name, dest, help=None, **kwargs): """ set a option for the command line parser, the default is read from the config file - @param option_name: name of the option - @type option_name: string - @param dest: where to store this option - @type dest: string - @param help: help text - @type help: string + param option_name: name of the option + type option_name: string + param dest: where to store this option + type dest: string + param help: help text + type help: string """ if not help: help = self.help[option_name] @@ -460,15 +483,16 @@ class GbpOptionParser(OptionParser): class GbpOptionGroup(OptionGroup): + @safe_option def add_config_file_option(self, option_name, dest, help=None, **kwargs): """ set a option for the command line parser, the default is read from the config file - @param option_name: name of the option - @type option_name: string - @param dest: where to store this option - @type dest: string - @param help: help text - @type help: string + param option_name: name of the option + type option_name: string + param dest: where to store this option + type dest: string + param help: help text + type help: string """ if not help: help = self.parser.help[option_name] diff --git a/gbp/scripts/buildpackage.py b/gbp/scripts/buildpackage.py index 753ad64..c077b9e 100755 --- a/gbp/scripts/buildpackage.py +++ b/gbp/scripts/buildpackage.py @@ -365,20 +365,12 @@ def changes_file_suffix(dpkg_args): return os.getenv('ARCH', None) or du.get_arch() -def parse_args(argv, prefix): - args = [ arg for arg in argv[1:] if arg.find('--%s' % prefix) == 0 ] - dpkg_args = [ arg for arg in argv[1:] if arg.find('--%s' % prefix) == -1 ] - - # We handle these although they don't have a --git- prefix - for arg in [ "--help", "-h", "--version" ]: - if arg in dpkg_args: - args.append(arg) - +def build_parser(name, prefix=None): try: - parser = GbpOptionParserDebian(command=os.path.basename(argv[0]), prefix=prefix) + parser = GbpOptionParserDebian(command=os.path.basename(name), prefix=prefix) except ConfigParser.ParsingError as err: gbp.log.err(err) - return None, None, None + return None tag_group = GbpOptionGroup(parser, "tag options", "options related to git tag creation") branch_group = GbpOptionGroup(parser, "branch options", "branch layout options") @@ -453,6 +445,21 @@ def parse_args(argv, prefix): export_group.add_option("--git-dont-purge", action="store_true", dest="dont_purge", default=False, help="deprecated, use --git-no-purge instead") export_group.add_boolean_config_file_option(option_name="overlay", dest="overlay") + return parser + + +def parse_args(argv, prefix): + args = [ arg for arg in argv[1:] if arg.find('--%s' % prefix) == 0 ] + dpkg_args = [ arg for arg in argv[1:] if arg.find('--%s' % prefix) == -1 ] + + # We handle these although they don't have a --git- prefix + for arg in [ "--help", "-h", "--version" ]: + if arg in dpkg_args: + args.append(arg) + + parser = build_parser(argv[0], prefix=prefix) + if not parser: + return None, None, None options, args = parser.parse_args(args) gbp.log.setup(options.color, options.verbose, options.color_scheme) diff --git a/gbp/scripts/clone.py b/gbp/scripts/clone.py index 251cef2..62d0dcc 100755 --- a/gbp/scripts/clone.py +++ b/gbp/scripts/clone.py @@ -29,13 +29,13 @@ from gbp.errors import GbpError import gbp.log -def parse_args (argv): +def build_parser(name): try: - parser = GbpOptionParser(command=os.path.basename(argv[0]), prefix='', + parser = GbpOptionParser(command=os.path.basename(name), prefix='', usage='%prog [options] repository - clone a remote repository') except ConfigParser.ParsingError as err: gbp.log.err(err) - return None, None + return None branch_group = GbpOptionGroup(parser, "branch options", "branch tracking and layout options") parser.add_option_group(branch_group) @@ -53,10 +53,16 @@ def parse_args (argv): parser.add_config_file_option(option_name="color", dest="color", type='tristate') parser.add_config_file_option(option_name="color-scheme", dest="color_scheme") + return parser + + +def parse_args (argv): + parser = build_parser(argv[0]) + if not parser: + return None, None (options, args) = parser.parse_args(argv) gbp.log.setup(options.color, options.verbose, options.color_scheme) - return (options, args) diff --git a/gbp/scripts/config.py b/gbp/scripts/config.py index 19966fe..0ebca13 100755 --- a/gbp/scripts/config.py +++ b/gbp/scripts/config.py @@ -22,49 +22,88 @@ import sys import os, os.path from gbp.config import (GbpOptionParser, GbpOptionGroup) from gbp.errors import GbpError +from gbp.scripts.supercommand import import_command import gbp.log -def parse_args(argv): + +def build_parser(name): try: - parser = GbpOptionParser(command=os.path.basename(argv[0]), prefix='', + parser = GbpOptionParser(command=os.path.basename(name), prefix='', usage='%prog [options] - display configuration settings') except ConfigParser.ParsingError as err: gbp.log.err(err) - return None, None + return None parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="verbose command execution") parser.add_config_file_option(option_name="color", dest="color", type='tristate') parser.add_config_file_option(option_name="color-scheme", dest="color_scheme") + return parser + + +def parse_args(argv): + parser = build_parser(argv[0]) + if not parser: + return None, None return parser.parse_args(argv) -def parse_config(command): +def parse_cmd_config(command): + """Make a command parse it's config files""" parser = GbpOptionParser(command) parser.parse_config_files() return parser -def print_single_value(query, printer): +def print_cmd_single_value(query, printer): + """Print a single configuration value of a command + + @param query: the cmd to print the value for + @param printer: the printer to output the value + """ try: cmd, option = query.split('.') except ValueError: return 2 - parser = parse_config(cmd) + parser = parse_cmd_config(cmd) value = parser.get_config_file_value(option) - printer(value) + printer("%s=%s" % (query, value)) return 0 if value else 1 -def single_value_printer(value): +def print_cmd_all_values(cmd, printer): + """ + Print all configuration values of a command + + @param cmd: the cmd to print the values for + @param printer: the printer to output the values + """ + if not cmd: + return 2 + try: + # Populae the parset to get a list of + # valid options + module = import_command(cmd) + parser = module.build_parser(cmd) + except (AttributeError, ImportError): + return 2 + + for option in parser.valid_options: + value = parser.get_config_file_value(option) + if value != '': + printer("%s.%s=%s" % (cmd, option, value)) + return 0 + + +def value_printer(value): if (value): print(value) def main(argv): - retval = 0 + retval = 1 (options, args) = parse_args(argv) gbp.log.setup(options.color, options.verbose, options.color_scheme) @@ -73,12 +112,15 @@ def main(argv): gbp.log.error("No command given") return 2 elif len(args) != 2: - gbp.log.error("Can only print a single value") + gbp.log.error("Can only take a single argument") return 2 else: query = args[1] - retval = print_single_value(query, single_value_printer) + if '.' in query: + retval = print_cmd_single_value(query, value_printer) + else: + retval = print_cmd_all_values(query, value_printer) return retval if __name__ == '__main__': diff --git a/gbp/scripts/create_remote_repo.py b/gbp/scripts/create_remote_repo.py index c8c4a36..f0e680b 100644 --- a/gbp/scripts/create_remote_repo.py +++ b/gbp/scripts/create_remote_repo.py @@ -18,6 +18,7 @@ # Based on the aa-create-git-repo and dom-new-git-repo shell scripts """Create a remote repo based on the current one""" +import ConfigParser import sys import os, os.path import urlparse @@ -225,30 +226,16 @@ def push_branches(remote, branches): gitPush([remote['url'], '--tags']) -def parse_args(argv, sections=[]): - """ - Parse the command line arguments and config files. - - @param argv: the command line arguments - @type argv: C{list} of C{str} - @param sections: additional sections to add to the config file parser - besides the command name - @type sections: C{list} of C{str} - """ - - # We simpley handle the template section as an additional config file - # section to parse, this makes e.g. --help work as expected: - for arg in argv: - if arg.startswith('--remote-config='): - sections = ['remote-config %s' % arg.split('=',1)[1]] - break - else: - sections = [] +def build_parser(name, sections=[]): + try: + parser = GbpOptionParserDebian(command=os.path.basename(name), prefix='', + usage='%prog [options] - ' + 'create a remote repository', + sections=sections) + except ConfigParser.ParsingError as err: + gbp.log.err(err) + return None - parser = GbpOptionParserDebian(command=os.path.basename(argv[0]), prefix='', - usage='%prog [options] - ' - 'create a remote repository', - sections=sections) branch_group = GbpOptionGroup(parser, "branch options", "branch layout and tracking options") @@ -281,10 +268,34 @@ def parse_args(argv, sections=[]): dest="template_dir") parser.add_config_file_option(option_name="remote-config", dest="remote_config") + return parser + + +def parse_args(argv, sections=[]): + """ + Parse the command line arguments and config files. + + @param argv: the command line arguments + @type argv: C{list} of C{str} + @param sections: additional sections to add to the config file parser + besides the command name + @type sections: C{list} of C{str} + """ + + # We simpley handle the template section as an additional config file + # section to parse, this makes e.g. --help work as expected: + for arg in argv: + if arg.startswith('--remote-config='): + sections = ['remote-config %s' % arg.split('=',1)[1]] + break + else: + sections = [] - (options, args) = parser.parse_args(argv) + parser = build_parser(argv[0], sections) + if not parser: + return None, None - return options, args + return parser.parse_args(argv) def main(argv): diff --git a/gbp/scripts/dch.py b/gbp/scripts/dch.py index a848d6d..f36f287 100644 --- a/gbp/scripts/dch.py +++ b/gbp/scripts/dch.py @@ -283,20 +283,14 @@ def changelog_commit_msg(options, version): return options.commit_msg % dict(version=version) -def main(argv): - ret = 0 - changelog = 'debian/changelog' - until = 'HEAD' - found_snapshot_banner = False - version_change = {} - branch = None - +def build_parser(name): try: - parser = GbpOptionParserDebian(command=os.path.basename(argv[0]), prefix='', + parser = GbpOptionParserDebian(command=os.path.basename(name), usage='%prog [options] paths') except ConfigParser.ParsingError as err: gbp.log.err(err) - return 1 + return None + range_group = GbpOptionGroup(parser, "commit range options", "which commits to add to the changelog") version_group = GbpOptionGroup(parser, "release & version number options", @@ -374,10 +368,31 @@ def main(argv): dest="customization_file", help=help_msg) + + return parser + + +def parse_args(argv): + parser = build_parser(argv[0]) + if not parser: + return None, None + (options, args) = parser.parse_args(argv[1:]) gbp.log.setup(options.color, options.verbose, options.color_scheme) dch_options = process_options(options, parser) editor_cmd = process_editor_option(options) + return options, args, dch_options, editor_cmd + +def main(argv): + ret = 0 + changelog = 'debian/changelog' + until = 'HEAD' + found_snapshot_banner = False + version_change = {} + branch = None + + + options, args, dch_options, editor_cmd = parse_args(argv) try: try: diff --git a/gbp/scripts/import_dsc.py b/gbp/scripts/import_dsc.py index 630422b..600b394 100644 --- a/gbp/scripts/import_dsc.py +++ b/gbp/scripts/import_dsc.py @@ -204,14 +204,13 @@ def set_bare_repo_options(options): % (["", " '--no-pristine-tar'"][options.pristine_tar], )) options.pristine_tar = False - -def parse_args(argv): +def build_parser(name): try: - parser = GbpOptionParserDebian(command=os.path.basename(argv[0]), prefix='', + parser = GbpOptionParserDebian(command=os.path.basename(name), prefix='', usage='%prog [options] /path/to/package.dsc') except ConfigParser.ParsingError as err: gbp.log.err(err) - return None, None + return None import_group = GbpOptionGroup(parser, "import options", "pristine-tar and filtering") @@ -263,9 +262,15 @@ def parse_args(argv): dest="author_committer_date") import_group.add_boolean_config_file_option(option_name="allow-unauthenticated", dest="allow_unauthenticated") + return parser + + +def parse_args(argv): + parser = build_parser(argv[0]) + if not parser: + return None, None (options, args) = parser.parse_args(argv[1:]) - gbp.log.setup(options.color, options.verbose) gbp.log.setup(options.color, options.verbose, options.color_scheme) return options, args diff --git a/gbp/scripts/import_orig.py b/gbp/scripts/import_orig.py index aae93fa..542896e 100644 --- a/gbp/scripts/import_orig.py +++ b/gbp/scripts/import_orig.py @@ -181,13 +181,13 @@ def set_bare_repo_options(options): options.merge = False -def parse_args(argv): +def build_parser(name): try: - parser = GbpOptionParserDebian(command=os.path.basename(argv[0]), prefix='', + parser = GbpOptionParserDebian(command=os.path.basename(name), prefix='', usage='%prog [options] /path/to/upstream-version.tar.gz | --uscan') except ConfigParser.ParsingError as err: gbp.log.err(err) - return None, None + return None import_group = GbpOptionGroup(parser, "import options", "pristine-tar and filtering") @@ -241,6 +241,13 @@ def parse_args(argv): default=False, help="deprecated - don't use.") parser.add_option("--uscan", dest='uscan', action="store_true", default=False, help="use uscan(1) to download the new tarball.") + return parser + + +def parse_args(argv): + parser = build_parser(argv[0]) + if not parser: + return None, None (options, args) = parser.parse_args(argv[1:]) gbp.log.setup(options.color, options.verbose, options.color_scheme) diff --git a/gbp/scripts/pq.py b/gbp/scripts/pq.py index 41d3ddf..fc205bf 100755 --- a/gbp/scripts/pq.py +++ b/gbp/scripts/pq.py @@ -210,9 +210,9 @@ def switch_pq(repo, current): switch_to_pq_branch(repo, current) -def parse_args(argv): +def build_parser(name): try: - parser = GbpOptionParserDebian(command=os.path.basename(argv[0]), prefix='', + parser = GbpOptionParserDebian(command=os.path.basename(name), usage="%prog [options] action - maintain patches on a patch queue branch\n" "Actions:\n" " export export the patch queue associated to the current branch\n" @@ -226,7 +226,7 @@ def parse_args(argv): " switch switch to patch-queue branch and vice versa") except ConfigParser.ParsingError as err: gbp.log.err(err) - return None, None + return None parser.add_boolean_config_file_option(option_name="patch-numbers", dest="patch_numbers") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, @@ -238,6 +238,13 @@ def parse_args(argv): parser.add_config_file_option(option_name="color", dest="color", type='tristate') parser.add_config_file_option(option_name="color-scheme", dest="color_scheme") + return parser + + +def parse_args(argv): + parser = build_parser(argv[0]) + if not parser: + return None, None return parser.parse_args(argv) diff --git a/gbp/scripts/pull.py b/gbp/scripts/pull.py index 03be9fc..fb0d827 100755 --- a/gbp/scripts/pull.py +++ b/gbp/scripts/pull.py @@ -68,13 +68,14 @@ def fast_forward_branch(branch, repo, options): msg="gbp: forward %s to %s" % (branch, remote)) return update -def parse_args(argv): + +def build_parser(name): try: - parser = GbpOptionParser(command=os.path.basename(argv[0]), prefix='', + parser = GbpOptionParser(command=os.path.basename(name), prefix='', usage='%prog [options] - safely update a repository from remote') except ConfigParser.ParsingError as err: gbp.log.err(err) - return None, None + return None branch_group = GbpOptionGroup(parser, "branch options", "branch update and layout options") parser.add_option_group(branch_group) @@ -93,6 +94,13 @@ def parse_args(argv): parser.add_config_file_option(option_name="color", dest="color", type='tristate') parser.add_config_file_option(option_name="color-scheme", dest="color_scheme") + return parser + + +def parse_args(argv): + parser = build_parser(argv[0]) + if not parser: + return None, None return parser.parse_args(argv) diff --git a/tests/18_test_Config.py b/tests/18_test_Config.py index ae39b5a..f7ba8c9 100644 --- a/tests/18_test_Config.py +++ b/tests/18_test_Config.py @@ -2,7 +2,7 @@ import os import unittest -from gbp.config import GbpOptionParser +from gbp.config import GbpOptionParser, GbpOptionGroup from . import context class TestConfigParser(unittest.TestCase): @@ -71,3 +71,17 @@ class TestConfigParser(unittest.TestCase): self.assertEqual(parser.get_config_file_value('new_overrides_git_option1'), 'new_overrides_git_value1') self.assertEqual(parser.get_config_file_value('doesnotexist'), None) + + def test_param_list(self): + parser = GbpOptionParser('cmd4') + + branch_group = GbpOptionGroup(parser, "branch options", "branch update and layout options") + parser.add_option_group(branch_group) + branch_group.add_config_file_option(option_name="upstream-branch", dest="upstream_branch") + branch_group.add_config_file_option("debian-branch", dest="upstream_branch") + parser.add_config_file_option(option_name="color", dest="color", type='tristate') + + params = parser.valid_options + self.assertTrue('upstream-branch' in params) + self.assertTrue('debian-branch' in params) + self.assertTrue('color' in params) diff --git a/tests/19_test_gbp_scripts_config.py b/tests/19_test_gbp_scripts_config.py index 1c3369b..f503ef5 100644 --- a/tests/19_test_gbp_scripts_config.py +++ b/tests/19_test_gbp_scripts_config.py @@ -21,6 +21,21 @@ import unittest import gbp.scripts.config class TestGbpConfigCommand(unittest.TestCase): + class SingleValuePrintStub(object): + def __init__(self): + self.result = None + + def __call__(self, arg): + self.result = arg + + class AllValuesPrintStub(object): + def __init__(self, cmd): + self.cmd = cmd + self.result = {} + + def __call__(self, arg): + k, v = arg.split('=', 1) + self.result[k] = v def setUp(self): self.conffiles_save = os.environ.get('GBP_CONF_FILES') @@ -29,28 +44,43 @@ class TestGbpConfigCommand(unittest.TestCase): os.environ['GBP_CONF_FILES'] = self.confname def test_invocation_single_value(self): - """Test if we an invoke it without error""" + """Can invoke it for a sngle value without error""" ret = gbp.scripts.config.main(['doesnotmatter', 'coolcommand.branchname']) self.assertEqual(ret, 0) def test_invocation_missing_value(self): - """Test if we an invoke it without error""" + """Can we detect a missing value""" ret = gbp.scripts.config.main(['doesnotmatter', 'coolcommand.doesnotexist']) self.assertEqual(ret, 1) - def test_invocation_parse_error(self): - """Test if we an invoke it without error""" - ret = gbp.scripts.config.main(['doesnotmatter', 'mustcontaindot']) - self.assertEqual(ret, 2) + def test_print_cmd_single_value(self): + """Can we fetch a single configuration value""" + printstub = self.SingleValuePrintStub() + query = 'coolcommand.branchname' + ret = gbp.scripts.config.print_cmd_single_value(query, printstub) + self.assertEqual(printstub.result, '%s=abranch' % query) + self.assertEqual(ret, 0) - def test_print_single_value(self): - class Printstub(object): - result = None - def __call__(self, arg): - self.result = arg + def test_print_cmd_all_values(self): + """Can we fetch the configuration for all commands""" + for cmd in [ 'buildpackage', + 'clone', + 'config', + 'create_remote_repo', + 'dch', + 'import_dsc', + 'import_orig', + 'pq', + 'pull' ]: + printstub = self.AllValuesPrintStub(cmd) + ret = gbp.scripts.config.print_cmd_all_values(cmd, printstub) + self.assertTrue('%s.color' % cmd in printstub.result.keys()) + self.assertEqual(ret, 0) - printstub = Printstub() - ret = gbp.scripts.config.print_single_value('coolcommand.branchname', printstub) - self.assertEqual(printstub.result, 'abranch') - self.assertEqual(ret, 0) + def test_invalid_cms(self): + """Invalid commands or those not using the config should rerturn an error code""" + for cmd in [ "import_dscs", "supercommand" ]: + printstub = self.AllValuesPrintStub(cmd) + ret = gbp.scripts.config.print_cmd_all_values(cmd, printstub) + self.assertEqual(ret, 2) -- cgit v1.2.3