PR#184: Port Koji comps/group functionality from yum.comps to libcomps
Merges #170 https://pagure.io/koji/pull-request/170 Fixes #184
This commit is contained in:
commit
0e664ad779
14 changed files with 44921 additions and 12 deletions
73
cli/koji
73
cli/koji
|
|
@ -62,12 +62,15 @@ import urlgrabber.grabber as grabber
|
|||
import urlgrabber.progress as progress
|
||||
import xmlrpclib
|
||||
try:
|
||||
import yum.comps as yumcomps
|
||||
import libcomps
|
||||
except ImportError:
|
||||
yumcomps = None
|
||||
libcomps = None
|
||||
try:
|
||||
import yum.comps as yumcomps
|
||||
except ImportError:
|
||||
yumcomps = None
|
||||
import optparse
|
||||
#for import-comps handler (currently disabled)
|
||||
#from rhpl.comps import Comps
|
||||
|
||||
|
||||
# fix OptionParser for python 2.3 (optparse verion 1.4.1+)
|
||||
# code taken from optparse version 1.5a2
|
||||
|
|
@ -1760,15 +1763,60 @@ def handle_import_comps(options, session, args):
|
|||
if len(args) != 2:
|
||||
parser.error(_("Incorrect number of arguments"))
|
||||
assert False
|
||||
if yumcomps is None:
|
||||
print "yum comps module not available"
|
||||
return 1
|
||||
# TODO: port to libcomps
|
||||
comps = yumcomps.Comps()
|
||||
comps.add(args[0])
|
||||
tag = args[1]
|
||||
force = local_options.force
|
||||
activate_session(session)
|
||||
# check if the tag exists
|
||||
dsttag = session.getTag(args[1])
|
||||
if dsttag is None:
|
||||
print "No such tag: %s" % args[1]
|
||||
return 1
|
||||
if libcomps is not None:
|
||||
_import_comps(session, args[0], args[1], local_options)
|
||||
elif yumcomps is not None:
|
||||
_import_comps_alt(session, args[0], args[1], local_options)
|
||||
else:
|
||||
print "comps module not available"
|
||||
return 1
|
||||
|
||||
|
||||
def _import_comps(session, filename, tag, options):
|
||||
"""Import comps data using libcomps module"""
|
||||
comps = libcomps.Comps()
|
||||
comps.fromxml_f(filename)
|
||||
force = options['force']
|
||||
ptypes = {
|
||||
libcomps.PACKAGE_TYPE_DEFAULT : 'default',
|
||||
libcomps.PACKAGE_TYPE_OPTIONAL : 'optional',
|
||||
libcomps.PACKAGE_TYPE_CONDITIONAL : 'conditional',
|
||||
libcomps.PACKAGE_TYPE_MANDATORY : 'mandatory',
|
||||
libcomps.PACKAGE_TYPE_UNKNOWN : 'unknown',
|
||||
}
|
||||
for group in comps.groups:
|
||||
print "Group: %s (%s)" % (group.id, group.name)
|
||||
session.groupListAdd(
|
||||
tag, group.id, force=force, display_name=group.name,
|
||||
is_default=bool(group.default),
|
||||
uservisible=bool(group.uservisible),
|
||||
description=group.desc,
|
||||
langonly=group.lang_only,
|
||||
biarchonly=bool(group.biarchonly))
|
||||
for pkg in group.packages:
|
||||
pkgopts = {'type' : ptypes[pkg.type],
|
||||
'basearchonly' : bool(pkg.basearchonly),
|
||||
}
|
||||
if pkg.type == libcomps.PACKAGE_TYPE_CONDITIONAL:
|
||||
pkgopts['requires'] = pkg.requires
|
||||
print " Package: %s: %r" % (pkg.name, pkgopts)
|
||||
session.groupPackageListAdd(tag, group.id, pkg.name, force=force, **pkgopts)
|
||||
# libcomps does not support group dependencies
|
||||
# libcomps does not support metapkgs
|
||||
|
||||
|
||||
def _import_comps_alt(session, filename, tag, options):
|
||||
"""Import comps data using yum.comps module"""
|
||||
print 'WARN: yum.comps does not support the biarchonly of group and basearchonly of package'
|
||||
comps = yumcomps.Comps()
|
||||
comps.add(filename)
|
||||
force = options['force']
|
||||
for group in comps.groups:
|
||||
print "Group: %(groupid)s (%(name)s)" % vars(group)
|
||||
session.groupListAdd(tag, group.groupid, force=force, display_name=group.name,
|
||||
|
|
@ -1791,6 +1839,7 @@ def handle_import_comps(options, session, args):
|
|||
#yum.comps does not support group dependencies
|
||||
#yum.comps does not support metapkgs
|
||||
|
||||
|
||||
def handle_import_sig(options, session, args):
|
||||
"[admin] Import signatures into the database"
|
||||
usage = _("usage: %prog import-sig [options] package [package...]")
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ BuildRequires: python
|
|||
BuildRequires: systemd
|
||||
BuildRequires: pkgconfig
|
||||
%endif
|
||||
%if 0%{?fedora} || 0%{?rhel} >= 7
|
||||
Requires: python-libcomps
|
||||
%endif
|
||||
|
||||
%description
|
||||
Koji is a system for building and tracking RPMS. The base package
|
||||
|
|
|
|||
5200
tests/test_cli/data/comps-example.libcomps.calls
Normal file
5200
tests/test_cli/data/comps-example.libcomps.calls
Normal file
File diff suppressed because it is too large
Load diff
5200
tests/test_cli/data/comps-example.libcomps.out
Normal file
5200
tests/test_cli/data/comps-example.libcomps.out
Normal file
File diff suppressed because it is too large
Load diff
23420
tests/test_cli/data/comps-example.xml
Normal file
23420
tests/test_cli/data/comps-example.xml
Normal file
File diff suppressed because it is too large
Load diff
5200
tests/test_cli/data/comps-example.yumcomps.calls
Normal file
5200
tests/test_cli/data/comps-example.yumcomps.calls
Normal file
File diff suppressed because it is too large
Load diff
5201
tests/test_cli/data/comps-example.yumcomps.out
Normal file
5201
tests/test_cli/data/comps-example.yumcomps.out
Normal file
File diff suppressed because it is too large
Load diff
39
tests/test_cli/data/comps-sample.libcomps.calls
Normal file
39
tests/test_cli/data/comps-sample.libcomps.calls
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
[call.groupListAdd('tag', u'additional-devel', biarchonly=True, description=u'Additional development headers and libraries for developing applications', display_name=u'Additional Development', force=None, is_default=False, langonly=u'fr', uservisible=False),
|
||||
call.groupPackageListAdd('tag', u'additional-devel', u'alsa-lib-devel', basearchonly=False, force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', u'additional-devel', u'audit-libs-devel', basearchonly=False, force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', u'additional-devel', u'binutils-devel', basearchonly=False, force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', u'additional-devel', u'boost-devel', basearchonly=False, force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', u'additional-devel', u'bzip2-devel', basearchonly=False, force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', u'additional-devel', u'cyrus-sasl-devel', basearchonly=False, force=None, type='default'),
|
||||
call.groupListAdd('tag', u'backup-client', biarchonly=False, description=u'Client tools for connecting to a backup server and doing backups.', display_name=u'Backup Client', force=None, is_default=True, langonly=None, uservisible=True),
|
||||
call.groupPackageListAdd('tag', u'backup-client', u'amanda-client', basearchonly=False, force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', u'backup-client', u'bacula-client', basearchonly=False, force=None, type='optional'),
|
||||
call.groupListAdd('tag', u'backup-server', biarchonly=False, description=u"Software to centralize your infrastructure's backups.", display_name=u'Backup Server', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupPackageListAdd('tag', u'backup-server', u'amanda-server', basearchonly=False, force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', u'backup-server', u'mt-st', basearchonly=False, force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', u'backup-server', u'mtx', basearchonly=False, force=None, type='optional'),
|
||||
call.groupListAdd('tag', u'ansible-node', biarchonly=False, description=None, display_name=u'Ansible node', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupPackageListAdd('tag', u'ansible-node', u'python2-dnf', basearchonly=False, force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', u'ansible-node', u'libselinux-python', basearchonly=False, force=None, requires=u'selinux-policy', type='conditional'),
|
||||
call.groupListAdd('tag', u'd-development', biarchonly=False, description=u'These include development tools and libraries such as ldc, and geany-tag.', display_name=u'D Development Tools and Libraries', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'ldc', basearchonly=True, force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'ldc-druntime', basearchonly=True, force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'ldc-druntime-devel', basearchonly=True, force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'ldc-phobos-devel', basearchonly=True, force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'make', basearchonly=False, force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'pkgconfig', basearchonly=False, force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'ctags', basearchonly=False, force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'indent', basearchonly=False, force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'astyle', basearchonly=False, force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'cmake', basearchonly=False, force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'derelict-devel', basearchonly=False, force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'geany', basearchonly=False, force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'gl3n-devel', basearchonly=False, force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'insight', basearchonly=False, force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'nemiver', basearchonly=False, force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', u'd-development', u'uncrustify', basearchonly=False, force=None, type='optional'),
|
||||
call.groupListAdd('tag', u'empty-group-1', biarchonly=False, description=u'empty group 1 desc', display_name=u'empty group 1', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupListAdd('tag', u'empty-group-2', biarchonly=False, description=u'empty group 2 desc', display_name=u'empty group 2', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupListAdd('tag', u'unknown-group', biarchonly=False, description=u'unknown group desc', display_name=u'unknown group', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupPackageListAdd('tag', u'unknown-group', u'unknown', basearchonly=False, force=None, type='unknown'),
|
||||
call.groupPackageListAdd('tag', u'unknown-group', u'unknown2', basearchonly=False, force=None, type='unknown')]
|
||||
39
tests/test_cli/data/comps-sample.libcomps.out
Normal file
39
tests/test_cli/data/comps-sample.libcomps.out
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
Group: additional-devel (Additional Development)
|
||||
Package: alsa-lib-devel: {'type': 'default', 'basearchonly': False}
|
||||
Package: audit-libs-devel: {'type': 'default', 'basearchonly': False}
|
||||
Package: binutils-devel: {'type': 'default', 'basearchonly': False}
|
||||
Package: boost-devel: {'type': 'default', 'basearchonly': False}
|
||||
Package: bzip2-devel: {'type': 'default', 'basearchonly': False}
|
||||
Package: cyrus-sasl-devel: {'type': 'default', 'basearchonly': False}
|
||||
Group: backup-client (Backup Client)
|
||||
Package: amanda-client: {'type': 'mandatory', 'basearchonly': False}
|
||||
Package: bacula-client: {'type': 'optional', 'basearchonly': False}
|
||||
Group: backup-server (Backup Server)
|
||||
Package: amanda-server: {'type': 'mandatory', 'basearchonly': False}
|
||||
Package: mt-st: {'type': 'optional', 'basearchonly': False}
|
||||
Package: mtx: {'type': 'optional', 'basearchonly': False}
|
||||
Group: ansible-node (Ansible node)
|
||||
Package: python2-dnf: {'type': 'mandatory', 'basearchonly': False}
|
||||
Package: libselinux-python: {'requires': u'selinux-policy', 'type': 'conditional', 'basearchonly': False}
|
||||
Group: d-development (D Development Tools and Libraries)
|
||||
Package: ldc: {'type': 'mandatory', 'basearchonly': True}
|
||||
Package: ldc-druntime: {'type': 'mandatory', 'basearchonly': True}
|
||||
Package: ldc-druntime-devel: {'type': 'mandatory', 'basearchonly': True}
|
||||
Package: ldc-phobos-devel: {'type': 'mandatory', 'basearchonly': True}
|
||||
Package: make: {'type': 'mandatory', 'basearchonly': False}
|
||||
Package: pkgconfig: {'type': 'mandatory', 'basearchonly': False}
|
||||
Package: ctags: {'type': 'default', 'basearchonly': False}
|
||||
Package: indent: {'type': 'default', 'basearchonly': False}
|
||||
Package: astyle: {'type': 'optional', 'basearchonly': False}
|
||||
Package: cmake: {'type': 'optional', 'basearchonly': False}
|
||||
Package: derelict-devel: {'type': 'optional', 'basearchonly': False}
|
||||
Package: geany: {'type': 'optional', 'basearchonly': False}
|
||||
Package: gl3n-devel: {'type': 'optional', 'basearchonly': False}
|
||||
Package: insight: {'type': 'optional', 'basearchonly': False}
|
||||
Package: nemiver: {'type': 'optional', 'basearchonly': False}
|
||||
Package: uncrustify: {'type': 'optional', 'basearchonly': False}
|
||||
Group: empty-group-1 (empty group 1)
|
||||
Group: empty-group-2 (empty group 2)
|
||||
Group: unknown-group (unknown group)
|
||||
Package: unknown: {'type': 'unknown', 'basearchonly': False}
|
||||
Package: unknown2: {'type': 'unknown', 'basearchonly': False}
|
||||
105
tests/test_cli/data/comps-sample.xml
Normal file
105
tests/test_cli/data/comps-sample.xml
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE comps PUBLIC "-//Red Hat, Inc.//DTD Comps info//EN" "comps.dtd">
|
||||
<comps>
|
||||
<group>
|
||||
<id>additional-devel</id>
|
||||
<name>Additional Development</name>
|
||||
<description>Additional development headers and libraries for developing applications</description>
|
||||
<default>false</default>
|
||||
<uservisible>false</uservisible>
|
||||
<biarchonly>true</biarchonly>
|
||||
<langonly>fr</langonly>
|
||||
<packagelist>
|
||||
<packagereq type="default">alsa-lib-devel</packagereq>
|
||||
<packagereq type="default">audit-libs-devel</packagereq>
|
||||
<packagereq type="default">binutils-devel</packagereq>
|
||||
<packagereq type="default">boost-devel</packagereq>
|
||||
<packagereq type="default">bzip2-devel</packagereq>
|
||||
<packagereq type="default">cyrus-sasl-devel</packagereq>
|
||||
</packagelist>
|
||||
</group>
|
||||
<group>
|
||||
<id>backup-client</id>
|
||||
<name>Backup Client</name>
|
||||
<description>Client tools for connecting to a backup server and doing backups.</description>
|
||||
<default>true</default>
|
||||
<uservisible>true</uservisible>
|
||||
<packagelist>
|
||||
<packagereq type="mandatory">amanda-client</packagereq>
|
||||
<packagereq type="optional">bacula-client</packagereq>
|
||||
</packagelist>
|
||||
</group>
|
||||
<group>
|
||||
<id>backup-server</id>
|
||||
<name>Backup Server</name>
|
||||
<description>Software to centralize your infrastructure's backups.</description>
|
||||
<default>false</default>
|
||||
<uservisible>true</uservisible>
|
||||
<packagelist>
|
||||
<packagereq type="mandatory">amanda-server</packagereq>
|
||||
<packagereq type="optional">mt-st</packagereq>
|
||||
<packagereq type="optional">mtx</packagereq>
|
||||
</packagelist>
|
||||
</group>
|
||||
<group>
|
||||
<id>ansible-node</id>
|
||||
<name>Ansible node</name>
|
||||
<default>false</default>
|
||||
<uservisible>true</uservisible>
|
||||
<packagelist>
|
||||
<packagereq type="mandatory">python2-dnf</packagereq>
|
||||
<packagereq type="conditional" requires="selinux-policy">libselinux-python</packagereq>
|
||||
</packagelist>
|
||||
</group>
|
||||
<group>
|
||||
<id>d-development</id>
|
||||
<name>D Development Tools and Libraries</name>
|
||||
<description>These include development tools and libraries such as ldc, and geany-tag.</description>
|
||||
<default>false</default>
|
||||
<uservisible>true</uservisible>
|
||||
<packagelist>
|
||||
<packagereq type="mandatory" basearchonly="true">ldc</packagereq>
|
||||
<packagereq type="mandatory" basearchonly="true">ldc-druntime</packagereq>
|
||||
<packagereq type="mandatory" basearchonly="true">ldc-druntime-devel</packagereq>
|
||||
<packagereq type="mandatory" basearchonly="true">ldc-phobos-devel</packagereq>
|
||||
<packagereq type="mandatory">make</packagereq>
|
||||
<packagereq type="mandatory">pkgconfig</packagereq>
|
||||
<packagereq type="default">ctags</packagereq>
|
||||
<packagereq type="default">indent</packagereq>
|
||||
<packagereq type="optional">astyle</packagereq>
|
||||
<packagereq type="optional">cmake</packagereq>
|
||||
<packagereq type="optional">derelict-devel</packagereq>
|
||||
<packagereq type="optional">geany</packagereq>
|
||||
<packagereq type="optional">gl3n-devel</packagereq>
|
||||
<packagereq type="optional">insight</packagereq>
|
||||
<packagereq type="optional">nemiver</packagereq>
|
||||
<packagereq type="optional">uncrustify</packagereq>
|
||||
</packagelist>
|
||||
</group>
|
||||
<group>
|
||||
<id>empty-group-1</id>
|
||||
<name>empty group 1</name>
|
||||
<description>empty group 1 desc</description>
|
||||
<default>false</default>
|
||||
<uservisible>true</uservisible>
|
||||
<packagelist/>
|
||||
</group>
|
||||
<group>
|
||||
<id>empty-group-2</id>
|
||||
<name>empty group 2</name>
|
||||
<description>empty group 2 desc</description>
|
||||
<default>false</default>
|
||||
<uservisible>true</uservisible>
|
||||
</group>
|
||||
<group>
|
||||
<id>unknown-group</id>
|
||||
<name>unknown group</name>
|
||||
<description>unknown group desc</description>
|
||||
<default>false</default>
|
||||
<uservisible>true</uservisible>
|
||||
<packagelist>
|
||||
<packagereq type="unknown">unknown</packagereq>
|
||||
<packagereq type="what">unknown2</packagereq>
|
||||
</packagelist>
|
||||
</group>
|
||||
</comps>
|
||||
37
tests/test_cli/data/comps-sample.yumcomps.calls
Normal file
37
tests/test_cli/data/comps-sample.yumcomps.calls
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
[call.groupListAdd('tag', 'additional-devel', description='Additional development headers and libraries for developing applications', display_name='Additional Development', force=None, is_default=False, langonly='fr', uservisible=False),
|
||||
call.groupPackageListAdd('tag', 'additional-devel', 'binutils-devel', force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', 'additional-devel', 'boost-devel', force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', 'additional-devel', 'bzip2-devel', force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', 'additional-devel', 'cyrus-sasl-devel', force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', 'additional-devel', 'audit-libs-devel', force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', 'additional-devel', 'alsa-lib-devel', force=None, type='default'),
|
||||
call.groupListAdd('tag', 'ansible-node', description='', display_name='Ansible node', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupPackageListAdd('tag', 'ansible-node', 'python2-dnf', force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', 'ansible-node', 'libselinux-python', force=None, requires='selinux-policy', type='conditional'),
|
||||
call.groupListAdd('tag', 'backup-client', description='Client tools for connecting to a backup server and doing backups.', display_name='Backup Client', force=None, is_default=True, langonly=None, uservisible=True),
|
||||
call.groupPackageListAdd('tag', 'backup-client', 'amanda-client', force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', 'backup-client', 'bacula-client', force=None, type='optional'),
|
||||
call.groupListAdd('tag', 'backup-server', description="Software to centralize your infrastructure's backups.", display_name='Backup Server', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupPackageListAdd('tag', 'backup-server', 'amanda-server', force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', 'backup-server', 'mtx', force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', 'backup-server', 'mt-st', force=None, type='optional'),
|
||||
call.groupListAdd('tag', 'd-development', description='These include development tools and libraries such as ldc, and geany-tag.', display_name='D Development Tools and Libraries', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'ldc', force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'ldc-druntime', force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'make', force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'pkgconfig', force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'ldc-phobos-devel', force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'ldc-druntime-devel', force=None, type='mandatory'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'ctags', force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'indent', force=None, type='default'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'geany', force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'cmake', force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'derelict-devel', force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'insight', force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'nemiver', force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'gl3n-devel', force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'astyle', force=None, type='optional'),
|
||||
call.groupPackageListAdd('tag', 'd-development', 'uncrustify', force=None, type='optional'),
|
||||
call.groupListAdd('tag', 'empty-group-1', description='empty group 1 desc', display_name='empty group 1', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupListAdd('tag', 'empty-group-2', description='empty group 2 desc', display_name='empty group 2', force=None, is_default=False, langonly=None, uservisible=True),
|
||||
call.groupListAdd('tag', 'unknown-group', description='unknown group desc', display_name='unknown group', force=None, is_default=False, langonly=None, uservisible=True)]
|
||||
38
tests/test_cli/data/comps-sample.yumcomps.out
Normal file
38
tests/test_cli/data/comps-sample.yumcomps.out
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
WARN: yum.comps does not support the biarchonly of group and basearchonly of package
|
||||
Group: additional-devel (Additional Development)
|
||||
Package: binutils-devel: {'type': 'default'}
|
||||
Package: boost-devel: {'type': 'default'}
|
||||
Package: bzip2-devel: {'type': 'default'}
|
||||
Package: cyrus-sasl-devel: {'type': 'default'}
|
||||
Package: audit-libs-devel: {'type': 'default'}
|
||||
Package: alsa-lib-devel: {'type': 'default'}
|
||||
Group: ansible-node (Ansible node)
|
||||
Package: python2-dnf: {'type': 'mandatory'}
|
||||
Package: libselinux-python: {'requires': 'selinux-policy', 'type': 'conditional'}
|
||||
Group: backup-client (Backup Client)
|
||||
Package: amanda-client: {'type': 'mandatory'}
|
||||
Package: bacula-client: {'type': 'optional'}
|
||||
Group: backup-server (Backup Server)
|
||||
Package: amanda-server: {'type': 'mandatory'}
|
||||
Package: mtx: {'type': 'optional'}
|
||||
Package: mt-st: {'type': 'optional'}
|
||||
Group: d-development (D Development Tools and Libraries)
|
||||
Package: ldc: {'type': 'mandatory'}
|
||||
Package: ldc-druntime: {'type': 'mandatory'}
|
||||
Package: make: {'type': 'mandatory'}
|
||||
Package: pkgconfig: {'type': 'mandatory'}
|
||||
Package: ldc-phobos-devel: {'type': 'mandatory'}
|
||||
Package: ldc-druntime-devel: {'type': 'mandatory'}
|
||||
Package: ctags: {'type': 'default'}
|
||||
Package: indent: {'type': 'default'}
|
||||
Package: geany: {'type': 'optional'}
|
||||
Package: cmake: {'type': 'optional'}
|
||||
Package: derelict-devel: {'type': 'optional'}
|
||||
Package: insight: {'type': 'optional'}
|
||||
Package: nemiver: {'type': 'optional'}
|
||||
Package: gl3n-devel: {'type': 'optional'}
|
||||
Package: astyle: {'type': 'optional'}
|
||||
Package: uncrustify: {'type': 'optional'}
|
||||
Group: empty-group-1 (empty group 1)
|
||||
Group: empty-group-2 (empty group 2)
|
||||
Group: unknown-group (unknown group)
|
||||
15
tests/test_cli/loadcli.py
Normal file
15
tests/test_cli/loadcli.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
# We have to do this craziness because 'import koji' is ambiguous. Is it the
|
||||
# koji module, or the koji cli module. Jump through hoops accordingly.
|
||||
# http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path
|
||||
CLI_FILENAME = os.path.dirname(__file__) + "/../../cli/koji"
|
||||
if sys.version_info[0] >= 3:
|
||||
import importlib.util
|
||||
spec = importlib.util.spec_from_file_location("koji_cli", CLI_FILENAME)
|
||||
cli = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(cli)
|
||||
else:
|
||||
import imp
|
||||
cli = imp.load_source('koji_cli', CLI_FILENAME)
|
||||
363
tests/test_cli/test_import_comps.py
Normal file
363
tests/test_cli/test_import_comps.py
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
import unittest
|
||||
|
||||
import StringIO as stringio
|
||||
|
||||
import os
|
||||
|
||||
import sys
|
||||
|
||||
import mock
|
||||
|
||||
import loadcli
|
||||
|
||||
try:
|
||||
import libcomps
|
||||
except ImportError:
|
||||
libcomps = None
|
||||
try:
|
||||
import yum.comps as yumcomps
|
||||
except ImportError:
|
||||
yumcomps = None
|
||||
|
||||
cli = loadcli.cli
|
||||
|
||||
|
||||
class TestImportComps(unittest.TestCase):
|
||||
# Show long diffs in error output...
|
||||
maxDiff = None
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.libcomps')
|
||||
@mock.patch('koji_cli.activate_session')
|
||||
@mock.patch('koji_cli._import_comps')
|
||||
@mock.patch('koji_cli._import_comps_alt')
|
||||
def test_handle_import_comps_libcomps(
|
||||
self,
|
||||
mock_import_comps_alt,
|
||||
mock_import_comps,
|
||||
mock_activate_session,
|
||||
libcomps,
|
||||
stdout):
|
||||
filename = './data/comps-example.xml'
|
||||
tag = 'tag'
|
||||
tag_info = {'name': tag, 'id': 1}
|
||||
force = None
|
||||
args = [filename, tag]
|
||||
kwargs = {'force': force}
|
||||
options = mock.MagicMock()
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
session.getTag.return_value = tag_info
|
||||
|
||||
# Run it and check immediate output
|
||||
# args: ./data/comps-example.xml, tag
|
||||
# expected: success
|
||||
rv = cli.handle_import_comps(options, session, args)
|
||||
actual = stdout.getvalue()
|
||||
expected = ''
|
||||
self.assertMultiLineEqual(actual, expected)
|
||||
|
||||
# Finally, assert that things were called as we expected.
|
||||
mock_activate_session.assert_called_once_with(session)
|
||||
session.getTag.assert_called_once_with(tag)
|
||||
mock_import_comps.assert_called_once_with(
|
||||
session, filename, tag, kwargs)
|
||||
mock_import_comps_alt.assert_not_called()
|
||||
self.assertNotEqual(rv, 1)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.libcomps', new=None)
|
||||
@mock.patch('koji_cli.yumcomps', create=True)
|
||||
@mock.patch('koji_cli.activate_session')
|
||||
@mock.patch('koji_cli._import_comps')
|
||||
@mock.patch('koji_cli._import_comps_alt')
|
||||
def test_handle_import_comps_yumcomps(
|
||||
self,
|
||||
mock_import_comps_alt,
|
||||
mock_import_comps,
|
||||
mock_activate_session,
|
||||
yumcomps,
|
||||
stdout):
|
||||
filename = './data/comps-example.xml'
|
||||
tag = 'tag'
|
||||
tag_info = {'name': tag, 'id': 1}
|
||||
force = True
|
||||
args = ['--force', filename, tag]
|
||||
local_options = {'force': force}
|
||||
options = mock.MagicMock()
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
session.getTag.return_value = tag_info
|
||||
|
||||
# Run it and check immediate output
|
||||
# args: --force, ./data/comps-example.xml, tag
|
||||
# expected: success
|
||||
rv = cli.handle_import_comps(options, session, args)
|
||||
actual = stdout.getvalue()
|
||||
expected = ''
|
||||
self.assertMultiLineEqual(actual, expected)
|
||||
|
||||
# Finally, assert that things were called as we expected.
|
||||
mock_activate_session.assert_called_once_with(session)
|
||||
session.getTag.assert_called_once_with(tag)
|
||||
mock_import_comps.assert_not_called()
|
||||
mock_import_comps_alt.assert_called_once_with(
|
||||
session, filename, tag, local_options)
|
||||
self.assertNotEqual(rv, 1)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.libcomps', new=None)
|
||||
@mock.patch('koji_cli.yumcomps', new=None, create=True)
|
||||
@mock.patch('koji_cli.activate_session')
|
||||
@mock.patch('koji_cli._import_comps')
|
||||
@mock.patch('koji_cli._import_comps_alt')
|
||||
def test_handle_import_comps_comps_na(
|
||||
self,
|
||||
mock_import_comps_alt,
|
||||
mock_import_comps,
|
||||
mock_activate_session,
|
||||
stdout):
|
||||
filename = './data/comps-example.xml'
|
||||
tag = 'tag'
|
||||
tag_info = {'name': tag, 'id': 1}
|
||||
args = ['--force', filename, tag]
|
||||
options = mock.MagicMock()
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
session.getTag.return_value = tag_info
|
||||
|
||||
# Run it and check immediate output
|
||||
# args: --force, ./data/comps-example.xml, tag
|
||||
# expected: failed, no comps available
|
||||
rv = cli.handle_import_comps(options, session, args)
|
||||
actual = stdout.getvalue()
|
||||
expected = 'comps module not available\n'
|
||||
self.assertMultiLineEqual(actual, expected)
|
||||
|
||||
# Finally, assert that things were called as we expected.
|
||||
mock_activate_session.assert_called_once_with(session)
|
||||
session.getTag.assert_called_once_with(tag)
|
||||
mock_import_comps.assert_not_called()
|
||||
mock_import_comps_alt.assert_not_called()
|
||||
self.assertEqual(rv, 1)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.activate_session')
|
||||
@mock.patch('koji_cli._import_comps')
|
||||
@mock.patch('koji_cli._import_comps_alt')
|
||||
def test_handle_import_comps_tag_not_exists(
|
||||
self,
|
||||
mock_import_comps_alt,
|
||||
mock_import_comps,
|
||||
mock_activate_session,
|
||||
stdout):
|
||||
filename = './data/comps-example.xml'
|
||||
tag = 'tag'
|
||||
tag_info = None
|
||||
args = [filename, tag]
|
||||
options = mock.MagicMock()
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
session.getTag.return_value = tag_info
|
||||
|
||||
# Run it and check immediate output
|
||||
# args: ./data/comps-example.xml, tag
|
||||
# expected: failed: tag does not exist
|
||||
rv = cli.handle_import_comps(options, session, args)
|
||||
actual = stdout.getvalue()
|
||||
expected = 'No such tag: tag\n'
|
||||
self.assertMultiLineEqual(actual, expected)
|
||||
|
||||
# Finally, assert that things were called as we expected.
|
||||
mock_activate_session.assert_called_once_with(session)
|
||||
session.getTag.assert_called_once_with(tag)
|
||||
mock_import_comps.assert_not_called()
|
||||
mock_import_comps_alt.assert_not_called()
|
||||
self.assertEqual(rv, 1)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('sys.stderr', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.activate_session')
|
||||
@mock.patch('koji_cli._import_comps')
|
||||
@mock.patch('koji_cli._import_comps_alt')
|
||||
def test_handle_import_comps_help(
|
||||
self,
|
||||
mock_import_comps_alt, mock_import_comps,
|
||||
mock_activate_session,
|
||||
stderr,
|
||||
stdout):
|
||||
args = []
|
||||
progname = os.path.basename(sys.argv[0]) or 'koji'
|
||||
options = mock.MagicMock()
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
|
||||
# Run it and check immediate output
|
||||
with self.assertRaises(SystemExit) as cm:
|
||||
rv = cli.handle_import_comps(options, session, args)
|
||||
actual_stdout = stdout.getvalue()
|
||||
actual_stderr = stderr.getvalue()
|
||||
expected_stdout = ''
|
||||
expected_stderr = """Usage: %s import-comps [options] <file> <tag>
|
||||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
%s: error: Incorrect number of arguments
|
||||
""" % (progname, progname)
|
||||
self.assertMultiLineEqual(actual_stdout, expected_stdout)
|
||||
self.assertMultiLineEqual(actual_stderr, expected_stderr)
|
||||
|
||||
# Finally, assert that things were called as we expected.
|
||||
mock_activate_session.assert_not_called()
|
||||
session.getTag.assert_not_called()
|
||||
session.getTagGroups.assert_not_called()
|
||||
session.groupListAdd.assert_not_called()
|
||||
self.assertEqual(cm.exception.code, 2)
|
||||
|
||||
@unittest.skipIf(libcomps is None, "No libcomps")
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
def test_import_comps_libcomps(self, stdout):
|
||||
comps_file = os.path.dirname(__file__) + '/data/comps-example.xml'
|
||||
stdout_file = os.path.dirname(
|
||||
__file__) + '/data/comps-example.libcomps.out'
|
||||
calls_file = os.path.dirname(
|
||||
__file__) + '/data/comps-example.libcomps.calls'
|
||||
self._test_import_comps(
|
||||
cli._import_comps,
|
||||
comps_file,
|
||||
stdout_file,
|
||||
calls_file,
|
||||
stdout)
|
||||
|
||||
@unittest.skipIf(libcomps is None, "No libcomps")
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
def test_import_comps_sample_libcomps(self, stdout):
|
||||
comps_file = os.path.dirname(__file__) + '/data/comps-sample.xml'
|
||||
stdout_file = os.path.dirname(
|
||||
__file__) + '/data/comps-sample.libcomps.out'
|
||||
calls_file = os.path.dirname(
|
||||
__file__) + '/data/comps-sample.libcomps.calls'
|
||||
self._test_import_comps(
|
||||
cli._import_comps,
|
||||
comps_file,
|
||||
stdout_file,
|
||||
calls_file,
|
||||
stdout)
|
||||
|
||||
@unittest.skipIf(yumcomps is None, "No yum.comps")
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.libcomps', new=None)
|
||||
@mock.patch('koji_cli.yumcomps', create=True, new=yumcomps)
|
||||
def test_import_comps_yumcomps(self, stdout):
|
||||
comps_file = os.path.dirname(__file__) + '/data/comps-example.xml'
|
||||
stdout_file = os.path.dirname(
|
||||
__file__) + '/data/comps-example.yumcomps.out'
|
||||
calls_file = os.path.dirname(
|
||||
__file__) + '/data/comps-example.yumcomps.calls'
|
||||
self._test_import_comps(
|
||||
cli._import_comps_alt,
|
||||
comps_file,
|
||||
stdout_file,
|
||||
calls_file,
|
||||
stdout)
|
||||
|
||||
@unittest.skipIf(yumcomps is None, "No yum.comps")
|
||||
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
|
||||
@mock.patch('koji_cli.libcomps', new=None)
|
||||
@mock.patch('koji_cli.yumcomps', create=True, new=yumcomps)
|
||||
def test_import_comps_sample_yumcomps(self, stdout):
|
||||
comps_file = os.path.dirname(__file__) + '/data/comps-sample.xml'
|
||||
stdout_file = os.path.dirname(
|
||||
__file__) + '/data/comps-sample.yumcomps.out'
|
||||
calls_file = os.path.dirname(
|
||||
__file__) + '/data/comps-sample.yumcomps.calls'
|
||||
self._test_import_comps(
|
||||
cli._import_comps_alt,
|
||||
comps_file,
|
||||
stdout_file,
|
||||
calls_file,
|
||||
stdout)
|
||||
|
||||
def _test_import_comps(
|
||||
self,
|
||||
method,
|
||||
comps_file,
|
||||
stdout_file,
|
||||
calls_file,
|
||||
stdout):
|
||||
tag = 'tag'
|
||||
force = None
|
||||
options = {'force': force}
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
|
||||
# Run it and check immediate output
|
||||
# args: comps.xml, tag
|
||||
# expected: success
|
||||
rv = method.__call__(session, comps_file, tag, options)
|
||||
expected = ''
|
||||
with open(stdout_file, 'rb') as f:
|
||||
expected = f.read().decode('ascii')
|
||||
self.assertMultiLineEqual(stdout.getvalue(), expected)
|
||||
# compare mock_calls by literal string
|
||||
with open(calls_file, 'rb') as f:
|
||||
expected = f.read().decode('ascii')
|
||||
self.assertMultiLineEqual(str(session.mock_calls) + '\n', expected)
|
||||
self.assertNotEqual(rv, 1)
|
||||
|
||||
|
||||
def _generate_out_calls(method, comps_file, stdout_file, calls_file):
|
||||
tag = 'tag'
|
||||
force = None
|
||||
options = {'force': force}
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
session = mock.MagicMock()
|
||||
|
||||
with open(stdout_file, 'wb') as f:
|
||||
# redirect stdout to stdout_file
|
||||
orig_stdout = sys.stdout
|
||||
sys.stdout = f
|
||||
# args: comps.xml, tag
|
||||
# expected: success
|
||||
method.__call__(session, comps_file, tag, options)
|
||||
sys.stdout = orig_stdout
|
||||
with open(calls_file, 'wb') as f:
|
||||
f.write(str(session.mock_calls).encode('ascii') + '\n')
|
||||
|
||||
|
||||
def generate_out_calls():
|
||||
"""Generate .out and .calls files for tests.
|
||||
These files should be carefully check to make sure they're excepted"""
|
||||
path = os.path.dirname(__file__)
|
||||
|
||||
comps_file = path + '/data/comps-example.xml'
|
||||
stdout_file = path + '/data/comps-example.libcomps.out'
|
||||
calls_file = path + '/data/comps-example.libcomps.calls'
|
||||
_generate_out_calls(cli._import_comps, comps_file, stdout_file, calls_file)
|
||||
|
||||
comps_file = path + '/data/comps-sample.xml'
|
||||
stdout_file = path + '/data/comps-sample.libcomps.out'
|
||||
calls_file = path + '/data/comps-sample.libcomps.calls'
|
||||
_generate_out_calls(cli._import_comps, comps_file, stdout_file, calls_file)
|
||||
|
||||
cli.yumcomps = yumcomps
|
||||
|
||||
comps_file = path + '/data/comps-example.xml'
|
||||
stdout_file = path + '/data/comps-example.yumcomps.out'
|
||||
calls_file = path + '/data/comps-example.yumcomps.calls'
|
||||
_generate_out_calls(cli._import_comps_alt, comps_file, stdout_file, calls_file)
|
||||
|
||||
comps_file = path + '/data/comps-sample.xml'
|
||||
stdout_file = path + '/data/comps-sample.yumcomps.out'
|
||||
calls_file = path + '/data/comps-sample.yumcomps.calls'
|
||||
_generate_out_calls(cli._import_comps_alt, comps_file, stdout_file, calls_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue