diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py index b8a77def..a4d19607 100644 --- a/cli/koji_cli/commands.py +++ b/cli/koji_cli/commands.py @@ -195,7 +195,7 @@ def handle_edit_host(options, session, args): if val is not None: vals[key] = val if 'arches' in vals: - vals['arches'] = parse_arches(vals['arches']) + vals['arches'] = koji.parse_arches(vals['arches']) session.multicall = True for host in args: @@ -350,7 +350,7 @@ def handle_add_pkg(goptions, session, args): continue to_add.append(package) if options.extra_arches: - opts['extra_arches'] = parse_arches(options.extra_arches) + opts['extra_arches'] = koji.parse_arches(options.extra_arches) # add the packages print("Adding %i packages to tag %s" % (len(to_add), dsttag['name'])) @@ -477,7 +477,7 @@ def handle_build(options, session, args): source = args[1] opts = {} if build_opts.arch_override: - opts['arch_override'] = parse_arches(build_opts.arch_override) + opts['arch_override'] = koji.parse_arches(build_opts.arch_override) for key in ('skip_tag', 'scratch', 'repo_id', 'fail_fast'): val = getattr(build_opts, key) if val is not None: @@ -4856,7 +4856,7 @@ def handle_add_tag(goptions, session, args): if options.parent: opts['parent'] = options.parent if options.arches: - opts['arches'] = parse_arches(options.arches) + opts['arches'] = koji.parse_arches(options.arches) if options.maven_support: opts['maven_support'] = True if options.include_all: @@ -4898,7 +4898,7 @@ def handle_edit_tag(goptions, session, args): tag = args[0] opts = {} if options.arches: - opts['arches'] = parse_arches(options.arches) + opts['arches'] = koji.parse_arches(options.arches) if options.no_perm: opts['perm_id'] = None elif options.perm: @@ -6270,7 +6270,7 @@ def handle_set_pkg_arches(goptions, session, args): parser.error(_("Please specify an archlist, a tag, and at least one package")) assert False # pragma: no cover activate_session(session, goptions) - arches = parse_arches(args[0]) + arches = koji.parse_arches(args[0]) tag = args[1] for package in args[2:]: #really should implement multicall... diff --git a/cli/koji_cli/lib.py b/cli/koji_cli/lib.py index 8e8bf99a..5d779542 100644 --- a/cli/koji_cli/lib.py +++ b/cli/koji_cli/lib.py @@ -20,6 +20,8 @@ except ImportError: # pragma: no cover import koji from koji.util import to_list +# import parse_arches to current namespace for backward compatibility +from koji import parse_arches # for compatibility with plugins based on older version of lib # Use optparse imports directly in new code. @@ -132,26 +134,6 @@ def print_task_recurse(task,depth=0): print_task_recurse(child,depth+1) -def parse_arches(arches, to_list=False): - """Normalize user input for a list of arches. - - This method parses a single comma- or space-separated string of arches and - returns a space-separated string. - - :param str arches: comma- or space-separated string of arches, eg. - "x86_64,ppc64le", or "x86_64 ppc64le" - :param bool to_list: return a list of each arch, instead of a single - string. This is False by default. - :returns: a space-separated string like "x86_64 ppc64le", or a list like - ['x86_64', 'ppc64le']. - """ - arches = arches.replace(',', ' ').split() - if to_list: - return arches - else: - return ' '.join(arches) - - class TaskWatcher(object): def __init__(self,task_id,session,level=0,quiet=False): diff --git a/hub/kojihub.py b/hub/kojihub.py index 9eb78519..99453f42 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -886,7 +886,7 @@ def _pkglist_add(tag_id, pkg_id, owner, block, extra_arches): data = dslice(locals(), ('tag_id', 'owner', 'extra_arches')) data['package_id'] = pkg_id data['blocked'] = block - validate_arches_string(data['extra_arches']) + data['extra_arches'] = koji.parse_arches(data['extra_arches'], strict=True, allow_none=True) _pkglist_remove(tag_id, pkg_id) insert = InsertProcessor('tag_packages', data=data) insert.make_create() #XXX user_id? @@ -925,7 +925,7 @@ def _direct_pkglist_add(taginfo, pkginfo, owner, block, extra_arches, force, if not pkg: pkg = lookup_package(pkginfo, create=True) # validate arches before running callbacks - validate_arches_string(extra_arches) + extra_arches = koji.parse_arches(extra_arches, strict=True, allow_none=True) koji.plugin.run_callbacks('prePackageListChange', action=action, tag=tag, package=pkg, owner=owner, block=block, extra_arches=extra_arches, force=force, update=update) # first check to see if package is: @@ -3024,16 +3024,6 @@ def lookup_build_target(info, strict=False, create=False): return lookup_name('build_target', info, strict, create) -def validate_arches_string(arches, strict=True): - """run checks against architectures space-separated strings""" - if re.match(r'^[a-zA-Z0-9_\- ]+$', arches): - return True - elif strict: - raise koji.GenericError("Architecture can be only [a-zA-Z0-9_-]") - else: - return False - - def create_tag(name, parent=None, arches=None, perm=None, locked=False, maven_support=False, maven_include_all=False, extra=None): """Create a new tag""" context.session.assertPerm('admin') @@ -3048,8 +3038,7 @@ def _create_tag(name, parent=None, arches=None, perm=None, locked=False, maven_s raise koji.GenericError("Tag name %s is too long. Max length is %s characters", name, max_name_length) - if arches is not None: - validate_arches_string(arches) + arches = koji.parse_arches(arches, strict=True, allow_none=True) if not context.opts.get('EnableMaven') and (maven_support or maven_include_all): raise koji.GenericError("Maven support not enabled") @@ -3234,7 +3223,7 @@ WHERE id = %(tagID)i""" # sanitize architecture names (space-separated string) arches = kwargs.get('arches') if arches and tag['arches'] != arches: - validate_arches_string(arches) + kwargs['arches'] = koji.parse_arches(arches, strict=True, allow_none=True) #check for changes data = tag.copy() diff --git a/koji/__init__.py b/koji/__init__.py index dfe35e9a..4388e8b2 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -1104,6 +1104,37 @@ def canonArch(arch): else: return arch +def parse_arches(arches, to_list=False, strict=False, allow_none=False): + """Normalize user input for a list of arches. + + This method parses a single comma- or space-separated string of arches and + returns a space-separated string. + + Raise an error if arches string contain non-allowed characters. In strict + version allow only space-separated strings (db input). + + :param str arches: comma- or space-separated string of arches, eg. + "x86_64,ppc64le", or "x86_64 ppc64le" + :param bool to_list: return a list of each arch, instead of a single + string. This is False by default. + :param bool allow_none: convert None to "" + :returns: a space-separated string like "x86_64 ppc64le", or a list like + ['x86_64', 'ppc64le']. + """ + if allow_none and arches is None: + arches = '' + if not strict: + arches = arches.replace(',', ' ') + if not re.match(r'^[a-zA-Z0-9_\- ]*$', arches): + raise GenericError("Architecture can be only [a-zA-Z0-9_-]") + + arches = arches.split() + if to_list: + return arches + else: + return ' '.join(arches) + + class POMHandler(xml.sax.handler.ContentHandler): def __init__(self, values, fields): xml.sax.handler.ContentHandler.__init__(self) diff --git a/tests/test_hub/test_validate_arches_string.py b/tests/test_hub/test_validate_arches_string.py deleted file mode 100644 index 9261421a..00000000 --- a/tests/test_hub/test_validate_arches_string.py +++ /dev/null @@ -1,25 +0,0 @@ -# coding: utf-8 -from __future__ import absolute_import -try: - import unittest2 as unittest -except ImportError: - import unittest -import koji -import kojihub - -class TestValidateArchesString(unittest.TestCase): - def test_valid_arches(self): - kojihub.validate_arches_string('i386') - kojihub.validate_arches_string('i386 x86_64') - kojihub.validate_arches_string('i386 x86_64 ') - - def test_invalid_arches(self): - with self.assertRaises(koji.GenericError): - kojihub.validate_arches_string(u'ěšč') - - with self.assertRaises(koji.GenericError): - kojihub.validate_arches_string(u'i386;x86_64') - - with self.assertRaises(koji.GenericError): - kojihub.validate_arches_string(u'i386,x86_64') - diff --git a/tests/test_lib/test_parse_arches.py b/tests/test_lib/test_parse_arches.py new file mode 100644 index 00000000..a5aaeac8 --- /dev/null +++ b/tests/test_lib/test_parse_arches.py @@ -0,0 +1,31 @@ +# coding: utf-8 +from __future__ import absolute_import +try: + import unittest2 as unittest +except ImportError: + import unittest +import koji + +class TestParseArchesString(unittest.TestCase): + def test_parse_valid_arches(self): + r = koji.parse_arches('i386', to_list=True) + self.assertEqual(['i386'], r) + + r = koji.parse_arches('i386 x86_64', to_list=True) + self.assertEqual(['i386', 'x86_64'], r) + + r = koji.parse_arches('i386 x86_64 ', to_list=True) + self.assertEqual(['i386', 'x86_64'], r) + + r = koji.parse_arches('i386,x86_64', to_list=True) + self.assertEqual(['i386', 'x86_64'], r) + + def test_parse_invalid_arches(self): + with self.assertRaises(koji.GenericError): + koji.parse_arches(u'ěšč') + + with self.assertRaises(koji.GenericError): + koji.parse_arches(u'i386;x86_64') + + with self.assertRaises(koji.GenericError): + koji.parse_arches(u'i386,x86_64', strict=True)