#576 Support for custom completers
Merged 2 years ago by onosek. Opened 2 years ago by drumian.
drumian/rpkg Issue_RHELCMP-89  into  master

file modified
+1 -1
@@ -1,4 +1,4 @@ 

- FROM fedora:33

+ FROM fedora:34

  LABEL \

      name="rpkg test" \

      description="Run tests using tox with Python 3" \

file modified
+57 -12
@@ -30,6 +30,7 @@ 

  from requests.auth import HTTPBasicAuth

  from six.moves import configparser

  

+ import pyrpkg.completers as completers

  import pyrpkg.utils as utils

  from pyrpkg import Modulemd, rpkgError

  
@@ -132,6 +133,11 @@ 

  class cliClient(object):

      """This is a client class for rpkg clients."""

  

+     # Structure contains completer methods. These are set from children

+     # classes in fedpkg/rhpkg before __init__ is run here.

+     # Methods are assigned to specific argument in register_xxx methods.

+     _completers = {}

+ 

      def __init__(self, config, name=None):

          """This requires a ConfigParser object

  
@@ -302,6 +308,31 @@ 

              except ImportError:

                  raise Exception('Unknown site %s' % site)

  

+     @staticmethod

+     def get_completer(name):

+         """Returns one custom completer from the '_completers' structure."""

+         res = cliClient._completers.get(name, None)  # get CustomCompleterWrapper object

+         if res is not None:

+             if res.__class__.__name__ == "CustomCompleterWrapper":

+                 return res.fetch_completer()

+             else:

+                 return res

+ 

+     @staticmethod

+     def set_completer(name, method, *args, **kwargs):

+         """Initializes custom completer and stores it into the '_completers' structure.

+         'name' is a search key in the '_completers' structure.

+         'method' is function that defines completer's values/choices.

+         Additional arguments are later passed to the 'method'"""

+         if args:

+             cliClient._completers[name] = completers.CustomCompleterWrapper(method, *args, *kwargs)

+         else:

+             cliClient._completers[name] = method

+ 

+     def setup_completers(self):

+         """Prepares custom completers."""

+         cliClient.set_completer("distgit_namespaces", completers.distgit_namespaces, self)

+ 

      def setup_argparser(self):

          """Setup the argument parser and register some basic commands."""

  
@@ -334,12 +365,13 @@ 

                   'namespace. If not specified, name is discovered from Git '

                   'push URL or Git URL (last part of path with .git extension '

                   'removed) or from Name macro in spec file, in that order.')

-         self.parser.add_argument(

+         distgit_namespaces = self.parser.add_argument(

              '--namespace',

              metavar='NAMESPACE',

              dest='repo_namespace',

              help='The package repository namespace. If omitted, default to '

                   'rpms if namespace is enabled.')

+         distgit_namespaces.completer = self.get_completer("distgit_namespaces")

          # Override the  discovered user name

          self.parser.add_argument('--user', default=None,

                                   help='Override the discovered user name')
@@ -444,17 +476,19 @@ 

  

          self.build_parser_common = ArgumentParser(

              'build_common', add_help=False, allow_abbrev=False)

-         self.build_parser_common.add_argument(

+         build_arches = self.build_parser_common.add_argument(

              '--arches', nargs='*', help='Build for specific arches')

+         build_arches.completer = cliClient.get_completer("build_arches")

          self.build_parser_common.add_argument(

              '--md5', action='store_const', const='md5', default=None,

              dest='hash', help='Use md5 checksums (for older rpm hosts)')

          self.build_parser_common.add_argument(

              '--nowait', action='store_true', default=False,

              help="Don't wait on build")

-         self.build_parser_common.add_argument(

+         list_targets = self.build_parser_common.add_argument(

              '--target', default=None,

              help='Define build target to build into')

+         list_targets.completer = cliClient.get_completer("list_targets")

          self.build_parser_common.add_argument(

              '--background', action='store_true', default=False,

              help='Run the build at a low priority')
@@ -482,8 +516,9 @@ 

          self.rpm_parser_common.add_argument(

              '--buildrootdir', default=None,

              help='Define an alternate buildrootdir')

-         self.rpm_parser_common.add_argument(

+         rpm_arches = self.rpm_parser_common.add_argument(

              '--arch', help='Prep for a specific arch')

+         rpm_arches.completer = cliClient.get_completer("build_arches")

          self.rpm_parser_common.add_argument(

              '--define', help='Pass custom macros to rpmbuild, may specify multiple times',

              action='append')
@@ -539,9 +574,10 @@ 

                  by libgizmo and then the current directory package. If no groups are

                  defined, packages will be built sequentially.

              """ % {'name': self.name}))

-         chainbuild_parser.add_argument(

+         packages = chainbuild_parser.add_argument(

              'package', nargs='+',

              help='List the packages and order you want to build in')

+         packages.completer = cliClient.get_completer("packages")

          chainbuild_parser.set_defaults(command=self.chainbuild)

  

      def register_clean(self):
@@ -587,8 +623,9 @@ 

              '--branches', '-B', action='store_true',

              help='Do an old style checkout with subdirs for branches')

          # provide a convenient way to get to a specific branch

-         clone_parser.add_argument(

+         branches = clone_parser.add_argument(

              '--branch', '-b', help='Check out a specific branch')

+         branches.completer = cliClient.get_completer("branches")

          # allow to clone without needing a account on the scm server

          clone_parser.add_argument(

              '--anonymous', '-a', action='store_true',
@@ -601,7 +638,7 @@ 

                  raise argparse.ArgumentTypeError("argument can't contain an URL")

              return raw_value

          # store the module to be cloned

-         clone_parser.add_argument(

+         packages = clone_parser.add_argument(

              'repo', nargs=1, type=validator_not_url,

              help="Name of the repository to clone. "

                   "It should not be a Git URL. "
@@ -609,6 +646,7 @@ 

                   "Otherwise, just 'repo-name'. "

                   "Namespace examples are 'rpms', 'container', 'modules', 'flatpaks'. "

                   "Default namespace 'rpms' can be ignored. ")

+         packages.completer = cliClient.get_completer("packages")

          # Eventually specify where to clone the module

          clone_parser.add_argument(

              "clone_target", default=None, nargs="?",
@@ -1089,9 +1127,12 @@ 

              'mock-config', help='Generate a mock config',

              description='This will generate a mock config based on the '

                          'buildsystem target')

-         mock_config_parser.add_argument(

+         mock_list_targets = mock_config_parser.add_argument(

              '--target', help='Override target used for config', default=None)

-         mock_config_parser.add_argument('--arch', help='Override local arch')

+         mock_list_targets.completer = cliClient.get_completer("list_targets")

+         mock_arches = mock_config_parser.add_argument('--arch',

+                                                       help='Override local arch')

+         mock_arches.completer = cliClient.get_completer("build_arches")

          mock_config_parser.set_defaults(command=self.mock_config)

  

      def register_module_build_common(self):
@@ -1465,8 +1506,10 @@ 

                          'have a local match it will create one.  It can also '

                          'be used to list the existing local and remote '

                          'branches.')

-         switch_branch_parser.add_argument(

+         branches = switch_branch_parser.add_argument(

              'branch', nargs='?', help='Branch name to switch to')

+         # TODO: Solve the issue with listing also other arguments

+         branches.completer = cliClient.get_completer("branches")

          switch_branch_parser.add_argument(

              '-l', '--list', action='store_true',

              help='List both remote-tracking branches and local branches')
@@ -1554,10 +1597,11 @@ 

  

          self.container_build_parser_common = parser

  

-         parser.add_argument(

+         container_list_targets = parser.add_argument(

              '--target',

              help='Override the default target',

              default=None)

+         container_list_targets.completer = cliClient.get_completer("list_targets")

  

          parser.add_argument(

              '--nowait',
@@ -1587,11 +1631,12 @@ 

              help='Scratch build',

              action="store_true")

  

-         parser.add_argument(

+         container_build_arches = parser.add_argument(

              '--arches',

              action='append',

              nargs='*',

              help='Limit a scratch or a isolated build to an arch. May have multiple arches.')

+         container_build_arches.completer = cliClient.get_completer("build_arches")

  

          parser.add_argument(

              '--repo-url',

file added
+36
@@ -0,0 +1,36 @@ 

+ # -*- coding: utf-8 -*-

+ # completers.py - custom argument completers module for fedpkg

+ #

+ # Copyright (C) 2019 Red Hat Inc.

+ # Author(s): Ondrej Nosek <onosek@redhat.com>,

+ #            Dominik Rumian <drumian@redhat.com>

+ #

+ # 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.  See http://www.gnu.org/copyleft/gpl.html for

+ # the full text of the license.

+ 

+ from argcomplete.completers import ChoicesCompleter

+ 

+ 

+ class CustomCompleterWrapper(object):

+     """

+     Class that allows passing additional arguments to custom completer methods.

+     Completer methods should provide ChoicesCompleter (or other similar object

+     from 'argcomplete.completers' class) as their results.

+     """

+     def __init__(self, method, *args, **kwargs):

+         self.method = method

+         self.args = args

+         self.kwargs = kwargs

+ 

+     def fetch_completer(self):

+         return self.method(*self.args, **self.kwargs)

+ 

+ 

+ def distgit_namespaces(cli):

+     if cli.config.has_option(cli.name, 'distgit_namespaces'):

+         return ChoicesCompleter(cli.config.get(cli.name, 'distgit_namespaces').split())

+     else:

+         return None

file modified
+1
@@ -7,6 +7,7 @@ 

  six >= 1.9.0

  requests

  PyYAML

+ argcomplete

  

  # rpm-py-installer

  #

@@ -3,6 +3,7 @@ 

  flake8

  pytest

  pytest-cov

+ argcomplete

  

  # used in MBS tests

  openidc-client

Argcomplete library supports custom completers, but their assigning
to arguments should be done before rpkg initialization. This patch
introduces mechanism how to pass specific completers for rhpkg/fedpkg
to rpkg.

JIRA: RHELCMP-89

Signed-off-by: Ondrej Nosek onosek@redhat.com
Signed-off-by: Dominik Rumian drumian@redhat.com

rebased onto 3b506342632047f55a9e18ebb635599b58f9a101

2 years ago

rebased onto 9afa0d777e0da851480797ee99ad14aba8259198

2 years ago

rebased onto 092d37162ec8e4f93ab5f84c41df25f9181a8a91

2 years ago

I would not use "fedpkg" in names here. rpkg is an underlying library and this completer's functionality might be used by more tools. Something more general?

1 new commit added

  • Argcomplete library supports custom completers, but their assigning
2 years ago

2 new commits added

  • Argcomplete library supports custom completers, but their assigning
  • Support for custom completers
2 years ago

2 new commits added

  • Argcomplete library supports custom completers, but their assigning
  • Support for custom completers
2 years ago

rebased onto 78059900ded1e98af035b3a85eef4b5129ad269c

2 years ago

rebased onto b50f846da5a8c13828e9cd89de086bdaad9b7a90

2 years ago

rebased onto 3e7cbdd9695a3bb405aa39ed0048fb5e86172e9e

2 years ago

rebased onto 0d86f25bc6e72d1ed0f7358478151b55f840426f

2 years ago

rebased onto 0e085b55192febefe2ce003f209f3836c56bd9a0

2 years ago

rebased onto 7e2ac47

2 years ago

Pull-Request has been merged by onosek

2 years ago