From 7f946b37bef689988392eda91f2d42625c97b017 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:21 +0000 Subject: [PATCH 1/61] python-modernize -f libmodernize.fixes.fix_xrange_six --- diff --git a/cli/koji b/cli/koji index 05c3e93..f851679 100755 --- a/cli/koji +++ b/cli/koji @@ -24,7 +24,9 @@ # Mike Bonnet # Cristian Balint +from __future__ import absolute_import import sys +from six.moves import range try: import krbV except ImportError: # pragma: no cover @@ -2119,7 +2121,7 @@ def handle_prune_signed_copies(options, session, args): timeline.sort() #find most recent creation entry for our build and crop there latest_ts = None - for i in xrange(len(timeline)-1, -1, -1): + for i in range(len(timeline)-1, -1, -1): #searching in reverse cronological order event_id, is_create, entry = timeline[i] if entry['build_id'] == binfo['id'] and is_create: diff --git a/hub/kojihub.py b/hub/kojihub.py index e3afce1..b33a2d6 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -22,6 +22,7 @@ # Mike Bonnet # Cristian Balint +from __future__ import absolute_import import base64 import calendar import cgi @@ -56,6 +57,7 @@ import types import xmlrpclib import zipfile from koji.context import context +from six.moves import range try: import json diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index 53cd229..1991d5a 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -18,6 +18,7 @@ # Authors: # Mike McLean +from __future__ import absolute_import from ConfigParser import RawConfigParser import datetime import inspect @@ -40,6 +41,7 @@ import koji.plugin import koji.policy import koji.util from koji.context import context +from six.moves import range # Workaround to allow xmlrpclib deal with iterators diff --git a/koji/__init__.py b/koji/__init__.py index 84aceb0..d26bdef 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -21,7 +21,9 @@ # Mike McLean # Mike Bonnet +from __future__ import absolute_import import sys +from six.moves import range try: import krbV except ImportError: # pragma: no cover @@ -528,7 +530,7 @@ def multibyte(data): """Convert a list of bytes to an integer (network byte order)""" sum = 0 n = len(data) - for i in xrange(n): + for i in range(n): sum += data[i] << (8 * (n - i - 1)) return sum @@ -606,9 +608,9 @@ class RawHeader(object): #read the index (starts at offset 16) index = {} - for i in xrange(il): + for i in range(il): entry = [] - for j in xrange(4): + for j in range(4): ofs = 16 + i*16 + j*4 data = [ord(x) for x in self.header[ofs:ofs+4]] entry.append(multibyte(data)) @@ -653,14 +655,14 @@ class RawHeader(object): next = pos elif dtype == 1: #char - for i in xrange(count): + for i in range(count): print("Char: %r" % self.header[pos]) pos += 1 next = pos elif dtype >= 2 and dtype <= 5: #integer n = 1 << (dtype - 2) - for i in xrange(count): + for i in range(count): data = [ord(x) for x in self.header[pos:pos+n]] print("%r" % data) num = multibyte(data) @@ -677,14 +679,14 @@ class RawHeader(object): next = pos+count elif dtype == 8: # string array - for i in xrange(count): + for i in range(count): end = self.header.find('\0', pos) print("String(%d): %r" % (end-pos, self.header[pos:end])) pos = end + 1 next = pos elif dtype == 9: # unicode string array - for i in xrange(count): + for i in range(count): end = self.header.find('\0', pos) print("i18n(%d): %r" % (end-pos, self.header[pos:end])) pos = end + 1 @@ -1754,7 +1756,7 @@ def get_profile_module(profile_name, config=None): class PathInfo(object): # ASCII numbers and upper- and lower-case letter for use in tmpdir() - ASCII_CHARS = [chr(i) for i in range(48, 58) + range(65, 91) + range(97, 123)] + ASCII_CHARS = [chr(i) for i in list(range(48, 58)) + list(range(65, 91)) + list(range(97, 123))] def __init__(self, topdir=None): self._topdir = topdir diff --git a/koji/auth.py b/koji/auth.py index 6044590..69cfca5 100644 --- a/koji/auth.py +++ b/koji/auth.py @@ -19,6 +19,7 @@ # Mike McLean # Mike Bonnet +from __future__ import absolute_import import socket import string import random @@ -27,6 +28,7 @@ import krbV import koji import cgi #for parse_qs from context import context +from six.moves import range # 1 - load session if provided # - check uri for session id diff --git a/koji/context.py b/koji/context.py index 56a79f7..03e22ed 100755 --- a/koji/context.py +++ b/koji/context.py @@ -24,7 +24,9 @@ # - request data # - auth data +from __future__ import absolute_import import thread +from six.moves import range class _data(object): pass @@ -97,7 +99,7 @@ if __name__ == '__main__': context._threadclear() print(context) - for x in xrange(1, 10): + for x in range(1, 10): thread.start_new_thread(test, ()) time.sleep(4) diff --git a/koji/daemon.py b/koji/daemon.py index 637566f..355a4cf 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -20,6 +20,7 @@ # Mike McLean # Mike Bonnet +from __future__ import absolute_import import koji import koji.tasks from koji.tasks import safe_rmtree @@ -35,6 +36,7 @@ import sys import traceback import errno import xmlrpclib +from six.moves import range def incremental_upload(session, fname, fd, path, retries=5, logger=None): @@ -664,7 +666,7 @@ class TaskManager(object): fo = file(fn, 'r') id = None name = None - for n in xrange(10): + for n in range(10): # data should be in first few lines line = fo.readline() if line.startswith('# Koji buildroot id:'): diff --git a/koji/tasks.py b/koji/tasks.py index 9591c23..8245cab 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -20,6 +20,7 @@ # Mike McLean # Mike Bonnet +from __future__ import absolute_import import koji import koji.util import os @@ -31,6 +32,7 @@ import shutil import random import time import pprint +from six.moves import range def scan_mounts(topdir): """Search path for mountpoints""" @@ -402,7 +404,7 @@ class SleepTask(BaseTaskHandler): class ForkTask(BaseTaskHandler): Methods = ['fork'] def handler(self, n=5, m=37): - for i in xrange(n): + for i in range(n): os.spawnvp(os.P_NOWAIT, 'sleep', ['sleep', str(m)]) class WaitTestTask(BaseTaskHandler): @@ -417,7 +419,7 @@ class WaitTestTask(BaseTaskHandler): _taskWeight = 0.1 def handler(self, count, seconds=10): tasks = [] - for i in xrange(count): + for i in range(count): task_id = self.subtask(method='sleep', arglist=[seconds], label=str(i), parent=self.id) tasks.append(task_id) bad_task = self.subtask('sleep', ['BAD_ARG'], label='bad') diff --git a/koji/util.py b/koji/util.py index f3d867f..5a3c7b9 100644 --- a/koji/util.py +++ b/koji/util.py @@ -18,6 +18,7 @@ # Mike McLean # Mike Bonnet +from __future__ import absolute_import import calendar from fnmatch import fnmatch import koji @@ -32,6 +33,7 @@ import sys import time import ConfigParser from zlib import adler32 +from six.moves import range # imported from kojiweb and kojihub try: diff --git a/tests/test_builder/test_choose_taskarch.py b/tests/test_builder/test_choose_taskarch.py index 2bce61d..129b89d 100644 --- a/tests/test_builder/test_choose_taskarch.py +++ b/tests/test_builder/test_choose_taskarch.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import os import sys @@ -7,6 +8,7 @@ import tempfile import koji from loadkojid import kojid +from six.moves import range class FakeHeader(dict): diff --git a/tests/test_cli/test_unique_path.py b/tests/test_cli/test_unique_path.py index f203581..e812775 100644 --- a/tests/test_cli/test_unique_path.py +++ b/tests/test_cli/test_unique_path.py @@ -1,6 +1,8 @@ +from __future__ import absolute_import import unittest import loadcli +from six.moves import range cli = loadcli.cli diff --git a/tests/test_cli/test_watch_tasks.py b/tests/test_cli/test_watch_tasks.py index 6ab971d..d9e7ce5 100644 --- a/tests/test_cli/test_watch_tasks.py +++ b/tests/test_cli/test_watch_tasks.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import os @@ -9,6 +10,7 @@ import mock from mock import call import loadcli +from six.moves import range cli = loadcli.cli @@ -64,7 +66,7 @@ class TestWatchTasks(unittest.TestCase): def side_effect(*args, **kwargs): rt = None - if args[0] not in range(2): + if args[0] not in list(range(2)): rt = mock.MagicMock() rt.level = args[2] rt.is_done.return_value = True @@ -76,7 +78,7 @@ class TestWatchTasks(unittest.TestCase): return rt twClzMock.side_effect = side_effect - rv = cli.watch_tasks(self.session, range(2), quiet=False) + rv = cli.watch_tasks(self.session, list(range(2)), quiet=False) actual = stdout.getvalue() self.assertMultiLineEqual( actual, "Watching tasks (this may be safely interrupted)...\n\n") @@ -201,7 +203,7 @@ class TestWatchTasks(unittest.TestCase): def side_effect(*args, **kwargs): rt = None - if args[0] not in range(2): + if args[0] not in list(range(2)): rt = mock.MagicMock() rt.level = args[2] rt.is_done.return_value = True @@ -215,7 +217,7 @@ class TestWatchTasks(unittest.TestCase): twClzMock.side_effect = side_effect with self.assertRaises(KeyboardInterrupt): - cli.watch_tasks(self.session, range(2), quiet=False) + cli.watch_tasks(self.session, list(range(2)), quiet=False) actual = stdout.getvalue() self.assertMultiLineEqual( diff --git a/tests/test_profiles.py b/tests/test_profiles.py index ef53a50..3903db1 100644 --- a/tests/test_profiles.py +++ b/tests/test_profiles.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import import unittest import koji import sys import threading import traceback +from six.moves import range class ProfilesTestCase(unittest.TestCase): @@ -14,7 +16,7 @@ class ProfilesTestCase(unittest.TestCase): # loop a few times to increase chances of hitting race conditions for i in range(20): errors = {} - threads = [threading.Thread(target=stress, args=(errors, _)) for _ in xrange(100)] + threads = [threading.Thread(target=stress, args=(errors, _)) for _ in range(100)] for t in threads: t.start() for t in threads: diff --git a/util/koji-shadow b/util/koji-shadow index 233d33d..e06b61d 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -22,6 +22,8 @@ # Dennis Gilmore # Karsten Hopp +from __future__ import absolute_import +from six.moves import range try: import krbV except ImportError: # pragma: no cover @@ -861,7 +863,7 @@ class BuildTracker(object): taginfo = remote.getTag(tag) builds = remote.listTagged(taginfo['id'], latest=True) for build in builds: - for retry in xrange(10): + for retry in range(10): try: self.scanBuild(build['id'], tag=tag) if options.first_one: diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py index 49ea24b..9d27f44 100644 --- a/www/kojiweb/index.py +++ b/www/kojiweb/index.py @@ -20,6 +20,7 @@ # Mike Bonnet # Mike McLean +from __future__ import absolute_import import os import os.path import re @@ -36,6 +37,7 @@ from kojiweb.util import _initValues from kojiweb.util import _genHTML from kojiweb.util import _getValidTokens from koji.util import sha1_constructor +from six.moves import range # Convenience definition of a commonly-used sort function _sortbyname = kojiweb.util.sortByKeyFunc('name') @@ -809,7 +811,7 @@ def tags(environ, start=None, order=None, childID=None): return _genHTML(environ, 'tags.chtml') -_PREFIX_CHARS = [chr(char) for char in range(48, 58) + range(97, 123)] +_PREFIX_CHARS = [chr(char) for char in list(range(48, 58)) + list(range(97, 123))] def packages(environ, tagID=None, userID=None, order='package_name', start=None, prefix=None, inherited='1'): values = _initValues(environ, 'Packages', 'packages') diff --git a/www/lib/kojiweb/util.py b/www/lib/kojiweb/util.py index 6cdcecc..4201297 100644 --- a/www/lib/kojiweb/util.py +++ b/www/lib/kojiweb/util.py @@ -20,6 +20,7 @@ # Mike Bonnet # Mike McLean +from __future__ import absolute_import import Cheetah.Template import datetime import koji @@ -32,6 +33,7 @@ from socket import sslerror as socket_sslerror from xmlrpclib import ProtocolError from xml.parsers.expat import ExpatError import cgi +from six.moves import range class NoSuchException(Exception): pass From 0eaf3349c4d09dbf9131c7417c1164c21f15db65 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:21 +0000 Subject: [PATCH 2/61] python-modernize -f libmodernize.fixes.fix_zip --- diff --git a/builder/kojid b/builder/kojid index 235cbeb..6d786a1 100755 --- a/builder/kojid +++ b/builder/kojid @@ -21,6 +21,8 @@ # Mike McLean # Mike Bonnet +from __future__ import absolute_import +from six.moves import zip try: import krbV except ImportError: # pragma: no cover @@ -4758,7 +4760,7 @@ Build Info: %(weburl)s/buildinfo?buildID=%(build_id)i\r def uniq(self, items): """Remove duplicates from the list of items, and sort the list.""" - m = dict(zip(items, [1] * len(items))) + m = dict(list(zip(items, [1] * len(items)))) l = m.keys() l.sort() return l diff --git a/cli/koji b/cli/koji index f851679..3dafd7e 100755 --- a/cli/koji +++ b/cli/koji @@ -27,6 +27,7 @@ from __future__ import absolute_import import sys from six.moves import range +from six.moves import zip try: import krbV except ImportError: # pragma: no cover diff --git a/hub/kojihub.py b/hub/kojihub.py index b33a2d6..144f6c0 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -58,6 +58,7 @@ import xmlrpclib import zipfile from koji.context import context from six.moves import range +from six.moves import zip try: import json @@ -492,7 +493,7 @@ def make_task(method, arglist, **opts): r = _fetchSingle(q, opts) if not r: raise koji.GenericError("Invalid parent task: %(parent)s" % opts) - pdata = dict(zip(fields, r)) + pdata = dict(list(zip(fields, r))) if pdata['state'] != koji.TASK_STATES['OPEN']: raise koji.GenericError("Parent task (id %(parent)s) is not open" % opts) #default to a higher priority than parent @@ -603,7 +604,7 @@ def readGlobalInheritance(event=None): """ % (",".join(fields), eventCondition(event)) c.execute(q, locals()) #convert list of lists into a list of dictionaries - return [dict(zip(fields, x)) for x in c.fetchall()] + return [dict(list(zip(fields, x))) for x in c.fetchall()] def readInheritanceData(tag_id, event=None): c = context.cnx.cursor() @@ -614,7 +615,7 @@ def readInheritanceData(tag_id, event=None): """ % (",".join(fields), eventCondition(event)) c.execute(q, locals()) #convert list of lists into a list of dictionaries - data = [dict(zip(fields, x)) for x in c.fetchall()] + data = [dict(list(zip(fields, x))) for x in c.fetchall()] # include the current tag_id as child_id, so we can retrace the inheritance chain later for datum in data: datum['child_id'] = tag_id @@ -629,7 +630,7 @@ def readDescendantsData(tag_id, event=None): """ % (",".join(fields), eventCondition(event)) c.execute(q, locals()) #convert list of lists into a list of dictionaries - data = [dict(zip(fields, x)) for x in c.fetchall()] + data = [dict(list(zip(fields, x))) for x in c.fetchall()] return data @@ -1308,7 +1309,7 @@ def readTaggedRPMS(tag, package=None, arch=None, event=None, inherit=False, late else: raise koji.GenericError('invalid arch option: %s' % arch) - fields, aliases = zip(*fields) + fields, aliases = list(zip(*fields)) query = QueryProcessor(tables=tables, joins=joins, clauses=clauses, columns=fields, aliases=aliases, values=data, transform=_fix_rpm_row) @@ -2141,7 +2142,7 @@ def get_ready_hosts(): """ % ','.join(fields) # XXX - magic number in query c.execute(q) - hosts = [dict(zip(aliases, row)) for row in c.fetchall()] + hosts = [dict(list(zip(aliases, row))) for row in c.fetchall()] for host in hosts: q = """SELECT channel_id FROM host_channels WHERE host_id=%(id)s""" c.execute(q, host) @@ -2420,7 +2421,7 @@ def _write_maven_repo_metadata(destdir, artifacts): # group_id and artifact_id should be the same for all entries, # so we're really only comparing versions. artifacts = sorted(artifacts, cmp=lambda a, b: rpm.labelCompare(a, b)) - artifactinfo = dict(zip(['group_id', 'artifact_id', 'version'], artifacts[-1])) + artifactinfo = dict(list(zip(['group_id', 'artifact_id', 'version'], artifacts[-1]))) artifactinfo['timestamp'] = datetime.datetime.now().strftime('%Y%m%d%H%M%S') contents = """ @@ -2547,7 +2548,7 @@ def repo_references(repo_id): 'host_id': 'host_id', 'create_event': 'create_event', 'state': 'state'} - fields, aliases = zip(*fields.items()) + fields, aliases = list(zip(*fields.items())) values = {'repo_id': repo_id} clauses = ['repo_id=%(repo_id)s', 'retire_event IS NULL'] query = QueryProcessor(columns=fields, aliases=aliases, tables=['standard_buildroot'], @@ -2977,7 +2978,7 @@ def get_tag(tagInfo, strict=False, event=None): raise koji.GenericError('invalid type for tagInfo: %s' % type(tagInfo)) data = {'tagInfo': tagInfo} - fields, aliases = zip(*fields.items()) + fields, aliases = list(zip(*fields.items())) query = QueryProcessor(columns=fields, aliases=aliases, tables=tables, joins=joins, clauses=clauses, values=data) result = query.executeOne() @@ -3519,7 +3520,7 @@ def get_build(buildInfo, strict=False): ('users.id', 'owner_id'), ('users.name', 'owner_name'), ('build.source', 'source'), ('build.extra', 'extra')) - fields, aliases = zip(*fields) + fields, aliases = list(zip(*fields)) joins = ['events ON build.create_event = events.id', 'package on build.pkg_id = package.id', 'volume on build.volume_id = volume.id', @@ -3754,7 +3755,7 @@ def list_rpms(buildID=None, buildrootID=None, imageID=None, componentBuildrootID else: raise koji.GenericError('invalid type for "arches" parameter: %s' % type(arches)) - fields, aliases = zip(*fields) + fields, aliases = list(zip(*fields)) query = QueryProcessor(columns=fields, aliases=aliases, tables=['rpminfo'], joins=joins, clauses=clauses, values=locals(), transform=_fix_rpm_row, opts=queryOpts) @@ -4079,7 +4080,7 @@ def list_archives(buildID=None, buildrootID=None, componentBuildrootID=None, hos clauses.append('archiveinfo.btype_id = %(btype_id)s') values['btype_id'] = btype['id'] - columns, aliases = zip(*fields) + columns, aliases = list(zip(*fields)) ret = QueryProcessor(tables=tables, columns=columns, aliases=aliases, joins=joins, transform=_fix_archive_row, clauses=clauses, values=values, opts=queryOpts).execute() @@ -4398,7 +4399,7 @@ def _multiRow(query, values, fields): as a list of maps. Each map in the list will have a key for each element in the "fields" list. If there are no results, an empty list will be returned.""" - return [dict(zip(fields, row)) for row in _fetchMulti(query, values)] + return [dict(list(zip(fields, row))) for row in _fetchMulti(query, values)] def _singleRow(query, values, fields, strict=False): """Return a single row from "query". Named parameters can be @@ -4410,7 +4411,7 @@ def _singleRow(query, values, fields, strict=False): returned.""" row = _fetchSingle(query, values, strict) if row: - return dict(zip(fields, row)) + return dict(list(zip(fields, row))) else: #strict enforced by _fetchSingle return None @@ -6706,7 +6707,7 @@ def query_history(tables=None, **kwargs): fields[r_test] = '_revoked_before_event' if skip: continue - fields, aliases = zip(*fields.items()) + fields, aliases = list(zip(*fields.items())) query = QueryProcessor(columns=fields, aliases=aliases, tables=[table], joins=joins, clauses=clauses, values=data) ret[table] = query.iterate() @@ -7600,7 +7601,7 @@ class QueryProcessor(object): if columns and aliases: if len(columns) != len(aliases): raise Exception('column and alias lists must be the same length') - self.colsByAlias = dict(zip(aliases, columns)) + self.colsByAlias = dict(list(zip(aliases, columns))) else: self.colsByAlias = {} self.tables = tables @@ -10432,7 +10433,7 @@ class RootExports(object): #XXX hard-coded interval c = context.cnx.cursor() c.execute(q, koji.TASK_STATES) - return [dict(zip([f[1] for f in fields], row)) for row in c.fetchall()] + return [dict(list(zip([f[1] for f in fields], row))) for row in c.fetchall()] def resubmitTask(self, taskID): """Retry a canceled or failed task, using the same parameter as the original task. @@ -11138,7 +11139,7 @@ class BuildRoot(object): ('checksum_type', 'checksum_type'), ('project_dep', 'project_dep'), ] - columns, aliases = zip(*fields) + columns, aliases = list(zip(*fields)) query = QueryProcessor(tables=tables, columns=columns, joins=joins, clauses=clauses, values=self.data, @@ -11316,7 +11317,7 @@ class Host(object): WHERE host_id = %%(host_id)s AND state = %%(st_open)s """ % (",".join(fields)) c.execute(q, locals()) - tasks = [dict(zip(fields, x)) for x in c.fetchall()] + tasks = [dict(list(zip(fields, x))) for x in c.fetchall()] for task in tasks: id = task['id'] if task['waiting']: @@ -11378,7 +11379,7 @@ class Host(object): """ % (",".join(fields)) c.execute(q, locals()) for data in c.fetchall(): - data = dict(zip(fields, data)) + data = dict(list(zip(fields, data))) # XXX - we should do some pruning here, but for now... # check arch if data['arch'] not in arches: diff --git a/hub/rpmdiff b/hub/rpmdiff index 7ef9562..4536a9d 100755 --- a/hub/rpmdiff +++ b/hub/rpmdiff @@ -20,11 +20,13 @@ # This library and program is heavily based on rpmdiff from the rpmlint package # It was modified to be used as standalone library for the Koji project. +from __future__ import absolute_import import rpm import os import itertools import sys, getopt +from six.moves import zip class Rpmdiff: @@ -175,8 +177,8 @@ class Rpmdiff: if not isinstance(oldflags, list): oldflags = [ oldflags ] if not isinstance(newflags, list): newflags = [ newflags ] - o = zip(old[name], oldflags, old[name[:-1]+'VERSION']) - n = zip(new[name], newflags, new[name[:-1]+'VERSION']) + o = list(zip(old[name], oldflags, old[name[:-1]+'VERSION'])) + n = list(zip(new[name], newflags, new[name[:-1]+'VERSION'])) if name == 'PROVIDES': # filter our self provide oldNV = (old['name'], rpm.RPMSENSE_EQUAL, diff --git a/koji/__init__.py b/koji/__init__.py index d26bdef..f938692 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -24,6 +24,7 @@ from __future__ import absolute_import import sys from six.moves import range +from six.moves import zip try: import krbV except ImportError: # pragma: no cover @@ -446,7 +447,7 @@ def decode_args2(args, names, strict=True): args, opts = decode_args(*args) if strict and len(names) < len(args): raise TypeError("Expecting at most %i arguments" % len(names)) - ret = dict(zip(names, args)) + ret = dict(list(zip(names, args))) ret.update(opts) return ret @@ -2139,7 +2140,7 @@ class ClientSession(object): # decode and decrypt the login info sinfo_priv = base64.decodestring(sinfo_enc) sinfo_str = ac.rd_priv(sinfo_priv) - sinfo = dict(zip(['session-id', 'session-key'], sinfo_str.split())) + sinfo = dict(list(zip(['session-id', 'session-key'], sinfo_str.split()))) if not sinfo: self.logger.warn('No session info received') diff --git a/koji/auth.py b/koji/auth.py index 69cfca5..3c7b1bf 100644 --- a/koji/auth.py +++ b/koji/auth.py @@ -29,6 +29,7 @@ import koji import cgi #for parse_qs from context import context from six.moves import range +from six.moves import zip # 1 - load session if provided # - check uri for session id @@ -98,7 +99,7 @@ class Session(object): 'EXTRACT(EPOCH FROM update_time)': 'update_ts', 'user_id': 'user_id', } - fields, aliases = zip(*fields.items()) + fields, aliases = list(zip(*fields.items())) q = """ SELECT %s FROM sessions WHERE id = %%(id)i @@ -110,7 +111,7 @@ class Session(object): row = c.fetchone() if not row: raise koji.AuthError('Invalid session or bad credentials') - session_data = dict(zip(aliases, row)) + session_data = dict(list(zip(aliases, row))) #check for expiration if session_data['expired']: raise koji.AuthExpired('session "%i" has expired' % id) @@ -148,7 +149,7 @@ class Session(object): fields = ('name', 'status', 'usertype') q = """SELECT %s FROM users WHERE id=%%(user_id)s""" % ','.join(fields) c.execute(q, session_data) - user_data = dict(zip(fields, c.fetchone())) + user_data = dict(list(zip(fields, c.fetchone()))) if user_data['status'] != koji.USER_STATUS['NORMAL']: raise koji.AuthError('logins by %s are not allowed' % user_data['name']) @@ -699,7 +700,7 @@ def get_user_data(user_id): row = c.fetchone() if not row: return None - return dict(zip(fields, row)) + return dict(list(zip(fields, row))) def login(*args, **opts): return context.session.login(*args, **opts) diff --git a/util/koji-gc b/util/koji-gc index bea2cd3..5fb1e23 100755 --- a/util/koji-gc +++ b/util/koji-gc @@ -6,6 +6,8 @@ # Authors: # Mike McLean +from __future__ import absolute_import +from six.moves import zip try: import krbV except ImportError: # pragma: no cover diff --git a/util/koji-shadow b/util/koji-shadow index e06b61d..a951771 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -24,6 +24,7 @@ from __future__ import absolute_import from six.moves import range +from six.moves import zip try: import krbV except ImportError: # pragma: no cover diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py index 9d27f44..9b03499 100644 --- a/www/kojiweb/index.py +++ b/www/kojiweb/index.py @@ -38,6 +38,7 @@ from kojiweb.util import _genHTML from kojiweb.util import _getValidTokens from koji.util import sha1_constructor from six.moves import range +from six.moves import zip # Convenience definition of a commonly-used sort function _sortbyname = kojiweb.util.sortByKeyFunc('name') From c579e36489dc72039ab7490d7910f0bb45d67d10 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:21 +0000 Subject: [PATCH 3/61] python-modernize -f libmodernize.fixes.fix_unicode_type --- diff --git a/hub/kojihub.py b/hub/kojihub.py index 144f6c0..aef3918 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -59,6 +59,7 @@ import zipfile from koji.context import context from six.moves import range from six.moves import zip +import six try: import json @@ -2795,7 +2796,7 @@ def lookup_name(table, info, strict=False, create=False): q = """SELECT id,name FROM %s WHERE id=%%(info)d""" % table elif isinstance(info, str): q = """SELECT id,name FROM %s WHERE name=%%(info)s""" % table - elif isinstance(info, unicode): + elif isinstance(info, six.text_type): info = koji.fixEncoding(info) q = """SELECT id,name FROM %s WHERE name=%%(info)s""" % table else: @@ -5132,7 +5133,7 @@ class CG_Importer(object): if metadata is None: #default to looking for uploaded file metadata = 'metadata.json' - if not isinstance(metadata, (str, unicode)): + if not isinstance(metadata, (str, six.text_type)): raise koji.GenericError("Invalid metadata value: %r" % metadata) if metadata.endswith('.json'): # handle uploaded metadata @@ -9341,7 +9342,7 @@ class RootExports(object): if before: if isinstance(before, datetime.datetime): before = calendar.timegm(before.utctimetuple()) - elif isinstance(before, (str, unicode)): + elif isinstance(before, (str, six.text_type)): before = koji.util.parseTime(before) elif isinstance(before, (int, long)): pass @@ -9351,7 +9352,7 @@ class RootExports(object): if after: if isinstance(after, datetime.datetime): after = calendar.timegm(after.utctimetuple()) - elif isinstance(after, (str, unicode)): + elif isinstance(after, (str, six.text_type)): after = koji.util.parseTime(after) elif isinstance(after, (int, long)): pass diff --git a/koji/__init__.py b/koji/__init__.py index f938692..b2ed1d3 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -25,6 +25,7 @@ from __future__ import absolute_import import sys from six.moves import range from six.moves import zip +import six try: import krbV except ImportError: # pragma: no cover @@ -550,7 +551,7 @@ def rpm_hdr_size(f, ofs=None): f = filename or file object ofs = offset of the header """ - if isinstance(f, (str, unicode)): + if isinstance(f, (str, six.text_type)): fo = file(f, 'rb') else: fo = f @@ -580,7 +581,7 @@ def rpm_hdr_size(f, ofs=None): # add eight bytes for section header hdrsize = hdrsize + 8 - if not isinstance(f, (str, unicode)): + if not isinstance(f, (str, six.text_type)): fo.close() return hdrsize @@ -870,7 +871,7 @@ def get_rpm_header(f, ts=None): if ts is None: ts = rpm.TransactionSet() ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS) - if isinstance(f, (str, unicode)): + if isinstance(f, (str, six.text_type)): fo = file(f, "r") else: fo = f @@ -2912,7 +2913,7 @@ def fixEncoding(value, fallback='iso8859-15', remove_nonprintable=False): if not value: return '' - if isinstance(value, unicode): + if isinstance(value, six.text_type): # value is already unicode, so just convert it # to a utf8-encoded str s = value.encode('utf8') @@ -2946,7 +2947,7 @@ def fixEncodingRecurse(value, fallback='iso8859-15', remove_nonprintable=False): k = fixEncodingRecurse(k, fallback=fallback, remove_nonprintable=remove_nonprintable) ret[k] = v return ret - elif isinstance(value, unicode): + elif isinstance(value, six.text_type): if remove_nonprintable: return removeNonprintable(value.encode('utf8')) else: diff --git a/tests/test_tasks.py b/tests/test_tasks.py index c66d5f6..28ab75b 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import random from io import StringIO from os import path, makedirs @@ -10,12 +11,13 @@ import koji from koji.tasks import BaseTaskHandler, FakeTask, ForkTask, SleepTask, \ WaitTestTask, scan_mounts, umount_all, \ safe_rmtree +import six def get_fake_mounts_file(): """ Returns contents of /prc/mounts in a file-like object """ - return StringIO(unicode(( + return StringIO(six.text_type(( 'sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' 'proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0\n' 'devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=238836k,nr_inodes=59709,mode=755 0 0\n' @@ -460,7 +462,7 @@ class TasksTestCase(TestCase): obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) self.assertEquals(obj.localPath('test.txt'), dummy_file) - @patch('urllib2.urlopen', return_value=StringIO(unicode('Important things\nSome more important things\n'))) + @patch('urllib2.urlopen', return_value=StringIO(six.text_type('Important things\nSome more important things\n'))) def test_BaseTaskHandler_localPath_no_file(self, mock_urlopen): """ """ diff --git a/www/lib/kojiweb/util.py b/www/lib/kojiweb/util.py index 4201297..3d5212f 100644 --- a/www/lib/kojiweb/util.py +++ b/www/lib/kojiweb/util.py @@ -34,6 +34,7 @@ from xmlrpclib import ProtocolError from xml.parsers.expat import ExpatError import cgi from six.moves import range +import six class NoSuchException(Exception): pass @@ -96,7 +97,7 @@ class DecodeUTF8(Cheetah.Filters.Filter): def filter(self, *args, **kw): """Convert all strs to unicode objects""" result = super(DecodeUTF8, self).filter(*args, **kw) - if isinstance(result, unicode): + if isinstance(result, six.text_type): pass else: result = result.decode('utf-8', 'replace') From 73356b50e5a01d4c2fe7654863a1d981945a1c5b Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:21 +0000 Subject: [PATCH 4/61] fix relative imports --- diff --git a/koji/__init__.py b/koji/__init__.py index b2ed1d3..0aa85c8 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -76,7 +76,7 @@ import traceback import urllib import urllib2 import urlparse -import util +from . import util import warnings import xmlrpclib import xml.sax diff --git a/koji/auth.py b/koji/auth.py index 3c7b1bf..c69a5b4 100644 --- a/koji/auth.py +++ b/koji/auth.py @@ -27,7 +27,7 @@ import base64 import krbV import koji import cgi #for parse_qs -from context import context +from .context import context from six.moves import range from six.moves import zip diff --git a/tests/test_builder/test_choose_taskarch.py b/tests/test_builder/test_choose_taskarch.py index 129b89d..c56c914 100644 --- a/tests/test_builder/test_choose_taskarch.py +++ b/tests/test_builder/test_choose_taskarch.py @@ -1,13 +1,11 @@ from __future__ import absolute_import import unittest -import os -import sys import mock import rpm import tempfile import koji -from loadkojid import kojid +from .loadkojid import kojid from six.moves import range diff --git a/tests/test_cli/test_unique_path.py b/tests/test_cli/test_unique_path.py index e812775..82aeea7 100644 --- a/tests/test_cli/test_unique_path.py +++ b/tests/test_cli/test_unique_path.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import unittest -import loadcli +from . import loadcli from six.moves import range cli = loadcli.cli diff --git a/tests/test_cli/test_watch_tasks.py b/tests/test_cli/test_watch_tasks.py index d9e7ce5..df5349d 100644 --- a/tests/test_cli/test_watch_tasks.py +++ b/tests/test_cli/test_watch_tasks.py @@ -9,7 +9,7 @@ import mock from mock import call -import loadcli +from . import loadcli from six.moves import range cli = loadcli.cli From b1da150c019e2b9b0019c7b27a0d6e036a2e15e0 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:21 +0000 Subject: [PATCH 5/61] python-modernize -f libmodernize.fixes.fix_imports_six --- diff --git a/builder/kojid b/builder/kojid index 6d786a1..6c2d490 100755 --- a/builder/kojid +++ b/builder/kojid @@ -57,11 +57,11 @@ import sys import time import traceback import xml.dom.minidom -import xmlrpclib +import six.moves.xmlrpc_client import zipfile import copy import Cheetah.Template -from ConfigParser import ConfigParser +from six.moves.configparser import ConfigParser from fnmatch import fnmatch from gzip import GzipFile from optparse import OptionParser, SUPPRESS_HELP @@ -1976,7 +1976,7 @@ class ChainMavenTask(MultiPlatformTask): del todo[package] try: results = self.wait(running.keys()) - except (xmlrpclib.Fault, koji.GenericError), e: + except (six.moves.xmlrpc_client.Fault, koji.GenericError), e: # One task has failed, wait for the rest to complete before the # chainmaven task fails. self.wait(all=True) should thrown an exception. self.wait(all=True) @@ -5635,7 +5635,7 @@ if __name__ == "__main__": options.serverca) except koji.AuthError, e: quit("Error: Unable to log in: %s" % e) - except xmlrpclib.ProtocolError: + except six.moves.xmlrpc_client.ProtocolError: quit("Error: Unable to connect to server %s" % (options.server)) elif options.user: try: @@ -5643,7 +5643,7 @@ if __name__ == "__main__": session.login() except koji.AuthError: quit("Error: Unable to log in. Bad credentials?") - except xmlrpclib.ProtocolError: + except six.moves.xmlrpc_client.ProtocolError: quit("Error: Unable to connect to server %s" % (options.server)) elif 'krbV' in sys.modules: krb_principal = options.krb_principal @@ -5669,7 +5669,7 @@ if __name__ == "__main__": #make sure it works try: ret = session.echo("OK") - except xmlrpclib.ProtocolError: + except six.moves.xmlrpc_client.ProtocolError: quit("Error: Unable to connect to server %s" % (options.server)) if ret != ["OK"]: quit("Error: incorrect server response: %r" % (ret)) diff --git a/cli/koji b/cli/koji index 3dafd7e..1c1b1c0 100755 --- a/cli/koji +++ b/cli/koji @@ -43,7 +43,7 @@ except ImportError: # pragma: no cover import simplejson as json except ImportError: json = None -import ConfigParser +import six.moves.configparser import base64 import dateutil.parser import errno @@ -63,7 +63,7 @@ import time import traceback import urlgrabber.grabber as grabber import urlgrabber.progress as progress -import xmlrpclib +import six.moves.xmlrpc_client try: import libcomps except ImportError: # pragma: no cover @@ -278,7 +278,7 @@ def get_options(): def ensure_connection(session): try: ret = session.getAPIVersion() - except xmlrpclib.ProtocolError: + except six.moves.xmlrpc_client.ProtocolError: error(_("Error: Unable to connect to server")) if ret != koji.API_VERSION: warn(_("WARNING: The server is at API version %d and the client is at %d" % (ret, koji.API_VERSION))) @@ -342,7 +342,7 @@ class TaskWatcher(object): error = None try: result = self.session.getTaskResult(self.id) - except (xmlrpclib.Fault,koji.GenericError),e: + except (six.moves.xmlrpc_client.Fault,koji.GenericError),e: error = e if error is None: # print("%s: complete" % self.str()) @@ -5917,7 +5917,7 @@ def handle_image_build(options, session, args): if not os.path.exists(task_options.config): parser.error(_("%s not found!" % task_options.config)) section = 'image-build' - config = ConfigParser.ConfigParser() + config = six.moves.configparser.ConfigParser() conf_fd = open(task_options.config) config.readfp(conf_fd) conf_fd.close() diff --git a/hub/kojihub.py b/hub/kojihub.py index aef3918..627fb78 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -54,7 +54,7 @@ import tarfile import tempfile import time import types -import xmlrpclib +import six.moves.xmlrpc_client import zipfile from koji.context import context from six.moves import range @@ -401,7 +401,7 @@ class Task(object): if xml_request.find(' from __future__ import absolute_import -from ConfigParser import RawConfigParser +from six.moves.configparser import RawConfigParser import datetime import inspect import logging @@ -30,8 +30,8 @@ import traceback import types import pprint import resource -import xmlrpclib -from xmlrpclib import getparser, dumps, Fault +import six.moves.xmlrpc_client +from six.moves.xmlrpc_client import getparser, dumps, Fault from koji.server import WSGIWrapper import koji @@ -45,9 +45,9 @@ from six.moves import range # Workaround to allow xmlrpclib deal with iterators -class Marshaller(xmlrpclib.Marshaller): +class Marshaller(six.moves.xmlrpc_client.Marshaller): - dispatch = xmlrpclib.Marshaller.dispatch.copy() + dispatch = six.moves.xmlrpc_client.Marshaller.dispatch.copy() def dump_generator(self, value, write): dump = self.__dump @@ -63,7 +63,7 @@ class Marshaller(xmlrpclib.Marshaller): self.dump_string(value, write) dispatch[datetime.datetime] = dump_datetime -xmlrpclib.Marshaller = Marshaller +six.moves.xmlrpc_client.Marshaller = Marshaller class HandlerRegistry(object): diff --git a/koji/__init__.py b/koji/__init__.py index 0aa85c8..ef21878 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -33,11 +33,11 @@ except ImportError: # pragma: no cover sys.stderr.flush() import base64 import datetime -import ConfigParser +import six.moves.configparser import errno import exceptions from fnmatch import fnmatch -import httplib +import six.moves.http_client import imp import logging import logging.handlers @@ -78,10 +78,10 @@ import urllib2 import urlparse from . import util import warnings -import xmlrpclib +import six.moves.xmlrpc_client import xml.sax import xml.sax.handler -from xmlrpclib import loads, dumps, Fault +from six.moves.xmlrpc_client import loads, dumps, Fault PROFILE_MODULES = {} # {module_name: module_instance} @@ -1663,7 +1663,7 @@ def read_config(profile_name, user_config=None): got_conf = False for configFile in configs: f = open(configFile) - config = ConfigParser.ConfigParser() + config = six.moves.configparser.ConfigParser() config.readfp(f) f.close() if config.has_section(profile_name): @@ -1946,7 +1946,7 @@ def is_conn_error(e): return True # else return False - if isinstance(e, httplib.BadStatusLine): + if isinstance(e, six.moves.http_client.BadStatusLine): return True if requests is not None: try: @@ -1956,7 +1956,7 @@ def is_conn_error(e): e2 = getattr(e, 'args', [None])[0] if isinstance(e2, requests.packages.urllib3.exceptions.ProtocolError): e3 = getattr(e2, 'args', [None, None])[1] - if isinstance(e3, httplib.BadStatusLine): + if isinstance(e3, six.moves.http_client.BadStatusLine): return True if isinstance(e2, socket.error): # same check as unwrapped socket error @@ -2368,7 +2368,7 @@ class ClientSession(object): return ret def _read_xmlrpc_response(self, response): - p, u = xmlrpclib.getparser() + p, u = six.moves.xmlrpc_client.getparser() for chunk in response.iter_content(8192): if self.opts.get('debug_xmlrpc', False): print("body: %r" % chunk) diff --git a/koji/compatrequests.py b/koji/compatrequests.py index d56f0f2..be04a5b 100644 --- a/koji/compatrequests.py +++ b/koji/compatrequests.py @@ -7,7 +7,7 @@ module that is based on the older codepaths in koji. It only provides the bits that koji needs. """ -import httplib +import six.moves.http_client import urlparse import urllib import sys @@ -84,11 +84,11 @@ class Session(object): # no verify ctx = pyssl._create_unverified_context() cnxOpts['context'] = ctx - cnxClass = httplib.HTTPSConnection + cnxClass = six.moves.http_client.HTTPSConnection default_port = 443 elif scheme == 'http': cnxOpts = {} - cnxClass = httplib.HTTPConnection + cnxClass = six.moves.http_client.HTTPConnection else: raise IOError("unsupported protocol: %s" % scheme) @@ -123,7 +123,7 @@ class Response(object): def raise_for_status(self): if self.response.status >= 400: - raise httplib.HTTPException("HTTP %s: %s" % (self.response.status, + raise six.moves.http_client.HTTPException("HTTP %s: %s" % (self.response.status, self.response.reason)) diff --git a/koji/context.py b/koji/context.py index 03e22ed..ef35a21 100755 --- a/koji/context.py +++ b/koji/context.py @@ -25,7 +25,7 @@ # - auth data from __future__ import absolute_import -import thread +import six.moves._thread from six.moves import range class _data(object): @@ -37,7 +37,7 @@ class ThreadLocal(object): # should probably be getattribute, but easier to debug this way def __getattr__(self, key): - id = thread.get_ident() + id = six.moves._thread.get_ident() tdict = object.__getattribute__(self, '_tdict') if id not in tdict: raise AttributeError(key) @@ -45,7 +45,7 @@ class ThreadLocal(object): return object.__getattribute__(data, key) def __setattr__(self, key, value): - id = thread.get_ident() + id = six.moves._thread.get_ident() tdict = object.__getattribute__(self, '_tdict') if id not in tdict: tdict[id] = _data() @@ -53,7 +53,7 @@ class ThreadLocal(object): return object.__setattr__(data, key, value) def __delattr__(self, key): - id = thread.get_ident() + id = six.moves._thread.get_ident() tdict = object.__getattribute__(self, '_tdict') if id not in tdict: raise AttributeError(key) @@ -64,14 +64,14 @@ class ThreadLocal(object): return ret def __str__(self): - id = thread.get_ident() + id = six.moves._thread.get_ident() tdict = object.__getattribute__(self, '_tdict') return "(current thread: %s) {" % id + \ ", ".join(["%s : %s" %(k, v.__dict__) for (k, v) in tdict.iteritems()]) + \ "}" def _threadclear(self): - id = thread.get_ident() + id = six.moves._thread.get_ident() tdict = object.__getattribute__(self, '_tdict') if id not in tdict: return @@ -100,7 +100,7 @@ if __name__ == '__main__': print(context) for x in range(1, 10): - thread.start_new_thread(test, ()) + six.moves._thread.start_new_thread(test, ()) time.sleep(4) print('') diff --git a/koji/daemon.py b/koji/daemon.py index 355a4cf..3743d27 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -35,7 +35,7 @@ import time import sys import traceback import errno -import xmlrpclib +import six.moves.xmlrpc_client from six.moves import range @@ -1190,12 +1190,12 @@ class TaskManager(object): try: response = (handler.run(),) # note that we wrap response in a singleton tuple - response = xmlrpclib.dumps(response, methodresponse=1, allow_none=1) + response = six.moves.xmlrpc_client.dumps(response, methodresponse=1, allow_none=1) self.logger.info("RESPONSE: %r" % response) self.session.host.closeTask(handler.id, response) return - except xmlrpclib.Fault, fault: - response = xmlrpclib.dumps(fault) + except six.moves.xmlrpc_client.Fault, fault: + response = six.moves.xmlrpc_client.dumps(fault) tb = ''.join(traceback.format_exception(*sys.exc_info())).replace(r"\n", "\n") self.logger.warn("FAULT:\n%s" % tb) except (SystemExit, koji.tasks.ServerExit, KeyboardInterrupt): @@ -1214,7 +1214,7 @@ class TaskManager(object): if issubclass(e_class, koji.GenericError): #just pass it through tb = str(e) - response = xmlrpclib.dumps(xmlrpclib.Fault(faultCode, tb)) + response = six.moves.xmlrpc_client.dumps(six.moves.xmlrpc_client.Fault(faultCode, tb)) # if we get here, then we're handling an exception, so fail the task self.session.host.failTask(handler.id, response) diff --git a/koji/ssl/SSLCommon.py b/koji/ssl/SSLCommon.py index a1ab2bb..cbecedf 100644 --- a/koji/ssl/SSLCommon.py +++ b/koji/ssl/SSLCommon.py @@ -17,7 +17,7 @@ import os, sys from OpenSSL import SSL import SSLConnection -import httplib +import six.moves.http_client import socket def our_verify(connection, x509, errNum, errDepth, preverifyOK): @@ -46,13 +46,13 @@ def CreateSSLContext(certs): return ctx -class PlgHTTPSConnection(httplib.HTTPConnection): +class PlgHTTPSConnection(six.moves.http_client.HTTPConnection): "This class allows communication via SSL." - response_class = httplib.HTTPResponse + response_class = six.moves.http_client.HTTPResponse def __init__(self, host, port=None, ssl_context=None, strict=None, timeout=None): - httplib.HTTPConnection.__init__(self, host, port, strict) + six.moves.http_client.HTTPConnection.__init__(self, host, port, strict) self.ssl_ctx = ssl_context self._timeout = timeout diff --git a/koji/tasks.py b/koji/tasks.py index 8245cab..d47fb7a 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -25,7 +25,7 @@ import koji import koji.util import os import logging -import xmlrpclib +import six.moves.xmlrpc_client import signal import urllib2 import shutil @@ -240,7 +240,7 @@ class BaseTaskHandler(object): continue try: self.session.getTaskResult(task) - except (koji.GenericError, xmlrpclib.Fault), task_error: + except (koji.GenericError, six.moves.xmlrpc_client.Fault), task_error: self.logger.info("task %s failed or was canceled" % task) failed = True break diff --git a/koji/util.py b/koji/util.py index 5a3c7b9..9fce070 100644 --- a/koji/util.py +++ b/koji/util.py @@ -31,7 +31,7 @@ import shutil import stat import sys import time -import ConfigParser +import six.moves.configparser from zlib import adler32 from six.moves import range @@ -588,7 +588,7 @@ def parse_maven_params(confs, chain=False, scratch=False): """ if not isinstance(confs, (list, tuple)): confs = [confs] - config = ConfigParser.ConfigParser() + config = six.moves.configparser.ConfigParser() for conf in confs: conf_fd = file(conf) config.readfp(conf_fd) diff --git a/plugins/builder/runroot.py b/plugins/builder/runroot.py index fe23bd0..f902659 100644 --- a/plugins/builder/runroot.py +++ b/plugins/builder/runroot.py @@ -2,7 +2,7 @@ import commands import koji -import ConfigParser +import six.moves.configparser import os import platform compat_mode = False @@ -56,7 +56,7 @@ class RunRootTask(tasks.BaseTaskHandler): return res def _read_config(self): - cp = ConfigParser.SafeConfigParser() + cp = six.moves.configparser.SafeConfigParser() cp.read(CONFIG_FILE) self.config = { 'default_mounts': [], @@ -84,7 +84,7 @@ class RunRootTask(tasks.BaseTaskHandler): 'fstype': cp.get(section_name, 'fstype'), 'options': cp.get(section_name, 'options'), }) - except ConfigParser.NoOptionError: + except six.moves.configparser.NoOptionError: raise koji.GenericError("bad config: missing options in %s section" % section_name) count += 1 diff --git a/plugins/builder/save_failed_tree.py b/plugins/builder/save_failed_tree.py index 4c202c9..b0f5cfd 100644 --- a/plugins/builder/save_failed_tree.py +++ b/plugins/builder/save_failed_tree.py @@ -2,7 +2,7 @@ import fnmatch import os import sys import tarfile -import ConfigParser +import six.moves.configparser import koji import koji.tasks as tasks @@ -27,7 +27,7 @@ def omit_paths3(tarinfo): def read_config(): global config - cp = ConfigParser.SafeConfigParser() + cp = six.moves.configparser.SafeConfigParser() cp.read(CONFIG_FILE) config = { 'path_filters': [], diff --git a/plugins/hub/messagebus.py b/plugins/hub/messagebus.py index 10c8b00..5bb2b01 100644 --- a/plugins/hub/messagebus.py +++ b/plugins/hub/messagebus.py @@ -6,7 +6,7 @@ from koji import PluginError from koji.plugin import callbacks, callback, ignore_error -import ConfigParser +import six.moves.configparser import logging import qpid.messaging import qpid.messaging.transports @@ -78,7 +78,7 @@ def get_sender(): session = None target = None - config = ConfigParser.SafeConfigParser() + config = six.moves.configparser.SafeConfigParser() config.read(CONFIG_FILE) if not config.has_option('broker', 'timeout'): config.set('broker', 'timeout', '60') diff --git a/plugins/hub/protonmsg.py b/plugins/hub/protonmsg.py index cf3a82c..0a65c4e 100644 --- a/plugins/hub/protonmsg.py +++ b/plugins/hub/protonmsg.py @@ -8,7 +8,7 @@ import koji from koji.plugin import callback, ignore_error from koji.context import context -import ConfigParser +import six.moves.configparser import logging import json import random @@ -246,7 +246,7 @@ def send_queued_msgs(cbtype, *args, **kws): log = logging.getLogger('koji.plugin.protonmsg') global CONFIG if not CONFIG: - conf = ConfigParser.SafeConfigParser() + conf = six.moves.configparser.SafeConfigParser() with open(CONFIG_FILE) as conffile: conf.readfp(conffile) CONFIG = conf diff --git a/plugins/hub/rpm2maven.py b/plugins/hub/rpm2maven.py index b1310ea..1a9b399 100644 --- a/plugins/hub/rpm2maven.py +++ b/plugins/hub/rpm2maven.py @@ -8,7 +8,7 @@ import koji from koji.context import context from koji.plugin import callback -import ConfigParser +import six.moves.configparser import fnmatch import os import shutil @@ -30,7 +30,7 @@ def maven_import(cbtype, *args, **kws): filepath = kws['filepath'] if not config: - config = ConfigParser.SafeConfigParser() + config = six.moves.configparser.SafeConfigParser() config.read(CONFIG_FILE) name_patterns = config.get('patterns', 'rpm_names').split() for pattern in name_patterns: diff --git a/plugins/hub/save_failed_tree.py b/plugins/hub/save_failed_tree.py index 3a98128..70caa26 100644 --- a/plugins/hub/save_failed_tree.py +++ b/plugins/hub/save_failed_tree.py @@ -1,5 +1,5 @@ import sys -import ConfigParser +import six.moves.configparser import koji from koji.context import context from koji.plugin import export @@ -28,7 +28,7 @@ def saveFailedTree(buildrootID, full=False, **opts): # read configuration only once if config is None: - config = ConfigParser.SafeConfigParser() + config = six.moves.configparser.SafeConfigParser() config.read(CONFIG_FILE) allowed_methods = config.get('permissions', 'allowed_methods').split() if len(allowed_methods) == 1 and allowed_methods[0] == '*': diff --git a/tests/test_compatrequests.py b/tests/test_compatrequests.py index c67f585..6a684ef 100644 --- a/tests/test_compatrequests.py +++ b/tests/test_compatrequests.py @@ -1,4 +1,4 @@ -import httplib +import six.moves.http_client import mock import unittest import urlparse @@ -59,7 +59,7 @@ class TestResponse(unittest.TestCase): self.response.response.status = 404 self.response.response.reason = 'Not Found' self.response.response.getheader.return_value = 42 - with self.assertRaises(httplib.HTTPException): + with self.assertRaises(six.moves.http_client.HTTPException): self.response.raise_for_status() diff --git a/tests/test_plugins/test_protonmsg.py b/tests/test_plugins/test_protonmsg.py index 02583b7..108be2e 100644 --- a/tests/test_plugins/test_protonmsg.py +++ b/tests/test_plugins/test_protonmsg.py @@ -4,7 +4,7 @@ import protonmsg from koji.context import context import tempfile from StringIO import StringIO -from ConfigParser import SafeConfigParser +from six.moves.configparser import SafeConfigParser class TestProtonMsg(unittest.TestCase): def tearDown(self): diff --git a/tests/test_plugins/test_runroot_builder.py b/tests/test_plugins/test_runroot_builder.py index e841d98..910c783 100644 --- a/tests/test_plugins/test_runroot_builder.py +++ b/tests/test_plugins/test_runroot_builder.py @@ -1,6 +1,6 @@ import unittest import mock -import ConfigParser +import six.moves.configparser # inject builder data from tests.test_builder.loadkojid import kojid @@ -40,7 +40,7 @@ class FakeConfigParser(object): try: return self.CONFIG[section][key] except KeyError: - raise ConfigParser.NoOptionError(section, key) + raise six.moves.configparser.NoOptionError(section, key) class TestRunrootConfig(unittest.TestCase): diff --git a/tests/test_utils.py b/tests/test_utils.py index 88cd1aa..ac533c1 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -4,7 +4,7 @@ from mock import call import os import optparse -import ConfigParser +import six.moves.configparser import koji import koji.util @@ -473,7 +473,7 @@ class MavenUtilTestCase(unittest.TestCase): self.assertEqual(cm.exception.args[0], 'total ordering not possible') def _read_conf(self, cfile): - config = ConfigParser.ConfigParser() + config = six.moves.configparser.ConfigParser() path = os.path.dirname(__file__) with open(path + cfile, 'r') as conf_file: config.readfp(conf_file) diff --git a/util/koji-gc b/util/koji-gc index 5fb1e23..fb29d54 100755 --- a/util/koji-gc +++ b/util/koji-gc @@ -15,7 +15,7 @@ except ImportError: # pragma: no cover import koji from koji.util import LazyDict, LazyValue import koji.policy -import ConfigParser +import six.moves.configparser from email.MIMEText import MIMEText import fnmatch import optparse @@ -25,7 +25,7 @@ import smtplib import socket # for socket.error import sys import time -import xmlrpclib # for ProtocolError and Fault +import six.moves.xmlrpc_client # for ProtocolError and Fault OptionParser = optparse.OptionParser @@ -114,7 +114,7 @@ def get_options(): defaults = parser.get_default_values() - config = ConfigParser.ConfigParser() + config = six.moves.configparser.ConfigParser() cf = getattr(options, 'config_file', None) if cf: if not os.access(cf, os.F_OK): @@ -339,7 +339,7 @@ def warn(msg): def ensure_connection(session): try: ret = session.getAPIVersion() - except xmlrpclib.ProtocolError: + except six.moves.xmlrpc_client.ProtocolError: error(_("Error: Unable to connect to server")) if ret != koji.API_VERSION: warn(_("WARNING: The server is at API version %d and the client is at %d" % (ret, koji.API_VERSION))) @@ -454,7 +454,7 @@ def handle_trash(): continue try: refs = session.buildReferences(binfo['id'], limit=10) - except xmlrpclib.Fault: + except six.moves.xmlrpc_client.Fault: print("[%i/%i] Error checking references for %s. Skipping" % (i, N, nvr)) continue #XXX - this is more data than we need @@ -656,7 +656,7 @@ def handle_delete(just_salvage=False): session.untagBuildBypass(trashcan_tag, binfo['id']) try: session.deleteBuild(binfo['id']) - except (xmlrpclib.Fault, koji.GenericError), e: + except (six.moves.xmlrpc_client.Fault, koji.GenericError), e: print("Warning: deletion failed: %s" % e) #server issue pass @@ -875,7 +875,7 @@ def handle_prune(): try: session.untagBuildBypass(taginfo['id'], entry['build_id'], force=bypass) untagged.setdefault(nvr, {})[tagname] = 1 - except (xmlrpclib.Fault, koji.GenericError), e: + except (six.moves.xmlrpc_client.Fault, koji.GenericError), e: print("Warning: untag operation failed: %s" % e) pass # if action == 'keep' do nothing @@ -909,7 +909,7 @@ def handle_prune(): print("Deleting untagged build: %s" % nvr) try: session.deleteBuild(build_id, strict=False) - except (xmlrpclib.Fault, koji.GenericError), e: + except (six.moves.xmlrpc_client.Fault, koji.GenericError), e: print("Warning: deletion failed: %s" % e) #server issue pass diff --git a/util/koji-shadow b/util/koji-shadow index a951771..d17f01c 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -30,7 +30,7 @@ try: except ImportError: # pragma: no cover pass import koji -import ConfigParser +import six.moves.configparser import fnmatch import optparse import os @@ -43,7 +43,7 @@ import sys import time import urllib2 import urlgrabber.grabber as grabber -import xmlrpclib # for ProtocolError and Fault +import six.moves.xmlrpc_client # for ProtocolError and Fault import rpm # koji.fp.o keeps stalling, probably network errors... @@ -163,7 +163,7 @@ def get_options(): (options, args) = parser.parse_args() defaults = parser.get_default_values() - config = ConfigParser.ConfigParser() + config = six.moves.configparser.ConfigParser() cf = getattr(options, 'config_file', None) if cf: if not os.access(cf, os.F_OK): @@ -299,7 +299,7 @@ def warn(msg): def ensure_connection(session): try: ret = session.getAPIVersion() - except xmlrpclib.ProtocolError: + except six.moves.xmlrpc_client.ProtocolError: error(_("Error: Unable to connect to server")) if ret != koji.API_VERSION: warn(_("WARNING: The server is at API version %d and the client is at " diff --git a/util/kojira b/util/kojira index 4a21332..c09c40b 100755 --- a/util/kojira +++ b/util/kojira @@ -29,7 +29,7 @@ import os import koji from koji.util import rmtree, parseStatus from optparse import OptionParser -from ConfigParser import ConfigParser +from six.moves.configparser import ConfigParser import errno import fnmatch import logging diff --git a/vm/kojikamid.py b/vm/kojikamid.py index 0499c74..87a8608 100755 --- a/vm/kojikamid.py +++ b/vm/kojikamid.py @@ -27,13 +27,13 @@ # in a cygwin shell. from optparse import OptionParser -from ConfigParser import ConfigParser +from six.moves.configparser import ConfigParser import os import subprocess import sys import tempfile import time -import xmlrpclib +import six.moves.xmlrpc_client import base64 import hashlib import logging @@ -586,13 +586,13 @@ def get_mgmt_server(): macaddr, gateway = find_net_info() logger.debug('found MAC address %s, connecting to %s:%s', macaddr, gateway, MANAGER_PORT) - server = xmlrpclib.ServerProxy('http://%s:%s/' % + server = six.moves.xmlrpc_client.ServerProxy('http://%s:%s/' % (gateway, MANAGER_PORT), allow_none=True) # we would set a timeout on the socket here, but that is apparently not # supported by python/cygwin/Windows task_port = server.getPort(macaddr) logger.debug('found task-specific port %s', task_port) - return xmlrpclib.ServerProxy('http://%s:%s/' % (gateway, task_port), allow_none=True) + return six.moves.xmlrpc_client.ServerProxy('http://%s:%s/' % (gateway, task_port), allow_none=True) def get_options(): """handle usage and parse options""" diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py index 9b03499..a7d8b74 100644 --- a/www/kojiweb/index.py +++ b/www/kojiweb/index.py @@ -26,7 +26,7 @@ import os.path import re import sys import mimetypes -import Cookie +import six.moves.http_cookies import datetime import logging import time @@ -56,7 +56,7 @@ def _setUserCookie(environ, user): shasum = sha1_constructor(value) shasum.update(options['Secret'].value) value = "%s:%s" % (shasum.hexdigest(), value) - cookies = Cookie.SimpleCookie() + cookies = six.moves.http_cookies.SimpleCookie() cookies['user'] = value c = cookies['user'] #morsel instance c['secure'] = True @@ -69,7 +69,7 @@ def _setUserCookie(environ, user): environ['koji.headers'].append(['Cache-Control', 'no-cache="set-cookie"']) def _clearUserCookie(environ): - cookies = Cookie.SimpleCookie() + cookies = six.moves.http_cookies.SimpleCookie() cookies['user'] = '' c = cookies['user'] #morsel instance c['path'] = os.path.dirname(environ['SCRIPT_NAME']) @@ -79,7 +79,7 @@ def _clearUserCookie(environ): def _getUserCookie(environ): options = environ['koji.options'] - cookies = Cookie.SimpleCookie(environ.get('HTTP_COOKIE', '')) + cookies = six.moves.http_cookies.SimpleCookie(environ.get('HTTP_COOKIE', '')) if 'user' not in cookies: return None value = cookies['user'].value diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py index e2d427b..9bbb40b 100644 --- a/www/kojiweb/wsgi_publisher.py +++ b/www/kojiweb/wsgi_publisher.py @@ -29,7 +29,7 @@ import pprint import sys import traceback -from ConfigParser import RawConfigParser +from six.moves.configparser import RawConfigParser from koji.server import WSGIWrapper, ServerError, ServerRedirect from koji.util import dslice diff --git a/www/lib/kojiweb/util.py b/www/lib/kojiweb/util.py index 3d5212f..dd48295 100644 --- a/www/lib/kojiweb/util.py +++ b/www/lib/kojiweb/util.py @@ -30,7 +30,7 @@ import stat #a bunch of exception classes that explainError needs from socket import error as socket_error from socket import sslerror as socket_sslerror -from xmlrpclib import ProtocolError +from six.moves.xmlrpc_client import ProtocolError from xml.parsers.expat import ExpatError import cgi from six.moves import range From 1220008f8f628a91fd56bde10994a8fe53bc3ebd Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 6/61] python-modernize -f lib2to3.fixes.fix_except --- diff --git a/builder/kojid b/builder/kojid index 6c2d490..3d740db 100755 --- a/builder/kojid +++ b/builder/kojid @@ -1976,7 +1976,7 @@ class ChainMavenTask(MultiPlatformTask): del todo[package] try: results = self.wait(running.keys()) - except (six.moves.xmlrpc_client.Fault, koji.GenericError), e: + except (six.moves.xmlrpc_client.Fault, koji.GenericError) as e: # One task has failed, wait for the rest to complete before the # chainmaven task fails. self.wait(all=True) should thrown an exception. self.wait(all=True) @@ -2113,7 +2113,7 @@ class TagBuildTask(BaseTaskHandler): #XXX - add more post tests self.session.host.tagBuild(self.id,tag_id,build_id,force=force,fromtag=fromtag) self.session.host.tagNotification(True, tag_id, fromtag, build_id, user_id, ignore_success) - except Exception, e: + except Exception as e: exctype, value = sys.exc_info()[:2] self.session.host.tagNotification(False, tag_id, fromtag, build_id, user_id, ignore_success, "%s: %s" % (exctype, value)) raise e @@ -2676,10 +2676,10 @@ class ImageTask(BaseTaskHandler): self.ks = ksparser.KickstartParser(version) try: self.ks.readKickstart(kspath) - except IOError, e: + except IOError as e: raise koji.LiveCDError("Failed to read kickstart file " "'%s' : %s" % (kspath, e)) - except kserrors.KickstartError, e: + except kserrors.KickstartError as e: raise koji.LiveCDError("Failed to parse kickstart file " "'%s' : %s" % (kspath, e)) @@ -3291,10 +3291,10 @@ class OzImageTask(BaseTaskHandler): self.logger.debug('attempting to read kickstart: %s' % kspath) try: ks.readKickstart(kspath) - except IOError, e: + except IOError as e: raise koji.BuildError("Failed to read kickstart file " "'%s' : %s" % (kspath, e)) - except kserrors.KickstartError, e: + except kserrors.KickstartError as e: raise koji.BuildError("Failed to parse kickstart file " "'%s' : %s" % (kspath, e)) return ks @@ -4228,7 +4228,7 @@ class BuildIndirectionImageTask(OzImageTask): base_factory_image = _nvr_to_image(opts['base_image_build'], opts['arch']) else: base_factory_image = _task_to_image(int(opts['base_image_task'])) - except Exception, e: + except Exception as e: self.logger.exception(e) raise @@ -4290,7 +4290,7 @@ class BuildIndirectionImageTask(OzImageTask): image_id=base_factory_image.identifier, parameters=params) target.target_thread.join() - except Exception, e: + except Exception as e: self.logger.debug("Exception encountered during target build") self.logger.exception(e) finally: @@ -5633,7 +5633,7 @@ if __name__ == "__main__": # authenticate using SSL client certificates session.ssl_login(options.cert, None, options.serverca) - except koji.AuthError, e: + except koji.AuthError as e: quit("Error: Unable to log in: %s" % e) except six.moves.xmlrpc_client.ProtocolError: quit("Error: Unable to connect to server %s" % (options.server)) @@ -5653,9 +5653,9 @@ if __name__ == "__main__": session.krb_login(principal=krb_principal, keytab=options.keytab, ccache=options.ccache) - except krbV.Krb5Error, e: + except krbV.Krb5Error as e: quit("Kerberos authentication failed: '%s' (%s)" % (e.args[1], e.args[0])) - except socket.error, e: + except socket.error as e: quit("Could not connect to Kerberos authentication service: '%s'" % e.args[1]) else: quit("No username/password supplied and Kerberos missing or not configured") diff --git a/cli/koji b/cli/koji index 1c1b1c0..4a192fc 100755 --- a/cli/koji +++ b/cli/koji @@ -240,7 +240,7 @@ def get_options(): # load local config try: result = koji.read_config(options.profile, user_config=options.configFile) - except koji.ConfigurationError, e: + except koji.ConfigurationError as e: parser.error(e.args[0]) assert False # pragma: no cover @@ -342,7 +342,7 @@ class TaskWatcher(object): error = None try: result = self.session.getTaskResult(self.id) - except (six.moves.xmlrpc_client.Fault,koji.GenericError),e: + except (six.moves.xmlrpc_client.Fault,koji.GenericError) as e: error = e if error is None: # print("%s: complete" % self.str()) @@ -550,7 +550,7 @@ def list_task_output_all_volumes(session, task_id): """List task output with all volumes, or fake it""" try: return session.listTaskOutput(task_id, all_volumes=True) - except koji.GenericError, e: + except koji.GenericError as e: if 'got an unexpected keyword argument' not in str(e): raise # otherwise leave off the option and fake it @@ -944,7 +944,7 @@ def _progress_callback(uploaded, total, piece, time, total_time): def _running_in_bg(): try: return (not os.isatty(0)) or (os.getpgrp() != os.tcgetpgrp(0)) - except OSError, e: + except OSError as e: return True def handle_build(options, session, args): @@ -1167,7 +1167,7 @@ def handle_maven_build(options, session, args): try: params = koji.util.parse_maven_param(build_opts.inis, scratch=build_opts.scratch, section=build_opts.section) - except ValueError, e: + except ValueError as e: parser.error(e.args[0]) opts = params.values()[0] if opts.pop('type', 'maven') != 'maven': @@ -1226,7 +1226,7 @@ def handle_wrapper_rpm(options, session, args): try: params = koji.util.parse_maven_param(build_opts.inis, scratch=build_opts.scratch, section=build_opts.section) - except ValueError, e: + except ValueError as e: parser.error(e.args[0]) opts = params.values()[0] if opts.get('type') != 'wrapper': @@ -1300,7 +1300,7 @@ def handle_maven_chain(options, session, args): opts[key] = val try: builds = koji.util.parse_maven_chain(args[1:], scratch=opts.get('scratch')) - except ValueError, e: + except ValueError as e: parser.error(e.args[0]) priority = None if build_opts.background: @@ -1675,7 +1675,7 @@ def handle_import(options, session, args): sys.stdout.flush() try: session.importRPM(serverdir, os.path.basename(path)) - except koji.GenericError, e: + except koji.GenericError as e: print(_("\nError importing: %s" % str(e).splitlines()[-1])) sys.stdout.flush() else: @@ -2284,7 +2284,7 @@ def handle_prune_signed_copies(options, session, args): print("Unlinking: %s" % signedpath) try: os.unlink(signedpath) - except OSError, e: + except OSError as e: print("Error removing %s: %s" % (signedpath, e)) print("This script needs write access to %s" % koji.BASEDIR) continue @@ -2304,7 +2304,7 @@ def handle_prune_signed_copies(options, session, args): print("Removing dir: %s" % dir) try: os.rmdir(dir) - except OSError, e: + except OSError as e: print("Error removing %s: %s" % (signedpath, e)) if len(sigdirs) == 1: dir = sigdirs.keys()[0] @@ -2315,7 +2315,7 @@ def handle_prune_signed_copies(options, session, args): print("Removing dir: %s" % dir) try: os.rmdir(dir) - except OSError, e: + except OSError as e: print("Error removing %s: %s" % (signedpath, e)) elif len(sigdirs) > 1: print("Warning: more than one signature dir for %s: %r" % (sigkey, sigdirs)) @@ -2549,7 +2549,7 @@ def handle_import_in_place(options, session, args): sys.stdout.write(_("importing %s... ") % nvr) try: session.importBuildInPlace(data) - except koji.GenericError, e: + except koji.GenericError as e: print(_("\nError importing: %s" % str(e).splitlines()[-1])) sys.stdout.flush() else: @@ -6735,7 +6735,7 @@ def anon_handle_download_build(options, session, args): # We want the latest build, not a specific build try: builds = session.listTagged(suboptions.latestfrom, latest=True, package=build, type=suboptions.type) - except koji.GenericError, data: + except koji.GenericError as data: print("Error finding latest build: %s" % data) return 1 if not builds: @@ -7382,7 +7382,7 @@ def handle_runroot(options, session, args): kwargs['new_chroot'] = True task_id = session.runroot(tag, arch, command, **kwargs) - except koji.GenericError, e: + except koji.GenericError as e: if 'Invalid method' in str(e): print("* The runroot plugin appears to not be installed on the" " koji hub. Please contact the administrator.") @@ -7458,7 +7458,7 @@ def handle_save_failed_tree(options, session, args): try: task_id = session.saveFailedTree(br_id, opts.full) - except koji.GenericError, e: + except koji.GenericError as e: m = str(e) if 'Invalid method' in m: print(_("* The save_failed_tree plugin appears to not be " @@ -7573,9 +7573,9 @@ def activate_session(session): session.krb_login(principal=options.principal, keytab=options.keytab, proxyuser=options.runas) else: session.krb_login(proxyuser=options.runas) - except socket.error, e: + except socket.error as e: warn(_("Could not connect to Kerberos authentication service: %s") % e.args[1]) - except Exception, e: + except Exception as e: if krbV is not None and isinstance(e, krbV.Krb5Error): error(_("Kerberos authentication failed: %s (%s)") % (e.args[1], e.args[0])) else: diff --git a/hub/kojihub.py b/hub/kojihub.py index 627fb78..2fec4ea 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -421,7 +421,7 @@ class Task(object): # If the result is a Fault, then loads will raise it # This is normally what we want to happen result, method = six.moves.xmlrpc_client.loads(xml_result) - except six.moves.xmlrpc_client.Fault, fault: + except six.moves.xmlrpc_client.Fault as fault: if raise_fault: raise # Note that you can't really return a fault over xmlrpc, except by @@ -8800,7 +8800,7 @@ class RootExports(object): fn = get_upload_path(path, name, create=True, volume=volume) try: st = os.lstat(fn) - except OSError, e: + except OSError as e: if e.errno == errno.ENOENT: pass else: @@ -8869,7 +8869,7 @@ class RootExports(object): data = {} try: fd = os.open(fn, os.O_RDONLY) - except OSError, e: + except OSError as e: if e.errno == errno.ENOENT: return None else: @@ -8877,7 +8877,7 @@ class RootExports(object): try: try: fcntl.lockf(fd, fcntl.LOCK_SH|fcntl.LOCK_NB) - except IOError, e: + except IOError as e: raise koji.LockError(e) st = os.fstat(fd) if not stat.S_ISREG(st.st_mode): @@ -10387,7 +10387,7 @@ class RootExports(object): #handle older base64 encoded data val = base64.decodestring(val) data, method = six.moves.xmlrpc_client.loads(val) - except six.moves.xmlrpc_client.Fault, fault: + except six.moves.xmlrpc_client.Fault as fault: data = fault task[f] = data yield task @@ -12430,7 +12430,7 @@ class HostExports(object): logger.debug("os.link(%r, %r)", rpmpath, l_dst) try: os.link(rpmpath, l_dst) - except OSError, ose: + except OSError as ose: if ose.errno == 18: shutil.copy2( rpmpath, os.path.join(archdir, bnplet, bnp)) @@ -12527,7 +12527,7 @@ def handle_upload(environ): try: try: fcntl.lockf(fd, fcntl.LOCK_EX|fcntl.LOCK_NB) - except IOError, e: + except IOError as e: raise koji.LockError(e) if offset == -1: offset = os.lseek(fd, 0, 2) diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index bee6b5b..4f4d2b8 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -244,7 +244,7 @@ class ModXMLRPCRequestHandler(object): # wrap response in a singleton tuple response = (response,) response = dumps(response, methodresponse=1, allow_none=1) - except Fault, fault: + except Fault as fault: self.traceback = True response = dumps(fault) except: @@ -338,7 +338,7 @@ class ModXMLRPCRequestHandler(object): for call in calls: try: result = self._dispatch(call['methodName'], call['params']) - except Fault, fault: + except Fault as fault: results.append({'faultCode': fault.faultCode, 'faultString': fault.faultString}) except: # transform unknown exceptions into XML-RPC Faults diff --git a/hub/rpmdiff b/hub/rpmdiff index 4536a9d..5972377 100755 --- a/hub/rpmdiff +++ b/hub/rpmdiff @@ -227,7 +227,7 @@ def main(): ignore_tags = [] try: opts, args = getopt.getopt(sys.argv[1:], "hi:", ["help", "ignore="]) - except getopt.GetoptError, e: + except getopt.GetoptError as e: print("Error: %s" % e) _usage() diff --git a/koji/__init__.py b/koji/__init__.py index ef21878..6e4fa45 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -475,7 +475,7 @@ def safe_xmlrpc_loads(s): """Load xmlrpc data from a string, but catch faults""" try: return loads(s) - except Fault, f: + except Fault as f: return f ## BEGIN kojikamid dup @@ -1582,7 +1582,7 @@ def config_directory_contents(dir_name): configs = [] try: conf_dir_contents = os.listdir(dir_name) - except OSError, exception: + except OSError as exception: if exception.errno != errno.ENOENT: raise else: @@ -2312,7 +2312,7 @@ class ClientSession(object): for i in (0, 1): try: return self._sendOneCall(handler, headers, request) - except Exception, e: + except Exception as e: if i or not is_conn_error(e): raise self.logger.debug("Connection Error: %s", e) @@ -2405,7 +2405,7 @@ class ClientSession(object): # note that, for logged-in sessions the server should tell us (via a RetryError fault) # if the call cannot be retried. For non-logged-in sessions, all calls should be read-only # and hence retryable. - except Fault, fault: + except Fault as fault: #try to convert the fault to a known exception err = convertFault(fault) if isinstance(err, ServerOffline): @@ -2421,7 +2421,7 @@ class ClientSession(object): except (SystemExit, KeyboardInterrupt): #(depending on the python version, these may or may not be subclasses of Exception) raise - except Exception, e: + except Exception as e: tb_str = ''.join(traceback.format_exception(*sys.exc_info())) self.new_session() diff --git a/koji/auth.py b/koji/auth.py index c69a5b4..d0dc5f4 100644 --- a/koji/auth.py +++ b/koji/auth.py @@ -79,7 +79,7 @@ class Session(object): try: id = long(args['session-id'][0]) key = args['session-key'][0] - except KeyError, field: + except KeyError as field: raise koji.AuthError('%s not specified in session args' % field) try: callnum = args['callnum'][0] diff --git a/koji/daemon.py b/koji/daemon.py index 3743d27..f298abc 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -609,7 +609,7 @@ class TaskManager(object): rootdir = "%s/root" % topdir try: st = os.lstat(rootdir) - except OSError, e: + except OSError as e: if e.errno == errno.ENOENT: rootdir = None else: @@ -630,13 +630,13 @@ class TaskManager(object): #also remove the config try: os.unlink(data['cfg']) - except OSError, e: + except OSError as e: self.logger.warn("%s: can't remove config: %s" % (desc, e)) elif age > 120: if rootdir: try: flist = os.listdir(rootdir) - except OSError, e: + except OSError as e: self.logger.warn("%s: can't list rootdir: %s" % (desc, e)) continue if flist: @@ -864,7 +864,7 @@ class TaskManager(object): prefix = "Task %i (pid %i)" % (task_id, pid) try: (childpid, status) = os.waitpid(pid, os.WNOHANG) - except OSError, e: + except OSError as e: #check errno if e.errno != errno.ECHILD: #should not happen @@ -905,7 +905,7 @@ class TaskManager(object): try: os.kill(pid, sig) - except OSError, e: + except OSError as e: # process probably went away, we'll find out on the next iteration self.logger.info('Error sending signal %i to %s (pid %i, taskID %i): %s' % (sig, execname, pid, task_id, e)) @@ -1194,7 +1194,7 @@ class TaskManager(object): self.logger.info("RESPONSE: %r" % response) self.session.host.closeTask(handler.id, response) return - except six.moves.xmlrpc_client.Fault, fault: + except six.moves.xmlrpc_client.Fault as fault: response = six.moves.xmlrpc_client.dumps(fault) tb = ''.join(traceback.format_exception(*sys.exc_info())).replace(r"\n", "\n") self.logger.warn("FAULT:\n%s" % tb) diff --git a/koji/ssl/SSLConnection.py b/koji/ssl/SSLConnection.py index d854770..2e53db7 100644 --- a/koji/ssl/SSLConnection.py +++ b/koji/ssl/SSLConnection.py @@ -106,7 +106,7 @@ class SSLConnection: try: sent = con.send(data, flags) - except SSL.SysCallError, e: + except SSL.SysCallError as e: if e[0] == 32: # Broken Pipe self.close() sent = 0 @@ -142,7 +142,7 @@ class SSLConnection: return None except SSL.WantReadError: time.sleep(0.2) - except SSL.SysCallError, e: + except SSL.SysCallError as e: if e.args == (-1, 'Unexpected EOF'): break raise diff --git a/koji/tasks.py b/koji/tasks.py index d47fb7a..41d6b5e 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -240,7 +240,7 @@ class BaseTaskHandler(object): continue try: self.session.getTaskResult(task) - except (koji.GenericError, six.moves.xmlrpc_client.Fault), task_error: + except (koji.GenericError, six.moves.xmlrpc_client.Fault) as task_error: self.logger.info("task %s failed or was canceled" % task) failed = True break diff --git a/koji/util.py b/koji/util.py index 9fce070..96d24ab 100644 --- a/koji/util.py +++ b/koji/util.py @@ -156,7 +156,7 @@ def call_with_argcheck(func, args, kwargs=None): kwargs = {} try: return func(*args, **kwargs) - except TypeError, e: + except TypeError as e: if sys.exc_info()[2].tb_next is None: # The stack is only one high, so the error occurred in this function. # Therefore, we assume the TypeError is due to a parameter mismatch @@ -459,7 +459,7 @@ def setup_rlimits(opts, logger=None): logger.warn('Setting resource limit: %s = %r', key, limits) try: resource.setrlimit(rcode, tuple(limits)) - except ValueError, e: + except ValueError as e: logger.error("Unable to set %s: %s", key, e) class adler32_constructor(object): diff --git a/util/koji-gc b/util/koji-gc index fb29d54..4a7e6e3 100755 --- a/util/koji-gc +++ b/util/koji-gc @@ -198,7 +198,7 @@ def get_options(): if len(parts) < 2: continue options.key_aliases[parts[0].upper()] = parts[1] - except ValueError, e: + except ValueError as e: print(e) parser.error(_("Invalid key alias data in config: %s") % config.get('main','key_aliases')) @@ -373,9 +373,9 @@ def activate_session(session): session.krb_login(principal=options.principal, keytab=options.keytab, proxyuser=options.runas) else: session.krb_login(proxyuser=options.runas) - except krbV.Krb5Error, e: + except krbV.Krb5Error as e: error(_("Kerberos authentication failed: %s (%s)") % (e.args[1], e.args[0])) - except socket.error, e: + except socket.error as e: warn(_("Could not connect to Kerberos authentication service: '%s'") % e.args[1]) if not options.noauth and not session.logged_in: error(_("Error: unable to log in, no authentication methods available")) @@ -656,7 +656,7 @@ def handle_delete(just_salvage=False): session.untagBuildBypass(trashcan_tag, binfo['id']) try: session.deleteBuild(binfo['id']) - except (six.moves.xmlrpc_client.Fault, koji.GenericError), e: + except (six.moves.xmlrpc_client.Fault, koji.GenericError) as e: print("Warning: deletion failed: %s" % e) #server issue pass @@ -875,7 +875,7 @@ def handle_prune(): try: session.untagBuildBypass(taginfo['id'], entry['build_id'], force=bypass) untagged.setdefault(nvr, {})[tagname] = 1 - except (six.moves.xmlrpc_client.Fault, koji.GenericError), e: + except (six.moves.xmlrpc_client.Fault, koji.GenericError) as e: print("Warning: untag operation failed: %s" % e) pass # if action == 'keep' do nothing @@ -909,7 +909,7 @@ def handle_prune(): print("Deleting untagged build: %s" % nvr) try: session.deleteBuild(build_id, strict=False) - except (six.moves.xmlrpc_client.Fault, koji.GenericError), e: + except (six.moves.xmlrpc_client.Fault, koji.GenericError) as e: print("Warning: deletion failed: %s" % e) #server issue pass diff --git a/util/koji-shadow b/util/koji-shadow index d17f01c..0b93b84 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -329,9 +329,9 @@ def activate_session(session): session.krb_login(principal=options.principal, keytab=options.keytab, proxyuser=options.runas) else: session.krb_login(proxyuser=options.runas) - except krbV.Krb5Error, e: + except krbV.Krb5Error as e: error(_("Kerberos authentication failed: '%s' (%s)") % (e.args[1], e.args[0])) - except socket.error, e: + except socket.error as e: warn(_("Could not connect to Kerberos authentication service: '%s'") % e.args[1]) if not options.noauth and not session.logged_in: error(_("Error: unable to log in")) diff --git a/util/kojira b/util/kojira index c09c40b..a875f29 100755 --- a/util/kojira +++ b/util/kojira @@ -146,7 +146,7 @@ class ManagedRepo(object): #also check dir age. We do this because a repo can be created from an older event #and should not be removed based solely on that event's timestamp. mtime = os.stat(path).st_mtime - except OSError, e: + except OSError as e: if e.errno == 2: # No such file or directory, so the repo either never existed, # or has already been deleted, so allow it to be marked deleted. @@ -226,7 +226,7 @@ class RepoManager(object): prefix = "pid %i (%s)" % (pid, self.delete_pids.get(pid)) try: (childpid, status) = os.waitpid(pid, os.WNOHANG) - except OSError, e: + except OSError as e: if e.errno != errno.ECHILD: #should not happen raise @@ -261,7 +261,7 @@ class RepoManager(object): for pid in self.delete_pids: try: os.kill(pid, sig) - except OSError, e: + except OSError as e: if e.errno != errno.ESRCH: logger.error("Unable to kill process %s", pid) From 67af38a1feda2fa357f3655c145f452417ec419c Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 7/61] python-modernize -f lib2to3.fixes.fix_funcattrs --- diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index 4f4d2b8..5fec9bb 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -158,13 +158,13 @@ class HandlerRegistry(object): def _getFuncArgs(self, func): args = [] - for x in range(0, func.func_code.co_argcount): - if x == 0 and func.func_code.co_varnames[x] == "self": + for x in range(0, func.__code__.co_argcount): + if x == 0 and func.__code__.co_varnames[x] == "self": continue - if func.func_defaults and func.func_code.co_argcount - x <= len(func.func_defaults): - args.append((func.func_code.co_varnames[x], func.func_defaults[x - func.func_code.co_argcount + len(func.func_defaults)])) + if func.__defaults__ and func.__code__.co_argcount - x <= len(func.__defaults__): + args.append((func.__code__.co_varnames[x], func.__defaults__[x - func.__code__.co_argcount + len(func.__defaults__)])) else: - args.append(func.func_code.co_varnames[x]) + args.append(func.__code__.co_varnames[x]) return args def system_listMethods(self): From e071f793eed104bdf7cb403e302eeb1235913d88 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 8/61] python-modernize -f lib2to3.fixes.fix_methodattrs --- diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index 5fec9bb..23a2904 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -131,7 +131,7 @@ class HandlerRegistry(object): if ret: return ret ret = tuple(inspect.getargspec(func)) - if inspect.ismethod(func) and func.im_self: + if inspect.ismethod(func) and func.__self__: # bound method, remove first arg args, varargs, varkw, defaults = ret if args: From f6e5bd11f387e06a4b5736ca603b7a7456939d96 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 9/61] python-modernize -f lib2to3.fixes.fix_numliterals --- diff --git a/builder/kojid b/builder/kojid index 3d740db..921bac4 100755 --- a/builder/kojid +++ b/builder/kojid @@ -430,7 +430,7 @@ class BuildRoot(object): if workdir: outfile = os.path.join(workdir, mocklog) flags = os.O_CREAT | os.O_WRONLY | os.O_APPEND - fd = os.open(outfile, flags, 0666) + fd = os.open(outfile, flags, 0o666) os.dup2(fd, 1) os.dup2(fd, 2) if os.getuid() == 0 and hasattr(self.options,"mockuser"): @@ -1347,7 +1347,7 @@ class BuildMavenTask(BaseBuildTask): st = os.lstat(filepath) mtime = time.localtime(st.st_mtime) info = zipfile.ZipInfo(filepath[roottrim:]) - info.external_attr |= 0120000 << 16L # symlink file type + info.external_attr |= 0o120000 << 16 # symlink file type info.compress_type = zipfile.ZIP_STORED info.date_time = mtime[:6] zfo.writestr(info, content) diff --git a/cli/koji b/cli/koji index 4a192fc..30e5ab2 100755 --- a/cli/koji +++ b/cli/koji @@ -1579,7 +1579,7 @@ def handle_restart_hosts(options, session, args): def linked_upload(localfile, path, name=None): """Link a file into the (locally writable) workdir, bypassing upload""" - old_umask = os.umask(002) + old_umask = os.umask(0o02) try: if name is None: name = os.path.basename(localfile) diff --git a/hub/kojihub.py b/hub/kojihub.py index 2fec4ea..839b648 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -8814,7 +8814,7 @@ class RootExports(object): # but we allow .log files to be uploaded multiple times to support # realtime log-file viewing raise koji.GenericError("file already exists: %s" % fn) - fd = os.open(fn, os.O_RDWR | os.O_CREAT, 0666) + fd = os.open(fn, os.O_RDWR | os.O_CREAT, 0o666) # log_error("fd=%r" %fd) try: if offset == 0 or (offset == -1 and size == len(contents)): @@ -12523,7 +12523,7 @@ def handle_upload(environ): size = 0 chksum = sum_cls() inf = environ['wsgi.input'] - fd = os.open(fn, os.O_RDWR | os.O_CREAT, 0666) + fd = os.open(fn, os.O_RDWR | os.O_CREAT, 0o666) try: try: fcntl.lockf(fd, fcntl.LOCK_EX|fcntl.LOCK_NB) diff --git a/koji/daemon.py b/koji/daemon.py index f298abc..9b98eea 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -113,7 +113,7 @@ def log_output(session, path, args, outfile, uploadpath, cwd=None, logerror=0, a flags = os.O_CREAT | os.O_WRONLY if append: flags |= os.O_APPEND - fd = os.open(outfile, flags, 0666) + fd = os.open(outfile, flags, 0o666) os.dup2(fd, 1) if logerror: os.dup2(fd, 2) diff --git a/koji/util.py b/koji/util.py index 96d24ab..dfbc020 100644 --- a/koji/util.py +++ b/koji/util.py @@ -466,12 +466,12 @@ class adler32_constructor(object): #mimicing the hashlib constructors def __init__(self, arg=''): - self._value = adler32(arg) & 0xffffffffL + self._value = adler32(arg) & 0xffffffff #the bitwise and works around a bug in some versions of python #see: https://bugs.python.org/issue1202 def update(self, arg): - self._value = adler32(arg, self._value) & 0xffffffffL + self._value = adler32(arg, self._value) & 0xffffffff def digest(self): return self._value diff --git a/util/koji-shadow b/util/koji-shadow index 0b93b84..d741c21 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -883,7 +883,7 @@ class BuildTracker(object): if options.link_imports: #bit of a hack, but faster than uploading dst = "%s/%s/%s" % (koji.pathinfo.work(), serverdir, fn) - old_umask = os.umask(002) + old_umask = os.umask(0o02) try: koji.ensuredir(os.path.dirname(dst)) os.chown(os.path.dirname(dst), 48, 48) #XXX - hack @@ -1303,7 +1303,7 @@ def main(args): if options.logfile: filename = options.logfile try: - logfile = os.open(filename,os.O_CREAT|os.O_RDWR|os.O_APPEND, 0777) + logfile = os.open(filename,os.O_CREAT|os.O_RDWR|os.O_APPEND, 0o777) except: logfile = None if logfile is not None: From e8cf04f6ad3f2467a5644aba2f51cc85b1e00368 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 10/61] python-modernize -f lib2to3.fixes.fix_paren --- diff --git a/builder/kojid b/builder/kojid index 921bac4..8e33150 100755 --- a/builder/kojid +++ b/builder/kojid @@ -658,7 +658,7 @@ class BuildRoot(object): repodir = pathinfo.repo(self.repo_info['id'], self.repo_info['tag_name']) repomdpath = os.path.join(repodir, self.br_arch, 'repodata', 'repomd.xml') - opts = dict([(k, getattr(self.options, k)) for k in 'topurl','topdir']) + opts = dict([(k, getattr(self.options, k)) for k in ('topurl','topdir')]) opts['tempdir'] = self.options.workdir fo = koji.openRemoteFile(repomdpath, **opts) try: @@ -913,7 +913,7 @@ class BuildTask(BaseTaskHandler): #srpm arg should be a path relative to /work self.logger.debug("Reading SRPM") relpath = "work/%s" % srpm - opts = dict([(k, getattr(self.options, k)) for k in 'topurl','topdir']) + opts = dict([(k, getattr(self.options, k)) for k in ('topurl','topdir')]) opts['tempdir'] = self.workdir fo = koji.openRemoteFile(relpath, **opts) h = koji.get_rpm_header(fo) @@ -3260,7 +3260,7 @@ class OzImageTask(BaseTaskHandler): self.getUploadDir(), logfile) kspath = os.path.join(scmsrcdir, os.path.basename(ksfile)) else: - tops = dict([(k, getattr(self.options, k)) for k in 'topurl','topdir']) + tops = dict([(k, getattr(self.options, k)) for k in ('topurl','topdir')]) tops['tempdir'] = self.workdir ks_src = koji.openRemoteFile(ksfile, **tops) kspath = os.path.join(self.workdir, os.path.basename(ksfile)) @@ -4067,7 +4067,7 @@ class BuildIndirectionImageTask(OzImageTask): self.getUploadDir(), logfile) final_path = os.path.join(scmsrcdir, os.path.basename(filepath)) else: - tops = dict([(k, getattr(self.options, k)) for k in 'topurl','topdir']) + tops = dict([(k, getattr(self.options, k)) for k in ('topurl','topdir')]) tops['tempdir'] = self.workdir remote_fileobj = koji.openRemoteFile(filepath, **tops) final_path = os.path.join(self.workdir, os.path.basename(filepath)) From c87cab8f54c6da07d47c1f03c2d8ca565969ad48 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 11/61] python-modernize -f lib2to3.fixes.fix_tuple_params --- diff --git a/util/koji-shadow b/util/koji-shadow index d741c21..da782bf 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -662,8 +662,10 @@ class BuildTracker(object): return grey return default - def rpmvercmp(self, (e1, v1, r1), (e2, v2, r2)): + def rpmvercmp(self, evr1, evr2): """find out which build is newer""" + (e1, v1, r1) = evr1 + (e2, v2, r2) = evr2 rc = rpm.labelCompare((e1, v1, r1), (e2, v2, r2)) if rc == 1: #first evr wins From 6a0a5a232bb0364ad7a1819b976ae2ec5a4d82b0 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 12/61] python-modernize -f libmodernize.fixes.fix_basestring --- diff --git a/builder/kojid b/builder/kojid index 8e33150..30a92db 100755 --- a/builder/kojid +++ b/builder/kojid @@ -23,6 +23,7 @@ from __future__ import absolute_import from six.moves import zip +import six try: import krbV except ImportError: # pragma: no cover @@ -2706,7 +2707,7 @@ class ImageTask(BaseTaskHandler): self.ks.handler.repo.repoList = [] # delete whatever the ks file told us if opts.get('repo'): user_repos = opts['repo'] - if isinstance(user_repos, basestring): + if isinstance(user_repos, six.string_types): user_repos = user_repos.split(',') index = 0 for user_repo in user_repos: @@ -5382,7 +5383,7 @@ class WaitrepoTask(BaseTaskHandler): if not targets: raise koji.GenericError("No build target for tag: %s" % taginfo['name']) - if isinstance(newer_than, basestring) and newer_than.lower() == "now": + if isinstance(newer_than, six.string_types) and newer_than.lower() == "now": newer_than = start if not isinstance(newer_than, (type(None), int, long, float)): raise koji.GenericError("Invalid value for newer_than: %s" % newer_than) diff --git a/hub/kojihub.py b/hub/kojihub.py index 839b648..febdc3b 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -862,7 +862,7 @@ def _direct_pkglist_add(taginfo, pkginfo, owner, block, extra_arches, force, tag_id = tag['id'] pkg = lookup_package(pkginfo, strict=False) if not pkg: - if not isinstance(pkginfo, basestring): + if not isinstance(pkginfo, six.string_types): raise koji.GenericError("Invalid package: %s" % pkginfo) if owner is not None: owner = get_user(owner, strict=True)['id'] @@ -1303,7 +1303,7 @@ def readTaggedRPMS(tag, package=None, arch=None, event=None, inherit=False, late joins.append('LEFT OUTER JOIN rpmsigs on rpminfo.id = rpmsigs.rpm_id') if arch: data['arch'] = arch - if isinstance(arch, basestring): + if isinstance(arch, six.string_types): clauses.append('rpminfo.arch = %(arch)s') elif isinstance(arch, (list, tuple)): clauses.append('rpminfo.arch IN %(arch)s') @@ -2089,7 +2089,7 @@ def remove_host_from_channel(hostname, channel_name): def rename_channel(old, new): """Rename a channel""" context.session.assertPerm('admin') - if not isinstance(new, basestring): + if not isinstance(new, six.string_types): raise koji.GenericError("new channel name must be a string") cinfo = get_channel(old, strict=True) dup_check = get_channel(new, strict=False) @@ -2973,7 +2973,7 @@ def get_tag(tagInfo, strict=False, event=None): clauses = [eventCondition(event, table='tag_config')] if isinstance(tagInfo, (int, long)): clauses.append("tag.id = %(tagInfo)i") - elif isinstance(tagInfo, basestring): + elif isinstance(tagInfo, six.string_types): clauses.append("tag.name = %(tagInfo)s") else: raise koji.GenericError('invalid type for tagInfo: %s' % type(tagInfo)) @@ -5191,7 +5191,7 @@ class CG_Importer(object): datetime.datetime.fromtimestamp(float(metadata['build']['end_time'])).isoformat(' ') owner = metadata['build'].get('owner', None) if owner: - if not isinstance(owner, basestring): + if not isinstance(owner, six.string_types): raise koji.GenericError("Invalid owner format (expected username): %s" % owner) buildinfo['owner'] = get_user(owner, strict=True)['id'] self.buildinfo = buildinfo @@ -5532,11 +5532,11 @@ def add_external_rpm(rpminfo, external_repo, strict=True): #sanity check rpminfo dtypes = ( - ('name', basestring), - ('version', basestring), - ('release', basestring), + ('name', six.string_types), + ('version', six.string_types), + ('release', six.string_types), ('epoch', (int, type(None))), - ('arch', basestring), + ('arch', six.string_types), ('payloadhash', str), ('size', int), ('buildtime', (int, long))) @@ -6677,7 +6677,7 @@ def query_history(tables=None, **kwargs): fields['creator.id = %(editor)i'] = '_created_by' fields['revoker.id = %(editor)i'] = '_revoked_by' elif arg == 'after': - if not isinstance(value, basestring): + if not isinstance(value, six.string_types): value = datetime.datetime.fromtimestamp(value).isoformat(' ') data['after'] = value clauses.append('ev1.time > %(after)s OR ev2.time > %(after)s') @@ -6692,7 +6692,7 @@ def query_history(tables=None, **kwargs): fields[c_test] = '_created_after_event' fields[r_test] = '_revoked_after_event' elif arg == 'before': - if not isinstance(value, basestring): + if not isinstance(value, six.string_types): value = datetime.datetime.fromtimestamp(value).isoformat(' ') data['before'] = value clauses.append('ev1.time < %(before)s OR ev2.time < %(before)s') @@ -7862,7 +7862,7 @@ def policy_get_pkg(data): if not pkginfo: #for some operations (e.g. adding a new package), the package #entry may not exist yet - if isinstance(data['package'], basestring): + if isinstance(data['package'], six.string_types): return {'id' : None, 'name' : data['package']} else: raise koji.GenericError("Invalid package: %s" % data['package']) @@ -8782,7 +8782,7 @@ class RootExports(object): # we will accept offset and size as strings to work around xmlrpc limits offset = koji.decode_int(offset) size = koji.decode_int(size) - if isinstance(md5sum, basestring): + if isinstance(md5sum, six.string_types): # this case is for backwards compatibility verify = "md5" digest = md5sum @@ -9888,7 +9888,7 @@ class RootExports(object): headers = koji.get_header_fields(rpm_path, headers) for key, value in headers.items(): - if isinstance(value, basestring): + if isinstance(value, six.string_types): headers[key] = koji.fixEncoding(value, remove_nonprintable=True) return headers diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index 23a2904..ec15856 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -583,7 +583,7 @@ def get_policy(opts, plugins): # tests can be limited to certain policies by setting a class variable for name, test in tests.iteritems(): if hasattr(test, 'policy'): - if isinstance(test.policy, basestring): + if isinstance(test.policy, six.string_types): if pname != test.policy: continue elif pname not in test.policy: diff --git a/koji/__init__.py b/koji/__init__.py index 6e4fa45..38c5c4b 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -997,7 +997,7 @@ def check_NVR(nvr, strict=False): return False def _check_NVR(nvr): - if isinstance(nvr, basestring): + if isinstance(nvr, six.string_types): nvr = parse_NVR(nvr) if '-' in nvr['version']: raise GenericError('The "-" character not allowed in version field') @@ -1026,7 +1026,7 @@ def check_NVRA(nvra, strict=False): def _check_NVRA(nvra): - if isinstance(nvra, basestring): + if isinstance(nvra, six.string_types): nvra = parse_NVRA(nvra) if '-' in nvra['version']: raise GenericError('The "-" character not allowed in version field') diff --git a/koji/compatrequests.py b/koji/compatrequests.py index be04a5b..7605efa 100644 --- a/koji/compatrequests.py +++ b/koji/compatrequests.py @@ -7,11 +7,13 @@ module that is based on the older codepaths in koji. It only provides the bits that koji needs. """ +from __future__ import absolute_import import six.moves.http_client import urlparse import urllib import sys import ssl.SSLCommon +import six try: from ssl import ssl as pyssl except ImportError: # pragma: no cover @@ -55,7 +57,7 @@ class Session(object): # Otherwise we make a new one default_port = 80 certs = {} - if isinstance(verify, basestring): + if isinstance(verify, six.string_types): certs['peer_ca_cert'] = verify if cert: certs['key_and_cert'] = cert diff --git a/koji/plugin.py b/koji/plugin.py index e4fe19d..2ac1db0 100644 --- a/koji/plugin.py +++ b/koji/plugin.py @@ -19,11 +19,13 @@ # Mike McLean # Mike Bonnet +from __future__ import absolute_import import imp import koji import logging import sys import traceback +import six # the available callback hooks and a list # of functions to be called for each event @@ -85,7 +87,7 @@ class PluginTracker(object): return self.plugins.get(name) def pathlist(self, path): - if isinstance(path, basestring): + if isinstance(path, six.string_types): return [path] else: return path diff --git a/koji/util.py b/koji/util.py index dfbc020..e5d0f7f 100644 --- a/koji/util.py +++ b/koji/util.py @@ -34,6 +34,7 @@ import time import six.moves.configparser from zlib import adler32 from six.moves import range +import six # imported from kojiweb and kojihub try: @@ -126,7 +127,7 @@ def multi_fnmatch(s, patterns): If patterns is a string, it will be split() first """ - if isinstance(patterns, basestring): + if isinstance(patterns, six.string_types): patterns = patterns.split() for pat in patterns: if fnmatch(s, pat): diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py index 9bbb40b..c775877 100644 --- a/www/kojiweb/wsgi_publisher.py +++ b/www/kojiweb/wsgi_publisher.py @@ -19,6 +19,7 @@ # Authors: # Mike McLean +from __future__ import absolute_import import cgi import inspect import koji @@ -32,6 +33,7 @@ import traceback from six.moves.configparser import RawConfigParser from koji.server import WSGIWrapper, ServerError, ServerRedirect from koji.util import dslice +import six class URLNotFound(ServerError): @@ -421,14 +423,14 @@ class Dispatcher(object): else: # last one wins headers[key] = (name, value) - if isinstance(result, basestring): + if isinstance(result, six.string_types): headers.setdefault('content-length', ('Content-Length', str(len(result)))) headers.setdefault('content-type', ('Content-Type', 'text/html')) headers = headers.values() + extra self.logger.debug("Headers:") self.logger.debug(koji.util.LazyString(pprint.pformat, [headers])) start_response(status, headers) - if isinstance(result, basestring): + if isinstance(result, six.string_types): result = [result] return result From 8567044a201da42382b403b6ccb36fcf387ab646 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 13/61] python-modernize -f libmodernize.fixes.fix_classic_division --- diff --git a/cli/koji b/cli/koji index 30e5ab2..e62ba3e 100755 --- a/cli/koji +++ b/cli/koji @@ -25,6 +25,7 @@ # Cristian Balint from __future__ import absolute_import +from __future__ import division import sys from six.moves import range from six.moves import zip @@ -5440,7 +5441,7 @@ def _pick_external_repo_priority(session, tag): if not repolist: priority = 5 else: - priority = (repolist[-1]['priority'] + 7) / 5 * 5 + priority = (repolist[-1]['priority'] + 7) // 5 * 5 #at least 3 higher than current max and a multiple of 5 return priority diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index ec15856..f10a120 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -19,6 +19,7 @@ # Mike McLean from __future__ import absolute_import +from __future__ import division from six.moves.configparser import RawConfigParser import datetime import inspect @@ -689,7 +690,7 @@ def handler(req): def get_memory_usage(): pagesize = resource.getpagesize() - statm = [pagesize*int(y)/1024 for y in "".join(open("/proc/self/statm").readlines()).strip().split()] + statm = [pagesize*int(y)//1024 for y in "".join(open("/proc/self/statm").readlines()).strip().split()] size, res, shr, text, lib, data, dirty = statm return res - shr diff --git a/koji/daemon.py b/koji/daemon.py index 9b98eea..538511f 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -21,6 +21,7 @@ # Mike Bonnet from __future__ import absolute_import +from __future__ import division import koji import koji.tasks from koji.tasks import safe_rmtree @@ -829,7 +830,7 @@ class TaskManager(object): #accept this task) bin_avail = avail.get(bin, [0]) self.logger.debug("available capacities for bin: %r" % bin_avail) - median = bin_avail[(len(bin_avail)-1)/2] + median = bin_avail[(len(bin_avail)-1)//2] self.logger.debug("ours: %.2f, median: %.2f" % (our_avail, median)) if not self.checkRelAvail(bin_avail, our_avail): #decline for now and give the upper half a chance @@ -847,7 +848,7 @@ class TaskManager(object): Check our available capacity against the capacity of other hosts in this bin. Return True if we should take a task, False otherwise. """ - median = bin_avail[(len(bin_avail)-1)/2] + median = bin_avail[(len(bin_avail)-1)//2] self.logger.debug("ours: %.2f, median: %.2f" % (avail, median)) if avail >= median: return True @@ -1040,7 +1041,7 @@ class TaskManager(object): raise IOError("No such directory: %s" % br_path) fs_stat = os.statvfs(br_path) available = fs_stat.f_bavail * fs_stat.f_bsize - availableMB = available / 1024 / 1024 + availableMB = available // 1024**2 self.logger.debug("disk space available in '%s': %i MB", br_path, availableMB) if availableMB < self.options.minspace: self.status = "Insufficient disk space: %i MB, %i MB required" % (availableMB, self.options.minspace) diff --git a/www/lib/kojiweb/util.py b/www/lib/kojiweb/util.py index dd48295..23d168f 100644 --- a/www/lib/kojiweb/util.py +++ b/www/lib/kojiweb/util.py @@ -21,6 +21,7 @@ # Mike McLean from __future__ import absolute_import +from __future__ import division import Cheetah.Template import datetime import koji @@ -152,7 +153,7 @@ def _genHTML(environ, fileName): def _truncTime(): now = datetime.datetime.now() # truncate to the nearest 15 minutes - return now.replace(minute=(now.minute / 15 * 15), second=0, microsecond=0) + return now.replace(minute=(now.minute // 15 * 15), second=0, microsecond=0) def _genToken(environ, tstamp=None): if 'koji.currentLogin' in environ and environ['koji.currentLogin']: @@ -357,9 +358,9 @@ def _populateValues(values, dataName, prefix, data, totalRows, start, count, pag values[(prefix and prefix + 'Count' or 'count')] = count values[(prefix and prefix + 'Range' or 'range')] = pageSize values[(prefix and prefix + 'Order' or 'order')] = order - currentPage = start / pageSize + currentPage = start // pageSize values[(prefix and prefix + 'CurrentPage' or 'currentPage')] = currentPage - totalPages = totalRows / pageSize + totalPages = totalRows // pageSize if totalRows % pageSize > 0: totalPages += 1 pages = [page for page in range(0, totalPages) if (abs(page - currentPage) < 100 or ((page + 1) % 100 == 0))] From 68bf19c73909553d50c0f11b722892c62da4b8f6 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 14/61] python-modernize -f libmodernize.fixes.fix_dict_six --- diff --git a/builder/kojid b/builder/kojid index 30a92db..bc7807e 100755 --- a/builder/kojid +++ b/builder/kojid @@ -967,7 +967,7 @@ class BuildTask(BaseTaskHandler): archdict[a] = 1 if not archdict: raise koji.BuildError("No matching arches were found") - return archdict.keys() + return list(archdict.keys()) def choose_taskarch(self, arch, srpm, build_tag): @@ -1029,7 +1029,7 @@ class BuildTask(BaseTaskHandler): # wait for subtasks to finish failany = not getattr(self.options, 'build_arch_can_fail', False) - results = self.wait(subtasks.values(), all=True, failany=failany) + results = self.wait(list(subtasks.values()), all=True, failany=failany) # finalize import # merge data into needed args for completeBuild call @@ -1037,7 +1037,7 @@ class BuildTask(BaseTaskHandler): brmap = {} logs = {} built_srpm = None - for (arch, task_id) in subtasks.iteritems(): + for (arch, task_id) in six.iteritems(subtasks): result = results[task_id] self.logger.debug("DEBUG: %r : %r " % (arch,result,)) brootid = result['brootid'] @@ -1516,7 +1516,7 @@ class BuildMavenTask(BaseBuildTask): for filepath in logs: self.uploadFile(os.path.join(outputdir, filepath), relPath=os.path.dirname(filepath)) - for relpath, files in output_files.iteritems(): + for relpath, files in six.iteritems(output_files): for filename in files: self.uploadFile(os.path.join(outputdir, relpath, filename), relPath=relpath) @@ -1976,7 +1976,7 @@ class ChainMavenTask(MultiPlatformTask): running[task_id] = package del todo[package] try: - results = self.wait(running.keys()) + results = self.wait(list(running.keys())) except (six.moves.xmlrpc_client.Fault, koji.GenericError) as e: # One task has failed, wait for the rest to complete before the # chainmaven task fails. self.wait(all=True) should thrown an exception. @@ -2029,8 +2029,8 @@ class ChainMavenTask(MultiPlatformTask): have the same keys and those keys have the same values. If a value is list, it will be considered equal to a list with the same values in a different order.""" - akeys = a.keys() - bkeys = b.keys() + akeys = list(a.keys()) + bkeys = list(b.keys()) if sorted(akeys) != sorted(bkeys): return False for key in akeys: @@ -2191,7 +2191,7 @@ class BuildBaseImageTask(BuildImageTask): canfail.append(subtasks[arch]) self.logger.debug("Got image subtasks: %r" % (subtasks)) self.logger.debug("Waiting on image subtasks (%s can fail)..." % canfail) - results = self.wait(subtasks.values(), all=True, failany=True, canfail=canfail) + results = self.wait(list(subtasks.values()), all=True, failany=True, canfail=canfail) # if everything failed, fail even if all subtasks are in canfail self.logger.debug('subtask results: %r', results) @@ -2500,7 +2500,7 @@ class BuildLiveMediaTask(BuildImageTask): self.logger.debug("Got image subtasks: %r", subtasks) self.logger.debug("Waiting on livemedia subtasks...") - results = self.wait(subtasks.values(), all=True, failany=True, canfail=canfail) + results = self.wait(list(subtasks.values()), all=True, failany=True, canfail=canfail) # if everything failed, fail even if all subtasks are in canfail self.logger.debug('subtask results: %r', results) @@ -2536,7 +2536,7 @@ class BuildLiveMediaTask(BuildImageTask): wrapper_tasks[arch] = self.subtask('wrapperRPM', arglist, label='wrapper %s' % arch, arch='noarch') - results2 = self.wait(wrapper_tasks.values(), all=True, failany=True) + results2 = self.wait(list(wrapper_tasks.values()), all=True, failany=True) self.logger.debug('wrapper results: %r', results2) # add wrapper rpm results into main results @@ -2781,7 +2781,7 @@ class ImageTask(BaseTaskHandler): 'TC': 'T', } - for k, v in substitutions.iteritems(): + for k, v in six.iteritems(substitutions): if k in name: name = name.replace(k, v) if k in version: @@ -3538,7 +3538,7 @@ class BaseImageTask(OzImageTask): if len(formats) == 0: # we only want a raw disk image (no format option given) f_dict['raw'] = True - elif 'raw' not in f_dict.keys(): + elif 'raw' not in list(f_dict.keys()): f_dict['raw'] = False self.logger.debug('Image delivery plan: %s' % f_dict) return f_dict @@ -4762,7 +4762,7 @@ Build Info: %(weburl)s/buildinfo?buildID=%(build_id)i\r def uniq(self, items): """Remove duplicates from the list of items, and sort the list.""" m = dict(list(zip(items, [1] * len(items)))) - l = m.keys() + l = list(m.keys()) l.sort() return l @@ -4807,8 +4807,8 @@ class NewRepoTask(BaseTaskHandler): # gather subtask results data = {} if subtasks: - results = self.wait(subtasks.values(), all=True, failany=True) - for (arch, task_id) in subtasks.iteritems(): + results = self.wait(list(subtasks.values()), all=True, failany=True) + for (arch, task_id) in six.iteritems(subtasks): data[arch] = results[task_id] self.logger.debug("DEBUG: %r : %r " % (arch,data[arch],)) @@ -4967,7 +4967,7 @@ class NewDistRepoTask(BaseTaskHandler): method='createdistrepo', arglist=arglist, label=arch, parent=self.id, arch='noarch') if len(subtasks) > 0 and task_opts['multilib']: - results = self.wait(subtasks.values(), all=True, failany=True) + results = self.wait(list(subtasks.values()), all=True, failany=True) for arch in arch32s: # move the 32-bit task output to the final resting place # so the 64-bit arches can use it for multilib @@ -4983,8 +4983,8 @@ class NewDistRepoTask(BaseTaskHandler): parent=self.id, arch='noarch') # wait for 64-bit subtasks to finish data = {} - results = self.wait(subtasks.values(), all=True, failany=True) - for (arch, task_id) in subtasks.iteritems(): + results = self.wait(list(subtasks.values()), all=True, failany=True) + for (arch, task_id) in six.iteritems(subtasks): data[arch] = results[task_id] self.logger.debug("DEBUG: %r : %r " % (arch, data[arch])) if task_opts['multilib'] and arch in arch32s: @@ -5078,7 +5078,7 @@ class createDistRepoTask(CreaterepoTask): files.append(f) self.session.uploadWrapper('%s/%s' % (ddir, f), self.uploadpath, f) - return [self.uploadpath, files, self.sigmap.items()] + return [self.uploadpath, files, list(self.sigmap.items())] def do_multilib(self, arch, ml_arch, conf): self.repo_id = self.rinfo['id'] @@ -5258,7 +5258,7 @@ enabled=1 # select our rpms selected = {} for rpm_id in rpm_idx: - avail_keys = rpm_idx[rpm_id].keys() + avail_keys = list(rpm_idx[rpm_id].keys()) best_key = self.pick_key(keys, avail_keys) if best_key is None: # we lack a matching key for this rpm @@ -5331,7 +5331,7 @@ enabled=1 fmt = '%(name)s-%(version)s-%(release)s.%(arch)s' filenames = [[fmt % selected[r], r] for r in sig_missing] for fname, rpm_id in sorted(filenames): - avail = rpm_idx.get(rpm_id, {}).keys() + avail = list(rpm_idx.get(rpm_id, {}).keys()) outfile.write('%s: %r\n' % (fname, avail)) outfile.close() self.session.uploadWrapper(missing_log, self.uploadpath) @@ -5546,7 +5546,7 @@ def get_options(): defaults[name] = config.getboolean('kojid', name) elif name in ['plugin', 'plugins']: defaults['plugin'] = value.split() - elif name in defaults.keys(): + elif name in list(defaults.keys()): defaults[name] = value elif name.upper().startswith('RLIMIT_'): defaults[name.upper()] = value diff --git a/cli/koji b/cli/koji index e62ba3e..d6acd55 100755 --- a/cli/koji +++ b/cli/koji @@ -29,6 +29,7 @@ from __future__ import division import sys from six.moves import range from six.moves import zip +import six try: import krbV except ImportError: # pragma: no cover @@ -146,7 +147,7 @@ categories = { def get_epilog_str(progname=None): if progname is None: progname = os.path.basename(sys.argv[0]) or 'koji' - categories_ordered=', '.join(sorted(['all'] + categories.keys())) + categories_ordered=', '.join(sorted(['all'] + list(categories.keys()))) epilog_str = ''' Try "%(progname)s --help" for help about global options Try "%(progname)s help" to get all available commands @@ -246,7 +247,7 @@ def get_options(): assert False # pragma: no cover # update options according to local config - for name, value in result.iteritems(): + for name, value in six.iteritems(result): if getattr(options, name, None) is None: setattr(options, name, value) @@ -465,7 +466,7 @@ def watch_tasks(session,tasklist,quiet=False): rv = 1 for child in session.getTaskChildren(task_id): child_id = child['id'] - if not child_id in tasks.keys(): + if not child_id in list(tasks.keys()): tasks[child_id] = TaskWatcher(child_id, session, task.level + 1, quiet=quiet) tasks[child_id].update() # If we found new children, go through the list again, @@ -515,7 +516,7 @@ def watch_logs(session, tasklist, opts): output = list_task_output_all_volumes(session, task_id) # convert to list of (file, volume) files = [] - for filename, volumes in output.iteritems(): + for filename, volumes in six.iteritems(output): files += [(filename, volume) for volume in volumes] if opts.log: @@ -1170,9 +1171,9 @@ def handle_maven_build(options, session, args): section=build_opts.section) except ValueError as e: parser.error(e.args[0]) - opts = params.values()[0] + opts = list(params.values())[0] if opts.pop('type', 'maven') != 'maven': - parser.error(_("Section %s does not contain a maven-build config") % params.keys()[0]) + parser.error(_("Section %s does not contain a maven-build config") % list(params.keys())[0]) source = opts.pop('scmurl') else: source = args[1] @@ -1229,9 +1230,9 @@ def handle_wrapper_rpm(options, session, args): section=build_opts.section) except ValueError as e: parser.error(e.args[0]) - opts = params.values()[0] + opts = list(params.values())[0] if opts.get('type') != 'wrapper': - parser.error(_("Section %s does not contain a wrapper-rpm config") % params.keys()[0]) + parser.error(_("Section %s does not contain a wrapper-rpm config") % list(params.keys())[0]) url = opts['scmurl'] package = opts['buildrequires'][0] target_info = session.getBuildTarget(target, strict=True) @@ -1629,7 +1630,7 @@ def handle_import(options, session, args): nvr = "%(name)s-%(version)s-%(release)s" % koji.parse_NVRA(data['sourcerpm']) to_import.setdefault(nvr,[]).append((path,data)) builds_missing = False - nvrs = to_import.keys() + nvrs = list(to_import.keys()) nvrs.sort() for nvr in nvrs: to_import[nvr].sort() @@ -2091,7 +2092,7 @@ def handle_prune_signed_copies(options, session, args): #that the build was recently untagged from tags.setdefault(entry['tag_name'], 1) if options.debug: - print("Tags: %s" % tags.keys()) + print("Tags: %s" % list(tags.keys())) for tag_name in tags: if tag_name == options.trashcan_tag: if options.debug: @@ -2261,7 +2262,7 @@ def handle_prune_signed_copies(options, session, args): build_space = 0 if not by_sig and options.debug: print("(build has no signatures)") - for sigkey, rpms in by_sig.iteritems(): + for sigkey, rpms in six.iteritems(by_sig): mycount = 0 archdirs = {} sigdirs = {} @@ -2308,7 +2309,7 @@ def handle_prune_signed_copies(options, session, args): except OSError as e: print("Error removing %s: %s" % (signedpath, e)) if len(sigdirs) == 1: - dir = sigdirs.keys()[0] + dir = list(sigdirs.keys())[0] if options.test: print("Would have removed dir: %s" % dir) else: @@ -3675,35 +3676,35 @@ def handle_clone_tag(options, session, args): dstgroups[group['name']] = group #construct to-do lists. paddlist = [] # list containing new packages to be added from src tag - for (package_name, pkg) in srcpkgs.iteritems(): + for (package_name, pkg) in six.iteritems(srcpkgs): if package_name not in dstpkgs: paddlist.append(pkg) paddlist.sort(key = lambda x: x['package_name']) pdellist = [] # list containing packages no more present in dst tag - for (package_name, pkg) in dstpkgs.iteritems(): + for (package_name, pkg) in six.iteritems(dstpkgs): if package_name not in srcpkgs: pdellist.append(pkg) pdellist.sort(key = lambda x: x['package_name']) baddlist = [] # list containing new builds to be added from src tag - for (nvr, lbld) in srclblds.iteritems(): + for (nvr, lbld) in six.iteritems(srclblds): if nvr not in dstlblds: baddlist.append(lbld) baddlist.sort(key = lambda x: x['package_name']) bdellist = [] # list containing new builds to be removed from src tag - for (nvr, lbld) in dstlblds.iteritems(): + for (nvr, lbld) in six.iteritems(dstlblds): if nvr not in srclblds: bdellist.append(lbld) bdellist.sort(key = lambda x: x['package_name']) gaddlist = [] # list containing new groups to be added from src tag - for (grpname, group) in srcgroups.iteritems(): + for (grpname, group) in six.iteritems(srcgroups): if grpname not in dstgroups: gaddlist.append(group) gdellist = [] # list containing groups to be removed from src tag - for (grpname, group) in dstgroups.iteritems(): + for (grpname, group) in six.iteritems(dstgroups): if grpname not in srcgroups: gdellist.append(group) grpchanges = {} # dict of changes to make in shared groups - for (grpname, group) in srcgroups.iteritems(): + for (grpname, group) in six.iteritems(srcgroups): if grpname in dstgroups: grpchanges[grpname] = {'adds':[], 'dels':[]} # Store whether group is inherited or not @@ -4397,7 +4398,7 @@ def _print_histline(entry, **kwargs): else: return '%s.name' % key if edit: - keys = x.keys() + keys = list(x.keys()) keys.sort() y = other[-1] for key in keys: @@ -4412,7 +4413,7 @@ def _print_histline(entry, **kwargs): continue print(" %s: %s -> %s" % (key, x[key], y[key])) elif create and options.verbose and table != 'tag_listing': - keys = x.keys() + keys = list(x.keys()) keys.sort() # the table keys have already been represented in the base format string also_hidden = list(_table_keys[table]) @@ -4888,7 +4889,7 @@ def anon_handle_taginfo(options, session, args): print("Include all Maven archives?: %s" % (info['maven_include_all'] and 'yes' or 'no')) if 'extra' in info: print("Tag options:") - keys = info['extra'].keys() + keys = list(info['extra'].keys()) keys.sort() for key in keys: print(" %s : %s" % (key, pprint.pformat(info['extra'][key]))) @@ -7068,7 +7069,7 @@ def anon_handle_wait_repo(options, session, args): targets = session.getBuildTargets(destTagID=tag_info['id']) if targets: maybe = {}.fromkeys([t['build_tag_name'] for t in targets]) - maybe = maybe.keys() + maybe = list(maybe.keys()) maybe.sort() print("Suggested tags: %s" % ', '.join(maybe)) return 1 @@ -7493,7 +7494,7 @@ def handle_help(options, session, args): chosen = set(args) if options.admin: chosen.add('admin') - avail = set(categories.keys() + ['all']) + avail = set(list(categories.keys()) + ['all']) unavail = chosen - avail for arg in unavail: print("No such help category: %s" % arg) @@ -7506,7 +7507,7 @@ def handle_help(options, session, args): def list_commands(categories_chosen=None): if categories_chosen is None or "all" in categories_chosen: - categories_chosen = categories.keys() + categories_chosen = list(categories.keys()) else: # copy list since we're about to modify it categories_chosen = list(categories_chosen) diff --git a/hub/kojihub.py b/hub/kojihub.py index febdc3b..d91b501 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -671,12 +671,12 @@ def _writeInheritanceData(tag_id, changes, clear=False): data[parent_id] = link break if clear: - for link in data.itervalues(): + for link in six.itervalues(data): if not link.get('is_update'): link['delete link'] = True link['is_update'] = True changed = False - for link in data.itervalues(): + for link in six.itervalues(data): if link.get('is_update'): changed = True break @@ -686,17 +686,17 @@ def _writeInheritanceData(tag_id, changes, clear=False): return #check for duplicate priorities pri_index = {} - for link in data.itervalues(): + for link in six.itervalues(data): if link.get('delete link'): continue pri_index.setdefault(link['priority'], []).append(link) - for pri, dups in pri_index.iteritems(): + for pri, dups in six.iteritems(pri_index): if len(dups) <= 1: continue #oops, duplicate entries for a single priority dup_ids = [link['parent_id'] for link in dups] raise koji.GenericError("Inheritance priorities must be unique (pri %s: %r )" % (pri, dup_ids)) - for parent_id, link in data.iteritems(): + for parent_id, link in six.iteritems(data): if not link.get('is_update'): continue # revoke old values @@ -704,7 +704,7 @@ def _writeInheritanceData(tag_id, changes, clear=False): clauses=['tag_id=%(tag_id)s', 'parent_id = %(parent_id)s']) update.make_revoke() update.execute() - for parent_id, link in data.iteritems(): + for parent_id, link in six.iteritems(data): if not link.get('is_update'): continue # skip rest if we are just deleting @@ -1972,7 +1972,7 @@ def get_tag_groups(tag, event=None, inherit=True, incl_pkgs=True, incl_reqs=True groups.setdefault(grp_id, group) if incl_pkgs: - for group in groups.itervalues(): + for group in six.itervalues(groups): group['packagelist'] = {} fields = ('group_id', 'tag_id', 'package', 'blocked', 'type', 'basearchonly', 'requires') q = """ @@ -1994,7 +1994,7 @@ def get_tag_groups(tag, event=None, inherit=True, incl_pkgs=True, incl_reqs=True if incl_reqs: # and now the group reqs - for group in groups.itervalues(): + for group in six.itervalues(groups): group['grouplist'] = {} fields = ('group_id', 'tag_id', 'req_id', 'blocked', 'type', 'is_metapkg', 'name') q = """SELECT %s FROM group_req_listing JOIN groups on req_id = id @@ -2160,7 +2160,7 @@ def get_all_arches(): #in a perfect world, this list would only include canonical #arches, but not all admins will undertand that. ret[koji.canonArch(arch)] = 1 - return ret.keys() + return list(ret.keys()) def get_active_tasks(host=None): """Return data on tasks that are yet to be run""" @@ -2410,7 +2410,7 @@ def repo_init(tag, with_src=False, with_debuginfo=False, event=None): os.symlink(relpath, destlink) except: log_error('Error linking %s to %s' % (destlink, relpath)) - for artifact_dir, artifacts in artifact_dirs.iteritems(): + for artifact_dir, artifacts in six.iteritems(artifact_dirs): _write_maven_repo_metadata(artifact_dir, artifacts) koji.plugin.run_callbacks('postRepoInit', tag=tinfo, with_src=with_src, with_debuginfo=with_debuginfo, @@ -2549,7 +2549,7 @@ def repo_references(repo_id): 'host_id': 'host_id', 'create_event': 'create_event', 'state': 'state'} - fields, aliases = list(zip(*fields.items())) + fields, aliases = list(zip(*list(fields.items()))) values = {'repo_id': repo_id} clauses = ['repo_id=%(repo_id)s', 'retire_event IS NULL'] query = QueryProcessor(columns=fields, aliases=aliases, tables=['standard_buildroot'], @@ -2914,7 +2914,7 @@ def _create_tag(name, parent=None, arches=None, perm=None, locked=False, maven_s # add extra data if extra is not None: - for key, value in extra.iteritems(): + for key, value in six.iteritems(extra): data = { 'tag_id': tag_id, 'key': key, @@ -2979,7 +2979,7 @@ def get_tag(tagInfo, strict=False, event=None): raise koji.GenericError('invalid type for tagInfo: %s' % type(tagInfo)) data = {'tagInfo': tagInfo} - fields, aliases = list(zip(*fields.items())) + fields, aliases = list(zip(*list(fields.items()))) query = QueryProcessor(columns=fields, aliases=aliases, tables=tables, joins=joins, clauses=clauses, values=data) result = query.executeOne() @@ -4964,7 +4964,7 @@ def import_build(srpm, rpms, brmap=None, task_id=None, build_id=None, logs=None) import_rpm_file(fn, binfo, rpminfo) add_rpm_sig(rpminfo['id'], koji.rip_rpm_sighdr(fn)) if logs: - for key, files in logs.iteritems(): + for key, files in six.iteritems(logs): if not key: key = None for relpath in files: @@ -6708,7 +6708,7 @@ def query_history(tables=None, **kwargs): fields[r_test] = '_revoked_before_event' if skip: continue - fields, aliases = list(zip(*fields.items())) + fields, aliases = list(zip(*list(fields.items()))) query = QueryProcessor(columns=fields, aliases=aliases, tables=[table], joins=joins, clauses=clauses, values=data) ret[table] = query.iterate() @@ -6847,7 +6847,7 @@ def build_references(build_id, limit=None): idx.setdefault(row['id'], row) if limit is not None and len(idx) > limit: break - ret['rpms'] = idx.values() + ret['rpms'] = list(idx.values()) ret['component_of'] = [] # find images/archives that contain the build rpms @@ -6878,7 +6878,7 @@ def build_references(build_id, limit=None): idx.setdefault(row['id'], row) if limit is not None and len(idx) > limit: break - ret['archives'] = idx.values() + ret['archives'] = list(idx.values()) # find images/archives that contain the build archives fields = ['archive_id'] @@ -7202,7 +7202,7 @@ def get_notification_recipients(build, tag_id, state): #FIXME - if tag_id is None, we don't have a good way to get the package owner. # using all package owners from all tags would be way overkill. - emails_uniq = dict([(x, 1) for x in emails]).keys() + emails_uniq = list(dict([(x, 1) for x in emails]).keys()) return emails_uniq def tag_notification(is_successful, tag_id, from_id, build_id, user_id, ignore_success=False, failure_msg=''): @@ -7225,7 +7225,7 @@ def tag_notification(is_successful, tag_id, from_id, build_id, user_id, ignore_s from_tag = get_tag(from_id) for email in get_notification_recipients(build, from_tag['id'], state): recipients[email] = 1 - recipients_uniq = recipients.keys() + recipients_uniq = list(recipients.keys()) if len(recipients_uniq) > 0 and not (is_successful and ignore_success): task_id = make_task('tagNotification', [recipients_uniq, is_successful, tag_id, from_id, build_id, user_id, ignore_success, failure_msg]) return task_id @@ -7439,8 +7439,8 @@ class InsertProcessor(object): if not self.data and not self.rawdata: return "-- incomplete update: no assigns" parts = ['INSERT INTO %s ' % self.table] - columns = self.data.keys() - columns.extend(self.rawdata.keys()) + columns = list(self.data.keys()) + columns.extend(list(self.rawdata.keys())) parts.append("(%s) " % ', '.join(columns)) values = [] for key in columns: @@ -7483,7 +7483,7 @@ class InsertProcessor(object): del data['create_event'] del data['creator_id'] clauses = ["%s = %%(%s)s" % (k, k) for k in data] - query = QueryProcessor(columns=data.keys(), tables=[self.table], + query = QueryProcessor(columns=list(data.keys()), tables=[self.table], clauses=clauses, values=data) if query.execute(): return True @@ -8144,7 +8144,7 @@ class UserInGroupTest(koji.policy.BaseSimpleTest): return False groups = koji.auth.get_user_groups(user['id']) args = self.str.split()[1:] - for group_id, group in groups.iteritems(): + for group_id, group in six.iteritems(groups): for pattern in args: if fnmatch.fnmatch(group, pattern): return True @@ -9953,9 +9953,9 @@ class RootExports(object): userID = get_user(userID, strict=True)['id'] if pkgID is not None: pkgID = get_package_id(pkgID, strict=True) - result_list = readPackageList(tagID=tagID, userID=userID, pkgID=pkgID, + result_list = list(readPackageList(tagID=tagID, userID=userID, pkgID=pkgID, inherit=inherited, with_dups=with_dups, - event=event).values() + event=event).values()) if with_dups: # when with_dups=True, readPackageList returns a list of list of dicts # convert it to a list of dicts for consistency @@ -11552,7 +11552,7 @@ class HostExports(object): safer_move(fn, dest) os.symlink(dest, fn) if logs: - for key, files in logs.iteritems(): + for key, files in six.iteritems(logs): if key: logdir = "%s/logs/%s" % (dir, key) else: @@ -11575,7 +11575,7 @@ class HostExports(object): scratchdir = koji.pathinfo.scratch() username = get_user(task.getOwner())['name'] destdir = os.path.join(scratchdir, username, 'task_%s' % task_id) - for reldir, files in results['files'].items() + [('', results['logs'])]: + for reldir, files in list(results['files'].items()) + [('', results['logs'])]: for filename in files: if reldir: relpath = os.path.join(reldir, filename) @@ -11607,7 +11607,7 @@ class HostExports(object): scratchdir = koji.pathinfo.scratch() username = get_user(task.getOwner())['name'] destdir = os.path.join(scratchdir, username, 'task_%s' % task_id) - for relpath in results['output'].keys() + results['logs']: + for relpath in list(results['output'].keys()) + results['logs']: filename = os.path.join(koji.pathinfo.task(results['task_id']), relpath) dest = os.path.join(destdir, relpath) koji.ensuredir(os.path.dirname(dest)) @@ -11763,7 +11763,7 @@ class HostExports(object): maven_buildroot_id = maven_results['buildroot_id'] maven_task_dir = koji.pathinfo.task(maven_task_id) # import the build output - for relpath, files in maven_results['files'].iteritems(): + for relpath, files in six.iteritems(maven_results['files']): dir_maven_info = maven_info poms = [f for f in files if f.endswith('.pom')] if len(poms) == 0: @@ -11911,7 +11911,7 @@ class HostExports(object): task_dir = koji.pathinfo.task(results['task_id']) # import the build output - for relpath, metadata in results['output'].iteritems(): + for relpath, metadata in six.iteritems(results['output']): archivetype = get_archive_type(relpath) if not archivetype: # Unknown archive type, fail the build @@ -12137,7 +12137,7 @@ class HostExports(object): for dep in extra_deps: if isinstance(dep, (int, long)): task_output = list_task_output(dep, stat=True) - for filepath, filestats in task_output.iteritems(): + for filepath, filestats in six.iteritems(task_output): if os.path.splitext(filepath)[1] in ['.log', '.md5', '.sha1']: continue tokens = filepath.split('/') @@ -12170,7 +12170,7 @@ class HostExports(object): logger.error("Current build is %s, new build is %s.", idx_build, archive['build_id']) maven_build_index[archive['group_id']][archive['artifact_id']][archive['version']] = archive['build_id'] - ignore.extend(task_deps.values()) + ignore.extend(list(task_deps.values())) SNAPSHOT_RE = re.compile(r'-\d{8}\.\d{6}-\d+') ignore_by_label = {} @@ -12223,7 +12223,7 @@ class HostExports(object): if build_id: build = get_build(build_id) logger.error("g:a:v supplied by build %(nvr)s", build) - logger.error("Build supplies %i archives: %r", len(build_archives), build_archives.keys()) + logger.error("Build supplies %i archives: %r", len(build_archives), list(build_archives.keys())) if tag_archive: logger.error("Size mismatch, br: %i, db: %i", fileinfo['size'], tag_archive['size']) raise koji.BuildrootError('Unknown file in build environment: %s, size: %s' % \ @@ -12301,7 +12301,7 @@ class HostExports(object): repodir = koji.pathinfo.repo(repo_id, rinfo['tag_name']) workdir = koji.pathinfo.work() if not rinfo['dist']: - for arch, (uploadpath, files) in data.iteritems(): + for arch, (uploadpath, files) in six.iteritems(data): archdir = "%s/%s" % (repodir, koji.canonArch(arch)) if not os.path.isdir(archdir): raise koji.GenericError("Repo arch directory missing: %s" % archdir) diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index f10a120..1f3ffd0 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -112,7 +112,7 @@ class HandlerRegistry(object): Handlers are functions marked with one of the decorators defined in koji.plugin """ - for v in vars(plugin).itervalues(): + for v in six.itervalues(vars(plugin)): if isinstance(v, type): #skip classes continue @@ -169,7 +169,7 @@ class HandlerRegistry(object): return args def system_listMethods(self): - return self.funcs.keys() + return list(self.funcs.keys()) def system_methodSignature(self, method): #it is not possible to autogenerate this data @@ -515,7 +515,7 @@ def load_config(environ): opts['policy'] = dict(config.items('policy')) else: opts['policy'] = {} - for pname, text in _default_policies.iteritems(): + for pname, text in six.iteritems(_default_policies): opts['policy'].setdefault(pname, text) # use configured KojiDir if opts.get('KojiDir') is not None: @@ -577,12 +577,12 @@ def get_policy(opts, plugins): for plugin_name in opts.get('Plugins', '').split(): alltests.append(koji.policy.findSimpleTests(vars(plugins.get(plugin_name)))) policy = {} - for pname, text in opts['policy'].iteritems(): + for pname, text in six.iteritems(opts['policy']): #filter/merge tests merged = {} for tests in alltests: # tests can be limited to certain policies by setting a class variable - for name, test in tests.iteritems(): + for name, test in six.iteritems(tests): if hasattr(test, 'policy'): if isinstance(test.policy, six.string_types): if pname != test.policy: diff --git a/hub/rpmdiff b/hub/rpmdiff index 5972377..b11c300 100755 --- a/hub/rpmdiff +++ b/hub/rpmdiff @@ -27,6 +27,7 @@ import itertools import sys, getopt from six.moves import zip +import six class Rpmdiff: @@ -113,8 +114,8 @@ class Rpmdiff: old_files_dict = self.__fileIteratorToDict(old.fiFromHeader()) new_files_dict = self.__fileIteratorToDict(new.fiFromHeader()) - files = list(set(itertools.chain(old_files_dict.iterkeys(), - new_files_dict.iterkeys()))) + files = list(set(itertools.chain(six.iterkeys(old_files_dict), + six.iterkeys(new_files_dict)))) files.sort() for f in files: diff --git a/koji/__init__.py b/koji/__init__.py index 38c5c4b..39be2eb 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -631,11 +631,11 @@ class RawHeader(object): print("Store at offset %d (%0x)" % (store, store)) #sort entries by offset, dtype #also rearrange: tag, dtype, offset, count -> offset, dtype, tag, count - order = sorted([(x[2], x[1], x[0], x[3]) for x in self.index.itervalues()]) + order = sorted([(x[2], x[1], x[0], x[3]) for x in six.itervalues(self.index)]) next = store #map some rpmtag codes tags = {} - for name, code in rpm.__dict__.iteritems(): + for name, code in six.iteritems(rpm.__dict__): if name.startswith('RPMTAG_') and isinstance(code, int): tags[code] = name[7:].lower() for entry in order: @@ -1137,7 +1137,7 @@ def parse_pom(path=None, contents=None): xml.sax.parseString(contents, handler) for field in fields: - if field not in values.keys(): + if field not in list(values.keys()): raise GenericError('could not extract %s from POM: %s' % (field, (path or ''))) return values @@ -1438,7 +1438,7 @@ def genMockConfig(name, arch, managed=False, repoid=None, tag_name=None, **opts) if opts.get('maven_opts'): mavenrc = 'export MAVEN_OPTS="%s"\n' % ' '.join(opts['maven_opts']) if opts.get('maven_envs'): - for name, val in opts['maven_envs'].iteritems(): + for name, val in six.iteritems(opts['maven_envs']): mavenrc += 'export %s="%s"\n' % (name, val) if mavenrc: files['etc/mavenrc'] = mavenrc @@ -1501,10 +1501,10 @@ name=build """ % locals()) parts.append("\n") - for key, value in config_opts.iteritems(): + for key, value in six.iteritems(config_opts): parts.append("config_opts[%r] = %r\n" % (key, value)) parts.append("\n") - for key, value in plugin_conf.iteritems(): + for key, value in six.iteritems(plugin_conf): parts.append("config_opts['plugin_conf'][%r] = %r\n" % (key, value)) parts.append("\n") @@ -1512,14 +1512,14 @@ name=build # This line is REQUIRED for mock to work if bind_opts defined. parts.append("config_opts['internal_dev_setup'] = False\n") for key in bind_opts.keys(): - for mnt_src, mnt_dest in bind_opts.get(key).iteritems(): + for mnt_src, mnt_dest in six.iteritems(bind_opts.get(key)): parts.append("config_opts['plugin_conf']['bind_mount_opts'][%r].append((%r, %r))\n" % (key, mnt_src, mnt_dest)) parts.append("\n") - for key, value in macros.iteritems(): + for key, value in six.iteritems(macros): parts.append("config_opts['macros'][%r] = %r\n" % (key, value)) parts.append("\n") - for key, value in files.iteritems(): + for key, value in six.iteritems(files): parts.append("config_opts['files'][%r] = %r\n" % (key, value)) return ''.join(parts) @@ -2699,7 +2699,7 @@ class DBHandler(logging.Handler): values = [] data = {} record.message = record.getMessage() - for key, value in self.mapping.iteritems(): + for key, value in six.iteritems(self.mapping): value = str(value) if value.find("%(asctime)") >= 0: if self.formatter: diff --git a/koji/auth.py b/koji/auth.py index d0dc5f4..3cc845b 100644 --- a/koji/auth.py +++ b/koji/auth.py @@ -30,6 +30,7 @@ import cgi #for parse_qs from .context import context from six.moves import range from six.moves import zip +import six # 1 - load session if provided # - check uri for session id @@ -99,7 +100,7 @@ class Session(object): 'EXTRACT(EPOCH FROM update_time)': 'update_ts', 'user_id': 'user_id', } - fields, aliases = list(zip(*fields.items())) + fields, aliases = list(zip(*list(fields.items()))) q = """ SELECT %s FROM sessions WHERE id = %%(id)i @@ -528,7 +529,7 @@ class Session(object): def getPerms(self): if not self.logged_in: return [] - return self.perms.keys() + return list(self.perms.keys()) def hasPerm(self, name): if not self.logged_in: @@ -741,7 +742,7 @@ if __name__ == '__main__': print("logging in with session 1") session_info = sess.login('host/1', 'foobar', {'hostip':'127.0.0.1'}) #wrap values in lists - session_info = dict([[k, [v]] for k, v in session_info.iteritems()]) + session_info = dict([[k, [v]] for k, v in six.iteritems(session_info)]) print("Session 1: %s" % sess) print("Session 1 info: %r" % session_info) print("Creating session 2") diff --git a/koji/context.py b/koji/context.py index ef35a21..707c626 100755 --- a/koji/context.py +++ b/koji/context.py @@ -27,6 +27,7 @@ from __future__ import absolute_import import six.moves._thread from six.moves import range +import six class _data(object): pass @@ -67,7 +68,7 @@ class ThreadLocal(object): id = six.moves._thread.get_ident() tdict = object.__getattribute__(self, '_tdict') return "(current thread: %s) {" % id + \ - ", ".join(["%s : %s" %(k, v.__dict__) for (k, v) in tdict.iteritems()]) + \ + ", ".join(["%s : %s" %(k, v.__dict__) for (k, v) in six.iteritems(tdict)]) + \ "}" def _threadclear(self): diff --git a/koji/daemon.py b/koji/daemon.py index 538511f..dbcbce3 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -38,6 +38,7 @@ import traceback import errno import six.moves.xmlrpc_client from six.moves import range +import six def incremental_upload(session, fname, fd, path, retries=5, logger=None): @@ -528,7 +529,7 @@ class TaskManager(object): """Attempt to shut down cleanly""" for task_id in self.pids.keys(): self.cleanupTask(task_id) - self.session.host.freeTasks(self.tasks.keys()) + self.session.host.freeTasks(list(self.tasks.keys())) self.session.host.updateHost(task_load=0.0, ready=False) def updateBuildroots(self, nolocal=False): @@ -559,14 +560,14 @@ class TaskManager(object): #task not running - expire the buildroot #TODO - consider recycling hooks here (with strong sanity checks) self.logger.info("Expiring buildroot: %(id)i/%(tag_name)s/%(arch)s" % br) - self.logger.debug("Buildroot task: %r, Current tasks: %r" % (task_id, self.tasks.keys())) + self.logger.debug("Buildroot task: %r, Current tasks: %r" % (task_id, list(self.tasks.keys()))) self.session.host.setBuildRootState(id, st_expired) continue if nolocal: return local_br = self._scanLocalBuildroots() # get info on local_only buildroots (most likely expired) - local_only = [id for id in local_br.iterkeys() if id not in db_br] + local_only = [id for id in six.iterkeys(local_br) if id not in db_br] if local_only: missed_br = self.session.listBuildroots(buildrootID=tuple(local_only)) #get all the task info in one call @@ -798,7 +799,7 @@ class TaskManager(object): # Note: we may still take an assigned task below #sort available capacities for each of our bins avail = {} - for bin in bins.iterkeys(): + for bin in six.iterkeys(bins): avail[bin] = [host['capacity'] - host['task_load'] for host in bin_hosts[bin]] avail[bin].sort() avail[bin].reverse() diff --git a/koji/policy.py b/koji/policy.py index ec2e119..808ad8a 100644 --- a/koji/policy.py +++ b/koji/policy.py @@ -17,8 +17,10 @@ # Authors: # Mike McLean +from __future__ import absolute_import import fnmatch import koji +import six class BaseSimpleTest(object): @@ -289,7 +291,7 @@ class SimpleRuleSet(object): index[name] = 1 index = {} _recurse(self.ruleset, index) - return index.keys() + return list(index.keys()) def _apply(self, rules, data, top=False): for tests, negate, action in rules: @@ -352,7 +354,7 @@ def findSimpleTests(namespace): namespace = (namespace,) ret = {} for ns in namespace: - for key, value in ns.iteritems(): + for key, value in six.iteritems(ns): if value is BaseSimpleTest: # skip this abstract base class if we encounter it # this module contains generic tests, so it is valid to include it diff --git a/koji/util.py b/koji/util.py index e5d0f7f..62e62fb 100644 --- a/koji/util.py +++ b/koji/util.py @@ -241,11 +241,11 @@ class LazyDict(dict): return [(key, lazy_eval(val)) for key, val in super(LazyDict, self).items()] def itervalues(self): - for val in super(LazyDict, self).itervalues(): + for val in six.itervalues(super(LazyDict, self)): yield lazy_eval(val) def iteritems(self): - for key, val in super(LazyDict, self).iteritems(): + for key, val in six.iteritems(super(LazyDict, self)): yield key, lazy_eval(val) def pop(self, key, *args, **kwargs): @@ -499,11 +499,11 @@ def tsort(parts): parts = parts.copy() result = [] while True: - level = set([name for name, deps in parts.iteritems() if not deps]) + level = set([name for name, deps in six.iteritems(parts) if not deps]) if not level: break result.append(level) - parts = dict([(name, deps - level) for name, deps in parts.iteritems() + parts = dict([(name, deps - level) for name, deps in six.iteritems(parts) if name not in level]) if parts: raise ValueError('total ordering not possible') diff --git a/plugins/hub/echo.py b/plugins/hub/echo.py index 6727d41..38c96ba 100644 --- a/plugins/hub/echo.py +++ b/plugins/hub/echo.py @@ -8,7 +8,7 @@ from koji.plugin import callbacks, callback, ignore_error import logging -@callback(*callbacks.keys()) +@callback(*list(callbacks.keys())) @ignore_error def echo(cbtype, *args, **kws): logging.getLogger('koji.plugin.echo').info('Called the %s callback, args: %s; kws: %s', diff --git a/tests/test_cli/test_edit_tag.py b/tests/test_cli/test_edit_tag.py index 3b7cbf2..f59bb48 100644 --- a/tests/test_cli/test_edit_tag.py +++ b/tests/test_cli/test_edit_tag.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -11,6 +12,7 @@ import mock from mock import call import loadcli +import six cli = loadcli.cli @@ -40,7 +42,7 @@ class TestEditTag(unittest.TestCase): args.append('--rename=' + rename) args.append('--maven-support') args.append('--include-all') - for k, x in extra.iteritems(): + for k, x in six.iteritems(extra): args.append('-x') args.append(k + '=' + str(x)) for r in remove_extra: diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 3d13dda..5587ec3 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -137,10 +137,10 @@ class HeaderTestCase(unittest.TestCase): self.assertEqual(koji.get_header_fields(self.rpm_path, []), {}) # correct - self.assertEqual(['REQUIRES'], koji.get_header_fields(self.rpm_path, ['REQUIRES']).keys()) + self.assertEqual(['REQUIRES'], list(koji.get_header_fields(self.rpm_path, ['REQUIRES']).keys())) self.assertEqual(['PROVIDES', 'REQUIRES'], sorted(koji.get_header_fields(self.rpm_path, ['REQUIRES', 'PROVIDES']))) hdr = koji.get_rpm_header(self.rpm_path) - self.assertEqual(['REQUIRES'], koji.get_header_fields(hdr, ['REQUIRES']).keys()) + self.assertEqual(['REQUIRES'], list(koji.get_header_fields(hdr, ['REQUIRES']).keys())) def test_get_header_field_src(self): diff --git a/util/koji-gc b/util/koji-gc index 4a7e6e3..cdae6e8 100755 --- a/util/koji-gc +++ b/util/koji-gc @@ -8,6 +8,7 @@ from __future__ import absolute_import from six.moves import zip +import six try: import krbV except ImportError: # pragma: no cover @@ -535,7 +536,7 @@ def handle_trash(): by_owner = {} for binfo in to_trash: by_owner.setdefault(binfo['owner_name'], []).append(binfo) - owners = by_owner.keys() + owners = list(by_owner.keys()) owners.sort() for owner_name in owners: builds = [(b['nvr'], b) for b in by_owner[owner_name]] @@ -557,7 +558,7 @@ def handle_trash(): #best we can do currently owner = binfo['owner_id'] else: - owner = max([(n, k) for k, n in count.iteritems()])[1] + owner = max([(n, k) for k, n in six.iteritems(count)])[1] session.packageListAdd(trashcan_tag, binfo['name'], owner) session.tagBuildBypass(trashcan_tag, binfo['id'], force=True) @@ -770,7 +771,7 @@ def get_build_sigs(build, cache=False): for sig in sigs: if sig['sigkey']: keys.setdefault(sig['sigkey'], 1) - ret = build_sig_cache[build] = keys.keys() + ret = build_sig_cache[build] = list(keys.keys()) return ret def handle_prune(): @@ -830,7 +831,7 @@ def handle_prune(): pkghist.setdefault(h['name'] + '-' + h['version'], []).append(h) else: pkghist.setdefault(h['name'], []).append(h) - pkgs = pkghist.keys() + pkgs = list(pkghist.keys()) pkgs.sort() for pkg in pkgs: if not check_package(pkg): diff --git a/util/koji-shadow b/util/koji-shadow index da782bf..36b7902 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -25,6 +25,7 @@ from __future__ import absolute_import from six.moves import range from six.moves import zip +import six try: import krbV except ImportError: # pragma: no cover @@ -498,7 +499,7 @@ class TrackedBuild(object): log("Warning: some rpms for %s lacked buildroots:" % self.nvr) for rinfo in bad: log(" %(name)s-%(version)s-%(release)s.%(arch)s" % rinfo) - return brs.keys() + return list(brs.keys()) def getDeps(self): buildroots = self.getBuildroots() @@ -547,7 +548,7 @@ class TrackedBuild(object): # changes happened during the build startup and some subtasks got the old # repo and others the new one. base = [] - for name, brlist in bases.iteritems(): + for name, brlist in six.iteritems(bases): #We want to determine for each name if that package was present #in /all/ the buildroots or just some. #Because brlist is constructed only from elements of buildroots, we @@ -557,12 +558,12 @@ class TrackedBuild(object): #each buildroot had this as a base package base.append(name) if len(tags) > 1: - log("Warning: found multiple buildroot tags for %s: %s" % (self.nvr, tags.keys())) - counts = [(n, tag) for tag, n in tags.iteritems()] + log("Warning: found multiple buildroot tags for %s: %s" % (self.nvr, list(tags.keys()))) + counts = [(n, tag) for tag, n in six.iteritems(tags)] sort(counts) tag = counts[-1][1] else: - tag = tags.keys()[0] + tag = list(tags.keys())[0] # due bugs in used tools mainline koji instance could store empty buildroot infos for builds if len(builds) == 0: self.setState("noroot") @@ -1008,7 +1009,7 @@ class BuildTracker(object): for pkg in session.listPackages(pkgID=name): owners.setdefault(pkg['owner_id'], []).append(pkg) if owners: - order = [(len(v), k) for k, v in owners.iteritems()] + order = [(len(v), k) for k, v in six.iteritems(owners)] order.sort() owner = order[-1][1] else: @@ -1124,7 +1125,7 @@ class BuildTracker(object): log("-- %s --" % time.asctime()) self.report_brief() for state in ('broken', 'noroot', 'blocked'): - builds = self.state_idx[state].values() + builds = list(self.state_idx[state].values()) not_replaced = [b for b in builds if not b.substitute] n_replaced = len(builds) - len(not_replaced) log("%s: %i (+%i replaced)" % (state, len(not_replaced), n_replaced)) @@ -1154,7 +1155,7 @@ class BuildTracker(object): nvr = dep.substitute problem_counts.setdefault(nvr, 0) problem_counts[nvr] += 1 - order = [(c, nvr) for (nvr, c) in problem_counts.iteritems()] + order = [(c, nvr) for (nvr, c) in six.iteritems(problem_counts)] if order: order.sort() order.reverse() @@ -1165,7 +1166,7 @@ class BuildTracker(object): def report_brief(self): N = len(self.builds) - states = self.state_idx.keys() + states = list(self.state_idx.keys()) states.sort() parts = ["%s: %i" % (s, len(self.state_idx[s])) for s in states] parts.append("total: %i" % N) @@ -1237,7 +1238,7 @@ class BuildTracker(object): ret = False if options.max_jobs and len(self.state_idx['pending']) >= options.max_jobs: return ret - missing = [(b.order, b.id, b) for b in self.state_idx['missing'].itervalues()] + missing = [(b.order, b.id, b) for b in six.itervalues(self.state_idx['missing'])] missing.sort() for order, build_id, build in missing: if not self.checkBuildDeps(build): diff --git a/util/kojira b/util/kojira index a875f29..e15c149 100755 --- a/util/kojira +++ b/util/kojira @@ -20,6 +20,8 @@ # Authors: # Mike McLean +from __future__ import absolute_import +import six try: import krbV except ImportError: # pragma: no cover @@ -85,7 +87,7 @@ class ManagedRepo(object): tags = {self.tag_id : 1} for x in order: tags[x['parent_id']] = 1 - self.taglist = tags.keys() + self.taglist = list(tags.keys()) def expire(self): """Mark the repo expired""" @@ -198,9 +200,9 @@ class RepoManager(object): def printState(self): self.logger.debug('Tracking %i repos, %i child processes', len(self.repos), len(self.delete_pids)) - for tag_id, task_id in self.tasks.iteritems(): + for tag_id, task_id in six.iteritems(self.tasks): self.logger.debug("Tracking task %s for tag %s", task_id, tag_id) - for pid, desc in self.delete_pids.iteritems(): + for pid, desc in six.iteritems(self.delete_pids): self.logger.debug("Delete job %s: %r", pid, desc) def rmtree(self, path): @@ -296,7 +298,7 @@ class RepoManager(object): if session is None: session = self.session to_check = [] - repo_ids = self.repos.keys() + repo_ids = list(self.repos.keys()) for repo_id in repo_ids: repo = self.repos.get(repo_id) if repo is None: @@ -531,8 +533,8 @@ class RepoManager(object): tag_repos = {} for repo in self.repos.values(): tag_repos.setdefault(repo.tag_id, []).append(repo) - self.logger.debug("Needed tags: %r" % tags.keys()) - self.logger.debug("Current tags: %r" % tag_repos.keys()) + self.logger.debug("Needed tags: %r" % list(tags.keys())) + self.logger.debug("Current tags: %r" % list(tag_repos.keys())) #we need to determine: # - which tags need a new repo @@ -540,7 +542,7 @@ class RepoManager(object): #self.checkCurrentRepos now runs continually in a separate thread regen = [] expire_times = {} - for tag_id in tags.iterkeys(): + for tag_id in six.iterkeys(tags): covered = False for repo in tag_repos.get(tag_id,[]): if repo.current: diff --git a/vm/kojikamid.py b/vm/kojikamid.py index 87a8608..756c4f7 100755 --- a/vm/kojikamid.py +++ b/vm/kojikamid.py @@ -26,6 +26,7 @@ # kojiwind --install # in a cygwin shell. +from __future__ import absolute_import from optparse import OptionParser from six.moves.configparser import ConfigParser import os @@ -42,6 +43,7 @@ import threading import re import glob import zipfile +import six MANAGER_PORT = 7000 @@ -639,7 +641,7 @@ def stream_logs(server, handler, builds): logpath = os.path.join(build.source_dir, relpath) if logpath not in logs: logs[logpath] = (relpath, None) - for log, (relpath, fd) in logs.iteritems(): + for log, (relpath, fd) in six.iteritems(logs): if not fd: if os.path.isfile(log): try: diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py index a7d8b74..85784bd 100644 --- a/www/kojiweb/index.py +++ b/www/kojiweb/index.py @@ -39,6 +39,7 @@ from kojiweb.util import _getValidTokens from koji.util import sha1_constructor from six.moves import range from six.moves import zip +import six # Convenience definition of a commonly-used sort function _sortbyname = kojiweb.util.sortByKeyFunc('name') @@ -682,7 +683,7 @@ def taskinfo(environ, taskID): values['pathinfo'] = pathinfo paths = [] # (volume, relpath) tuples - for relname, volumes in server.listTaskOutput(task['id'], all_volumes=True).iteritems(): + for relname, volumes in six.iteritems(server.listTaskOutput(task['id'], all_volumes=True)): paths += [(volume, relname) for volume in volumes] values['output'] = sorted(paths, cmp = _sortByExtAndName) if environ['koji.currentUser']: @@ -701,8 +702,8 @@ def taskstatus(environ, taskID): return '' files = server.listTaskOutput(taskID, stat=True, all_volumes=True) output = '%i:%s\n' % (task['id'], koji.TASK_STATES[task['state']]) - for filename, volumes_data in files.iteritems(): - for volume, file_stats in volumes_data.iteritems(): + for filename, volumes_data in six.iteritems(files): + for volume, file_stats in six.iteritems(volumes_data): output += '%s:%s:%s\n' % (volume, filename, file_stats['st_size']) return output @@ -2115,7 +2116,7 @@ def buildsbytarget(environ, days='7', start=None, order='-builds'): if builds > maxBuilds: maxBuilds = builds - kojiweb.util.paginateList(values, targets.values(), start, 'targets', 'target', order) + kojiweb.util.paginateList(values, list(targets.values()), start, 'targets', 'target', order) values['order'] = order diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py index c775877..5140625 100644 --- a/www/kojiweb/wsgi_publisher.py +++ b/www/kojiweb/wsgi_publisher.py @@ -426,7 +426,7 @@ class Dispatcher(object): if isinstance(result, six.string_types): headers.setdefault('content-length', ('Content-Length', str(len(result)))) headers.setdefault('content-type', ('Content-Type', 'text/html')) - headers = headers.values() + extra + headers = list(headers.values()) + extra self.logger.debug("Headers:") self.logger.debug(koji.util.LazyString(pprint.pformat, [headers])) start_response(status, headers) From a4a1536a038f68a388296eaaaae29fbf9bd23a96 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 15/61] python-modernize -f libmodernize.fixes.fix_file --- diff --git a/builder/kojid b/builder/kojid index bc7807e..d0d1915 100755 --- a/builder/kojid +++ b/builder/kojid @@ -256,7 +256,7 @@ class BuildRoot(object): output = koji.genMockConfig(self.name, self.br_arch, managed=True, **opts) #write config - fo = file(configfile,'w') + fo = open(configfile,'w') fo.write(output) fo.close() @@ -356,7 +356,7 @@ class BuildRoot(object): """ settings = settings % locals() - fo = file(self.rootdir() + destfile, 'w') + fo = open(self.rootdir() + destfile, 'w') fo.write(settings) fo.close() @@ -410,7 +410,7 @@ class BuildRoot(object): self.logger.info('Rereading %s, inode: %s -> %s, size: %s -> %s' % (fpath, inode, stat_info.st_ino, size, stat_info.st_size)) fd.close() - fd = file(fpath, 'r') + fd = open(fpath, 'r') logs[fname] = (fd, stat_info.st_ino, stat_info.st_size, fpath) except: self.logger.error("Error reading mock log: %s", fpath) @@ -1746,7 +1746,7 @@ class WrapperRPMTask(BaseBuildTask): contents = contents.encode('utf-8') specfile = spec_template[:-5] - specfd = file(specfile, 'w') + specfd = open(specfile, 'w') specfd.write(contents) specfd.close() @@ -4849,7 +4849,7 @@ class CreaterepoTask(BaseTaskHandler): if external_repos: self.merge_repos(external_repos, arch, groupdata) elif pkglist is None: - fo = file(os.path.join(self.datadir, "EMPTY_REPO"), 'w') + fo = open(os.path.join(self.datadir, "EMPTY_REPO"), 'w') fo.write("This repo is empty because its tag has no content for this arch\n") fo.close() @@ -5064,7 +5064,7 @@ class createDistRepoTask(CreaterepoTask): self.pkglist = None self.create_local_repo(self.rinfo, arch, self.pkglist, groupdata, None, oldpkgs=oldpkgs) if self.pkglist is None: - fo = file(os.path.join(self.datadir, "EMPTY_REPO"), 'w') + fo = open(os.path.join(self.datadir, "EMPTY_REPO"), 'w') fo.write("This repo is empty because its tag has no content for this arch\n") fo.close() files = ['pkglist', 'kojipkgs'] @@ -5271,7 +5271,7 @@ enabled=1 #generate pkglist files pkgfile = os.path.join(self.repodir, 'pkglist') - pkglist = file(pkgfile, 'w') + pkglist = open(pkgfile, 'w') fs_missing = [] sig_missing = [] kojipkgs = {} @@ -5344,7 +5344,7 @@ enabled=1 def write_kojipkgs(self): filename = os.path.join(self.repodir, 'kojipkgs') - datafile = file(filename, 'w') + datafile = open(filename, 'w') try: json.dump(self.kojipkgs, datafile, indent=4) finally: diff --git a/builder/mergerepos b/builder/mergerepos index cb081bb..1e95f56 100755 --- a/builder/mergerepos +++ b/builder/mergerepos @@ -238,7 +238,7 @@ class RepoMerge(object): include_srpms[srpm_name] = (pkg.sourcerpm, pkg.repoid) pkgorigins = os.path.join(self.yumbase.conf.cachedir, 'pkgorigins') - origins = file(pkgorigins, 'w') + origins = open(pkgorigins, 'w') seen_rpms = {} for repo in repos: @@ -283,7 +283,7 @@ def main(args): opts = parse_args(args) if opts.blocked: - blocked_fo = file(opts.blocked) + blocked_fo = open(opts.blocked) blocked_list = blocked_fo.readlines() blocked_fo.close() blocked = dict([(b.strip(), 1) for b in blocked_list]) diff --git a/cli/koji b/cli/koji index d6acd55..a555388 100755 --- a/cli/koji +++ b/cli/koji @@ -1496,7 +1496,7 @@ def anon_handle_mock_config(options, session, args): name = "%(tag_name)s-repo_%(repoid)s" % opts output = koji.genMockConfig(name, arch, **opts) if options.ofile: - fo = file(options.ofile, 'w') + fo = open(options.ofile, 'w') fo.write(output) fo.close() else: @@ -1764,7 +1764,7 @@ def handle_import_cg(options, session, args): parser.error(_("Unable to find json module")) assert False # pragma: no cover activate_session(session) - metadata = json.load(file(args[0], 'r')) + metadata = json.load(open(args[0], 'r')) if 'output' not in metadata: print(_("Metadata contains no output")) sys.exit(1) @@ -2029,11 +2029,11 @@ def handle_prune_signed_copies(options, session, args): #(with the modification that we check to see if the build was latest within #the last N days) if options.ignore_tag_file: - fo = file(options.ignore_tag_file) + fo = open(options.ignore_tag_file) options.ignore_tag.extend([line.strip() for line in fo.readlines()]) fo.close() if options.protect_tag_file: - fo = file(options.protect_tag_file) + fo = open(options.protect_tag_file) options.protect_tag.extend([line.strip() for line in fo.readlines()]) fo.close() if options.debug: @@ -6866,7 +6866,7 @@ def anon_handle_download_logs(options, session, args): full_filename = os.path.normpath(os.path.join(task_log_dir, FAIL_LOG)) koji.ensuredir(os.path.dirname(full_filename)) sys.stdout.write("Writing: %s\n" % full_filename) - file(full_filename, 'w').write(content) + open(full_filename, 'w').write(content) def download_log(task_log_dir, task_id, filename, blocksize=102400, volume=None): # Create directories only if there is any log file to write to @@ -6879,11 +6879,11 @@ def anon_handle_download_logs(options, session, args): contents = 'IGNORE ME!' if suboptions.cont and os.path.exists(full_filename): sys.stdout.write("Continuing: %s\n" % full_filename) - fd = file(full_filename, 'ab') + fd = open(full_filename, 'ab') offset = fd.tell() else: sys.stdout.write("Downloading: %s\n" % full_filename) - fd = file(full_filename, 'wb') + fd = open(full_filename, 'wb') offset = 0 try: while contents: diff --git a/hub/kojihub.py b/hub/kojihub.py index d91b501..7253b14 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -2330,7 +2330,7 @@ def repo_init(tag, with_src=False, with_debuginfo=False, event=None): groupsdir = "%s/groups" % (repodir) koji.ensuredir(groupsdir) comps = koji.generate_comps(groups, expand_groups=True) - fo = file("%s/comps.xml" % groupsdir, 'w') + fo = open("%s/comps.xml" % groupsdir, 'w') fo.write(comps) fo.close() @@ -2349,7 +2349,7 @@ def repo_init(tag, with_src=False, with_debuginfo=False, event=None): top_relpath = koji.util.relpath(koji.pathinfo.topdir, archdir) top_link = os.path.join(archdir, 'toplink') os.symlink(top_relpath, top_link) - pkglist[repoarch] = file(os.path.join(archdir, 'pkglist'), 'w') + pkglist[repoarch] = open(os.path.join(archdir, 'pkglist'), 'w') #NOTE - rpms is now an iterator for rpminfo in rpms: if not with_debuginfo and koji.is_debuginfo(rpminfo['name']): @@ -2374,7 +2374,7 @@ def repo_init(tag, with_src=False, with_debuginfo=False, event=None): #write blocked package lists for repoarch in repo_arches: - blocklist = file(os.path.join(repodir, repoarch, 'blocklist'), 'w') + blocklist = open(os.path.join(repodir, repoarch, 'blocklist'), 'w') for pkg in blocks: blocklist.write(pkg['package_name']) blocklist.write('\n') @@ -2441,7 +2441,7 @@ def _write_maven_repo_metadata(destdir, artifacts): """ % datetime.datetime.now().strftime('%Y%m%d%H%M%S') - mdfile = file(os.path.join(destdir, 'maven-metadata.xml'), 'w') + mdfile = open(os.path.join(destdir, 'maven-metadata.xml'), 'w') mdfile.write(contents) mdfile.close() _generate_maven_metadata(destdir) @@ -5973,7 +5973,7 @@ def check_old_image_files(old): (img_path, img_size, old['filesize'])) # old images always used sha256 hashes sha256sum = hashlib.sha256() - image_fo = file(img_path, 'r') + image_fo = open(img_path, 'r') while True: data = image_fo.read(1048576) sha256sum.update(data) @@ -6125,7 +6125,7 @@ def import_archive_internal(filepath, buildinfo, type, typeInfo, buildroot_id=No filename = koji.fixEncoding(os.path.basename(filepath)) archiveinfo['filename'] = filename archiveinfo['size'] = os.path.getsize(filepath) - archivefp = file(filepath) + archivefp = open(filepath) m = md5_constructor() while True: contents = archivefp.read(8192) @@ -6265,14 +6265,14 @@ def _generate_maven_metadata(mavendir): sumfile = mavenfile + ext if sumfile not in mavenfiles: sum = sum_constr() - fobj = file('%s/%s' % (mavendir, mavenfile)) + fobj = open('%s/%s' % (mavendir, mavenfile)) while True: content = fobj.read(8192) if not content: break sum.update(content) fobj.close() - sumobj = file('%s/%s' % (mavendir, sumfile), 'w') + sumobj = open('%s/%s' % (mavendir, sumfile), 'w') sumobj.write(sum.hexdigest()) sumobj.close() @@ -6328,7 +6328,7 @@ def add_rpm_sig(an_rpm, sighdr): # - write to fs sigpath = "%s/%s" % (builddir, koji.pathinfo.sighdr(rinfo, sigkey)) koji.ensuredir(os.path.dirname(sigpath)) - fo = file(sigpath, 'wb') + fo = open(sigpath, 'wb') fo.write(sighdr) fo.close() koji.plugin.run_callbacks('postRPMSign', sigkey=sigkey, sighash=sighash, build=binfo, rpm=rinfo) @@ -6344,7 +6344,7 @@ def _scan_sighdr(sighdr, fn): sig_start, sigsize = koji.find_rpm_sighdr(fn) hdr_start = sig_start + sigsize hdrsize = koji.rpm_hdr_size(fn, hdr_start) - inp = file(fn, 'rb') + inp = open(fn, 'rb') outp = tempfile.TemporaryFile(mode='w+b') #before signature outp.write(inp.read(sig_start)) @@ -6381,7 +6381,7 @@ def check_rpm_sig(an_rpm, sigkey, sighdr): koji.splice_rpm_sighdr(sighdr, rpm_path, temp) ts = rpm.TransactionSet() ts.setVSFlags(0) #full verify - fo = file(temp, 'rb') + fo = open(temp, 'rb') hdr = ts.hdrFromFdno(fo.fileno()) fo.close() except: @@ -6444,7 +6444,7 @@ def write_signed_rpm(an_rpm, sigkey, force=False): else: os.unlink(signedpath) sigpath = "%s/%s" % (builddir, koji.pathinfo.sighdr(rinfo, sigkey)) - fo = file(sigpath, 'rb') + fo = open(sigpath, 'rb') sighdr = fo.read() fo.close() koji.ensuredir(os.path.dirname(signedpath)) @@ -8916,7 +8916,7 @@ class RootExports(object): if not os.path.isfile(filePath): raise koji.GenericError('no file "%s" output by task %i' % (fileName, taskID)) # Let the caller handler any IO or permission errors - f = file(filePath, 'r') + f = open(filePath, 'r') if isinstance(offset, str): offset = int(offset) if offset != None and offset > 0: @@ -12478,11 +12478,11 @@ def get_upload_path(reldir, name, create=False, volume=None): # assuming login was asserted earlier u_fn = os.path.join(udir, '.user') if os.path.exists(u_fn): - user_id = int(file(u_fn, 'r').read()) + user_id = int(open(u_fn, 'r').read()) if context.session.user_id != user_id: raise koji.GenericError("Invalid upload directory, not owner: %s" % orig_reldir) else: - fo = file(u_fn, 'w') + fo = open(u_fn, 'w') fo.write(str(context.session.user_id)) fo.close() return os.path.join(udir, name) diff --git a/koji/__init__.py b/koji/__init__.py index 39be2eb..d20840b 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -552,7 +552,7 @@ def rpm_hdr_size(f, ofs=None): ofs = offset of the header """ if isinstance(f, (str, six.text_type)): - fo = file(f, 'rb') + fo = open(f, 'rb') else: fo = f if ofs != None: @@ -742,7 +742,7 @@ class RawHeader(object): def rip_rpm_sighdr(src): """Rip the signature header out of an rpm""" (start, size) = find_rpm_sighdr(src) - fo = file(src, 'rb') + fo = open(src, 'rb') fo.seek(start, 0) sighdr = fo.read(size) fo.close() @@ -753,7 +753,7 @@ def rip_rpm_hdr(src): (start, size) = find_rpm_sighdr(src) start += size size = rpm_hdr_size(src, start) - fo = file(src, 'rb') + fo = open(src, 'rb') fo.seek(start, 0) hdr = fo.read(size) fo.close() @@ -852,8 +852,8 @@ def splice_rpm_sighdr(sighdr, src, dst=None, bufsize=8192): if dst is None: (fd, dst) = tempfile.mkstemp() os.close(fd) - src_fo = file(src, 'rb') - dst_fo = file(dst, 'wb') + src_fo = open(src, 'rb') + dst_fo = open(dst, 'wb') dst_fo.write(src_fo.read(start)) dst_fo.write(sighdr) src_fo.seek(size, 1) @@ -872,7 +872,7 @@ def get_rpm_header(f, ts=None): ts = rpm.TransactionSet() ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS) if isinstance(f, (str, six.text_type)): - fo = file(f, "r") + fo = open(f, "r") else: fo = f hdr = ts.hdrFromFdno(fo.fileno()) @@ -1116,7 +1116,7 @@ def parse_pom(path=None, contents=None): values = {} handler = POMHandler(values, fields) if path: - fd = file(path) + fd = open(path) contents = fd.read() fd.close() @@ -1431,7 +1431,7 @@ def genMockConfig(name, arch, managed=False, repoid=None, tag_name=None, **opts) if opts.get('use_host_resolv', False) and os.path.exists('/etc/hosts'): # if we're setting up DNS, # also copy /etc/hosts from the host - etc_hosts = file('/etc/hosts') + etc_hosts = open('/etc/hosts') files['etc/hosts'] = etc_hosts.read() etc_hosts.close() mavenrc = '' @@ -2494,7 +2494,7 @@ class ClientSession(object): if name is None: name = os.path.basename(localfile) self.logger.debug("Fast upload: %s to %s/%s", localfile, path, name) - fo = file(localfile, 'rb') + fo = open(localfile, 'rb') ofs = 0 size = os.path.getsize(localfile) start = time.time() @@ -2602,7 +2602,7 @@ class ClientSession(object): start = time.time() # XXX - stick in a config or something retries = 3 - fo = file(localfile, "r") #specify bufsize? + fo = open(localfile, "r") #specify bufsize? totalsize = os.path.getsize(localfile) ofs = 0 md5sum = md5_constructor() diff --git a/koji/daemon.py b/koji/daemon.py index dbcbce3..82c5c4c 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -146,7 +146,7 @@ def log_output(session, path, args, outfile, uploadpath, cwd=None, logerror=0, a if not outfd: try: - outfd = file(outfile, 'r') + outfd = open(outfile, 'r') except IOError: # will happen if the forked process has not created the logfile yet continue @@ -665,7 +665,7 @@ class TaskManager(object): fn = "%s/%s" % (configdir, f) if not os.path.isfile(fn): continue - fo = file(fn, 'r') + fo = open(fn, 'r') id = None name = None for n in range(10): @@ -931,14 +931,14 @@ class TaskManager(object): proc_path = '/proc/%i/stat' % pid if not os.path.isfile(proc_path): return None - proc_file = file(proc_path) + proc_file = open(proc_path) procstats = [not field.isdigit() and field or int(field) for field in proc_file.read().split()] proc_file.close() cmd_path = '/proc/%i/cmdline' % pid if not os.path.isfile(cmd_path): return None - cmd_file = file(cmd_path) + cmd_file = open(cmd_path) procstats[1] = cmd_file.read().replace('\0', ' ').strip() cmd_file.close() if not procstats[1]: diff --git a/koji/tasks.py b/koji/tasks.py index 41d6b5e..e43a243 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -314,7 +314,7 @@ class BaseTaskHandler(object): fsrc = urllib2.urlopen(url) if not os.path.exists(os.path.dirname(fn)): os.makedirs(os.path.dirname(fn)) - fdst = file(fn, 'w') + fdst = open(fn, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() fdst.close() diff --git a/koji/util.py b/koji/util.py index 62e62fb..5535223 100644 --- a/koji/util.py +++ b/koji/util.py @@ -591,7 +591,7 @@ def parse_maven_params(confs, chain=False, scratch=False): confs = [confs] config = six.moves.configparser.ConfigParser() for conf in confs: - conf_fd = file(conf) + conf_fd = open(conf) config.readfp(conf_fd) conf_fd.close() builds = {} diff --git a/plugins/hub/rpm2maven.py b/plugins/hub/rpm2maven.py index 1a9b399..ddf1a9f 100644 --- a/plugins/hub/rpm2maven.py +++ b/plugins/hub/rpm2maven.py @@ -51,7 +51,7 @@ def maven_import(cbtype, *args, **kws): shutil.rmtree(tmpdir) def expand_rpm(filepath, tmpdir): - devnull = file('/dev/null', 'r+') + devnull = open('/dev/null', 'r+') rpm2cpio = subprocess.Popen(['/usr/bin/rpm2cpio', filepath], stdout=subprocess.PIPE, stdin=devnull, stderr=devnull, diff --git a/tests/test_hub/test_get_upload_path.py b/tests/test_hub/test_get_upload_path.py index f789192..a1191ce 100644 --- a/tests/test_hub/test_get_upload_path.py +++ b/tests/test_hub/test_get_upload_path.py @@ -36,7 +36,7 @@ class TestGetUploadPath(unittest.TestCase): fullpath = '{0}/{1}'.format(work.return_value, reldir) os.makedirs(fullpath) - with file('{0}/.user'.format(fullpath), 'wb') as f: + with open('{0}/.user'.format(fullpath), 'wb') as f: f.write('1') with self.assertRaises(GenericError): diff --git a/util/koji-gc b/util/koji-gc index cdae6e8..7289f7a 100755 --- a/util/koji-gc +++ b/util/koji-gc @@ -736,7 +736,7 @@ def read_policies(fn=None): The expected format as follows test [params] [&& test [params] ...] :: (keep|untag|skip) """ - fo = file(fn, 'r') + fo = open(fn, 'r') tests = koji.policy.findSimpleTests(globals()) ret = koji.policy.SimpleRuleSet(fo, tests) fo.close() diff --git a/util/koji-shadow b/util/koji-shadow index 36b7902..d820e65 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -452,7 +452,7 @@ class TrackedBuild(object): fsrc = urllib2.urlopen(url) fn = "%s/%s.src.rpm" % (options.workpath, self.nvr) koji.ensuredir(os.path.dirname(fn)) - fdst = file(fn, 'w') + fdst = open(fn, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() fdst.close() @@ -892,7 +892,7 @@ class BuildTracker(object): os.chown(os.path.dirname(dst), 48, 48) #XXX - hack log ("Downloading %s to %s" % (url, dst)) fsrc = urllib2.urlopen(url) - fdst = file(fn, 'w') + fdst = open(fn, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() fdst.close() @@ -905,7 +905,7 @@ class BuildTracker(object): dst = "%s/%s" % (options.workpath, fn) log ("Downloading %s to %s..." % (url, dst)) fsrc = urllib2.urlopen(url) - fdst = file(dst, 'w') + fdst = open(dst, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() fdst.close() diff --git a/vm/kojikamid.py b/vm/kojikamid.py index 756c4f7..fe70dd6 100755 --- a/vm/kojikamid.py +++ b/vm/kojikamid.py @@ -303,7 +303,7 @@ class WindowsBuild(object): """Download the file from buildreq, at filepath, into the basedir""" destpath = os.path.join(basedir, fileinfo['localpath']) ensuredir(os.path.dirname(destpath)) - destfile = file(destpath, 'w') + destfile = open(destpath, 'w') offset = 0 checksum = hashlib.md5() while True: @@ -562,7 +562,7 @@ def upload_file(server, prefix, path): """upload a single file to the vmd""" logger = logging.getLogger('koji.vm') destpath = os.path.join(prefix, path) - fobj = file(destpath, 'r') + fobj = open(destpath, 'r') offset = 0 sum = hashlib.md5() while True: @@ -616,7 +616,7 @@ def setup_logging(opts): if opts.debug: level = logging.DEBUG logger.setLevel(level) - logfd = file(logfile, 'w') + logfd = open(logfile, 'w') handler = logging.StreamHandler(logfd) handler.setLevel(level) handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(name)s: %(message)s')) @@ -645,7 +645,7 @@ def stream_logs(server, handler, builds): if not fd: if os.path.isfile(log): try: - fd = file(log, 'r') + fd = open(log, 'r') logs[log] = (relpath, fd) except: log_local('Error opening %s' % log) From 62288597f13a75110161a027ba8bf2b770bfeacb Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:22 +0000 Subject: [PATCH 16/61] python-modernize -f libmodernize.fixes.fix_filter --- diff --git a/cli/koji b/cli/koji index a555388..e147b2a 100755 --- a/cli/koji +++ b/cli/koji @@ -30,6 +30,7 @@ import sys from six.moves import range from six.moves import zip import six +from six.moves import filter try: import krbV except ImportError: # pragma: no cover @@ -6980,7 +6981,7 @@ def anon_handle_download_task(options, session, args): downloadable_tasks.append(base_task) else: subtasks = session.getTaskChildren(base_task_id) - downloadable_tasks.extend(filter(check_downloadable, subtasks)) + downloadable_tasks.extend(list(filter(check_downloadable, subtasks))) # get files for download From 8962c26080515b0ce2cd684a6ead594787b884d7 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 17/61] python-modernize -f libmodernize.fixes.fix_import --- diff --git a/builder/mergerepos b/builder/mergerepos index 1e95f56..a27c1ee 100755 --- a/builder/mergerepos +++ b/builder/mergerepos @@ -21,6 +21,7 @@ # Largely borrowed from the mergerepo script included in createrepo and # written by Seth Vidal +from __future__ import absolute_import import createrepo import os.path import rpmUtils.miscutils diff --git a/koji/db.py b/koji/db.py index 9e92191..c4e9ab3 100644 --- a/koji/db.py +++ b/koji/db.py @@ -21,6 +21,7 @@ # Mike McLean +from __future__ import absolute_import import logging import sys import psycopg2 @@ -33,7 +34,7 @@ import psycopg2 # del psycopg2.extensions.string_types[1266] import time import traceback -import context +from . import context import re POSITIONAL_RE = re.compile(r'%[a-z]') diff --git a/koji/server.py b/koji/server.py index 6a6ae6a..47ebacf 100644 --- a/koji/server.py +++ b/koji/server.py @@ -19,6 +19,7 @@ # Authors: # Mike McLean +from __future__ import absolute_import import sys import traceback from koji.util import LazyDict diff --git a/koji/ssl/SSLCommon.py b/koji/ssl/SSLCommon.py index cbecedf..0cff1ee 100644 --- a/koji/ssl/SSLCommon.py +++ b/koji/ssl/SSLCommon.py @@ -14,9 +14,10 @@ # # Copyright 2005 Dan Williams and Red Hat, Inc. +from __future__ import absolute_import import os, sys from OpenSSL import SSL -import SSLConnection +from . import SSLConnection import six.moves.http_client import socket diff --git a/koji/ssl/SSLConnection.py b/koji/ssl/SSLConnection.py index 2e53db7..92de572 100644 --- a/koji/ssl/SSLConnection.py +++ b/koji/ssl/SSLConnection.py @@ -6,6 +6,7 @@ # Modifications by Dan Williams +from __future__ import absolute_import from OpenSSL import SSL import time, socket, select diff --git a/koji/ssl/__init__.py b/koji/ssl/__init__.py index 7b4c2b3..fb2e3c7 100644 --- a/koji/ssl/__init__.py +++ b/koji/ssl/__init__.py @@ -1,6 +1,7 @@ # identify this as the ssl module # our own ssl submodule masks python's in the main lib, so we import this here +from __future__ import absolute_import try: import ssl # python's ssl module except ImportError: # pragma: no cover diff --git a/plugins/builder/runroot.py b/plugins/builder/runroot.py index f902659..7856ce8 100644 --- a/plugins/builder/runroot.py +++ b/plugins/builder/runroot.py @@ -1,5 +1,6 @@ # kojid plugin +from __future__ import absolute_import import commands import koji import six.moves.configparser diff --git a/plugins/builder/save_failed_tree.py b/plugins/builder/save_failed_tree.py index b0f5cfd..7c579a7 100644 --- a/plugins/builder/save_failed_tree.py +++ b/plugins/builder/save_failed_tree.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import fnmatch import os import sys diff --git a/plugins/hub/echo.py b/plugins/hub/echo.py index 38c96ba..739dfeb 100644 --- a/plugins/hub/echo.py +++ b/plugins/hub/echo.py @@ -5,6 +5,7 @@ # Authors: # Mike Bonnet +from __future__ import absolute_import from koji.plugin import callbacks, callback, ignore_error import logging diff --git a/plugins/hub/messagebus.py b/plugins/hub/messagebus.py index 5bb2b01..4841624 100644 --- a/plugins/hub/messagebus.py +++ b/plugins/hub/messagebus.py @@ -4,6 +4,7 @@ # Authors: # Mike Bonnet +from __future__ import absolute_import from koji import PluginError from koji.plugin import callbacks, callback, ignore_error import six.moves.configparser diff --git a/plugins/hub/protonmsg.py b/plugins/hub/protonmsg.py index 0a65c4e..91e7e66 100644 --- a/plugins/hub/protonmsg.py +++ b/plugins/hub/protonmsg.py @@ -5,6 +5,7 @@ # Authors: # Mike Bonnet +from __future__ import absolute_import import koji from koji.plugin import callback, ignore_error from koji.context import context diff --git a/plugins/hub/rpm2maven.py b/plugins/hub/rpm2maven.py index ddf1a9f..e918013 100644 --- a/plugins/hub/rpm2maven.py +++ b/plugins/hub/rpm2maven.py @@ -5,6 +5,7 @@ # Authors: # Mike Bonnet +from __future__ import absolute_import import koji from koji.context import context from koji.plugin import callback diff --git a/plugins/hub/runroot_hub.py b/plugins/hub/runroot_hub.py index e6ee0b3..708aede 100644 --- a/plugins/hub/runroot_hub.py +++ b/plugins/hub/runroot_hub.py @@ -3,6 +3,7 @@ # plugin has a config file. This hub plugin has no config file. +from __future__ import absolute_import from koji.context import context from koji.plugin import export import koji diff --git a/plugins/hub/save_failed_tree.py b/plugins/hub/save_failed_tree.py index 70caa26..70a796f 100644 --- a/plugins/hub/save_failed_tree.py +++ b/plugins/hub/save_failed_tree.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import sys import six.moves.configparser import koji diff --git a/tests/test_builder/loadkojid.py b/tests/test_builder/loadkojid.py index 7ff8780..d4e26e5 100644 --- a/tests/test_builder/loadkojid.py +++ b/tests/test_builder/loadkojid.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os import sys diff --git a/tests/test_cli/loadcli.py b/tests/test_cli/loadcli.py index f9449fc..703aeaa 100644 --- a/tests/test_cli/loadcli.py +++ b/tests/test_cli/loadcli.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os import sys diff --git a/tests/test_cli/test_add_group.py b/tests/test_cli/test_add_group.py index 929d42a..f2d4aed 100644 --- a/tests/test_cli/test_add_group.py +++ b/tests/test_cli/test_add_group.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -8,7 +9,7 @@ import sys import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_add_host.py b/tests/test_cli/test_add_host.py index 552bcf3..a7ecf7d 100644 --- a/tests/test_cli/test_add_host.py +++ b/tests/test_cli/test_add_host.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -8,7 +9,7 @@ import sys import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_add_host_to_channel.py b/tests/test_cli/test_add_host_to_channel.py index 4324c06..7197836 100644 --- a/tests/test_cli/test_add_host_to_channel.py +++ b/tests/test_cli/test_add_host_to_channel.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -8,7 +9,7 @@ import sys import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_add_pkg.py b/tests/test_cli/test_add_pkg.py index 94483b0..909e1fd 100644 --- a/tests/test_cli/test_add_pkg.py +++ b/tests/test_cli/test_add_pkg.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest @@ -11,7 +12,7 @@ import mock from mock import call -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_block_pkg.py b/tests/test_cli/test_block_pkg.py index f493c32..f521909 100644 --- a/tests/test_cli/test_block_pkg.py +++ b/tests/test_cli/test_block_pkg.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest @@ -11,7 +12,7 @@ import mock from mock import call -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_build.py b/tests/test_cli/test_build.py index 1afe54e..306df0b 100644 --- a/tests/test_cli/test_build.py +++ b/tests/test_cli/test_build.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -8,7 +9,7 @@ import sys import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_chain_build.py b/tests/test_cli/test_chain_build.py index 55699ca..61449f7 100644 --- a/tests/test_cli/test_chain_build.py +++ b/tests/test_cli/test_chain_build.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -8,7 +9,7 @@ import sys import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_edit_host.py b/tests/test_cli/test_edit_host.py index 0680fe6..bb86d11 100644 --- a/tests/test_cli/test_edit_host.py +++ b/tests/test_cli/test_edit_host.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -10,7 +11,7 @@ import mock from mock import call -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_import_comps.py b/tests/test_cli/test_import_comps.py index 5b17a90..5d01f55 100644 --- a/tests/test_cli/test_import_comps.py +++ b/tests/test_cli/test_import_comps.py @@ -1,10 +1,11 @@ +from __future__ import absolute_import import json import unittest import StringIO as stringio import os import sys import mock -import loadcli +from . import loadcli try: import libcomps diff --git a/tests/test_cli/test_list_commands.py b/tests/test_cli/test_list_commands.py index afc9a14..b7779eb 100644 --- a/tests/test_cli/test_list_commands.py +++ b/tests/test_cli/test_list_commands.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os import sys import unittest @@ -6,7 +7,7 @@ import StringIO as stringio import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_maven_build.py b/tests/test_cli/test_maven_build.py index 53f7737..3b8b187 100644 --- a/tests/test_cli/test_maven_build.py +++ b/tests/test_cli/test_maven_build.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -8,7 +9,7 @@ import sys import mock -import loadcli +from . import loadcli import optparse cli = loadcli.cli diff --git a/tests/test_cli/test_remove_channel.py b/tests/test_cli/test_remove_channel.py index b76691a..f881c55 100644 --- a/tests/test_cli/test_remove_channel.py +++ b/tests/test_cli/test_remove_channel.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -8,7 +9,7 @@ import sys import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_remove_host_from_channel.py b/tests/test_cli/test_remove_host_from_channel.py index 490edf4..4a56282 100644 --- a/tests/test_cli/test_remove_host_from_channel.py +++ b/tests/test_cli/test_remove_host_from_channel.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -8,7 +9,7 @@ import sys import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_remove_pkg.py b/tests/test_cli/test_remove_pkg.py index 9926158..cad99a0 100644 --- a/tests/test_cli/test_remove_pkg.py +++ b/tests/test_cli/test_remove_pkg.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest @@ -11,7 +12,7 @@ import mock from mock import call -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_rename_channel.py b/tests/test_cli/test_rename_channel.py index fb64c01..eca5a08 100644 --- a/tests/test_cli/test_rename_channel.py +++ b/tests/test_cli/test_rename_channel.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import StringIO as stringio @@ -8,7 +9,7 @@ import sys import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_running_in_bg.py b/tests/test_cli/test_running_in_bg.py index db5bc3f..64d21d4 100644 --- a/tests/test_cli/test_running_in_bg.py +++ b/tests/test_cli/test_running_in_bg.py @@ -1,8 +1,9 @@ +from __future__ import absolute_import import unittest import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_runroot.py b/tests/test_cli/test_runroot.py index 4823bf3..b056105 100644 --- a/tests/test_cli/test_runroot.py +++ b/tests/test_cli/test_runroot.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os import sys import unittest @@ -7,7 +8,7 @@ import StringIO as stringio import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_save_failed_tree.py b/tests/test_cli/test_save_failed_tree.py index b8acf12..6b1dcfe 100644 --- a/tests/test_cli/test_save_failed_tree.py +++ b/tests/test_cli/test_save_failed_tree.py @@ -1,9 +1,10 @@ +from __future__ import absolute_import import StringIO import unittest import koji import mock -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_cli/test_upload_progress_callback.py b/tests/test_cli/test_upload_progress_callback.py index f330dd7..aa1a8f2 100644 --- a/tests/test_cli/test_upload_progress_callback.py +++ b/tests/test_cli/test_upload_progress_callback.py @@ -1,9 +1,10 @@ +from __future__ import absolute_import import unittest import mock import sys import StringIO as stringio -import loadcli +from . import loadcli cli = loadcli.cli diff --git a/tests/test_client_session.py b/tests/test_client_session.py index 46ba9ea..2506f09 100644 --- a/tests/test_client_session.py +++ b/tests/test_client_session.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import mock import unittest diff --git a/tests/test_compatrequests.py b/tests/test_compatrequests.py index 6a684ef..250cc3d 100644 --- a/tests/test_compatrequests.py +++ b/tests/test_compatrequests.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import six.moves.http_client import mock import unittest diff --git a/tests/test_fixEncoding.py b/tests/test_fixEncoding.py index 4af66e9..ee8e089 100644 --- a/tests/test_fixEncoding.py +++ b/tests/test_fixEncoding.py @@ -3,6 +3,7 @@ """Test the __init__.py module""" +from __future__ import absolute_import import koji import unittest diff --git a/tests/test_hub/test_add_btype.py b/tests/test_hub/test_add_btype.py index e64cc0f..6a73b0d 100644 --- a/tests/test_hub/test_add_btype.py +++ b/tests/test_hub/test_add_btype.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_apply_query_opts.py b/tests/test_hub/test_apply_query_opts.py index 653723c..6d23d6a 100644 --- a/tests/test_hub/test_apply_query_opts.py +++ b/tests/test_hub/test_apply_query_opts.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import copy import unittest diff --git a/tests/test_hub/test_cg_importer.py b/tests/test_hub/test_cg_importer.py index f77ce67..f891610 100644 --- a/tests/test_hub/test_cg_importer.py +++ b/tests/test_hub/test_cg_importer.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock import os diff --git a/tests/test_hub/test_create_tag.py b/tests/test_hub/test_create_tag.py index 91dea25..4635658 100644 --- a/tests/test_hub/test_create_tag.py +++ b/tests/test_hub/test_create_tag.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import copy import mock import shutil diff --git a/tests/test_hub/test_delete_build.py b/tests/test_hub/test_delete_build.py index 2cd2dae..91e497f 100644 --- a/tests/test_hub/test_delete_build.py +++ b/tests/test_hub/test_delete_build.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import mock import unittest import kojihub diff --git a/tests/test_hub/test_dist_repo.py b/tests/test_hub/test_dist_repo.py index 33f1b6c..50b6057 100644 --- a/tests/test_hub/test_dist_repo.py +++ b/tests/test_hub/test_dist_repo.py @@ -1,4 +1,5 @@ +from __future__ import absolute_import import unittest import mock import os diff --git a/tests/test_hub/test_edit_tag.py b/tests/test_hub/test_edit_tag.py index 65d6dc6..0c57e75 100644 --- a/tests/test_hub/test_edit_tag.py +++ b/tests/test_hub/test_edit_tag.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import mock import unittest diff --git a/tests/test_hub/test_getRPMDeps.py b/tests/test_hub/test_getRPMDeps.py index 0d3149e..6bfcfcc 100644 --- a/tests/test_hub/test_getRPMDeps.py +++ b/tests/test_hub/test_getRPMDeps.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import mock import os import unittest diff --git a/tests/test_hub/test_get_build_type.py b/tests/test_hub/test_get_build_type.py index b4013e9..e4a0862 100644 --- a/tests/test_hub/test_get_build_type.py +++ b/tests/test_hub/test_get_build_type.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_get_next_release.py b/tests/test_hub/test_get_next_release.py index adfeea3..92a3e14 100644 --- a/tests/test_hub/test_get_next_release.py +++ b/tests/test_hub/test_get_next_release.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import mock import unittest diff --git a/tests/test_hub/test_get_upload_path.py b/tests/test_hub/test_get_upload_path.py index a1191ce..d11e1b1 100644 --- a/tests/test_hub/test_get_upload_path.py +++ b/tests/test_hub/test_get_upload_path.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os import mock import shutil diff --git a/tests/test_hub/test_get_verify_class.py b/tests/test_hub/test_get_verify_class.py index ae94ed6..57809e8 100644 --- a/tests/test_hub/test_get_verify_class.py +++ b/tests/test_hub/test_get_verify_class.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import kojihub from koji import GenericError diff --git a/tests/test_hub/test_import_build.py b/tests/test_hub/test_import_build.py index 108f911..7abea63 100644 --- a/tests/test_hub/test_import_build.py +++ b/tests/test_hub/test_import_build.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import copy import mock import shutil diff --git a/tests/test_hub/test_import_image_internal.py b/tests/test_hub/test_import_image_internal.py index b23f728..9dcb3d3 100644 --- a/tests/test_hub/test_import_image_internal.py +++ b/tests/test_hub/test_import_image_internal.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock import os diff --git a/tests/test_hub/test_insert_processor.py b/tests/test_hub/test_insert_processor.py index 1771681..fde1cc3 100644 --- a/tests/test_hub/test_insert_processor.py +++ b/tests/test_hub/test_insert_processor.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_list_btypes.py b/tests/test_hub/test_list_btypes.py index b5f4bc5..6649e89 100644 --- a/tests/test_hub/test_list_btypes.py +++ b/tests/test_hub/test_list_btypes.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_list_task_output.py b/tests/test_hub/test_list_task_output.py index 0b27af1..6a5f15c 100644 --- a/tests/test_hub/test_list_task_output.py +++ b/tests/test_hub/test_list_task_output.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_listing.py b/tests/test_hub/test_listing.py index a39f2b0..1647934 100644 --- a/tests/test_hub/test_listing.py +++ b/tests/test_hub/test_listing.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_models/test_host.py b/tests/test_hub/test_models/test_host.py index c1bc6e5..80f6667 100644 --- a/tests/test_hub/test_models/test_host.py +++ b/tests/test_hub/test_models/test_host.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_new_typed_build.py b/tests/test_hub/test_new_typed_build.py index a1ae47f..b7b6ccf 100644 --- a/tests/test_hub/test_new_typed_build.py +++ b/tests/test_hub/test_new_typed_build.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_query_processor.py b/tests/test_hub/test_query_processor.py index 7b229bd..e7c7cb8 100644 --- a/tests/test_hub/test_query_processor.py +++ b/tests/test_hub/test_query_processor.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_recycle_build.py b/tests/test_hub/test_recycle_build.py index 2179b04..5de0d70 100644 --- a/tests/test_hub/test_recycle_build.py +++ b/tests/test_hub/test_recycle_build.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import mock import koji diff --git a/tests/test_hub/test_rpmdiff.py b/tests/test_hub/test_rpmdiff.py index 277902f..4f94f38 100644 --- a/tests/test_hub/test_rpmdiff.py +++ b/tests/test_hub/test_rpmdiff.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import copy import unittest import mock diff --git a/tests/test_hub/test_tag_operations.py b/tests/test_hub/test_tag_operations.py index 2f0d10c..1b05efb 100644 --- a/tests/test_hub/test_tag_operations.py +++ b/tests/test_hub/test_tag_operations.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import copy import mock import shutil diff --git a/tests/test_hub/test_update_processor.py b/tests/test_hub/test_update_processor.py index e765b3b..b31956a 100644 --- a/tests/test_hub/test_update_processor.py +++ b/tests/test_hub/test_update_processor.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_krbv.py b/tests/test_krbv.py index 0fea679..f96b525 100644 --- a/tests/test_krbv.py +++ b/tests/test_krbv.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest # This is python-mock, not the rpm mock tool we know and love diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 5587ec3..02ff1c2 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -2,6 +2,7 @@ """Test the __init__.py module""" +from __future__ import absolute_import import mock import os import rpm diff --git a/tests/test_plugins/test_protonmsg.py b/tests/test_plugins/test_protonmsg.py index 108be2e..442be5f 100644 --- a/tests/test_plugins/test_protonmsg.py +++ b/tests/test_plugins/test_protonmsg.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest from mock import patch, MagicMock import protonmsg diff --git a/tests/test_plugins/test_runroot_builder.py b/tests/test_plugins/test_runroot_builder.py index 910c783..d82e710 100644 --- a/tests/test_plugins/test_runroot_builder.py +++ b/tests/test_plugins/test_runroot_builder.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock import six.moves.configparser diff --git a/tests/test_plugins/test_runroot_hub.py b/tests/test_plugins/test_runroot_hub.py index 79b5696..4f129c8 100644 --- a/tests/test_plugins/test_runroot_hub.py +++ b/tests/test_plugins/test_runroot_hub.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest import mock diff --git a/tests/test_plugins/test_save_failed_tree_builder.py b/tests/test_plugins/test_save_failed_tree_builder.py index 56c92a5..920f605 100644 --- a/tests/test_plugins/test_save_failed_tree_builder.py +++ b/tests/test_plugins/test_save_failed_tree_builder.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import mock import os import sys diff --git a/tests/test_policy.py b/tests/test_policy.py index 2fbc0aa..d228df7 100644 --- a/tests/test_policy.py +++ b/tests/test_policy.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import unittest from nose.tools import raises diff --git a/tests/test_utils.py b/tests/test_utils.py index ac533c1..1c58836 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import mock import unittest from mock import call From 5abd334e85282c35e97781aee552a98140246b58 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 18/61] python-modernize -f libmodernize.fixes.fix_map --- diff --git a/cli/koji b/cli/koji index e147b2a..9c7363f 100755 --- a/cli/koji +++ b/cli/koji @@ -31,6 +31,7 @@ from six.moves import range from six.moves import zip import six from six.moves import filter +from six.moves import map try: import krbV except ImportError: # pragma: no cover @@ -6530,7 +6531,7 @@ def handle_make_task(opts, session, args): if value is not None: taskopts[key] = value task_id = session.makeTask(method=args[0], - arglist=map(arg_filter,args[1:]), + arglist=list(map(arg_filter,args[1:])), **taskopts) print("Created task id %d" % task_id) if _running_in_bg() or not options.watch: From 2c8a4d332e0e90a9c999e781a68af46ca1988747 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 19/61] python-modernize -f libmodernize.fixes.fix_int_long_tuple --- diff --git a/builder/kojid b/builder/kojid index d0d1915..2da22fb 100755 --- a/builder/kojid +++ b/builder/kojid @@ -269,7 +269,7 @@ class BuildRoot(object): id_suffix = 'repo' name_prefix = 'Repository for Koji' for dep in self.deps: - if isinstance(dep, (int, long)): + if isinstance(dep, six.integer_types): # dep is a task ID, the url points to the task output directory repo_type = 'task' dep_url = pi.task(dep) @@ -1957,7 +1957,7 @@ class ChainMavenTask(MultiPlatformTask): pkg_to_wrap = params['buildrequires'][0] to_wrap = self.done[pkg_to_wrap] - if isinstance(to_wrap, (int, long)): + if isinstance(to_wrap, six.integer_types): task_to_wrap = self.session.getTaskInfo(to_wrap, request=True) build_to_wrap = None else: diff --git a/hub/kojihub.py b/hub/kojihub.py index 7253b14..0283ee5 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -2971,7 +2971,7 @@ def get_tag(tagInfo, strict=False, event=None): 'tag_config.maven_include_all': 'maven_include_all' } clauses = [eventCondition(event, table='tag_config')] - if isinstance(tagInfo, (int, long)): + if isinstance(tagInfo, six.integer_types): clauses.append("tag.id = %(tagInfo)i") elif isinstance(tagInfo, six.string_types): clauses.append("tag.name = %(tagInfo)s") @@ -3199,7 +3199,7 @@ def get_external_repos(info=None, url=None, event=None, queryOpts=None): if info is not None: if isinstance(info, str): clauses.append('name = %(info)s') - elif isinstance(info, (int, long)): + elif isinstance(info, six.integer_types): clauses.append('id = %(info)i') else: raise koji.GenericError('invalid type for lookup: %s' % type(info)) @@ -3638,7 +3638,7 @@ def get_rpm(rpminfo, strict=False, multi=False): ) # we can look up by id or NVRA data = None - if isinstance(rpminfo, (int, long)): + if isinstance(rpminfo, six.integer_types): data = {'id': rpminfo} elif isinstance(rpminfo, str): data = koji.parse_NVRA(rpminfo) @@ -5539,7 +5539,7 @@ def add_external_rpm(rpminfo, external_repo, strict=True): ('arch', six.string_types), ('payloadhash', str), ('size', int), - ('buildtime', (int, long))) + ('buildtime', six.integer_types)) for field, allowed in dtypes: if field not in rpminfo: raise koji.GenericError("%s field missing: %r" % (field, rpminfo)) @@ -9344,7 +9344,7 @@ class RootExports(object): before = calendar.timegm(before.utctimetuple()) elif isinstance(before, (str, six.text_type)): before = koji.util.parseTime(before) - elif isinstance(before, (int, long)): + elif isinstance(before, six.integer_types): pass else: raise koji.GenericError('invalid type for before: %s' % type(before)) @@ -9354,7 +9354,7 @@ class RootExports(object): after = calendar.timegm(after.utctimetuple()) elif isinstance(after, (str, six.text_type)): after = koji.util.parseTime(after) - elif isinstance(after, (int, long)): + elif isinstance(after, six.integer_types): pass else: raise koji.GenericError('invalid type for after: %s' % type(after)) @@ -9443,7 +9443,7 @@ class RootExports(object): def listTagged(self, tag, event=None, inherit=False, prefix=None, latest=False, package=None, owner=None, type=None): """List builds tagged with tag""" - if not isinstance(tag, (int, long)): + if not isinstance(tag, six.integer_types): #lookup tag id tag = get_tag_id(tag, strict=True) results = readTaggedBuilds(tag, event, inherit=inherit, latest=latest, package=package, owner=owner, type=type) @@ -9454,14 +9454,14 @@ class RootExports(object): def listTaggedRPMS(self, tag, event=None, inherit=False, latest=False, package=None, arch=None, rpmsigs=False, owner=None, type=None): """List rpms and builds within tag""" - if not isinstance(tag, (int, long)): + if not isinstance(tag, six.integer_types): #lookup tag id tag = get_tag_id(tag, strict=True) return readTaggedRPMS(tag, event=event, inherit=inherit, latest=latest, package=package, arch=arch, rpmsigs=rpmsigs, owner=owner, type=type) def listTaggedArchives(self, tag, event=None, inherit=False, latest=False, package=None, type=None): """List archives and builds within a tag""" - if not isinstance(tag, (int, long)): + if not isinstance(tag, six.integer_types): tag = get_tag_id(tag, strict=True) return readTaggedArchives(tag, event=event, inherit=inherit, latest=latest, package=package, type=type) @@ -9618,14 +9618,14 @@ class RootExports(object): def getLatestBuilds(self, tag, event=None, package=None, type=None): """List latest builds for tag (inheritance enabled)""" - if not isinstance(tag, (int, long)): + if not isinstance(tag, six.integer_types): #lookup tag id tag = get_tag_id(tag, strict=True) return readTaggedBuilds(tag, event, inherit=True, latest=True, package=package, type=type) def getLatestRPMS(self, tag, package=None, arch=None, event=None, rpmsigs=False, type=None): """List latest RPMS for tag (inheritance enabled)""" - if not isinstance(tag, (int, long)): + if not isinstance(tag, six.integer_types): #lookup tag id tag = get_tag_id(tag, strict=True) return readTaggedRPMS(tag, package=package, arch=arch, event=event, inherit=True, latest=True, rpmsigs=rpmsigs, type=type) @@ -9685,13 +9685,13 @@ class RootExports(object): def getInheritanceData(self, tag, event=None): """Return inheritance data for tag""" - if not isinstance(tag, (int, long)): + if not isinstance(tag, six.integer_types): #lookup tag id tag = get_tag_id(tag, strict=True) return readInheritanceData(tag, event) def setInheritanceData(self, tag, data, clear=False): - if not isinstance(tag, (int, long)): + if not isinstance(tag, six.integer_types): #lookup tag id tag = get_tag_id(tag, strict=True) context.session.assertPerm('admin') @@ -9702,7 +9702,7 @@ class RootExports(object): stops = {} if jumps is None: jumps = {} - if not isinstance(tag, (int, long)): + if not isinstance(tag, six.integer_types): #lookup tag id tag = get_tag_id(tag, strict=True) for mapping in [stops, jumps]: @@ -9729,7 +9729,7 @@ class RootExports(object): - buildroot_id If no build has the given ID, or the build generated no RPMs, an empty list is returned.""" - if not isinstance(build, (int, long)): + if not isinstance(build, six.integer_types): #lookup build id build = self.findBuildID(build, strict=True) return self.listRPMs(buildID=build) @@ -10120,7 +10120,7 @@ class RootExports(object): return taginfo def getRepo(self, tag, state=None, event=None, dist=False): - if isinstance(tag, (int, long)): + if isinstance(tag, six.integer_types): id = tag else: id = get_tag_id(tag, strict=True) @@ -12135,7 +12135,7 @@ class HostExports(object): extra_deps = [] task_deps = {} for dep in extra_deps: - if isinstance(dep, (int, long)): + if isinstance(dep, six.integer_types): task_output = list_task_output(dep, stat=True) for filepath, filestats in six.iteritems(task_output): if os.path.splitext(filepath)[1] in ['.log', '.md5', '.sha1']: diff --git a/koji/__init__.py b/koji/__init__.py index d20840b..0cbe502 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -464,7 +464,7 @@ def encode_int(n): def decode_int(n): """If n is not an integer, attempt to convert it""" - if isinstance(n, (int, long)): + if isinstance(n, six.integer_types): return n #else return int(n) @@ -914,7 +914,7 @@ def get_header_field(hdr, name, src_arch=False): # HACK: workaround for https://bugzilla.redhat.com/show_bug.cgi?id=991329 if result is None: result = [] - elif isinstance(result, (int, long)): + elif isinstance(result, six.integer_types): result = [result] return result From 0ac44b53741a63f5c70c29062b5819df9692f812 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 20/61] fix relative import --- diff --git a/koji/compatrequests.py b/koji/compatrequests.py index 7605efa..8d7d6a3 100644 --- a/koji/compatrequests.py +++ b/koji/compatrequests.py @@ -12,10 +12,10 @@ import six.moves.http_client import urlparse import urllib import sys -import ssl.SSLCommon +from .ssl import SSLCommon import six try: - from ssl import ssl as pyssl + from .ssl import ssl as pyssl except ImportError: # pragma: no cover pass @@ -61,9 +61,9 @@ class Session(object): certs['peer_ca_cert'] = verify if cert: certs['key_and_cert'] = cert - ctx = ssl.SSLCommon.CreateSSLContext(certs) + ctx = SSLCommon.CreateSSLContext(certs) cnxOpts = {'ssl_context' : ctx} - cnxClass = ssl.SSLCommon.PlgHTTPSConnection + cnxClass = SSLCommon.PlgHTTPSConnection default_port = 443 elif scheme == 'https': cnxOpts = {} diff --git a/tests/test_cli/test_edit_tag.py b/tests/test_cli/test_edit_tag.py index f59bb48..e11c485 100644 --- a/tests/test_cli/test_edit_tag.py +++ b/tests/test_cli/test_edit_tag.py @@ -11,7 +11,7 @@ import mock from mock import call -import loadcli +from . import loadcli import six cli = loadcli.cli From 0c0cf92b4ca195e83b75faf518fcf518c325fb81 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 21/61] PythonImportError --- diff --git a/koji/__init__.py b/koji/__init__.py index 0cbe502..5d6b28c 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -35,7 +35,6 @@ import base64 import datetime import six.moves.configparser import errno -import exceptions from fnmatch import fnmatch import six.moves.http_client import imp @@ -265,6 +264,8 @@ PRIO_DEFAULT = 20 ## BEGIN kojikamid dup #Exceptions +PythonImportError = ImportError # will be masked by koji's one + class GenericError(Exception): """Base class for our custom exceptions""" faultCode = 1000 @@ -2090,7 +2091,7 @@ class ClientSession(object): pass if not krbV: - raise exceptions.ImportError( + raise PythonImportError( "Please install python-krbV to use kerberos." ) @@ -2168,7 +2169,7 @@ class ClientSession(object): def gssapi_login(self, proxyuser=None): if not HTTPKerberosAuth: - raise exceptions.ImportError( + raise PythonImportError( "Please install python-requests-kerberos to use GSSAPI." ) From 7d277a8ad564de0a0fe12943935220ef991a691d Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 22/61] urllib changes --- diff --git a/koji/__init__.py b/koji/__init__.py index 5d6b28c..2cf41c1 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -72,15 +72,13 @@ import struct import tempfile import time import traceback -import urllib -import urllib2 -import urlparse from . import util import warnings import six.moves.xmlrpc_client import xml.sax import xml.sax.handler from six.moves.xmlrpc_client import loads, dumps, Fault +import six.moves.urllib PROFILE_MODULES = {} # {module_name: module_instance} @@ -1566,7 +1564,7 @@ def openRemoteFile(relpath, topurl=None, topdir=None, tempdir=None): on options""" if topurl: url = "%s/%s" % (topurl, relpath) - src = urllib2.urlopen(url) + src = six.moves.urllib.request.urlopen(url) fo = tempfile.TemporaryFile(dir=tempdir) shutil.copyfileobj(src, fo) src.close() @@ -2156,8 +2154,7 @@ class ClientSession(object): """Get the Kerberos principal of the server we're connecting to, based on baseurl.""" - uri = urlparse.urlsplit(self.baseurl) - host, port = urllib.splitport(uri[1]) + host = six.moves.urllib.parse.urlparse(self.baseurl).hostname if self.opts.get('krb_rdns', True): servername = socket.getfqdn(host) else: @@ -2175,7 +2172,7 @@ class ClientSession(object): # force https old_baseurl = self.baseurl - uri = urlparse.urlsplit(self.baseurl) + uri = six.moves.urllib.parse.urlsplit(self.baseurl) if uri[0] != 'https': self.baseurl = 'https://%s%s' % (uri[1], uri[2]) @@ -2219,7 +2216,7 @@ class ClientSession(object): # when API is changed # force https - uri = urlparse.urlsplit(self.baseurl) + uri = six.moves.urllib.parse.urlsplit(self.baseurl) if uri[0] != 'https': self.baseurl = 'https://%s%s' % (uri[1], uri[2]) @@ -2294,7 +2291,7 @@ class ClientSession(object): sinfo = self.sinfo.copy() sinfo['callnum'] = self.callnum self.callnum += 1 - handler = "%s?%s" % (self.baseurl, urllib.urlencode(sinfo)) + handler = "%s?%s" % (self.baseurl, six.moves.urllib.parse.urlencode(sinfo)) elif name == 'sslLogin': handler = self.baseurl + '/ssllogin' else: @@ -2565,7 +2562,7 @@ class ClientSession(object): args['volume'] = volume size = len(chunk) self.callnum += 1 - handler = "%s?%s" % (self.baseurl, urllib.urlencode(args)) + handler = "%s?%s" % (self.baseurl, six.moves.urllib.parse.urlencode(args)) headers = [ ('User-Agent', 'koji/1'), ("Content-Type", "application/octet-stream"), diff --git a/koji/compatrequests.py b/koji/compatrequests.py index 8d7d6a3..5f1347a 100644 --- a/koji/compatrequests.py +++ b/koji/compatrequests.py @@ -9,8 +9,7 @@ the bits that koji needs. from __future__ import absolute_import import six.moves.http_client -import urlparse -import urllib +import six.moves.urllib import sys from .ssl import SSLCommon import six @@ -27,7 +26,7 @@ class Session(object): def post(self, url, data=None, headers=None, stream=None, verify=None, cert=None, timeout=None): - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) if uri[3]: handler = "%s?%s" % (uri[2], uri[3]) else: @@ -46,7 +45,7 @@ class Session(object): def get_connection(self, uri, cert, verify, timeout): scheme = uri[0] - host, port = urllib.splitport(uri[1]) + host, port = six.moves.urllib.splitport(uri[1]) key = (scheme, host, cert, verify, timeout) #if self.connection and self.opts.get('keepalive'): if self.connection: # XXX honor keepalive diff --git a/koji/tasks.py b/koji/tasks.py index e43a243..dcf0bdc 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -27,12 +27,12 @@ import os import logging import six.moves.xmlrpc_client import signal -import urllib2 import shutil import random import time import pprint from six.moves import range +import six.moves.urllib def scan_mounts(topdir): """Search path for mountpoints""" @@ -311,7 +311,7 @@ class BaseTaskHandler(object): return fn self.logger.debug("Downloading %s", relpath) url = "%s/%s" % (self.options.topurl, relpath) - fsrc = urllib2.urlopen(url) + fsrc = six.moves.urllib.request.urlopen(url) if not os.path.exists(os.path.dirname(fn)): os.makedirs(os.path.dirname(fn)) fdst = open(fn, 'w') diff --git a/tests/test_client_session.py b/tests/test_client_session.py index 2506f09..cfbf82a 100644 --- a/tests/test_client_session.py +++ b/tests/test_client_session.py @@ -10,7 +10,7 @@ class TestClientSession(unittest.TestCase): @mock.patch('socket.getfqdn') def test_server_principal_rdns(self, getfqdn): opts = {'krb_rdns': True} - session = koji.ClientSession('http://koji.example.com/kojihub', opts) + session = koji.ClientSession('http://koji.example.com:30/kojihub', opts) cprinc = mock.MagicMock() cprinc.realm = "REALM" getfqdn.return_value = 'koji02.example.com' diff --git a/tests/test_compatrequests.py b/tests/test_compatrequests.py index 250cc3d..dfd9226 100644 --- a/tests/test_compatrequests.py +++ b/tests/test_compatrequests.py @@ -2,7 +2,7 @@ from __future__ import absolute_import import six.moves.http_client import mock import unittest -import urlparse +import six.moves.urllib import koji.compatrequests @@ -106,7 +106,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, no verify, no timeout session = koji.compatrequests.Session() url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) cnx = session.get_connection(uri, None, None, None) HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) @@ -124,7 +124,7 @@ class TestSessionConnection(unittest.TestCase): def test_cached(self): session = koji.compatrequests.Session() url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) key = ('http', 'www.fakedomain234234.org', None, None, None) cnx = mock.MagicMock() session.connection = (key, cnx) @@ -135,10 +135,10 @@ class TestSessionConnection(unittest.TestCase): def test_badproto(self): session = koji.compatrequests.Session() url = 'nosuchproto://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) with self.assertRaises(IOError): - ret = session.get_connection(uri, None, None, None) + session.get_connection(uri, None, None, None) @mock.patch('httplib.HTTPConnection') @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) @@ -146,12 +146,12 @@ class TestSessionConnection(unittest.TestCase): # no cert, no verify session = koji.compatrequests.Session() url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) timeout = 1701 - cnx = session.get_connection(uri, None, None, 1701) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=1701) - key = ('http', 'www.fakedomain234234.org', None, None, 1701) + cnx = session.get_connection(uri, None, None, timeout) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=timeout) + key = ('http', 'www.fakedomain234234.org', None, None, timeout) self.assertEqual(session.connection, (key, cnx)) @mock.patch('httplib.HTTPConnection') @@ -160,22 +160,22 @@ class TestSessionConnection(unittest.TestCase): # no cert, no verify session = koji.compatrequests.Session() url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) timeout = 1701 - cnx = session.get_connection(uri, None, None, 1701) + cnx = session.get_connection(uri, None, None, timeout) HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) - key = ('http', 'www.fakedomain234234.org', None, None, 1701) + key = ('http', 'www.fakedomain234234.org', None, None, timeout) self.assertEqual(session.connection, (key, cnx)) cnx.connect.assert_called_once() - cnx.sock.settimeout.assert_called_with(1701) + cnx.sock.settimeout.assert_called_with(timeout) @mock.patch('httplib.HTTPSConnection') def test_https(self, HTTPSConnection): # no cert, no verify, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) cnx = session.get_connection(uri, None, None, None) HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) @@ -188,7 +188,7 @@ class TestSessionConnection(unittest.TestCase): # no verify, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) cert = '/path/to/cert/file' context = mock.MagicMock() CreateSSLContext.return_value = context @@ -205,7 +205,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, verify=False, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) context = mock.MagicMock() create_unverified_context.return_value = context @@ -221,7 +221,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, verify=False, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) cnx = session.get_connection(uri, None, False, None) HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) @@ -236,7 +236,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) context = mock.MagicMock() SSLContext.return_value = context verify = '/path/to/verify/cert' @@ -257,7 +257,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) + uri = six.moves.urllib.parse.urlsplit(url) verify = '/path/to/verify/cert' cnx = session.get_connection(uri, None, verify, None) diff --git a/tests/test_tasks.py b/tests/test_tasks.py index 28ab75b..1abe47e 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -462,7 +462,7 @@ class TasksTestCase(TestCase): obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) self.assertEquals(obj.localPath('test.txt'), dummy_file) - @patch('urllib2.urlopen', return_value=StringIO(six.text_type('Important things\nSome more important things\n'))) + @patch('six.moves.urllib.request.urlopen', return_value=StringIO(six.text_type('Important things\nSome more important things\n'))) def test_BaseTaskHandler_localPath_no_file(self, mock_urlopen): """ """ diff --git a/tests/test_utils.py b/tests/test_utils.py index 1c58836..6809088 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -82,7 +82,7 @@ class MiscFunctionTestCase(unittest.TestCase): islink.assert_called_once_with(dst) move.assert_not_called() - @mock.patch('urllib2.urlopen') + @mock.patch('six.moves.urllib.request.urlopen') @mock.patch('tempfile.TemporaryFile') @mock.patch('shutil.copyfileobj') @mock.patch('__builtin__.open') diff --git a/util/koji-shadow b/util/koji-shadow index d820e65..c170665 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -42,9 +42,8 @@ import socket # for socket.error and socket.setdefaulttimeout import string import sys import time -import urllib2 -import urlgrabber.grabber as grabber import six.moves.xmlrpc_client # for ProtocolError and Fault +import six.moves.urllib import rpm # koji.fp.o keeps stalling, probably network errors... @@ -449,7 +448,7 @@ class TrackedBuild(object): url = "%s/%s" % (pathinfo.build(self.info), pathinfo.rpm(self.srpm)) log("Downloading %s" % url) #XXX - this is not really the right place for this - fsrc = urllib2.urlopen(url) + fsrc = six.moves.urllib.request.urlopen(url) fn = "%s/%s.src.rpm" % (options.workpath, self.nvr) koji.ensuredir(os.path.dirname(fn)) fdst = open(fn, 'w') @@ -891,7 +890,7 @@ class BuildTracker(object): koji.ensuredir(os.path.dirname(dst)) os.chown(os.path.dirname(dst), 48, 48) #XXX - hack log ("Downloading %s to %s" % (url, dst)) - fsrc = urllib2.urlopen(url) + fsrc = six.moves.urllib.request.urlopen(url) fdst = open(fn, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() @@ -904,7 +903,7 @@ class BuildTracker(object): koji.ensuredir(options.workpath) dst = "%s/%s" % (options.workpath, fn) log ("Downloading %s to %s..." % (url, dst)) - fsrc = urllib2.urlopen(url) + fsrc = six.moves.urllib.request.urlopen(url) fdst = open(dst, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() diff --git a/www/kojiweb/archiveinfo.chtml b/www/kojiweb/archiveinfo.chtml index ee2d3f4..1b763ca 100644 --- a/www/kojiweb/archiveinfo.chtml +++ b/www/kojiweb/archiveinfo.chtml @@ -1,7 +1,7 @@ #import koji #from kojiweb import util #from pprint import pformat -#import urllib +#import six.moves.urllib #attr _PASSTHROUGH = ['archiveID', 'fileOrder', 'fileStart', 'buildrootOrder', 'buildrootStart'] @@ -97,7 +97,7 @@ #for $file in $files - $file.name$file.size + $file.name$file.size #end for diff --git a/www/kojiweb/fileinfo.chtml b/www/kojiweb/fileinfo.chtml index 6359d60..b402527 100644 --- a/www/kojiweb/fileinfo.chtml +++ b/www/kojiweb/fileinfo.chtml @@ -1,12 +1,12 @@ #from kojiweb import util -#import urllib +#import six.moves.urllib #import datetime #include "includes/header.chtml" #if $rpm -

Information for file $file.name

+

Information for file $file.name

#elif $archive -

Information for file $file.name

+

Information for file $file.name

#end if diff --git a/www/kojiweb/rpminfo.chtml b/www/kojiweb/rpminfo.chtml index 38b7a00..9b357d4 100644 --- a/www/kojiweb/rpminfo.chtml +++ b/www/kojiweb/rpminfo.chtml @@ -2,7 +2,7 @@ #from kojiweb import util #from pprint import pformat #import time -#import urllib +#import six.moves.urllib #attr _PASSTHROUGH = ['rpmID', 'fileOrder', 'fileStart', 'buildrootOrder', 'buildrootStart'] @@ -237,7 +237,7 @@ #for $file in $files - + #end for
$util.escapeHTML($file.name)$file.size$util.escapeHTML($file.name)$file.size
diff --git a/www/kojiweb/searchresults.chtml b/www/kojiweb/searchresults.chtml index e0c4ece..882d673 100644 --- a/www/kojiweb/searchresults.chtml +++ b/www/kojiweb/searchresults.chtml @@ -1,5 +1,5 @@ #from kojiweb import util -#import urllib +#import six.moves.urllib #include "includes/header.chtml" @@ -38,7 +38,7 @@ $result.id #set $quoted = $result.copy() - #silent $quoted['name'] = $urllib.quote($quoted['name']) + #silent $quoted['name'] = $six.moves.urllib.parse.quote($quoted['name']) $result.name #end for diff --git a/www/kojiweb/taskinfo.chtml b/www/kojiweb/taskinfo.chtml index a4e050f..1f02cf7 100644 --- a/www/kojiweb/taskinfo.chtml +++ b/www/kojiweb/taskinfo.chtml @@ -1,6 +1,6 @@ #import koji #from kojiweb import util -#import urllib +#import six.moves.urllib #import cgi #def printValue($key, $value, $sep=', ') @@ -424,9 +424,9 @@ $value Output #for $volume, $filename in $output - $filename + $filename #if $filename.endswith('.log') - (tail) + (tail) #end if
#end for From 7ff24d717d642e824473044dd1fb70bb7bef36f7 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 23/61] fix session --- diff --git a/koji/util.py b/koji/util.py index 5535223..af1a0b0 100644 --- a/koji/util.py +++ b/koji/util.py @@ -467,11 +467,15 @@ class adler32_constructor(object): #mimicing the hashlib constructors def __init__(self, arg=''): + if six.PY3: + arg = bytes(arg, 'utf-8') self._value = adler32(arg) & 0xffffffff #the bitwise and works around a bug in some versions of python #see: https://bugs.python.org/issue1202 def update(self, arg): + if six.PY3: + arg = bytes(arg, 'utf-8') self._value = adler32(arg, self._value) & 0xffffffff def digest(self): diff --git a/tests/test_client_session.py b/tests/test_client_session.py index cfbf82a..5edab10 100644 --- a/tests/test_client_session.py +++ b/tests/test_client_session.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import mock import unittest +import six import koji @@ -31,31 +32,30 @@ class TestClientSession(unittest.TestCase): self.assertEqual(princ, 'host/koji.example.com@REALM') getfqdn.assert_not_called() - @mock.patch('koji.compatrequests.Session') @mock.patch('requests.Session') - def test_new_session(self, rsession, compat_session): + def test_new_session(self, rsession): opts = {'use_old_ssl': False} ksession = koji.ClientSession('http://koji.example.com/kojihub', opts) # init should have called new_session for us rsession.assert_called_once() - compat_session.assert_not_called() - @mock.patch('koji.compatrequests.Session') @mock.patch('requests.Session') - def test_new_session_old(self, rsession, compat_session): + def test_new_session_old(self, rsession): + if six.PY3: + return opts = {'use_old_ssl': True} ksession = koji.ClientSession('http://koji.example.com/kojihub', opts) # init should have called new_session for us rsession.assert_not_called() - compat_session.assert_called_once() - @mock.patch('koji.compatrequests.Session') @mock.patch('requests.Session') - def test_new_session_close(self, rsession, compat_session): + def test_new_session_close(self, rsession): + if six.PY3: + return opts = {'use_old_ssl': True} ksession = koji.ClientSession('http://koji.example.com/kojihub', opts) my_rsession = mock.MagicMock() @@ -73,9 +73,12 @@ class TestFastUpload(unittest.TestCase): self.do_fake_login() # mocks self.ksession._callMethod = mock.MagicMock() - self.compat_session = mock.patch('koji.compatrequests.Session').start() + self.ksession.retries = 1 self.rsession = mock.patch('requests.Session').start() - self.file_mock = mock.patch('__builtin__.file').start() + if six.PY2: + self.file_mock = mock.patch('__builtin__.open').start() + else: + self.file_mock = mock.patch('builtins.open').start() self.getsize_mock = mock.patch('os.path.getsize').start() def tearDown(self): diff --git a/tests/test_utils.py b/tests/test_utils.py index 6809088..b4a3b21 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -85,11 +85,17 @@ class MiscFunctionTestCase(unittest.TestCase): @mock.patch('six.moves.urllib.request.urlopen') @mock.patch('tempfile.TemporaryFile') @mock.patch('shutil.copyfileobj') - @mock.patch('__builtin__.open') - def test_openRemoteFile(self, m_open, m_copyfileobj, m_TemporaryFile, + def test_openRemoteFile(self, m_copyfileobj, m_TemporaryFile, m_urlopen): """Test openRemoteFile function""" + if six.PY2: + __builtins__.open = mock.MagicMock() + m_open = __builtins__.open + else: + import builtins + builtins.open = mock.MagicMock() + m_open = builtins.open mocks = [m_open, m_copyfileobj, m_TemporaryFile, m_urlopen] topurl = 'http://example.com/koji' From ce9b538e43092f0dd677867efa1475c53da541f4 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 24/61] fix compatrequests --- diff --git a/koji/compatrequests.py b/koji/compatrequests.py index 5f1347a..3422907 100644 --- a/koji/compatrequests.py +++ b/koji/compatrequests.py @@ -45,7 +45,11 @@ class Session(object): def get_connection(self, uri, cert, verify, timeout): scheme = uri[0] - host, port = six.moves.urllib.splitport(uri[1]) + # TODO: unnecessary remerging of values + parsed = six.moves.urllib.parse.urlparse('%s://%s' % (uri[0], uri[1])) + host = parsed.hostname + port = parsed.port + #host, port = six.moves.urllib.splitport(uri[1]) key = (scheme, host, cert, verify, timeout) #if self.connection and self.opts.get('keepalive'): if self.connection: # XXX honor keepalive diff --git a/tests/test_utils.py b/tests/test_utils.py index b4a3b21..09df6ef 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -90,8 +90,9 @@ class MiscFunctionTestCase(unittest.TestCase): """Test openRemoteFile function""" if six.PY2: - __builtins__.open = mock.MagicMock() - m_open = __builtins__.open + import __builtin__ + __builtin__.open = mock.MagicMock() + m_open = __builtin__.open else: import builtins builtins.open = mock.MagicMock() From 6d5dc301d3ced6ea28e0b4a83a31ed29049e55c6 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 25/61] don't use krbV under python3 --- diff --git a/koji/auth.py b/koji/auth.py index 3cc845b..e095c5d 100644 --- a/koji/auth.py +++ b/koji/auth.py @@ -24,7 +24,10 @@ import socket import string import random import base64 -import krbV +try: + import krbV +except ImportError: + krbV = None import koji import cgi #for parse_qs from .context import context @@ -301,6 +304,10 @@ class Session(object): if self.logged_in: raise koji.AuthError("Already logged in") + if krbV is None: + # python3 is not supported + raise koji.AuthError("krbV module not installed") + if not (context.opts.get('AuthPrincipal') and context.opts.get('AuthKeytab')): raise koji.AuthError('not configured for Kerberos authentication') From 119ecf2122b5f6d60382fad18361e9b67c64c439 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 26/61] propagate exception correctly to outer scope --- diff --git a/koji/tasks.py b/koji/tasks.py index dcf0bdc..9a4080e 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -234,13 +234,15 @@ class BaseTaskHandler(object): if all: if failany: failed = False + task_error = None for task in finished: if task in canfail: # no point in checking continue try: self.session.getTaskResult(task) - except (koji.GenericError, six.moves.xmlrpc_client.Fault) as task_error: + except (koji.GenericError, six.moves.xmlrpc_client.Fault) as te: + task_error = te self.logger.info("task %s failed or was canceled" % task) failed = True break From 0eebe53b279eecb07063402553f9cb4ddaac6bd2 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 27/61] Exception.message is deprecated --- diff --git a/tests/test_tasks.py b/tests/test_tasks.py index 1abe47e..3d52855 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -112,7 +112,7 @@ class TasksTestCase(TestCase): umount_all('/dev') raise Exception('A GenericError was not raised during the test') except koji.GenericError as e: - self.assertEquals(e.message, + self.assertEquals(e.args[0], 'umount failed (exit code 1) for /dev/shm') # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all @@ -126,7 +126,7 @@ class TasksTestCase(TestCase): umount_all('/dev') raise Exception('A GenericError was not raised during the test') except koji.GenericError as e: - self.assertEquals(e.message, 'Unmounting incomplete: [\'/dev/shm\', \'/dev/mqueue\']') + self.assertEquals(e.args[0], 'Unmounting incomplete: [\'/dev/shm\', \'/dev/mqueue\']') @patch('os.path.isfile', return_value=True) @patch('os.remove') @@ -172,7 +172,7 @@ class TasksTestCase(TestCase): safe_rmtree('/mnt/folder', False, True) raise Exception('A GenericError was not raised during the test') except koji.GenericError as e: - self.assertEquals(e.message, 'file removal failed (code 1) for /mnt/folder') + self.assertEquals(e.args[0], 'file removal failed (code 1) for /mnt/folder') @patch('os.path.isfile', return_value=False) @patch('os.path.islink', return_value=False) @@ -186,7 +186,7 @@ class TasksTestCase(TestCase): safe_rmtree('/mnt/folder', False, True) raise Exception('A GenericError was not raised during the test') except koji.GenericError as e: - self.assertEquals(e.message, 'dir removal failed (code 1) for /mnt/folder') + self.assertEquals(e.args[0], 'dir removal failed (code 1) for /mnt/folder') def test_BaseTaskHandler_handler_not_set(self): """ Tests that an exception is thrown when the handler function is not overwritten by the child class. @@ -357,7 +357,7 @@ class TasksTestCase(TestCase): obj.wait([1551234, 1591234], all=True, failany=True) raise Exception('A GeneralError was not raised.') except koji.GenericError as e: - self.assertEquals(e.message, 'Uh oh, we\'ve got a problem here!') + self.assertEquals(e.args[0], 'Uh oh, we\'ve got a problem here!') obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) def test_BaseTaskHandler_getUploadDir(self): @@ -514,7 +514,7 @@ class TasksTestCase(TestCase): obj.find_arch('noarch', host, None) raise Exception('The BuildError Exception was not raised') except koji.BuildError as e: - self.assertEquals(e.message, 'No arch list for this host: test.domain.local') + self.assertEquals(e.args[0], 'No arch list for this host: test.domain.local') def test_BaseTaskHandler_find_arch_noarch_bad_tag(self): """ Tests that the find_arch function raises an exception when the tag parameter doesn't contain a @@ -529,7 +529,7 @@ class TasksTestCase(TestCase): obj.find_arch('noarch', host, tag) raise Exception('The BuildError Exception was not raised') except koji.BuildError as e: - self.assertEquals(e.message, 'No arch list for tag: some_package-1.2-build') + self.assertEquals(e.args[0], 'No arch list for tag: some_package-1.2-build') def test_BaseTaskHandler_find_arch_noarch(self): """ Tests that the find_arch function finds a match of x86_64 when the host only supports x86_64 @@ -555,7 +555,7 @@ class TasksTestCase(TestCase): obj.find_arch('noarch', host, tag) raise Exception('The BuildError Exception was not raised') except koji.BuildError as e: - self.assertEquals(e.message, ('host test.domain.local (i386) does not support ' + self.assertEquals(e.args[0], ('host test.domain.local (i386) does not support ' 'any arches of tag some_package-1.2-build (aarch64, x86_64)')) def test_getRepo_tied_to_session(self): @@ -652,7 +652,7 @@ class TasksTestCase(TestCase): raise Exception('The BuildError Exception was not raised') except koji.BuildError as e: obj.session.getRepo.assert_called_once_with(8472) - self.assertEquals(e.message, 'no repo (and no target) for tag rhel-7.3-build') + self.assertEquals(e.args[0], 'no repo (and no target) for tag rhel-7.3-build') def test_FakeTask_handler(self): """ Tests that the FakeTest handler can be instantiated and returns 42 when run From f8f373e2b69235dd4f5a91e290fb28955fe363ff Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 28/61] use sorted(archs) to not confuse tests --- diff --git a/koji/tasks.py b/koji/tasks.py index 9a4080e..05606cb 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -365,7 +365,7 @@ class BaseTaskHandler(object): else: # no overlap raise koji.BuildError("host %s (%s) does not support any arches of tag %s (%s)" % \ - (host['name'], ', '.join(host_arches), tag['name'], ', '.join(tag_arches))) + (host['name'], ', '.join(sorted(host_arches)), tag['name'], ', '.join(sorted(tag_arches)))) def getRepo(self, tag): """ From cab2c7b4ea271713f778a73448ebf0db540f751e Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 29/61] return rpm headers as string instead of bytes --- diff --git a/koji/__init__.py b/koji/__init__.py index 2cf41c1..fda9e4a 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -915,6 +915,8 @@ def get_header_field(hdr, name, src_arch=False): result = [] elif isinstance(result, six.integer_types): result = [result] + if isinstance(result, bytes): + result = result.decode('utf-8') return result From b4c7433cc46eb0460c885eff5ed5259b5cb7d8f0 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 30/61] StringIO to six --- diff --git a/koji/daemon.py b/koji/daemon.py index 82c5c4c..45a14c5 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -29,7 +29,6 @@ from koji.util import md5_constructor, adler32_constructor, parseStatus import os import signal import logging -import urlparse from fnmatch import fnmatch import base64 import time @@ -38,6 +37,7 @@ import traceback import errno import six.moves.xmlrpc_client from six.moves import range +import six.moves.urllib import six @@ -247,7 +247,7 @@ class SCM(object): # replace the scheme with http:// so that the urlparse works in all cases dummyurl = self.url.replace(scheme, 'http://', 1) - dummyscheme, netloc, path, params, query, fragment = urlparse.urlparse(dummyurl) + dummyscheme, netloc, path, params, query, fragment = six.moves.urllib.parse.urlparse(dummyurl) user = None userhost = netloc.split('@') diff --git a/tests/test_cli/test_add_group.py b/tests/test_cli/test_add_group.py index f2d4aed..d2899c7 100644 --- a/tests/test_cli/test_add_group.py +++ b/tests/test_cli/test_add_group.py @@ -1,13 +1,13 @@ from __future__ import absolute_import import unittest -import StringIO as stringio import os import sys import mock +import six from . import loadcli @@ -19,7 +19,7 @@ class TestAddGroup(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_group(self, activate_session_mock, stdout): tag = 'tag' @@ -48,7 +48,7 @@ class TestAddGroup(unittest.TestCase): session.groupListAdd.assert_called_once_with(tag, group) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_group_dupl(self, activate_session_mock, stdout): tag = 'tag' @@ -77,8 +77,8 @@ class TestAddGroup(unittest.TestCase): session.groupListAdd.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('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_group_help( self, @@ -114,7 +114,7 @@ class TestAddGroup(unittest.TestCase): session.groupListAdd.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_group_no_perm(self, activate_session_mock, stdout): tag = 'tag' @@ -140,7 +140,7 @@ class TestAddGroup(unittest.TestCase): session.groupListAdd.assert_not_called() self.assertEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_group_no_tag(self, activate_session_mock, stdout): tag = 'tag' diff --git a/tests/test_cli/test_add_host.py b/tests/test_cli/test_add_host.py index a7ecf7d..026c4fa 100644 --- a/tests/test_cli/test_add_host.py +++ b/tests/test_cli/test_add_host.py @@ -1,13 +1,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock +import six from . import loadcli @@ -19,7 +16,7 @@ class TestAddHost(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host(self, activate_session_mock, stdout): host = 'host' @@ -49,7 +46,7 @@ class TestAddHost(unittest.TestCase): session.addHost.assert_called_once_with(host, arches, **kwargs) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_no_krb_principal( self, activate_session_mock, stdout): @@ -76,7 +73,7 @@ class TestAddHost(unittest.TestCase): session.addHost.assert_called_once_with(host, arches) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_dupl(self, activate_session_mock, stdout): host = 'host' @@ -103,8 +100,8 @@ class TestAddHost(unittest.TestCase): session.addHost.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('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_help(self, activate_session_mock, stderr, stdout): arguments = [] @@ -134,7 +131,7 @@ class TestAddHost(unittest.TestCase): session.addHost.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_failed(self, activate_session_mock, stdout): host = 'host' diff --git a/tests/test_cli/test_add_host_to_channel.py b/tests/test_cli/test_add_host_to_channel.py index 7197836..5daabe1 100644 --- a/tests/test_cli/test_add_host_to_channel.py +++ b/tests/test_cli/test_add_host_to_channel.py @@ -1,13 +1,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock +import six from . import loadcli @@ -19,7 +16,7 @@ class TestAddHostToChannel(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_to_channel(self, activate_session_mock, stdout): host = 'host' @@ -48,7 +45,7 @@ class TestAddHostToChannel(unittest.TestCase): session.addHostToChannel.assert_called_once_with(host, channel) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_to_channel_list( self, activate_session_mock, stdout): @@ -76,7 +73,7 @@ class TestAddHostToChannel(unittest.TestCase): session.addHostToChannel.assert_not_called() self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_to_channel_new( self, activate_session_mock, stdout): @@ -107,7 +104,7 @@ class TestAddHostToChannel(unittest.TestCase): host, channel, **kwargs) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_to_channel_no_channel( self, activate_session_mock, stdout): @@ -135,7 +132,7 @@ class TestAddHostToChannel(unittest.TestCase): session.addHostToChannel.assert_not_called() self.assertEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_to_channel_no_host( self, activate_session_mock, stdout): @@ -165,8 +162,8 @@ class TestAddHostToChannel(unittest.TestCase): session.addHostToChannel.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('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_host_to_channel_help( self, activate_session_mock, stderr, stdout): diff --git a/tests/test_cli/test_add_pkg.py b/tests/test_cli/test_add_pkg.py index 909e1fd..93965c8 100644 --- a/tests/test_cli/test_add_pkg.py +++ b/tests/test_cli/test_add_pkg.py @@ -1,14 +1,10 @@ from __future__ import absolute_import import unittest - -import StringIO as stringio - import os - import sys - import mock +import six from mock import call @@ -22,7 +18,7 @@ class TestAddPkg(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_pkg(self, activate_session_mock, stdout): tag = 'tag' @@ -67,7 +63,7 @@ class TestAddPkg(unittest.TestCase): session.multiCall.assert_called_once_with(strict=True) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_pkg_multi_pkg(self, activate_session_mock, stdout): tag = 'tag' @@ -111,7 +107,7 @@ class TestAddPkg(unittest.TestCase): call.multiCall(strict=True)]) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_pkg_owner_no_exists( self, activate_session_mock, stdout): @@ -144,7 +140,7 @@ class TestAddPkg(unittest.TestCase): [call.getUser(owner)]) self.assertEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_pkg_tag_no_exists(self, activate_session_mock, stdout): tag = 'tag' @@ -180,8 +176,8 @@ class TestAddPkg(unittest.TestCase): call.getTag(tag)]) self.assertEqual(cm.exception.code, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_pkg_no_owner( self, activate_session_mock, stderr, stdout): @@ -218,8 +214,8 @@ class TestAddPkg(unittest.TestCase): session.packageListAdd.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_add_pkg_no_arg( self, activate_session_mock, stderr, stdout): diff --git a/tests/test_cli/test_block_pkg.py b/tests/test_cli/test_block_pkg.py index f521909..7b00615 100644 --- a/tests/test_cli/test_block_pkg.py +++ b/tests/test_cli/test_block_pkg.py @@ -1,14 +1,10 @@ from __future__ import absolute_import import unittest - -import StringIO as stringio - import os - import sys - import mock +import six from mock import call @@ -22,7 +18,7 @@ class TestBlockPkg(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_block_pkg(self, activate_session_mock, stdout): tag = 'tag' @@ -54,7 +50,7 @@ class TestBlockPkg(unittest.TestCase): session.multiCall.assert_called_once_with(strict=True) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_block_pkg_multi_pkg(self, activate_session_mock, stdout): tag = 'tag' @@ -92,7 +88,7 @@ class TestBlockPkg(unittest.TestCase): strict=True)]) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_block_pkg_no_package(self, activate_session_mock, stdout): tag = 'tag' @@ -125,7 +121,7 @@ class TestBlockPkg(unittest.TestCase): session.multiCall.assert_not_called() self.assertEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_block_pkg_tag_no_exists( self, activate_session_mock, stdout): @@ -153,8 +149,8 @@ class TestBlockPkg(unittest.TestCase): session.packageListBlock.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('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_block_pkg_help( self, activate_session_mock, stderr, stdout): diff --git a/tests/test_cli/test_build.py b/tests/test_cli/test_build.py index 306df0b..2a10f44 100644 --- a/tests/test_cli/test_build.py +++ b/tests/test_cli/test_build.py @@ -1,13 +1,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock +import six from . import loadcli @@ -26,7 +23,7 @@ class TestBuild(unittest.TestCase): # Mock out the xmlrpc server self.session = mock.MagicMock() - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -77,7 +74,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -125,8 +122,8 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -168,8 +165,8 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -222,8 +219,8 @@ Options: watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -268,7 +265,7 @@ Options: watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -313,7 +310,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -357,7 +354,7 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -405,7 +402,7 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -453,7 +450,7 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -508,7 +505,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -556,7 +553,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=True) @@ -607,7 +604,7 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertIsNone(rv) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -659,7 +656,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -708,7 +705,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) @@ -761,7 +758,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._unique_path', return_value='random_path') @mock.patch('koji_cli._running_in_bg', return_value=False) diff --git a/tests/test_cli/test_chain_build.py b/tests/test_cli/test_chain_build.py index 61449f7..9ded5e6 100644 --- a/tests/test_cli/test_chain_build.py +++ b/tests/test_cli/test_chain_build.py @@ -1,13 +1,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock +import six from . import loadcli @@ -26,7 +23,7 @@ class TestChainBuild(unittest.TestCase): # Mock out the xmlrpc server self.session = mock.MagicMock() - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -85,8 +82,8 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -125,8 +122,8 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -169,7 +166,7 @@ Options: watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 0) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -218,7 +215,7 @@ Options: watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -277,7 +274,7 @@ Options: watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -364,7 +361,7 @@ Target target is not usable for a chain-build self.session.getBuildTarget.return_value = target_info self.session.getTag.return_value = dest_tag_info self.session.getFullInheritance.return_value = tag_tree - with mock.patch('sys.stdout', new_callable=stringio.StringIO) as stdout: + with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout: # Run it and check immediate output # args: target badnvr : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3 # expected: failed, src is neither scm nor good n-v-r @@ -385,7 +382,7 @@ Target target is not usable for a chain-build watch_tasks_mock.assert_not_called() self.assertEqual(rv, 1) - with mock.patch('sys.stdout', new_callable=stringio.StringIO) as stdout: + with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout: source_args = [ 'path/n-v-r', ':', @@ -403,7 +400,7 @@ Target target is not usable for a chain-build expected = '"path/n-v-r" is not a SCM URL or package N-V-R\n' self.assertMultiLineEqual(actual, expected) - with mock.patch('sys.stdout', new_callable=stringio.StringIO) as stdout: + with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout: source_args = [ 'badn-vr', ':', @@ -421,7 +418,7 @@ Target target is not usable for a chain-build expected = '"badn-vr" is not a SCM URL or package N-V-R\n' self.assertMultiLineEqual(actual, expected) - with mock.patch('sys.stdout', new_callable=stringio.StringIO) as stdout: + with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout: source_args = [ 'badn-v-r.rpm', ':', @@ -439,7 +436,7 @@ Target target is not usable for a chain-build expected = '"badn-v-r.rpm" is not a SCM URL or package N-V-R\n' self.assertMultiLineEqual(actual, expected) - with mock.patch('sys.stderr', new_callable=stringio.StringIO) as stderr: + with mock.patch('sys.stderr', new_callable=six.StringIO) as stderr: source_args = ['http://scm'] args = [target] + source_args @@ -459,7 +456,7 @@ If there are no dependencies, use the build command instead self.assertMultiLineEqual(actual, expected) self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -522,7 +519,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -584,7 +581,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=True) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -646,7 +643,7 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertIsNone(rv) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) diff --git a/tests/test_cli/test_edit_host.py b/tests/test_cli/test_edit_host.py index bb86d11..ccf0b7d 100644 --- a/tests/test_cli/test_edit_host.py +++ b/tests/test_cli/test_edit_host.py @@ -1,14 +1,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock - +import six from mock import call from . import loadcli @@ -21,7 +17,7 @@ class TestEditHost(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_edit_host(self, activate_session_mock, stdout): host = 'host' @@ -60,7 +56,7 @@ class TestEditHost(unittest.TestCase): self.assertEqual(session.multiCall.call_count, 2) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_edit_host_failed(self, activate_session_mock, stdout): host = 'host' @@ -99,7 +95,7 @@ class TestEditHost(unittest.TestCase): self.assertEqual(session.multiCall.call_count, 2) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_edit_multi_host(self, activate_session_mock, stdout): hosts = ['host1', 'host2'] @@ -145,8 +141,8 @@ class TestEditHost(unittest.TestCase): call.multiCall(strict=True)]) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_edit_host_no_arg( self, activate_session_mock, stderr, stdout): @@ -181,7 +177,7 @@ class TestEditHost(unittest.TestCase): session.multiCall.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_edit_host_no_host(self, activate_session_mock, stdout): host = 'host' diff --git a/tests/test_cli/test_edit_tag.py b/tests/test_cli/test_edit_tag.py index e11c485..31d62c5 100644 --- a/tests/test_cli/test_edit_tag.py +++ b/tests/test_cli/test_edit_tag.py @@ -1,18 +1,13 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock +import six -from mock import call from . import loadcli -import six cli = loadcli.cli @@ -23,7 +18,7 @@ class TestEditTag(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_edit_tag(self, activate_session_mock, stdout): tag = 'tag' @@ -100,8 +95,8 @@ class TestEditTag(unittest.TestCase): session.editTag2.assert_called_once_with(tag, **opts) self.assertEqual(rv, None) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_edit_tag_help(self, activate_session_mock, stderr, stdout): args = ['--help'] @@ -147,8 +142,8 @@ Options: session.editTag2.assert_not_called() self.assertEqual(cm.exception.code, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_edit_tag_no_arg(self, activate_session_mock, stderr, stdout): args = [] diff --git a/tests/test_cli/test_import_comps.py b/tests/test_cli/test_import_comps.py index 5d01f55..0a5404c 100644 --- a/tests/test_cli/test_import_comps.py +++ b/tests/test_cli/test_import_comps.py @@ -1,10 +1,10 @@ from __future__ import absolute_import import json import unittest -import StringIO as stringio import os import sys import mock +import six from . import loadcli try: @@ -23,7 +23,7 @@ class TestImportComps(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.libcomps') @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._import_comps') @@ -63,7 +63,7 @@ class TestImportComps(unittest.TestCase): mock_import_comps_alt.assert_not_called() self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.libcomps', new=None) @mock.patch('koji_cli.yumcomps', create=True) @mock.patch('koji_cli.activate_session') @@ -104,7 +104,7 @@ class TestImportComps(unittest.TestCase): session, filename, tag, local_options) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.libcomps', new=None) @mock.patch('koji_cli.yumcomps', new=None, create=True) @mock.patch('koji_cli.activate_session') @@ -141,7 +141,7 @@ class TestImportComps(unittest.TestCase): mock_import_comps_alt.assert_not_called() self.assertEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._import_comps') @mock.patch('koji_cli._import_comps_alt') @@ -176,8 +176,8 @@ class TestImportComps(unittest.TestCase): 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('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._import_comps') @mock.patch('koji_cli._import_comps_alt') @@ -216,7 +216,7 @@ class TestImportComps(unittest.TestCase): self.assertEqual(cm.exception.code, 2) @unittest.skipIf(libcomps is None, "No libcomps") - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) def test_import_comps_libcomps(self, stdout): comps_file = os.path.dirname(__file__) + '/data/comps-example.xml' stdout_file = os.path.dirname( @@ -231,7 +231,7 @@ class TestImportComps(unittest.TestCase): stdout) @unittest.skipIf(libcomps is None, "No libcomps") - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) def test_import_comps_sample_libcomps(self, stdout): comps_file = os.path.dirname(__file__) + '/data/comps-sample.xml' stdout_file = os.path.dirname( @@ -246,7 +246,7 @@ class TestImportComps(unittest.TestCase): stdout) @unittest.skipIf(yumcomps is None, "No yum.comps") - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.libcomps', new=None) @mock.patch('koji_cli.yumcomps', create=True, new=yumcomps) def test_import_comps_yumcomps(self, stdout): @@ -263,7 +263,7 @@ class TestImportComps(unittest.TestCase): stdout) @unittest.skipIf(yumcomps is None, "No yum.comps") - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.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): diff --git a/tests/test_cli/test_list_commands.py b/tests/test_cli/test_list_commands.py index b7779eb..56c0b23 100644 --- a/tests/test_cli/test_list_commands.py +++ b/tests/test_cli/test_list_commands.py @@ -1,11 +1,8 @@ from __future__ import absolute_import +import mock import os -import sys import unittest - -import StringIO as stringio - -import mock +import six from . import loadcli cli = loadcli.cli @@ -27,7 +24,7 @@ class TestListCommands(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) def test_list_commands(self, stdout): cli.list_commands() actual = stdout.getvalue() @@ -37,7 +34,7 @@ class TestListCommands(unittest.TestCase): expected = f.read().decode('ascii') self.assertMultiLineEqual(actual, expected) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) def test_handle_admin_help(self, stdout): options, arguments = mock.MagicMock(), mock.MagicMock() options.admin = True diff --git a/tests/test_cli/test_maven_build.py b/tests/test_cli/test_maven_build.py index 3b8b187..c3a0b07 100644 --- a/tests/test_cli/test_maven_build.py +++ b/tests/test_cli/test_maven_build.py @@ -1,13 +1,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock +import six from . import loadcli import optparse @@ -46,7 +43,7 @@ class TestMavenBuild(unittest.TestCase): # Mock out the xmlrpc server self.session = mock.MagicMock() - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -87,8 +84,8 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -127,8 +124,8 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -167,8 +164,8 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -235,7 +232,7 @@ Options: watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 0) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -276,7 +273,7 @@ Options: watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -321,7 +318,7 @@ Options: watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -366,8 +363,8 @@ Options: watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch( 'koji.util.parse_maven_param', @@ -499,7 +496,7 @@ Task info: weburl/taskinfo?taskID=1 self.session.mavenBuild.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stderr', new_callable=stringio.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji.util.parse_maven_param') @mock.patch('koji.util.maven_opts') @@ -551,7 +548,7 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertEqual(cm.exception.code, 2) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji.util.parse_maven_param') @mock.patch('koji.util.maven_opts', return_value={}) @@ -633,7 +630,7 @@ Task info: weburl/taskinfo?taskID=1 self.session.mavenBuild.assert_called_once_with( source, target, opts, priority=priority) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=False) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -677,7 +674,7 @@ Task info: weburl/taskinfo?taskID=1 self.session, [task_id], quiet=self.options.quiet) self.assertEqual(rv, 0) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli._running_in_bg', return_value=True) @mock.patch('koji_cli.watch_tasks', return_value=0) @@ -721,7 +718,7 @@ Task info: weburl/taskinfo?taskID=1 watch_tasks_mock.assert_not_called() self.assertIsNone(rv) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji.util.parse_maven_param') @mock.patch('koji.util.maven_opts', return_value={}) diff --git a/tests/test_cli/test_remove_channel.py b/tests/test_cli/test_remove_channel.py index f881c55..8967158 100644 --- a/tests/test_cli/test_remove_channel.py +++ b/tests/test_cli/test_remove_channel.py @@ -1,13 +1,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock +import six from . import loadcli @@ -19,7 +16,7 @@ class TestRemoveChannel(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_channel(self, activate_session_mock, stdout): channel = 'channel' @@ -44,7 +41,7 @@ class TestRemoveChannel(unittest.TestCase): session.removeChannel.assert_called_once_with(channel, force=None) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_channel_force(self, activate_session_mock, stdout): channel = 'channel' @@ -70,7 +67,7 @@ class TestRemoveChannel(unittest.TestCase): session.removeChannel.assert_called_once_with(channel, force=True) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_channel_no_channel( self, activate_session_mock, stdout): @@ -96,8 +93,8 @@ class TestRemoveChannel(unittest.TestCase): session.removeChannel.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('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_channel_help( self, activate_session_mock, stderr, stdout): diff --git a/tests/test_cli/test_remove_host_from_channel.py b/tests/test_cli/test_remove_host_from_channel.py index 4a56282..68eb508 100644 --- a/tests/test_cli/test_remove_host_from_channel.py +++ b/tests/test_cli/test_remove_host_from_channel.py @@ -1,13 +1,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock +import six from . import loadcli @@ -19,7 +16,7 @@ class TestRemoveHostFromChannel(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_host_from_channel( self, activate_session_mock, stdout): @@ -49,7 +46,7 @@ class TestRemoveHostFromChannel(unittest.TestCase): session.removeHostFromChannel.assert_called_once_with(host, channel) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_host_from_channel_no_host( self, activate_session_mock, stdout): @@ -77,7 +74,7 @@ class TestRemoveHostFromChannel(unittest.TestCase): session.removeHostFromChannel.assert_not_called() self.assertEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_host_from_channel_not_a_member( self, activate_session_mock, stdout): @@ -108,8 +105,8 @@ class TestRemoveHostFromChannel(unittest.TestCase): session.removeHostFromChannel.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('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_host_from_channel_help( self, activate_session_mock, stderr, stdout): diff --git a/tests/test_cli/test_remove_pkg.py b/tests/test_cli/test_remove_pkg.py index cad99a0..e21fb6f 100644 --- a/tests/test_cli/test_remove_pkg.py +++ b/tests/test_cli/test_remove_pkg.py @@ -2,14 +2,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock - +import six from mock import call from . import loadcli @@ -22,7 +18,7 @@ class TestRemovePkg(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_pkg(self, activate_session_mock, stdout): tag = 'tag' @@ -55,7 +51,7 @@ class TestRemovePkg(unittest.TestCase): session.multiCall.assert_called_once_with(strict=True) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_pkg_multi_pkg(self, activate_session_mock, stdout): tag = 'tag' @@ -94,7 +90,7 @@ class TestRemovePkg(unittest.TestCase): strict=True)]) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_pkg_force(self, activate_session_mock, stdout): tag = 'tag' @@ -133,7 +129,7 @@ class TestRemovePkg(unittest.TestCase): strict=True)]) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_pkg_no_package(self, activate_session_mock, stdout): tag = 'tag' @@ -166,7 +162,7 @@ class TestRemovePkg(unittest.TestCase): session.multiCall.assert_not_called() self.assertEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_pkg_tag_no_exists( self, activate_session_mock, stdout): @@ -194,8 +190,8 @@ class TestRemovePkg(unittest.TestCase): session.packageListRemove.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('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_remove_pkg_help( self, activate_session_mock, stderr, stdout): diff --git a/tests/test_cli/test_rename_channel.py b/tests/test_cli/test_rename_channel.py index eca5a08..9b0402d 100644 --- a/tests/test_cli/test_rename_channel.py +++ b/tests/test_cli/test_rename_channel.py @@ -1,13 +1,10 @@ from __future__ import absolute_import import unittest -import StringIO as stringio - import os - import sys - import mock +import six from . import loadcli @@ -19,7 +16,7 @@ class TestRenameChannel(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_rename_channel(self, activate_session_mock, stdout): old_name = 'old_name' @@ -45,7 +42,7 @@ class TestRenameChannel(unittest.TestCase): session.renameChannel.assert_called_once_with(old_name, new_name) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_rename_channel_no_channel( self, activate_session_mock, stdout): @@ -72,8 +69,8 @@ class TestRenameChannel(unittest.TestCase): session.renameChannel.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('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') def test_handle_rename_channel_help( self, activate_session_mock, stderr, stdout): diff --git a/tests/test_cli/test_runroot.py b/tests/test_cli/test_runroot.py index b056105..9b1392c 100644 --- a/tests/test_cli/test_runroot.py +++ b/tests/test_cli/test_runroot.py @@ -3,8 +3,7 @@ import os import sys import unittest import koji - -import StringIO as stringio +import six import mock @@ -30,7 +29,7 @@ class TestListCommands(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) def test_handle_runroot(self, stdout): tag = 'tag' arch = 'arch' diff --git a/tests/test_cli/test_save_failed_tree.py b/tests/test_cli/test_save_failed_tree.py index 6b1dcfe..cdb8927 100644 --- a/tests/test_cli/test_save_failed_tree.py +++ b/tests/test_cli/test_save_failed_tree.py @@ -1,8 +1,8 @@ from __future__ import absolute_import -import StringIO import unittest import koji import mock +import six from . import loadcli cli = loadcli.cli @@ -127,7 +127,7 @@ class TestSaveFailedTree(unittest.TestCase): watch_tasks_mock.assert_called_once_with(self.session, [spawned_id], quiet=options.quiet) - @mock.patch('sys.stdout', new_callable=StringIO.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.activate_session') @mock.patch('koji_cli.watch_tasks') def test_handle_save_failed_tree_errors(self, watch_tasks_mock, activate_session_mock, stdout): diff --git a/tests/test_cli/test_upload_progress_callback.py b/tests/test_cli/test_upload_progress_callback.py index aa1a8f2..5f0823d 100644 --- a/tests/test_cli/test_upload_progress_callback.py +++ b/tests/test_cli/test_upload_progress_callback.py @@ -2,7 +2,7 @@ from __future__ import absolute_import import unittest import mock import sys -import StringIO as stringio +import six from . import loadcli @@ -31,7 +31,7 @@ class TestUploadProgressCallBack(unittest.TestCase): self.assertEqual(cli._format_secs(4321), '01:12:01') self.assertEqual(cli._format_secs(4321.567), '01:12:01') - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) def test_progress_callback(self, stdout): cli._progress_callback(12300, 234000, 5670, 80, 900) cli._progress_callback(45600, 234000, 5670, 0, 900) diff --git a/tests/test_cli/test_watch_tasks.py b/tests/test_cli/test_watch_tasks.py index df5349d..f967c8a 100644 --- a/tests/test_cli/test_watch_tasks.py +++ b/tests/test_cli/test_watch_tasks.py @@ -3,7 +3,6 @@ import unittest import os import sys -import StringIO as stringio import mock @@ -11,6 +10,7 @@ from mock import call from . import loadcli from six.moves import range +import six cli = loadcli.cli @@ -32,7 +32,7 @@ class TestWatchTasks(unittest.TestCase): # Show long diffs in error output... maxDiff = None - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) def test_watch_tasks_no_tasklist(self, stdout): returned = cli.watch_tasks(self.session, []) actual = stdout.getvalue() @@ -40,7 +40,7 @@ class TestWatchTasks(unittest.TestCase): self.assertIsNone(returned) self.assertEqual(actual, expected) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.TaskWatcher') @mock.patch('koji_cli.display_tasklist_status') @mock.patch('koji_cli.display_task_results') @@ -170,7 +170,7 @@ class TestWatchTasks(unittest.TestCase): call.display_task_results_mock({0: tw1, 1: tw2, 11: manager.tw11, 12: manager.tw12}) ]) - @mock.patch('sys.stdout', new_callable=stringio.StringIO) + @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.TaskWatcher') @mock.patch('koji_cli.display_tasklist_status') @mock.patch('koji_cli.display_task_results') diff --git a/tests/test_plugins/test_protonmsg.py b/tests/test_plugins/test_protonmsg.py index 442be5f..e73da5a 100644 --- a/tests/test_plugins/test_protonmsg.py +++ b/tests/test_plugins/test_protonmsg.py @@ -4,8 +4,8 @@ from mock import patch, MagicMock import protonmsg from koji.context import context import tempfile -from StringIO import StringIO from six.moves.configparser import SafeConfigParser +import six class TestProtonMsg(unittest.TestCase): def tearDown(self): @@ -205,7 +205,7 @@ send_timeout = 60 class TestTimeoutHandler(unittest.TestCase): def setUp(self): - confdata = StringIO("""[broker] + confdata = six.StringIO("""[broker] urls = amqps://broker1.example.com:5671 amqps://broker2.example.com:5671 cert = /etc/koji-hub/plugins/client.pem cacert = /etc/koji-hub/plugins/ca.pem @@ -228,7 +228,7 @@ send_timeout = 60 @patch('protonmsg.SSLDomain') def test_on_start_no_ssl(self, SSLDomain): - confdata = StringIO("""[broker] + confdata = six.StringIO("""[broker] urls = amqp://broker1.example.com:5672 amqp://broker2.example.com:5672 topic_prefix = koji connect_timeout = 10 diff --git a/tests/test_tasks.py b/tests/test_tasks.py index 3d52855..551cb05 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -1,6 +1,5 @@ from __future__ import absolute_import import random -from io import StringIO from os import path, makedirs from shutil import rmtree from tempfile import gettempdir @@ -17,7 +16,7 @@ import six def get_fake_mounts_file(): """ Returns contents of /prc/mounts in a file-like object """ - return StringIO(six.text_type(( + return six.StringIO(six.text_type(( 'sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' 'proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0\n' 'devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=238836k,nr_inodes=59709,mode=755 0 0\n' @@ -462,7 +461,7 @@ class TasksTestCase(TestCase): obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) self.assertEquals(obj.localPath('test.txt'), dummy_file) - @patch('six.moves.urllib.request.urlopen', return_value=StringIO(six.text_type('Important things\nSome more important things\n'))) + @patch('six.moves.urllib.request.urlopen', return_value=six.StringIO(six.text_type('Important things\nSome more important things\n'))) def test_BaseTaskHandler_localPath_no_file(self, mock_urlopen): """ """ From 644792ff765aa9570dfd0e019b9efd28e0b415b1 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 31/61] replace urlgrabber with pycurl --- diff --git a/cli/koji b/cli/koji index 9c7363f..34c33c2 100755 --- a/cli/koji +++ b/cli/koji @@ -59,14 +59,13 @@ import logging import os import re import pprint +import pycurl import random import socket import stat import string import time import traceback -import urlgrabber.grabber as grabber -import urlgrabber.progress as progress import six.moves.xmlrpc_client try: import libcomps @@ -6820,15 +6819,29 @@ def anon_handle_download_build(options, session, args): url = pathinfo.build(info) + '/' + fname urls.append((url, os.path.basename(fname))) - if suboptions.quiet: - pg = None - else: - pg = progress.TextMeter() + def _progress(download_t, download_d, upload_t, upload_d): + if download_t == 0: + percent_done = 0.0 + else: + percent_done = float(download_d)/float(download_t) + percent_done_str = "%02d%%" % (percent_done * 100) + data_done = _format_size(download_d) + + sys.stdout.write("[% -36s] % 4s % 10s\r" % ('='*(int(percent_done * 36)), percent_done_str, data_done)) + sys.stdout.flush() for url, relpath in urls: if '/' in relpath: koji.ensuredir(os.path.dirname(relpath)) - grabber.urlgrab(url, filename=relpath, progress_obj=pg, text=relpath) + print(relpath) + c = pycurl.Curl() + c.setopt(c.URL, url) + c.setopt(c.WRITEDATA, open(relpath, 'wb')) + if not suboptions.quiet: + c.setopt(c.NOPROGRESS, False) + c.setopt(c.XFERINFOFUNCTION, _progress) + c.perform() + print('') def anon_handle_download_logs(options, session, args): diff --git a/docs/source/writing_koji_code.rst b/docs/source/writing_koji_code.rst index 2d92dea..6d81ee3 100644 --- a/docs/source/writing_koji_code.rst +++ b/docs/source/writing_koji_code.rst @@ -667,8 +667,8 @@ You will need to install the following packages to actually run the tests. * ``python-krbV`` * ``python-mock`` * ``python-simplejson`` - * ``python-urlgrabber`` * ``python-psycopg2`` + * ``python-pycurl`` * ``python-requests`` * ``python-qpid-proton`` diff --git a/koji.spec b/koji.spec index 89fa418..22a7cb6 100644 --- a/koji.spec +++ b/koji.spec @@ -30,7 +30,7 @@ Requires: rpm-python Requires: pyOpenSSL Requires: python-requests Requires: python-requests-kerberos -Requires: python-urlgrabber +Requires: python-pycurl Requires: python-dateutil BuildRequires: python %if %{use_systemd} diff --git a/vm/kojivmd b/vm/kojivmd index b003b54..3ca7342 100755 --- a/vm/kojivmd +++ b/vm/kojivmd @@ -40,7 +40,7 @@ import SimpleXMLRPCServer import threading import base64 import pwd -import urlgrabber +import pycurl import fnmatch from ConfigParser import ConfigParser from optparse import OptionParser @@ -665,7 +665,10 @@ class VMExecTask(BaseTaskHandler): else: raise koji.BuildError('unsupported file type: %s' % type) koji.ensuredir(os.path.dirname(localpath)) - urlgrabber.urlgrab(remote_url, filename=localpath) + c = pycurl.Curl() + c.setopt(c.URL, remote_url) + c.setopt(c.WRITEDATA, open(localpath, 'wb')) + c.perform() return file(localpath, 'r') From 449390cff9dca001ac593c65b546c748b463f8bb Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 32/61] cli-related test fixes --- diff --git a/cli/koji b/cli/koji index 34c33c2..ccb1022 100755 --- a/cli/koji +++ b/cli/koji @@ -454,7 +454,7 @@ def watch_tasks(session,tasklist,quiet=False): tasks[task_id] = TaskWatcher(task_id,session,quiet=quiet) while True: all_done = True - for task_id,task in tasks.items(): + for task_id, task in list(tasks.items()): changed = task.update() if not task.is_done(): all_done = False @@ -1856,7 +1856,11 @@ def _import_comps(session, filename, tag, options): } if pkg.type == libcomps.PACKAGE_TYPE_CONDITIONAL: pkgopts['requires'] = pkg.requires - print(" Package: %s: %r" % (pkg.name, pkgopts)) + for k in pkgopts.keys(): + if isinstance(pkgopts[k], unicode): + pkgopts[k] = str(pkgopts[k]) + s_opts = ', '.join(["'%s': %r" % (k, pkgopts[k]) for k in sorted(list(pkgopts.keys()))]) + print(" Package: %s: {%s}" % (pkg.name, s_opts)) session.groupPackageListAdd(tag, group.id, pkg.name, force=force, **pkgopts) # libcomps does not support group dependencies # libcomps does not support metapkgs @@ -1881,11 +1885,15 @@ def _import_comps_alt(session, filename, tag, options): ('optional', group.optional_packages), ('conditional', group.conditional_packages)]: for pkg in pdata: + #yum.comps does not support basearchonly pkgopts = {'type' : ptype} if ptype == 'conditional': pkgopts['requires'] = pdata[pkg] - #yum.comps does not support basearchonly - print(" Package: %s: %r" % (pkg, pkgopts)) + for k in pkgopts.keys(): + if isinstance(pkgopts[k], unicode): + pkgopts[k] = str(pkgopts[k]) + s_opts = ', '.join(["'%s': %r" % (k, pkgopts[k]) for k in sorted(list(pkgopts.keys()))]) + print(" Package: %s: {%s}" % (pkg, s_opts)) session.groupPackageListAdd(tag, group.groupid, pkg, force=force, **pkgopts) #yum.comps does not support group dependencies #yum.comps does not support metapkgs diff --git a/tests/test_cli/data/comps-example.libcomps.out b/tests/test_cli/data/comps-example.libcomps.out index a9f2256..1fd4703 100644 --- a/tests/test_cli/data/comps-example.libcomps.out +++ b/tests/test_cli/data/comps-example.libcomps.out @@ -1,5200 +1,5200 @@ Group: 3d-printing (3D Printing) - Package: admesh: {'type': 'default', 'basearchonly': False} - Package: blender: {'type': 'default', 'basearchonly': False} - Package: cura: {'type': 'default', 'basearchonly': False} - Package: cura-lulzbot: {'type': 'default', 'basearchonly': False} - Package: meshlab: {'type': 'default', 'basearchonly': False} - Package: openscad: {'type': 'default', 'basearchonly': False} - Package: openscad-MCAD: {'type': 'default', 'basearchonly': False} - Package: printrun: {'type': 'default', 'basearchonly': False} - Package: slic3r: {'type': 'default', 'basearchonly': False} - Package: RepetierHost: {'type': 'optional', 'basearchonly': False} - Package: repsnapper: {'type': 'optional', 'basearchonly': False} - Package: sfact: {'type': 'optional', 'basearchonly': False} - Package: skeinforge: {'type': 'optional', 'basearchonly': False} + Package: admesh: {'basearchonly': False, 'type': 'default'} + Package: blender: {'basearchonly': False, 'type': 'default'} + Package: cura: {'basearchonly': False, 'type': 'default'} + Package: cura-lulzbot: {'basearchonly': False, 'type': 'default'} + Package: meshlab: {'basearchonly': False, 'type': 'default'} + Package: openscad: {'basearchonly': False, 'type': 'default'} + Package: openscad-MCAD: {'basearchonly': False, 'type': 'default'} + Package: printrun: {'basearchonly': False, 'type': 'default'} + Package: slic3r: {'basearchonly': False, 'type': 'default'} + Package: RepetierHost: {'basearchonly': False, 'type': 'optional'} + Package: repsnapper: {'basearchonly': False, 'type': 'optional'} + Package: sfact: {'basearchonly': False, 'type': 'optional'} + Package: skeinforge: {'basearchonly': False, 'type': 'optional'} Group: admin-tools (Administration Tools) - Package: abrt-desktop: {'type': 'mandatory', 'basearchonly': False} - Package: authconfig-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: fros-recordmydesktop: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-disk-utility: {'type': 'mandatory', 'basearchonly': False} - Package: recordmydesktop: {'type': 'mandatory', 'basearchonly': False} - Package: setroubleshoot: {'type': 'mandatory', 'basearchonly': False} - Package: system-config-date: {'type': 'mandatory', 'basearchonly': False} - Package: system-config-keyboard: {'type': 'mandatory', 'basearchonly': False} - Package: system-config-language: {'type': 'mandatory', 'basearchonly': False} - Package: system-config-users: {'type': 'mandatory', 'basearchonly': False} + Package: abrt-desktop: {'basearchonly': False, 'type': 'mandatory'} + Package: authconfig-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: fros-recordmydesktop: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-disk-utility: {'basearchonly': False, 'type': 'mandatory'} + Package: recordmydesktop: {'basearchonly': False, 'type': 'mandatory'} + Package: setroubleshoot: {'basearchonly': False, 'type': 'mandatory'} + Package: system-config-date: {'basearchonly': False, 'type': 'mandatory'} + Package: system-config-keyboard: {'basearchonly': False, 'type': 'mandatory'} + Package: system-config-language: {'basearchonly': False, 'type': 'mandatory'} + Package: system-config-users: {'basearchonly': False, 'type': 'mandatory'} Group: anaconda-tools (Anaconda tools) - Package: authconfig: {'type': 'mandatory', 'basearchonly': False} - Package: btrfs-progs: {'type': 'mandatory', 'basearchonly': False} - Package: chrony: {'type': 'mandatory', 'basearchonly': False} - Package: cryptsetup: {'type': 'mandatory', 'basearchonly': False} - Package: device-mapper-multipath: {'type': 'mandatory', 'basearchonly': False} - Package: dmraid: {'type': 'mandatory', 'basearchonly': False} - Package: dosfstools: {'type': 'mandatory', 'basearchonly': False} - Package: dracut-network: {'type': 'mandatory', 'basearchonly': False} - Package: e2fsprogs: {'type': 'mandatory', 'basearchonly': False} - Package: efibootmgr: {'type': 'mandatory', 'basearchonly': False} - Package: extlinux-bootloader: {'type': 'mandatory', 'basearchonly': False} - Package: fcoe-utils: {'type': 'mandatory', 'basearchonly': False} - Package: firewalld: {'type': 'mandatory', 'basearchonly': False} - Package: gfs2-utils: {'type': 'mandatory', 'basearchonly': False} - Package: glibc-all-langpacks: {'type': 'mandatory', 'basearchonly': False} - Package: grub2: {'type': 'mandatory', 'basearchonly': False} - Package: grub2-efi: {'type': 'mandatory', 'basearchonly': False} - Package: hfsplus-tools: {'type': 'mandatory', 'basearchonly': False} - Package: iscsi-initiator-utils: {'type': 'mandatory', 'basearchonly': False} - Package: kexec-tools-anaconda-addon: {'type': 'mandatory', 'basearchonly': False} - Package: lvm2: {'type': 'mandatory', 'basearchonly': False} - Package: mactel-boot: {'type': 'mandatory', 'basearchonly': False} - Package: mdadm: {'type': 'mandatory', 'basearchonly': False} - Package: ntfsprogs: {'type': 'mandatory', 'basearchonly': False} - Package: realmd: {'type': 'mandatory', 'basearchonly': False} - Package: reiserfs-utils: {'type': 'mandatory', 'basearchonly': False} - Package: s390utils: {'type': 'mandatory', 'basearchonly': False} - Package: s390utils-base: {'type': 'mandatory', 'basearchonly': False} - Package: shim: {'type': 'mandatory', 'basearchonly': False} - Package: syslinux-extlinux: {'type': 'mandatory', 'basearchonly': False} - Package: teamd: {'type': 'mandatory', 'basearchonly': False} - Package: xfsprogs: {'type': 'mandatory', 'basearchonly': False} + Package: authconfig: {'basearchonly': False, 'type': 'mandatory'} + Package: btrfs-progs: {'basearchonly': False, 'type': 'mandatory'} + Package: chrony: {'basearchonly': False, 'type': 'mandatory'} + Package: cryptsetup: {'basearchonly': False, 'type': 'mandatory'} + Package: device-mapper-multipath: {'basearchonly': False, 'type': 'mandatory'} + Package: dmraid: {'basearchonly': False, 'type': 'mandatory'} + Package: dosfstools: {'basearchonly': False, 'type': 'mandatory'} + Package: dracut-network: {'basearchonly': False, 'type': 'mandatory'} + Package: e2fsprogs: {'basearchonly': False, 'type': 'mandatory'} + Package: efibootmgr: {'basearchonly': False, 'type': 'mandatory'} + Package: extlinux-bootloader: {'basearchonly': False, 'type': 'mandatory'} + Package: fcoe-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: firewalld: {'basearchonly': False, 'type': 'mandatory'} + Package: gfs2-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: glibc-all-langpacks: {'basearchonly': False, 'type': 'mandatory'} + Package: grub2: {'basearchonly': False, 'type': 'mandatory'} + Package: grub2-efi: {'basearchonly': False, 'type': 'mandatory'} + Package: hfsplus-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: iscsi-initiator-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: kexec-tools-anaconda-addon: {'basearchonly': False, 'type': 'mandatory'} + Package: lvm2: {'basearchonly': False, 'type': 'mandatory'} + Package: mactel-boot: {'basearchonly': False, 'type': 'mandatory'} + Package: mdadm: {'basearchonly': False, 'type': 'mandatory'} + Package: ntfsprogs: {'basearchonly': False, 'type': 'mandatory'} + Package: realmd: {'basearchonly': False, 'type': 'mandatory'} + Package: reiserfs-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: s390utils: {'basearchonly': False, 'type': 'mandatory'} + Package: s390utils-base: {'basearchonly': False, 'type': 'mandatory'} + Package: shim: {'basearchonly': False, 'type': 'mandatory'} + Package: syslinux-extlinux: {'basearchonly': False, 'type': 'mandatory'} + Package: teamd: {'basearchonly': False, 'type': 'mandatory'} + Package: xfsprogs: {'basearchonly': False, 'type': 'mandatory'} Group: ansible-node (Ansible node) - Package: python2-dnf: {'type': 'mandatory', 'basearchonly': False} - Package: libselinux-python: {'requires': u'selinux-policy', 'type': 'conditional', 'basearchonly': False} + Package: python2-dnf: {'basearchonly': False, 'type': 'mandatory'} + Package: libselinux-python: {'basearchonly': False, 'requires': 'selinux-policy', 'type': 'conditional'} Group: arabic-support (Arabic Support) - Package: dejavu-sans-fonts: {'type': 'default', 'basearchonly': False} - Package: dejavu-sans-mono-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-art-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-book-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-decorative-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-digital-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-farsi-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-letter-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-naskh-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-office-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-one-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-pen-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-poster-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-qurn-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-screen-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-title-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-titlel-fonts: {'type': 'default', 'basearchonly': False} - Package: paktype-naqsh-fonts: {'type': 'default', 'basearchonly': False} - Package: paktype-tehreer-fonts: {'type': 'default', 'basearchonly': False} - Package: scim-tables-arabic: {'type': 'optional', 'basearchonly': False} - Package: sil-lateef-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-scheherazade-fonts: {'type': 'optional', 'basearchonly': False} + Package: dejavu-sans-fonts: {'basearchonly': False, 'type': 'default'} + Package: dejavu-sans-mono-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-art-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-book-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-decorative-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-digital-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-farsi-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-letter-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-naskh-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-office-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-one-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-pen-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-poster-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-qurn-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-screen-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-title-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-titlel-fonts: {'basearchonly': False, 'type': 'default'} + Package: paktype-naqsh-fonts: {'basearchonly': False, 'type': 'default'} + Package: paktype-tehreer-fonts: {'basearchonly': False, 'type': 'default'} + Package: scim-tables-arabic: {'basearchonly': False, 'type': 'optional'} + Package: sil-lateef-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-scheherazade-fonts: {'basearchonly': False, 'type': 'optional'} Group: arm-tools (ARM Tools) - Package: fedora-arm-installer: {'type': 'mandatory', 'basearchonly': False} - Package: cloud-utils-growpart: {'type': 'mandatory', 'basearchonly': False} - Package: uboot-images-armv7: {'type': 'mandatory', 'basearchonly': False} + Package: fedora-arm-installer: {'basearchonly': False, 'type': 'mandatory'} + Package: cloud-utils-growpart: {'basearchonly': False, 'type': 'mandatory'} + Package: uboot-images-armv7: {'basearchonly': False, 'type': 'mandatory'} Group: assamese-support (Assamese Support) - Package: lohit-assamese-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-bengali-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-bengali-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} + Package: lohit-assamese-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-bengali-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-bengali-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} Group: audio (Audio Production) - Package: a2jmidid: {'type': 'default', 'basearchonly': False} - Package: Add64: {'type': 'default', 'basearchonly': False} - Package: aj-snapshot: {'type': 'default', 'basearchonly': False} - Package: alsa-firmware: {'type': 'default', 'basearchonly': False} - Package: alsa-plugins-jack: {'type': 'default', 'basearchonly': False} - Package: alsa-plugins-samplerate: {'type': 'default', 'basearchonly': False} - Package: alsa-plugins-upmix: {'type': 'default', 'basearchonly': False} - Package: alsa-plugins-usbstream: {'type': 'default', 'basearchonly': False} - Package: alsa-plugins-vdownmix: {'type': 'default', 'basearchonly': False} - Package: alsa-tools: {'type': 'default', 'basearchonly': False} - Package: alsa-ucm: {'type': 'default', 'basearchonly': False} - Package: alsa-utils: {'type': 'default', 'basearchonly': False} - Package: alsamixergui: {'type': 'default', 'basearchonly': False} - Package: ams: {'type': 'default', 'basearchonly': False} - Package: amsynth: {'type': 'default', 'basearchonly': False} - Package: ardour5: {'type': 'default', 'basearchonly': False} - Package: arpage: {'type': 'default', 'basearchonly': False} - Package: audacity: {'type': 'default', 'basearchonly': False} - Package: bristol: {'type': 'default', 'basearchonly': False} - Package: calf: {'type': 'default', 'basearchonly': False} - Package: drumkv1: {'type': 'default', 'basearchonly': False} - Package: dssi: {'type': 'default', 'basearchonly': False} - Package: fluid-soundfont-gm: {'type': 'default', 'basearchonly': False} - Package: fluidsynth: {'type': 'default', 'basearchonly': False} - Package: fluidsynth-dssi: {'type': 'default', 'basearchonly': False} - Package: frescobaldi: {'type': 'default', 'basearchonly': False} - Package: gladish: {'type': 'default', 'basearchonly': False} - Package: guitarix: {'type': 'default', 'basearchonly': False} - Package: harmonyseq: {'type': 'default', 'basearchonly': False} - Package: hexter-dssi: {'type': 'default', 'basearchonly': False} - Package: hydrogen: {'type': 'default', 'basearchonly': False} - Package: idjc: {'type': 'default', 'basearchonly': False} - Package: jaaa: {'type': 'default', 'basearchonly': False} - Package: jack-audio-connection-kit: {'type': 'default', 'basearchonly': False} - Package: jack-audio-connection-kit-dbus: {'type': 'default', 'basearchonly': False} - Package: jack-rack: {'type': 'default', 'basearchonly': False} - Package: jackctlmmc: {'type': 'default', 'basearchonly': False} - Package: jack_capture: {'type': 'default', 'basearchonly': False} - Package: jamin: {'type': 'default', 'basearchonly': False} - Package: japa: {'type': 'default', 'basearchonly': False} - Package: jmeters: {'type': 'default', 'basearchonly': False} - Package: kernel-tools: {'type': 'default', 'basearchonly': False} - Package: ladish: {'type': 'default', 'basearchonly': False} - Package: ladspa: {'type': 'default', 'basearchonly': False} - Package: ladspa-amb-plugins: {'type': 'default', 'basearchonly': False} - Package: ladspa-autotalent-plugins: {'type': 'default', 'basearchonly': False} - Package: ladspa-blop-plugins: {'type': 'default', 'basearchonly': False} - Package: ladspa-cmt-plugins: {'type': 'default', 'basearchonly': False} - Package: ladspa-fil-plugins: {'type': 'default', 'basearchonly': False} - Package: ladspa-mcp-plugins: {'type': 'default', 'basearchonly': False} - Package: ladspa-rev-plugins: {'type': 'default', 'basearchonly': False} - Package: ladspa-swh-plugins: {'type': 'default', 'basearchonly': False} - Package: ladspa-tap-plugins: {'type': 'default', 'basearchonly': False} - Package: ladspa-vco-plugins: {'type': 'default', 'basearchonly': False} - Package: lash: {'type': 'default', 'basearchonly': False} - Package: lilypond: {'type': 'default', 'basearchonly': False} - Package: lv2: {'type': 'default', 'basearchonly': False} - Package: lv2-abGate: {'type': 'default', 'basearchonly': False} - Package: lv2-artyfx-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2-avw-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2-c++-tools : {'type': 'default', 'basearchonly': False} - Package: lv2-drumkv1: {'type': 'default', 'basearchonly': False} - Package: lv2-fabla: {'type': 'default', 'basearchonly': False} - Package: lv2-fil-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2-fomp-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2-invada-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2-kn0ck0ut: {'type': 'default', 'basearchonly': False} - Package: lv2-ll-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2-newtonator: {'type': 'default', 'basearchonly': False} - Package: lv2-samplv1: {'type': 'default', 'basearchonly': False} - Package: lv2-sorcer: {'type': 'default', 'basearchonly': False} - Package: lv2-swh-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2-synthv1: {'type': 'default', 'basearchonly': False} - Package: lv2-triceratops: {'type': 'default', 'basearchonly': False} - Package: lv2-vocoder-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2-x42-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2-zynadd-plugins: {'type': 'default', 'basearchonly': False} - Package: lv2dynparam: {'type': 'default', 'basearchonly': False} - Package: monobristol: {'type': 'default', 'basearchonly': False} - Package: mscore: {'type': 'default', 'basearchonly': False} - Package: multimedia-menus: {'type': 'default', 'basearchonly': False} - Package: mup: {'type': 'default', 'basearchonly': False} - Package: muse: {'type': 'default', 'basearchonly': False} - Package: nekobee-dssi: {'type': 'default', 'basearchonly': False} - Package: non-daw: {'type': 'default', 'basearchonly': False} - Package: non-mixer: {'type': 'default', 'basearchonly': False} - Package: non-sequencer: {'type': 'default', 'basearchonly': False} - Package: non-session-manager: {'type': 'default', 'basearchonly': False} - Package: opus-tools: {'type': 'default', 'basearchonly': False} - Package: qastools: {'type': 'default', 'basearchonly': False} - Package: qjackctl: {'type': 'default', 'basearchonly': False} - Package: qmidiarp: {'type': 'default', 'basearchonly': False} - Package: qsynth: {'type': 'default', 'basearchonly': False} - Package: qtractor: {'type': 'default', 'basearchonly': False} - Package: radium-compressor: {'type': 'default', 'basearchonly': False} - Package: rakarrack: {'type': 'default', 'basearchonly': False} - Package: realTimeConfigQuickScan: {'type': 'default', 'basearchonly': False} - Package: rosegarden4: {'type': 'default', 'basearchonly': False} - Package: rtirq: {'type': 'default', 'basearchonly': False} - Package: samplv1: {'type': 'default', 'basearchonly': False} - Package: sbc: {'type': 'default', 'basearchonly': False} - Package: seq24: {'type': 'default', 'basearchonly': False} - Package: sooperlooper: {'type': 'default', 'basearchonly': False} - Package: swami: {'type': 'default', 'basearchonly': False} - Package: synthv1: {'type': 'default', 'basearchonly': False} - Package: timidity++: {'type': 'default', 'basearchonly': False} - Package: tinycompress-utils: {'type': 'default', 'basearchonly': False} - Package: tuxguitar: {'type': 'default', 'basearchonly': False} - Package: vmpk: {'type': 'default', 'basearchonly': False} - Package: whysynth-dssi: {'type': 'default', 'basearchonly': False} - Package: xsynth-dssi: {'type': 'default', 'basearchonly': False} - Package: yoshimi: {'type': 'default', 'basearchonly': False} - Package: zita-at1: {'type': 'default', 'basearchonly': False} - Package: zita-rev1: {'type': 'default', 'basearchonly': False} - Package: zynaddsubfx: {'type': 'default', 'basearchonly': False} - Package: zynjacku: {'type': 'default', 'basearchonly': False} + Package: a2jmidid: {'basearchonly': False, 'type': 'default'} + Package: Add64: {'basearchonly': False, 'type': 'default'} + Package: aj-snapshot: {'basearchonly': False, 'type': 'default'} + Package: alsa-firmware: {'basearchonly': False, 'type': 'default'} + Package: alsa-plugins-jack: {'basearchonly': False, 'type': 'default'} + Package: alsa-plugins-samplerate: {'basearchonly': False, 'type': 'default'} + Package: alsa-plugins-upmix: {'basearchonly': False, 'type': 'default'} + Package: alsa-plugins-usbstream: {'basearchonly': False, 'type': 'default'} + Package: alsa-plugins-vdownmix: {'basearchonly': False, 'type': 'default'} + Package: alsa-tools: {'basearchonly': False, 'type': 'default'} + Package: alsa-ucm: {'basearchonly': False, 'type': 'default'} + Package: alsa-utils: {'basearchonly': False, 'type': 'default'} + Package: alsamixergui: {'basearchonly': False, 'type': 'default'} + Package: ams: {'basearchonly': False, 'type': 'default'} + Package: amsynth: {'basearchonly': False, 'type': 'default'} + Package: ardour5: {'basearchonly': False, 'type': 'default'} + Package: arpage: {'basearchonly': False, 'type': 'default'} + Package: audacity: {'basearchonly': False, 'type': 'default'} + Package: bristol: {'basearchonly': False, 'type': 'default'} + Package: calf: {'basearchonly': False, 'type': 'default'} + Package: drumkv1: {'basearchonly': False, 'type': 'default'} + Package: dssi: {'basearchonly': False, 'type': 'default'} + Package: fluid-soundfont-gm: {'basearchonly': False, 'type': 'default'} + Package: fluidsynth: {'basearchonly': False, 'type': 'default'} + Package: fluidsynth-dssi: {'basearchonly': False, 'type': 'default'} + Package: frescobaldi: {'basearchonly': False, 'type': 'default'} + Package: gladish: {'basearchonly': False, 'type': 'default'} + Package: guitarix: {'basearchonly': False, 'type': 'default'} + Package: harmonyseq: {'basearchonly': False, 'type': 'default'} + Package: hexter-dssi: {'basearchonly': False, 'type': 'default'} + Package: hydrogen: {'basearchonly': False, 'type': 'default'} + Package: idjc: {'basearchonly': False, 'type': 'default'} + Package: jaaa: {'basearchonly': False, 'type': 'default'} + Package: jack-audio-connection-kit: {'basearchonly': False, 'type': 'default'} + Package: jack-audio-connection-kit-dbus: {'basearchonly': False, 'type': 'default'} + Package: jack-rack: {'basearchonly': False, 'type': 'default'} + Package: jackctlmmc: {'basearchonly': False, 'type': 'default'} + Package: jack_capture: {'basearchonly': False, 'type': 'default'} + Package: jamin: {'basearchonly': False, 'type': 'default'} + Package: japa: {'basearchonly': False, 'type': 'default'} + Package: jmeters: {'basearchonly': False, 'type': 'default'} + Package: kernel-tools: {'basearchonly': False, 'type': 'default'} + Package: ladish: {'basearchonly': False, 'type': 'default'} + Package: ladspa: {'basearchonly': False, 'type': 'default'} + Package: ladspa-amb-plugins: {'basearchonly': False, 'type': 'default'} + Package: ladspa-autotalent-plugins: {'basearchonly': False, 'type': 'default'} + Package: ladspa-blop-plugins: {'basearchonly': False, 'type': 'default'} + Package: ladspa-cmt-plugins: {'basearchonly': False, 'type': 'default'} + Package: ladspa-fil-plugins: {'basearchonly': False, 'type': 'default'} + Package: ladspa-mcp-plugins: {'basearchonly': False, 'type': 'default'} + Package: ladspa-rev-plugins: {'basearchonly': False, 'type': 'default'} + Package: ladspa-swh-plugins: {'basearchonly': False, 'type': 'default'} + Package: ladspa-tap-plugins: {'basearchonly': False, 'type': 'default'} + Package: ladspa-vco-plugins: {'basearchonly': False, 'type': 'default'} + Package: lash: {'basearchonly': False, 'type': 'default'} + Package: lilypond: {'basearchonly': False, 'type': 'default'} + Package: lv2: {'basearchonly': False, 'type': 'default'} + Package: lv2-abGate: {'basearchonly': False, 'type': 'default'} + Package: lv2-artyfx-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2-avw-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2-c++-tools : {'basearchonly': False, 'type': 'default'} + Package: lv2-drumkv1: {'basearchonly': False, 'type': 'default'} + Package: lv2-fabla: {'basearchonly': False, 'type': 'default'} + Package: lv2-fil-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2-fomp-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2-invada-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2-kn0ck0ut: {'basearchonly': False, 'type': 'default'} + Package: lv2-ll-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2-newtonator: {'basearchonly': False, 'type': 'default'} + Package: lv2-samplv1: {'basearchonly': False, 'type': 'default'} + Package: lv2-sorcer: {'basearchonly': False, 'type': 'default'} + Package: lv2-swh-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2-synthv1: {'basearchonly': False, 'type': 'default'} + Package: lv2-triceratops: {'basearchonly': False, 'type': 'default'} + Package: lv2-vocoder-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2-x42-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2-zynadd-plugins: {'basearchonly': False, 'type': 'default'} + Package: lv2dynparam: {'basearchonly': False, 'type': 'default'} + Package: monobristol: {'basearchonly': False, 'type': 'default'} + Package: mscore: {'basearchonly': False, 'type': 'default'} + Package: multimedia-menus: {'basearchonly': False, 'type': 'default'} + Package: mup: {'basearchonly': False, 'type': 'default'} + Package: muse: {'basearchonly': False, 'type': 'default'} + Package: nekobee-dssi: {'basearchonly': False, 'type': 'default'} + Package: non-daw: {'basearchonly': False, 'type': 'default'} + Package: non-mixer: {'basearchonly': False, 'type': 'default'} + Package: non-sequencer: {'basearchonly': False, 'type': 'default'} + Package: non-session-manager: {'basearchonly': False, 'type': 'default'} + Package: opus-tools: {'basearchonly': False, 'type': 'default'} + Package: qastools: {'basearchonly': False, 'type': 'default'} + Package: qjackctl: {'basearchonly': False, 'type': 'default'} + Package: qmidiarp: {'basearchonly': False, 'type': 'default'} + Package: qsynth: {'basearchonly': False, 'type': 'default'} + Package: qtractor: {'basearchonly': False, 'type': 'default'} + Package: radium-compressor: {'basearchonly': False, 'type': 'default'} + Package: rakarrack: {'basearchonly': False, 'type': 'default'} + Package: realTimeConfigQuickScan: {'basearchonly': False, 'type': 'default'} + Package: rosegarden4: {'basearchonly': False, 'type': 'default'} + Package: rtirq: {'basearchonly': False, 'type': 'default'} + Package: samplv1: {'basearchonly': False, 'type': 'default'} + Package: sbc: {'basearchonly': False, 'type': 'default'} + Package: seq24: {'basearchonly': False, 'type': 'default'} + Package: sooperlooper: {'basearchonly': False, 'type': 'default'} + Package: swami: {'basearchonly': False, 'type': 'default'} + Package: synthv1: {'basearchonly': False, 'type': 'default'} + Package: timidity++: {'basearchonly': False, 'type': 'default'} + Package: tinycompress-utils: {'basearchonly': False, 'type': 'default'} + Package: tuxguitar: {'basearchonly': False, 'type': 'default'} + Package: vmpk: {'basearchonly': False, 'type': 'default'} + Package: whysynth-dssi: {'basearchonly': False, 'type': 'default'} + Package: xsynth-dssi: {'basearchonly': False, 'type': 'default'} + Package: yoshimi: {'basearchonly': False, 'type': 'default'} + Package: zita-at1: {'basearchonly': False, 'type': 'default'} + Package: zita-rev1: {'basearchonly': False, 'type': 'default'} + Package: zynaddsubfx: {'basearchonly': False, 'type': 'default'} + Package: zynjacku: {'basearchonly': False, 'type': 'default'} Group: authoring-and-publishing (Authoring and Publishing) - Package: docbook-slides: {'type': 'default', 'basearchonly': False} - Package: docbook-style-dsssl: {'type': 'default', 'basearchonly': False} - Package: docbook-style-xsl: {'type': 'default', 'basearchonly': False} - Package: docbook-utils: {'type': 'default', 'basearchonly': False} - Package: docbook-utils-pdf: {'type': 'default', 'basearchonly': False} - Package: docbook5-schemas: {'type': 'default', 'basearchonly': False} - Package: docbook5-style-xsl: {'type': 'default', 'basearchonly': False} - Package: linuxdoc-tools: {'type': 'default', 'basearchonly': False} - Package: tex-fonts-hebrew: {'type': 'default', 'basearchonly': False} - Package: texlive: {'type': 'default', 'basearchonly': False} - Package: texlive-cm-lgc: {'type': 'default', 'basearchonly': False} - Package: texlive-kerkis: {'type': 'default', 'basearchonly': False} - Package: xhtml1-dtds: {'type': 'default', 'basearchonly': False} - Package: xmlto: {'type': 'default', 'basearchonly': False} - Package: abcm2ps: {'type': 'optional', 'basearchonly': False} - Package: BibTool: {'type': 'optional', 'basearchonly': False} - Package: dblatex: {'type': 'optional', 'basearchonly': False} - Package: docbook2X: {'type': 'optional', 'basearchonly': False} - Package: html401-dtds: {'type': 'optional', 'basearchonly': False} - Package: kbibtex: {'type': 'optional', 'basearchonly': False} - Package: kile: {'type': 'optional', 'basearchonly': False} - Package: latex-mk: {'type': 'optional', 'basearchonly': False} - Package: latexmk: {'type': 'optional', 'basearchonly': False} - Package: lilypond: {'type': 'optional', 'basearchonly': False} - Package: lout: {'type': 'optional', 'basearchonly': False} - Package: ooo2txt: {'type': 'optional', 'basearchonly': False} - Package: pandoc: {'type': 'optional', 'basearchonly': False} - Package: python-docutils: {'type': 'optional', 'basearchonly': False} - Package: python-manuel: {'type': 'optional', 'basearchonly': False} - Package: scribus: {'type': 'optional', 'basearchonly': False} - Package: tex-zfuzz: {'type': 'optional', 'basearchonly': False} - Package: texlive-latex: {'type': 'optional', 'basearchonly': False} - Package: texlive-xdvi: {'type': 'optional', 'basearchonly': False} - Package: txt2rss: {'type': 'optional', 'basearchonly': False} - Package: w3c-markup-validator: {'type': 'optional', 'basearchonly': False} - Package: xmlcopyeditor: {'type': 'optional', 'basearchonly': False} + Package: docbook-slides: {'basearchonly': False, 'type': 'default'} + Package: docbook-style-dsssl: {'basearchonly': False, 'type': 'default'} + Package: docbook-style-xsl: {'basearchonly': False, 'type': 'default'} + Package: docbook-utils: {'basearchonly': False, 'type': 'default'} + Package: docbook-utils-pdf: {'basearchonly': False, 'type': 'default'} + Package: docbook5-schemas: {'basearchonly': False, 'type': 'default'} + Package: docbook5-style-xsl: {'basearchonly': False, 'type': 'default'} + Package: linuxdoc-tools: {'basearchonly': False, 'type': 'default'} + Package: tex-fonts-hebrew: {'basearchonly': False, 'type': 'default'} + Package: texlive: {'basearchonly': False, 'type': 'default'} + Package: texlive-cm-lgc: {'basearchonly': False, 'type': 'default'} + Package: texlive-kerkis: {'basearchonly': False, 'type': 'default'} + Package: xhtml1-dtds: {'basearchonly': False, 'type': 'default'} + Package: xmlto: {'basearchonly': False, 'type': 'default'} + Package: abcm2ps: {'basearchonly': False, 'type': 'optional'} + Package: BibTool: {'basearchonly': False, 'type': 'optional'} + Package: dblatex: {'basearchonly': False, 'type': 'optional'} + Package: docbook2X: {'basearchonly': False, 'type': 'optional'} + Package: html401-dtds: {'basearchonly': False, 'type': 'optional'} + Package: kbibtex: {'basearchonly': False, 'type': 'optional'} + Package: kile: {'basearchonly': False, 'type': 'optional'} + Package: latex-mk: {'basearchonly': False, 'type': 'optional'} + Package: latexmk: {'basearchonly': False, 'type': 'optional'} + Package: lilypond: {'basearchonly': False, 'type': 'optional'} + Package: lout: {'basearchonly': False, 'type': 'optional'} + Package: ooo2txt: {'basearchonly': False, 'type': 'optional'} + Package: pandoc: {'basearchonly': False, 'type': 'optional'} + Package: python-docutils: {'basearchonly': False, 'type': 'optional'} + Package: python-manuel: {'basearchonly': False, 'type': 'optional'} + Package: scribus: {'basearchonly': False, 'type': 'optional'} + Package: tex-zfuzz: {'basearchonly': False, 'type': 'optional'} + Package: texlive-latex: {'basearchonly': False, 'type': 'optional'} + Package: texlive-xdvi: {'basearchonly': False, 'type': 'optional'} + Package: txt2rss: {'basearchonly': False, 'type': 'optional'} + Package: w3c-markup-validator: {'basearchonly': False, 'type': 'optional'} + Package: xmlcopyeditor: {'basearchonly': False, 'type': 'optional'} Group: base-x (base-x) - Package: glx-utils: {'type': 'mandatory', 'basearchonly': False} - Package: mesa-dri-drivers: {'type': 'mandatory', 'basearchonly': False} - Package: plymouth-system-theme: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-armsoc: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-ati: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-evdev: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-fbdev: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-freedreno: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-intel: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-libinput: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-nouveau: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-omap: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-openchrome: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-qxl: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-vesa: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-vmmouse: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-vmware: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-wacom: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-server-Xorg: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-utils: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-xauth: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-xinit: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-geode: {'type': 'optional', 'basearchonly': False} + Package: glx-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: mesa-dri-drivers: {'basearchonly': False, 'type': 'mandatory'} + Package: plymouth-system-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-armsoc: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-ati: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-evdev: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-fbdev: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-freedreno: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-intel: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-libinput: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-nouveau: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-omap: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-openchrome: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-qxl: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-vesa: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-vmmouse: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-vmware: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-wacom: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-server-Xorg: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-xauth: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-xinit: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-geode: {'basearchonly': False, 'type': 'optional'} Group: basic-desktop (Basic Desktop) - Package: adwaita-gtk2-theme: {'type': 'mandatory', 'basearchonly': False} - Package: adwaita-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: awesome: {'type': 'mandatory', 'basearchonly': False} - Package: dwm: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: i3: {'type': 'mandatory', 'basearchonly': False} - Package: initial-setup-gui: {'type': 'mandatory', 'basearchonly': False} - Package: lightdm: {'type': 'mandatory', 'basearchonly': False} - Package: metacity: {'type': 'mandatory', 'basearchonly': False} - Package: openbox: {'type': 'mandatory', 'basearchonly': False} - Package: qtile: {'type': 'mandatory', 'basearchonly': False} - Package: ratpoison: {'type': 'mandatory', 'basearchonly': False} - Package: xmonad-basic: {'type': 'mandatory', 'basearchonly': False} + Package: adwaita-gtk2-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: adwaita-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: awesome: {'basearchonly': False, 'type': 'mandatory'} + Package: dwm: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: i3: {'basearchonly': False, 'type': 'mandatory'} + Package: initial-setup-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: lightdm: {'basearchonly': False, 'type': 'mandatory'} + Package: metacity: {'basearchonly': False, 'type': 'mandatory'} + Package: openbox: {'basearchonly': False, 'type': 'mandatory'} + Package: qtile: {'basearchonly': False, 'type': 'mandatory'} + Package: ratpoison: {'basearchonly': False, 'type': 'mandatory'} + Package: xmonad-basic: {'basearchonly': False, 'type': 'mandatory'} Group: bengali-support (Bengali Support) - Package: lohit-bengali-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-bengali-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-bengali-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} + Package: lohit-bengali-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-bengali-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-bengali-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} Group: bhutanese-support (Bhutanese Support) - Package: jomolhari-fonts: {'type': 'mandatory', 'basearchonly': False} + Package: jomolhari-fonts: {'basearchonly': False, 'type': 'mandatory'} Group: bodo-support (Bodo Support) - Package: lohit-devanagari-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: samyak-devanagari-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: samyak-devanagari-fonts: {'basearchonly': False, 'type': 'default'} Group: books (Books and Guides) - Package: diveintopython: {'type': 'default', 'basearchonly': False} - Package: ldd-pdf: {'type': 'default', 'basearchonly': False} + Package: diveintopython: {'basearchonly': False, 'type': 'default'} + Package: ldd-pdf: {'basearchonly': False, 'type': 'default'} Group: buildsys-build (Buildsystem building group) - Package: bash: {'type': 'mandatory', 'basearchonly': False} - Package: bzip2: {'type': 'mandatory', 'basearchonly': False} - Package: coreutils: {'type': 'mandatory', 'basearchonly': False} - Package: cpio: {'type': 'mandatory', 'basearchonly': False} - Package: diffutils: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-release: {'type': 'mandatory', 'basearchonly': False} - Package: findutils: {'type': 'mandatory', 'basearchonly': False} - Package: gawk: {'type': 'mandatory', 'basearchonly': False} - Package: gcc: {'type': 'mandatory', 'basearchonly': False} - Package: gcc-c++: {'type': 'mandatory', 'basearchonly': False} - Package: grep: {'type': 'mandatory', 'basearchonly': False} - Package: gzip: {'type': 'mandatory', 'basearchonly': False} - Package: info: {'type': 'mandatory', 'basearchonly': False} - Package: make: {'type': 'mandatory', 'basearchonly': False} - Package: patch: {'type': 'mandatory', 'basearchonly': False} - Package: redhat-rpm-config: {'type': 'mandatory', 'basearchonly': False} - Package: rpm-build: {'type': 'mandatory', 'basearchonly': False} - Package: sed: {'type': 'mandatory', 'basearchonly': False} - Package: shadow-utils: {'type': 'mandatory', 'basearchonly': False} - Package: tar: {'type': 'mandatory', 'basearchonly': False} - Package: unzip: {'type': 'mandatory', 'basearchonly': False} - Package: util-linux: {'type': 'mandatory', 'basearchonly': False} - Package: which: {'type': 'mandatory', 'basearchonly': False} - Package: xz: {'type': 'mandatory', 'basearchonly': False} + Package: bash: {'basearchonly': False, 'type': 'mandatory'} + Package: bzip2: {'basearchonly': False, 'type': 'mandatory'} + Package: coreutils: {'basearchonly': False, 'type': 'mandatory'} + Package: cpio: {'basearchonly': False, 'type': 'mandatory'} + Package: diffutils: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-release: {'basearchonly': False, 'type': 'mandatory'} + Package: findutils: {'basearchonly': False, 'type': 'mandatory'} + Package: gawk: {'basearchonly': False, 'type': 'mandatory'} + Package: gcc: {'basearchonly': False, 'type': 'mandatory'} + Package: gcc-c++: {'basearchonly': False, 'type': 'mandatory'} + Package: grep: {'basearchonly': False, 'type': 'mandatory'} + Package: gzip: {'basearchonly': False, 'type': 'mandatory'} + Package: info: {'basearchonly': False, 'type': 'mandatory'} + Package: make: {'basearchonly': False, 'type': 'mandatory'} + Package: patch: {'basearchonly': False, 'type': 'mandatory'} + Package: redhat-rpm-config: {'basearchonly': False, 'type': 'mandatory'} + Package: rpm-build: {'basearchonly': False, 'type': 'mandatory'} + Package: sed: {'basearchonly': False, 'type': 'mandatory'} + Package: shadow-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: tar: {'basearchonly': False, 'type': 'mandatory'} + Package: unzip: {'basearchonly': False, 'type': 'mandatory'} + Package: util-linux: {'basearchonly': False, 'type': 'mandatory'} + Package: which: {'basearchonly': False, 'type': 'mandatory'} + Package: xz: {'basearchonly': False, 'type': 'mandatory'} Group: burmese-support (Myanmar (Burmese) Support) - Package: sil-padauk-fonts: {'type': 'default', 'basearchonly': False} + Package: sil-padauk-fonts: {'basearchonly': False, 'type': 'default'} Group: c-development (C Development Tools and Libraries) - Package: autoconf: {'type': 'mandatory', 'basearchonly': False} - Package: automake: {'type': 'mandatory', 'basearchonly': False} - Package: binutils: {'type': 'mandatory', 'basearchonly': False} - Package: bison: {'type': 'mandatory', 'basearchonly': False} - Package: flex: {'type': 'mandatory', 'basearchonly': False} - Package: gcc: {'type': 'mandatory', 'basearchonly': True} - Package: gcc-c++: {'type': 'mandatory', 'basearchonly': True} - Package: gdb: {'type': 'mandatory', 'basearchonly': True} - Package: glibc-devel: {'type': 'mandatory', 'basearchonly': False} - Package: libtool: {'type': 'mandatory', 'basearchonly': False} - Package: make: {'type': 'mandatory', 'basearchonly': False} - Package: pkgconfig: {'type': 'mandatory', 'basearchonly': False} - Package: strace: {'type': 'mandatory', 'basearchonly': False} - Package: byacc: {'type': 'default', 'basearchonly': False} - Package: ccache: {'type': 'default', 'basearchonly': False} - Package: cscope: {'type': 'default', 'basearchonly': False} - Package: ctags: {'type': 'default', 'basearchonly': False} - Package: elfutils: {'type': 'default', 'basearchonly': False} - Package: indent: {'type': 'default', 'basearchonly': False} - Package: ltrace: {'type': 'default', 'basearchonly': True} - Package: oprofile: {'type': 'default', 'basearchonly': True} - Package: valgrind: {'type': 'default', 'basearchonly': False} - Package: astyle: {'type': 'optional', 'basearchonly': False} - Package: cbmc: {'type': 'optional', 'basearchonly': False} - Package: check: {'type': 'optional', 'basearchonly': False} - Package: cmake: {'type': 'optional', 'basearchonly': False} - Package: coan: {'type': 'optional', 'basearchonly': False} - Package: cproto: {'type': 'optional', 'basearchonly': False} - Package: ElectricFence: {'type': 'optional', 'basearchonly': False} - Package: elfinfo: {'type': 'optional', 'basearchonly': False} - Package: insight: {'type': 'optional', 'basearchonly': False} - Package: nasm: {'type': 'optional', 'basearchonly': False} - Package: pscan: {'type': 'optional', 'basearchonly': False} - Package: remake: {'type': 'optional', 'basearchonly': False} - Package: scons: {'type': 'optional', 'basearchonly': False} - Package: scorep: {'type': 'optional', 'basearchonly': False} - Package: splint: {'type': 'optional', 'basearchonly': False} - Package: trinity: {'type': 'optional', 'basearchonly': False} - Package: undertaker: {'type': 'optional', 'basearchonly': False} - Package: yasm: {'type': 'optional', 'basearchonly': False} - Package: zzuf: {'type': 'optional', 'basearchonly': False} + Package: autoconf: {'basearchonly': False, 'type': 'mandatory'} + Package: automake: {'basearchonly': False, 'type': 'mandatory'} + Package: binutils: {'basearchonly': False, 'type': 'mandatory'} + Package: bison: {'basearchonly': False, 'type': 'mandatory'} + Package: flex: {'basearchonly': False, 'type': 'mandatory'} + Package: gcc: {'basearchonly': True, 'type': 'mandatory'} + Package: gcc-c++: {'basearchonly': True, 'type': 'mandatory'} + Package: gdb: {'basearchonly': True, 'type': 'mandatory'} + Package: glibc-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: libtool: {'basearchonly': False, 'type': 'mandatory'} + Package: make: {'basearchonly': False, 'type': 'mandatory'} + Package: pkgconfig: {'basearchonly': False, 'type': 'mandatory'} + Package: strace: {'basearchonly': False, 'type': 'mandatory'} + Package: byacc: {'basearchonly': False, 'type': 'default'} + Package: ccache: {'basearchonly': False, 'type': 'default'} + Package: cscope: {'basearchonly': False, 'type': 'default'} + Package: ctags: {'basearchonly': False, 'type': 'default'} + Package: elfutils: {'basearchonly': False, 'type': 'default'} + Package: indent: {'basearchonly': False, 'type': 'default'} + Package: ltrace: {'basearchonly': True, 'type': 'default'} + Package: oprofile: {'basearchonly': True, 'type': 'default'} + Package: valgrind: {'basearchonly': False, 'type': 'default'} + Package: astyle: {'basearchonly': False, 'type': 'optional'} + Package: cbmc: {'basearchonly': False, 'type': 'optional'} + Package: check: {'basearchonly': False, 'type': 'optional'} + Package: cmake: {'basearchonly': False, 'type': 'optional'} + Package: coan: {'basearchonly': False, 'type': 'optional'} + Package: cproto: {'basearchonly': False, 'type': 'optional'} + Package: ElectricFence: {'basearchonly': False, 'type': 'optional'} + Package: elfinfo: {'basearchonly': False, 'type': 'optional'} + Package: insight: {'basearchonly': False, 'type': 'optional'} + Package: nasm: {'basearchonly': False, 'type': 'optional'} + Package: pscan: {'basearchonly': False, 'type': 'optional'} + Package: remake: {'basearchonly': False, 'type': 'optional'} + Package: scons: {'basearchonly': False, 'type': 'optional'} + Package: scorep: {'basearchonly': False, 'type': 'optional'} + Package: splint: {'basearchonly': False, 'type': 'optional'} + Package: trinity: {'basearchonly': False, 'type': 'optional'} + Package: undertaker: {'basearchonly': False, 'type': 'optional'} + Package: yasm: {'basearchonly': False, 'type': 'optional'} + Package: zzuf: {'basearchonly': False, 'type': 'optional'} Group: cinnamon-desktop (Cinnamon) - Package: abrt-desktop: {'type': 'mandatory', 'basearchonly': False} - Package: abrt-java-connector: {'type': 'mandatory', 'basearchonly': False} - Package: alsa-plugins-pulseaudio: {'type': 'mandatory', 'basearchonly': False} - Package: blueman: {'type': 'mandatory', 'basearchonly': False} - Package: brasero: {'type': 'mandatory', 'basearchonly': False} - Package: cinnamon: {'type': 'mandatory', 'basearchonly': False} - Package: cinnamon-control-center: {'type': 'mandatory', 'basearchonly': False} - Package: cinnamon-screensaver: {'type': 'mandatory', 'basearchonly': False} - Package: eog: {'type': 'mandatory', 'basearchonly': False} - Package: evince: {'type': 'mandatory', 'basearchonly': False} - Package: f24-backgrounds-base: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: firefox: {'type': 'mandatory', 'basearchonly': False} - Package: firewall-config: {'type': 'mandatory', 'basearchonly': False} - Package: fros-recordmydesktop: {'type': 'mandatory', 'basearchonly': False} - Package: gedit: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-backgrounds: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-calculator: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-disk-utility: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-screenshot: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-system-monitor: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-terminal: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-archive: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-gphoto2: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-mtp: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-smb: {'type': 'mandatory', 'basearchonly': False} - Package: icedtea-web: {'type': 'mandatory', 'basearchonly': False} - Package: imsettings-cinnamon: {'type': 'mandatory', 'basearchonly': False} - Package: initial-setup-gui: {'type': 'mandatory', 'basearchonly': False} - Package: lightdm-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: lightdm-gtk-greeter-settings: {'type': 'mandatory', 'basearchonly': False} - Package: metacity: {'type': 'mandatory', 'basearchonly': False} - Package: nemo-fileroller: {'type': 'mandatory', 'basearchonly': False} - Package: nemo-image-converter: {'type': 'mandatory', 'basearchonly': False} - Package: nemo-preview: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-adsl: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-bluetooth: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-iodine-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-l2tp-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-libreswan-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-openconnect: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-openvpn-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-pptp-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-vpnc-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-wifi: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-wwan: {'type': 'mandatory', 'basearchonly': False} - Package: nm-connection-editor: {'type': 'mandatory', 'basearchonly': False} - Package: redshift: {'type': 'mandatory', 'basearchonly': False} - Package: sane-backends-drivers-scanners: {'type': 'mandatory', 'basearchonly': False} - Package: setroubleshoot: {'type': 'mandatory', 'basearchonly': False} - Package: shotwell: {'type': 'mandatory', 'basearchonly': False} - Package: simple-scan: {'type': 'mandatory', 'basearchonly': False} - Package: system-config-printer: {'type': 'mandatory', 'basearchonly': False} - Package: thunderbird: {'type': 'mandatory', 'basearchonly': False} - Package: xdg-user-dirs-gtk: {'type': 'mandatory', 'basearchonly': False} + Package: abrt-desktop: {'basearchonly': False, 'type': 'mandatory'} + Package: abrt-java-connector: {'basearchonly': False, 'type': 'mandatory'} + Package: alsa-plugins-pulseaudio: {'basearchonly': False, 'type': 'mandatory'} + Package: blueman: {'basearchonly': False, 'type': 'mandatory'} + Package: brasero: {'basearchonly': False, 'type': 'mandatory'} + Package: cinnamon: {'basearchonly': False, 'type': 'mandatory'} + Package: cinnamon-control-center: {'basearchonly': False, 'type': 'mandatory'} + Package: cinnamon-screensaver: {'basearchonly': False, 'type': 'mandatory'} + Package: eog: {'basearchonly': False, 'type': 'mandatory'} + Package: evince: {'basearchonly': False, 'type': 'mandatory'} + Package: f24-backgrounds-base: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: firefox: {'basearchonly': False, 'type': 'mandatory'} + Package: firewall-config: {'basearchonly': False, 'type': 'mandatory'} + Package: fros-recordmydesktop: {'basearchonly': False, 'type': 'mandatory'} + Package: gedit: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-backgrounds: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-calculator: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-disk-utility: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-screenshot: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-system-monitor: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-terminal: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-archive: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-gphoto2: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-mtp: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-smb: {'basearchonly': False, 'type': 'mandatory'} + Package: icedtea-web: {'basearchonly': False, 'type': 'mandatory'} + Package: imsettings-cinnamon: {'basearchonly': False, 'type': 'mandatory'} + Package: initial-setup-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: lightdm-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: lightdm-gtk-greeter-settings: {'basearchonly': False, 'type': 'mandatory'} + Package: metacity: {'basearchonly': False, 'type': 'mandatory'} + Package: nemo-fileroller: {'basearchonly': False, 'type': 'mandatory'} + Package: nemo-image-converter: {'basearchonly': False, 'type': 'mandatory'} + Package: nemo-preview: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-adsl: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-bluetooth: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-iodine-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-l2tp-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-libreswan-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-openconnect: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-openvpn-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-pptp-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-vpnc-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-wifi: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-wwan: {'basearchonly': False, 'type': 'mandatory'} + Package: nm-connection-editor: {'basearchonly': False, 'type': 'mandatory'} + Package: redshift: {'basearchonly': False, 'type': 'mandatory'} + Package: sane-backends-drivers-scanners: {'basearchonly': False, 'type': 'mandatory'} + Package: setroubleshoot: {'basearchonly': False, 'type': 'mandatory'} + Package: shotwell: {'basearchonly': False, 'type': 'mandatory'} + Package: simple-scan: {'basearchonly': False, 'type': 'mandatory'} + Package: system-config-printer: {'basearchonly': False, 'type': 'mandatory'} + Package: thunderbird: {'basearchonly': False, 'type': 'mandatory'} + Package: xdg-user-dirs-gtk: {'basearchonly': False, 'type': 'mandatory'} Group: cloud-infrastructure (Cloud Infrastructure) - Package: ceph: {'type': 'optional', 'basearchonly': False} - Package: euca2ools: {'type': 'optional', 'basearchonly': False} - Package: glusterfs: {'type': 'optional', 'basearchonly': False} - Package: hail: {'type': 'optional', 'basearchonly': False} - Package: imagefactory: {'type': 'optional', 'basearchonly': False} - Package: iwhd: {'type': 'optional', 'basearchonly': False} - Package: sheepdog: {'type': 'optional', 'basearchonly': False} - Package: StarCluster: {'type': 'optional', 'basearchonly': False} - Package: tabled: {'type': 'optional', 'basearchonly': False} + Package: ceph: {'basearchonly': False, 'type': 'optional'} + Package: euca2ools: {'basearchonly': False, 'type': 'optional'} + Package: glusterfs: {'basearchonly': False, 'type': 'optional'} + Package: hail: {'basearchonly': False, 'type': 'optional'} + Package: imagefactory: {'basearchonly': False, 'type': 'optional'} + Package: iwhd: {'basearchonly': False, 'type': 'optional'} + Package: sheepdog: {'basearchonly': False, 'type': 'optional'} + Package: StarCluster: {'basearchonly': False, 'type': 'optional'} + Package: tabled: {'basearchonly': False, 'type': 'optional'} Group: cloud-management (Cloud Management Tools) - Package: cloud-utils: {'type': 'default', 'basearchonly': False} - Package: imagefactory: {'type': 'default', 'basearchonly': False} - Package: imagefactory-plugins: {'type': 'default', 'basearchonly': False} - Package: imagefactory-plugins-EC2: {'type': 'default', 'basearchonly': False} - Package: imagefactory-plugins-EC2-JEOS-images: {'type': 'default', 'basearchonly': False} - Package: imagefactory-plugins-OpenStack: {'type': 'default', 'basearchonly': False} - Package: imagefactory-plugins-Rackspace: {'type': 'default', 'basearchonly': False} - Package: imagefactory-plugins-Rackspace-JEOS-images: {'type': 'default', 'basearchonly': False} - Package: imagefactory-plugins-TinMan: {'type': 'default', 'basearchonly': False} - Package: python-boto: {'type': 'default', 'basearchonly': False} - Package: python-libcloud: {'type': 'default', 'basearchonly': False} - Package: rubygem-amazon-ec2: {'type': 'default', 'basearchonly': False} - Package: python-openstackclient: {'type': 'optional', 'basearchonly': False} - Package: rubygem-amazon-ec2-doc: {'type': 'optional', 'basearchonly': False} + Package: cloud-utils: {'basearchonly': False, 'type': 'default'} + Package: imagefactory: {'basearchonly': False, 'type': 'default'} + Package: imagefactory-plugins: {'basearchonly': False, 'type': 'default'} + Package: imagefactory-plugins-EC2: {'basearchonly': False, 'type': 'default'} + Package: imagefactory-plugins-EC2-JEOS-images: {'basearchonly': False, 'type': 'default'} + Package: imagefactory-plugins-OpenStack: {'basearchonly': False, 'type': 'default'} + Package: imagefactory-plugins-Rackspace: {'basearchonly': False, 'type': 'default'} + Package: imagefactory-plugins-Rackspace-JEOS-images: {'basearchonly': False, 'type': 'default'} + Package: imagefactory-plugins-TinMan: {'basearchonly': False, 'type': 'default'} + Package: python-boto: {'basearchonly': False, 'type': 'default'} + Package: python-libcloud: {'basearchonly': False, 'type': 'default'} + Package: rubygem-amazon-ec2: {'basearchonly': False, 'type': 'default'} + Package: python-openstackclient: {'basearchonly': False, 'type': 'optional'} + Package: rubygem-amazon-ec2-doc: {'basearchonly': False, 'type': 'optional'} Group: cloud-server (Cloud Server Tools) - Package: cloud-init: {'type': 'mandatory', 'basearchonly': False} - Package: cloud-utils-growpart: {'type': 'mandatory', 'basearchonly': False} - Package: dracut-config-generic: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-release-cloud: {'type': 'mandatory', 'basearchonly': False} - Package: grubby: {'type': 'mandatory', 'basearchonly': False} - Package: heat-cfntools: {'type': 'mandatory', 'basearchonly': False} - Package: rsync: {'type': 'mandatory', 'basearchonly': False} - Package: syslinux-extlinux: {'type': 'mandatory', 'basearchonly': False} - Package: tar: {'type': 'mandatory', 'basearchonly': False} + Package: cloud-init: {'basearchonly': False, 'type': 'mandatory'} + Package: cloud-utils-growpart: {'basearchonly': False, 'type': 'mandatory'} + Package: dracut-config-generic: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-release-cloud: {'basearchonly': False, 'type': 'mandatory'} + Package: grubby: {'basearchonly': False, 'type': 'mandatory'} + Package: heat-cfntools: {'basearchonly': False, 'type': 'mandatory'} + Package: rsync: {'basearchonly': False, 'type': 'mandatory'} + Package: syslinux-extlinux: {'basearchonly': False, 'type': 'mandatory'} + Package: tar: {'basearchonly': False, 'type': 'mandatory'} Group: container-management (Container Management) - Package: docker: {'type': 'mandatory', 'basearchonly': False} - Package: docker-cockpit: {'type': 'mandatory', 'basearchonly': False} - Package: docker-registry: {'type': 'optional', 'basearchonly': False} - Package: fedora-dockerfiles: {'type': 'optional', 'basearchonly': False} + Package: docker: {'basearchonly': False, 'type': 'mandatory'} + Package: docker-cockpit: {'basearchonly': False, 'type': 'mandatory'} + Package: docker-registry: {'basearchonly': False, 'type': 'optional'} + Package: fedora-dockerfiles: {'basearchonly': False, 'type': 'optional'} Group: core (Core) - Package: audit: {'type': 'mandatory', 'basearchonly': False} - Package: basesystem: {'type': 'mandatory', 'basearchonly': False} - Package: bash: {'type': 'mandatory', 'basearchonly': False} - Package: coreutils: {'type': 'mandatory', 'basearchonly': False} - Package: cronie: {'type': 'mandatory', 'basearchonly': False} - Package: curl: {'type': 'mandatory', 'basearchonly': False} - Package: dhcp-client: {'type': 'mandatory', 'basearchonly': False} - Package: dnf: {'type': 'mandatory', 'basearchonly': False} - Package: dnf-yum: {'type': 'mandatory', 'basearchonly': False} - Package: e2fsprogs: {'type': 'mandatory', 'basearchonly': False} - Package: filesystem: {'type': 'mandatory', 'basearchonly': False} - Package: glibc: {'type': 'mandatory', 'basearchonly': False} - Package: grubby: {'type': 'mandatory', 'basearchonly': False} - Package: hostname: {'type': 'mandatory', 'basearchonly': False} - Package: initscripts: {'type': 'mandatory', 'basearchonly': False} - Package: iproute: {'type': 'mandatory', 'basearchonly': False} - Package: iputils: {'type': 'mandatory', 'basearchonly': False} - Package: kbd: {'type': 'mandatory', 'basearchonly': False} - Package: less: {'type': 'mandatory', 'basearchonly': False} - Package: man-db: {'type': 'mandatory', 'basearchonly': False} - Package: ncurses: {'type': 'mandatory', 'basearchonly': False} - Package: openssh-clients: {'type': 'mandatory', 'basearchonly': False} - Package: openssh-server: {'type': 'mandatory', 'basearchonly': False} - Package: parted: {'type': 'mandatory', 'basearchonly': False} - Package: passwd: {'type': 'mandatory', 'basearchonly': False} - Package: plymouth: {'type': 'mandatory', 'basearchonly': False} - Package: policycoreutils: {'type': 'mandatory', 'basearchonly': False} - Package: procps-ng: {'type': 'mandatory', 'basearchonly': False} - Package: rootfiles: {'type': 'mandatory', 'basearchonly': False} - Package: rpm: {'type': 'mandatory', 'basearchonly': False} - Package: selinux-policy-targeted: {'type': 'mandatory', 'basearchonly': False} - Package: setup: {'type': 'mandatory', 'basearchonly': False} - Package: shadow-utils: {'type': 'mandatory', 'basearchonly': False} - Package: sudo: {'type': 'mandatory', 'basearchonly': False} - Package: systemd: {'type': 'mandatory', 'basearchonly': False} - Package: util-linux: {'type': 'mandatory', 'basearchonly': False} - Package: vim-minimal: {'type': 'mandatory', 'basearchonly': False} - Package: authconfig: {'type': 'default', 'basearchonly': False} - Package: dnf-plugins-core: {'type': 'default', 'basearchonly': False} - Package: dracut-config-rescue: {'type': 'default', 'basearchonly': False} - Package: firewalld: {'type': 'default', 'basearchonly': False} - Package: NetworkManager: {'type': 'default', 'basearchonly': False} - Package: ppc64-utils: {'type': 'default', 'basearchonly': False} - Package: dracut-config-generic: {'type': 'optional', 'basearchonly': False} - Package: initial-setup: {'type': 'optional', 'basearchonly': False} - Package: uboot-images-armv7: {'type': 'optional', 'basearchonly': False} - Package: uboot-tools: {'type': 'optional', 'basearchonly': False} + Package: audit: {'basearchonly': False, 'type': 'mandatory'} + Package: basesystem: {'basearchonly': False, 'type': 'mandatory'} + Package: bash: {'basearchonly': False, 'type': 'mandatory'} + Package: coreutils: {'basearchonly': False, 'type': 'mandatory'} + Package: cronie: {'basearchonly': False, 'type': 'mandatory'} + Package: curl: {'basearchonly': False, 'type': 'mandatory'} + Package: dhcp-client: {'basearchonly': False, 'type': 'mandatory'} + Package: dnf: {'basearchonly': False, 'type': 'mandatory'} + Package: dnf-yum: {'basearchonly': False, 'type': 'mandatory'} + Package: e2fsprogs: {'basearchonly': False, 'type': 'mandatory'} + Package: filesystem: {'basearchonly': False, 'type': 'mandatory'} + Package: glibc: {'basearchonly': False, 'type': 'mandatory'} + Package: grubby: {'basearchonly': False, 'type': 'mandatory'} + Package: hostname: {'basearchonly': False, 'type': 'mandatory'} + Package: initscripts: {'basearchonly': False, 'type': 'mandatory'} + Package: iproute: {'basearchonly': False, 'type': 'mandatory'} + Package: iputils: {'basearchonly': False, 'type': 'mandatory'} + Package: kbd: {'basearchonly': False, 'type': 'mandatory'} + Package: less: {'basearchonly': False, 'type': 'mandatory'} + Package: man-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ncurses: {'basearchonly': False, 'type': 'mandatory'} + Package: openssh-clients: {'basearchonly': False, 'type': 'mandatory'} + Package: openssh-server: {'basearchonly': False, 'type': 'mandatory'} + Package: parted: {'basearchonly': False, 'type': 'mandatory'} + Package: passwd: {'basearchonly': False, 'type': 'mandatory'} + Package: plymouth: {'basearchonly': False, 'type': 'mandatory'} + Package: policycoreutils: {'basearchonly': False, 'type': 'mandatory'} + Package: procps-ng: {'basearchonly': False, 'type': 'mandatory'} + Package: rootfiles: {'basearchonly': False, 'type': 'mandatory'} + Package: rpm: {'basearchonly': False, 'type': 'mandatory'} + Package: selinux-policy-targeted: {'basearchonly': False, 'type': 'mandatory'} + Package: setup: {'basearchonly': False, 'type': 'mandatory'} + Package: shadow-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: sudo: {'basearchonly': False, 'type': 'mandatory'} + Package: systemd: {'basearchonly': False, 'type': 'mandatory'} + Package: util-linux: {'basearchonly': False, 'type': 'mandatory'} + Package: vim-minimal: {'basearchonly': False, 'type': 'mandatory'} + Package: authconfig: {'basearchonly': False, 'type': 'default'} + Package: dnf-plugins-core: {'basearchonly': False, 'type': 'default'} + Package: dracut-config-rescue: {'basearchonly': False, 'type': 'default'} + Package: firewalld: {'basearchonly': False, 'type': 'default'} + Package: NetworkManager: {'basearchonly': False, 'type': 'default'} + Package: ppc64-utils: {'basearchonly': False, 'type': 'default'} + Package: dracut-config-generic: {'basearchonly': False, 'type': 'optional'} + Package: initial-setup: {'basearchonly': False, 'type': 'optional'} + Package: uboot-images-armv7: {'basearchonly': False, 'type': 'optional'} + Package: uboot-tools: {'basearchonly': False, 'type': 'optional'} Group: critical-path-apps (Critical Path (Applications)) - Package: evolution: {'type': 'default', 'basearchonly': False} - Package: firefox: {'type': 'default', 'basearchonly': False} - Package: thunderbird: {'type': 'default', 'basearchonly': False} + Package: evolution: {'basearchonly': False, 'type': 'default'} + Package: firefox: {'basearchonly': False, 'type': 'default'} + Package: thunderbird: {'basearchonly': False, 'type': 'default'} Group: critical-path-base (Critical Path (Base)) - Package: anaconda: {'type': 'mandatory', 'basearchonly': False} - Package: createrepo: {'type': 'mandatory', 'basearchonly': False} - Package: dash: {'type': 'mandatory', 'basearchonly': False} - Package: dracut: {'type': 'mandatory', 'basearchonly': False} - Package: dnf: {'type': 'mandatory', 'basearchonly': False} - Package: gcc-c++: {'type': 'mandatory', 'basearchonly': False} - Package: initial-setup: {'type': 'mandatory', 'basearchonly': False} - Package: kernel: {'type': 'mandatory', 'basearchonly': False} - Package: livecd-tools: {'type': 'mandatory', 'basearchonly': False} - Package: mash: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager: {'type': 'mandatory', 'basearchonly': False} - Package: pungi: {'type': 'mandatory', 'basearchonly': False} - Package: redhat-rpm-config: {'type': 'mandatory', 'basearchonly': False} - Package: rpm-build: {'type': 'mandatory', 'basearchonly': False} - Package: yum: {'type': 'mandatory', 'basearchonly': False} + Package: anaconda: {'basearchonly': False, 'type': 'mandatory'} + Package: createrepo: {'basearchonly': False, 'type': 'mandatory'} + Package: dash: {'basearchonly': False, 'type': 'mandatory'} + Package: dracut: {'basearchonly': False, 'type': 'mandatory'} + Package: dnf: {'basearchonly': False, 'type': 'mandatory'} + Package: gcc-c++: {'basearchonly': False, 'type': 'mandatory'} + Package: initial-setup: {'basearchonly': False, 'type': 'mandatory'} + Package: kernel: {'basearchonly': False, 'type': 'mandatory'} + Package: livecd-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: mash: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager: {'basearchonly': False, 'type': 'mandatory'} + Package: pungi: {'basearchonly': False, 'type': 'mandatory'} + Package: redhat-rpm-config: {'basearchonly': False, 'type': 'mandatory'} + Package: rpm-build: {'basearchonly': False, 'type': 'mandatory'} + Package: yum: {'basearchonly': False, 'type': 'mandatory'} Group: critical-path-gnome (Critical Path (GNOME)) - Package: control-center: {'type': 'mandatory', 'basearchonly': False} - Package: dconf: {'type': 'mandatory', 'basearchonly': False} - Package: gdm: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-session-xsession: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-shell: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-terminal: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-themes-standard: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-fuse: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-ati: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-evdev: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-fbdev: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-intel: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-libinput: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-nouveau: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-qxl: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-vesa: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-server-Xorg: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-xauth: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-xinit: {'type': 'mandatory', 'basearchonly': False} - Package: avahi: {'type': 'default', 'basearchonly': False} - Package: gnome-bluetooth: {'type': 'default', 'basearchonly': False} - Package: gnome-software: {'type': 'default', 'basearchonly': False} - Package: libcanberra-gtk3: {'type': 'default', 'basearchonly': False} - Package: nautilus: {'type': 'default', 'basearchonly': False} - Package: pulseaudio-module-x11: {'type': 'default', 'basearchonly': False} + Package: control-center: {'basearchonly': False, 'type': 'mandatory'} + Package: dconf: {'basearchonly': False, 'type': 'mandatory'} + Package: gdm: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-session-xsession: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-shell: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-terminal: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-themes-standard: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-fuse: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-ati: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-evdev: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-fbdev: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-intel: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-libinput: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-nouveau: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-qxl: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-vesa: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-server-Xorg: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-xauth: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-xinit: {'basearchonly': False, 'type': 'mandatory'} + Package: avahi: {'basearchonly': False, 'type': 'default'} + Package: gnome-bluetooth: {'basearchonly': False, 'type': 'default'} + Package: gnome-software: {'basearchonly': False, 'type': 'default'} + Package: libcanberra-gtk3: {'basearchonly': False, 'type': 'default'} + Package: nautilus: {'basearchonly': False, 'type': 'default'} + Package: pulseaudio-module-x11: {'basearchonly': False, 'type': 'default'} Group: critical-path-hawaii (Critical Path (Hawaii)) - Package: hawaii-shell: {'type': 'mandatory', 'basearchonly': False} - Package: sddm: {'type': 'mandatory', 'basearchonly': False} + Package: hawaii-shell: {'basearchonly': False, 'type': 'mandatory'} + Package: sddm: {'basearchonly': False, 'type': 'mandatory'} Group: critical-path-kde (Critical Path (KDE)) - Package: kdelibs: {'type': 'mandatory', 'basearchonly': False} - Package: sddm: {'type': 'mandatory', 'basearchonly': False} + Package: kdelibs: {'basearchonly': False, 'type': 'mandatory'} + Package: sddm: {'basearchonly': False, 'type': 'mandatory'} Group: critical-path-lxde (Critical Path (LXDE)) - Package: lxde-common: {'type': 'mandatory', 'basearchonly': False} - Package: notification-daemon: {'type': 'default', 'basearchonly': False} + Package: lxde-common: {'basearchonly': False, 'type': 'mandatory'} + Package: notification-daemon: {'basearchonly': False, 'type': 'default'} Group: critical-path-lxqt (Critical Path (LXQt)) - Package: lxqt-common: {'type': 'mandatory', 'basearchonly': False} - Package: notification-daemon: {'type': 'default', 'basearchonly': False} + Package: lxqt-common: {'basearchonly': False, 'type': 'mandatory'} + Package: notification-daemon: {'basearchonly': False, 'type': 'default'} Group: critical-path-xfce (Critical Path (Xfce)) - Package: xfce4-session: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-settings: {'type': 'mandatory', 'basearchonly': False} + Package: xfce4-session: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-settings: {'basearchonly': False, 'type': 'mandatory'} 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} + Package: ldc: {'basearchonly': True, 'type': 'mandatory'} + Package: ldc-druntime: {'basearchonly': True, 'type': 'mandatory'} + Package: ldc-druntime-devel: {'basearchonly': True, 'type': 'mandatory'} + Package: ldc-phobos-devel: {'basearchonly': True, 'type': 'mandatory'} + Package: make: {'basearchonly': False, 'type': 'mandatory'} + Package: pkgconfig: {'basearchonly': False, 'type': 'mandatory'} + Package: ctags: {'basearchonly': False, 'type': 'default'} + Package: indent: {'basearchonly': False, 'type': 'default'} + Package: astyle: {'basearchonly': False, 'type': 'optional'} + Package: cmake: {'basearchonly': False, 'type': 'optional'} + Package: derelict-devel: {'basearchonly': False, 'type': 'optional'} + Package: geany: {'basearchonly': False, 'type': 'optional'} + Package: gl3n-devel: {'basearchonly': False, 'type': 'optional'} + Package: insight: {'basearchonly': False, 'type': 'optional'} + Package: nemiver: {'basearchonly': False, 'type': 'optional'} + Package: uncrustify: {'basearchonly': False, 'type': 'optional'} Group: design-suite (Design Suite) - Package: gimp-data-extras: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-dbp: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-dds-plugin: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-elsamuko: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-fourier-plugin: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-gap: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-help: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-help-browser: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-high-pass-filter: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-layer-via-copy-cut: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-lensfun: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-lqr-plugin: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-normalmap: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-paint-studio: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-resynthesizer: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-save-for-web: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-separate+: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimp-wavelet-denoise-plugin: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gimpfx-foundry: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: gmic-gimp: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: inkscape-psd: {'requires': u'inkscape', 'type': 'conditional', 'basearchonly': False} - Package: inkscape-sozi: {'requires': u'inkscape', 'type': 'conditional', 'basearchonly': False} - Package: inkscape-table: {'requires': u'inkscape', 'type': 'conditional', 'basearchonly': False} - Package: LuxRender-blender: {'requires': u'blender', 'type': 'conditional', 'basearchonly': False} - Package: sane-backends-drivers-scanners: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: xsane-gimp: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: YafaRay-blender: {'requires': u'blender', 'type': 'conditional', 'basearchonly': False} - Package: aajohan-comfortaa-fonts: {'type': 'default', 'basearchonly': False} - Package: adobe-source-sans-pro-fonts: {'type': 'default', 'basearchonly': False} - Package: astigmatic-grand-hotel-fonts: {'type': 'default', 'basearchonly': False} - Package: audacity: {'type': 'default', 'basearchonly': False} - Package: blender: {'type': 'default', 'basearchonly': False} - Package: campivisivi-titillium-fonts: {'type': 'default', 'basearchonly': False} - Package: colord-extra-profiles: {'type': 'default', 'basearchonly': False} - Package: darktable: {'type': 'default', 'basearchonly': False} - Package: dia: {'type': 'default', 'basearchonly': False} - Package: entangle: {'type': 'default', 'basearchonly': False} - Package: font-manager: {'type': 'default', 'basearchonly': False} - Package: fontforge: {'type': 'default', 'basearchonly': False} - Package: gimp: {'type': 'default', 'basearchonly': False} - Package: google-roboto-fonts: {'type': 'default', 'basearchonly': False} - Package: google-roboto-condensed-fonts: {'type': 'default', 'basearchonly': False} - Package: google-roboto-slab-fonts: {'type': 'default', 'basearchonly': False} - Package: gpick: {'type': 'default', 'basearchonly': False} - Package: GraphicsMagick: {'type': 'default', 'basearchonly': False} - Package: hugin: {'type': 'default', 'basearchonly': False} - Package: inkscape: {'type': 'default', 'basearchonly': False} - Package: julietaula-montserrat-fonts: {'type': 'default', 'basearchonly': False} - Package: krita: {'type': 'default', 'basearchonly': False} - Package: lato-fonts: {'type': 'default', 'basearchonly': False} - Package: mypaint: {'type': 'default', 'basearchonly': False} - Package: nautilus-image-converter: {'type': 'default', 'basearchonly': False} - Package: open-sans-fonts: {'type': 'default', 'basearchonly': False} - Package: optipng: {'type': 'default', 'basearchonly': False} - Package: overpass-fonts: {'type': 'default', 'basearchonly': False} - Package: pdfmod: {'type': 'default', 'basearchonly': False} - Package: pdfshuffler: {'type': 'default', 'basearchonly': False} - Package: phatch: {'type': 'default', 'basearchonly': False} - Package: pitivi: {'type': 'default', 'basearchonly': False} - Package: screenruler: {'type': 'default', 'basearchonly': False} - Package: scribus: {'type': 'default', 'basearchonly': False} - Package: shotwell: {'type': 'default', 'basearchonly': False} - Package: shutter: {'type': 'default', 'basearchonly': False} - Package: sparkleshare: {'type': 'default', 'basearchonly': False} - Package: synfigstudio: {'type': 'default', 'basearchonly': False} - Package: typetype-molot-fonts: {'type': 'default', 'basearchonly': False} - Package: xournal: {'type': 'default', 'basearchonly': False} - Package: calligra-karbon: {'type': 'optional', 'basearchonly': False} - Package: geeqie: {'type': 'optional', 'basearchonly': False} - Package: ImageMagick: {'type': 'optional', 'basearchonly': False} - Package: LuxRender: {'type': 'optional', 'basearchonly': False} - Package: openclipart: {'type': 'optional', 'basearchonly': False} - Package: pencil: {'type': 'optional', 'basearchonly': False} - Package: pngcrush: {'type': 'optional', 'basearchonly': False} - Package: rapid-photo-downloader: {'type': 'optional', 'basearchonly': False} - Package: YafaRay: {'type': 'optional', 'basearchonly': False} + Package: gimp-data-extras: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-dbp: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-dds-plugin: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-elsamuko: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-fourier-plugin: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-gap: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-help: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-help-browser: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-high-pass-filter: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-layer-via-copy-cut: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-lensfun: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-lqr-plugin: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-normalmap: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-paint-studio: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-resynthesizer: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-save-for-web: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-separate+: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimp-wavelet-denoise-plugin: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gimpfx-foundry: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: gmic-gimp: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: inkscape-psd: {'basearchonly': False, 'requires': 'inkscape', 'type': 'conditional'} + Package: inkscape-sozi: {'basearchonly': False, 'requires': 'inkscape', 'type': 'conditional'} + Package: inkscape-table: {'basearchonly': False, 'requires': 'inkscape', 'type': 'conditional'} + Package: LuxRender-blender: {'basearchonly': False, 'requires': 'blender', 'type': 'conditional'} + Package: sane-backends-drivers-scanners: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: xsane-gimp: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: YafaRay-blender: {'basearchonly': False, 'requires': 'blender', 'type': 'conditional'} + Package: aajohan-comfortaa-fonts: {'basearchonly': False, 'type': 'default'} + Package: adobe-source-sans-pro-fonts: {'basearchonly': False, 'type': 'default'} + Package: astigmatic-grand-hotel-fonts: {'basearchonly': False, 'type': 'default'} + Package: audacity: {'basearchonly': False, 'type': 'default'} + Package: blender: {'basearchonly': False, 'type': 'default'} + Package: campivisivi-titillium-fonts: {'basearchonly': False, 'type': 'default'} + Package: colord-extra-profiles: {'basearchonly': False, 'type': 'default'} + Package: darktable: {'basearchonly': False, 'type': 'default'} + Package: dia: {'basearchonly': False, 'type': 'default'} + Package: entangle: {'basearchonly': False, 'type': 'default'} + Package: font-manager: {'basearchonly': False, 'type': 'default'} + Package: fontforge: {'basearchonly': False, 'type': 'default'} + Package: gimp: {'basearchonly': False, 'type': 'default'} + Package: google-roboto-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-roboto-condensed-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-roboto-slab-fonts: {'basearchonly': False, 'type': 'default'} + Package: gpick: {'basearchonly': False, 'type': 'default'} + Package: GraphicsMagick: {'basearchonly': False, 'type': 'default'} + Package: hugin: {'basearchonly': False, 'type': 'default'} + Package: inkscape: {'basearchonly': False, 'type': 'default'} + Package: julietaula-montserrat-fonts: {'basearchonly': False, 'type': 'default'} + Package: krita: {'basearchonly': False, 'type': 'default'} + Package: lato-fonts: {'basearchonly': False, 'type': 'default'} + Package: mypaint: {'basearchonly': False, 'type': 'default'} + Package: nautilus-image-converter: {'basearchonly': False, 'type': 'default'} + Package: open-sans-fonts: {'basearchonly': False, 'type': 'default'} + Package: optipng: {'basearchonly': False, 'type': 'default'} + Package: overpass-fonts: {'basearchonly': False, 'type': 'default'} + Package: pdfmod: {'basearchonly': False, 'type': 'default'} + Package: pdfshuffler: {'basearchonly': False, 'type': 'default'} + Package: phatch: {'basearchonly': False, 'type': 'default'} + Package: pitivi: {'basearchonly': False, 'type': 'default'} + Package: screenruler: {'basearchonly': False, 'type': 'default'} + Package: scribus: {'basearchonly': False, 'type': 'default'} + Package: shotwell: {'basearchonly': False, 'type': 'default'} + Package: shutter: {'basearchonly': False, 'type': 'default'} + Package: sparkleshare: {'basearchonly': False, 'type': 'default'} + Package: synfigstudio: {'basearchonly': False, 'type': 'default'} + Package: typetype-molot-fonts: {'basearchonly': False, 'type': 'default'} + Package: xournal: {'basearchonly': False, 'type': 'default'} + Package: calligra-karbon: {'basearchonly': False, 'type': 'optional'} + Package: geeqie: {'basearchonly': False, 'type': 'optional'} + Package: ImageMagick: {'basearchonly': False, 'type': 'optional'} + Package: LuxRender: {'basearchonly': False, 'type': 'optional'} + Package: openclipart: {'basearchonly': False, 'type': 'optional'} + Package: pencil: {'basearchonly': False, 'type': 'optional'} + Package: pngcrush: {'basearchonly': False, 'type': 'optional'} + Package: rapid-photo-downloader: {'basearchonly': False, 'type': 'optional'} + Package: YafaRay: {'basearchonly': False, 'type': 'optional'} Group: development-libs (Development Libraries) - Package: bzip2-devel: {'type': 'mandatory', 'basearchonly': False} - Package: glibc-devel: {'type': 'mandatory', 'basearchonly': False} - Package: ncurses-devel: {'type': 'mandatory', 'basearchonly': False} - Package: pam-devel: {'type': 'mandatory', 'basearchonly': False} - Package: readline-devel: {'type': 'mandatory', 'basearchonly': False} - Package: zlib-devel: {'type': 'mandatory', 'basearchonly': False} - Package: binutils-devel: {'type': 'default', 'basearchonly': False} - Package: boost-devel: {'type': 'default', 'basearchonly': False} - Package: cyrus-sasl-devel: {'type': 'default', 'basearchonly': False} - Package: dbus-devel: {'type': 'default', 'basearchonly': False} - Package: gmp-devel: {'type': 'default', 'basearchonly': False} - Package: hesiod-devel: {'type': 'default', 'basearchonly': False} - Package: krb5-devel: {'type': 'default', 'basearchonly': False} - Package: libacl-devel: {'type': 'default', 'basearchonly': False} - Package: libattr-devel: {'type': 'default', 'basearchonly': False} - Package: libcap-devel: {'type': 'default', 'basearchonly': False} - Package: libcurl-devel: {'type': 'default', 'basearchonly': False} - Package: libdb-devel: {'type': 'default', 'basearchonly': False} - Package: libogg-devel: {'type': 'default', 'basearchonly': False} - Package: libselinux-devel: {'type': 'default', 'basearchonly': False} - Package: libuser-devel: {'type': 'default', 'basearchonly': False} - Package: libvorbis-devel: {'type': 'default', 'basearchonly': False} - Package: libxml2-devel: {'type': 'default', 'basearchonly': False} - Package: lockdev-devel: {'type': 'default', 'basearchonly': False} - Package: openldap-devel: {'type': 'default', 'basearchonly': False} - Package: openssl-devel: {'type': 'default', 'basearchonly': False} - Package: pciutils-devel: {'type': 'default', 'basearchonly': False} - Package: pcsc-lite-devel: {'type': 'default', 'basearchonly': False} - Package: perl-devel: {'type': 'default', 'basearchonly': False} - Package: python-devel: {'type': 'default', 'basearchonly': False} - Package: python-ldap: {'type': 'default', 'basearchonly': False} - Package: rpm-devel: {'type': 'default', 'basearchonly': False} - Package: slang-devel: {'type': 'default', 'basearchonly': False} - Package: check-devel: {'type': 'optional', 'basearchonly': False} - Package: coolkey-devel: {'type': 'optional', 'basearchonly': False} - Package: DSDP-devel: {'type': 'optional', 'basearchonly': False} - Package: expat-devel: {'type': 'optional', 'basearchonly': False} - Package: ffcall: {'type': 'optional', 'basearchonly': False} - Package: gdbm-devel: {'type': 'optional', 'basearchonly': False} - Package: geoclue-devel: {'type': 'optional', 'basearchonly': False} - Package: gf2x-devel: {'type': 'optional', 'basearchonly': False} - Package: givaro-devel: {'type': 'optional', 'basearchonly': False} - Package: gmp-ecm-devel: {'type': 'optional', 'basearchonly': False} - Package: gpm-devel: {'type': 'optional', 'basearchonly': False} - Package: gssdp-devel: {'type': 'optional', 'basearchonly': False} - Package: gupnp-devel: {'type': 'optional', 'basearchonly': False} - Package: gypsy-devel: {'type': 'optional', 'basearchonly': False} - Package: iml-devel: {'type': 'optional', 'basearchonly': False} - Package: lexertl-devel: {'type': 'optional', 'basearchonly': False} - Package: libdwarf-devel: {'type': 'optional', 'basearchonly': False} - Package: libedit-devel: {'type': 'optional', 'basearchonly': False} - Package: libusbx-devel: {'type': 'optional', 'basearchonly': False} - Package: linbox-devel: {'type': 'optional', 'basearchonly': False} - Package: m4ri-devel: {'type': 'optional', 'basearchonly': False} - Package: m4rie-devel: {'type': 'optional', 'basearchonly': False} - Package: mpir-devel: {'type': 'optional', 'basearchonly': False} - Package: newt-devel: {'type': 'optional', 'basearchonly': False} - Package: poco-devel: {'type': 'optional', 'basearchonly': False} - Package: poco-doc: {'type': 'optional', 'basearchonly': False} - Package: python-ZODB3-devel: {'type': 'optional', 'basearchonly': False} + Package: bzip2-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: glibc-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: ncurses-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: pam-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: readline-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: zlib-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: binutils-devel: {'basearchonly': False, 'type': 'default'} + Package: boost-devel: {'basearchonly': False, 'type': 'default'} + Package: cyrus-sasl-devel: {'basearchonly': False, 'type': 'default'} + Package: dbus-devel: {'basearchonly': False, 'type': 'default'} + Package: gmp-devel: {'basearchonly': False, 'type': 'default'} + Package: hesiod-devel: {'basearchonly': False, 'type': 'default'} + Package: krb5-devel: {'basearchonly': False, 'type': 'default'} + Package: libacl-devel: {'basearchonly': False, 'type': 'default'} + Package: libattr-devel: {'basearchonly': False, 'type': 'default'} + Package: libcap-devel: {'basearchonly': False, 'type': 'default'} + Package: libcurl-devel: {'basearchonly': False, 'type': 'default'} + Package: libdb-devel: {'basearchonly': False, 'type': 'default'} + Package: libogg-devel: {'basearchonly': False, 'type': 'default'} + Package: libselinux-devel: {'basearchonly': False, 'type': 'default'} + Package: libuser-devel: {'basearchonly': False, 'type': 'default'} + Package: libvorbis-devel: {'basearchonly': False, 'type': 'default'} + Package: libxml2-devel: {'basearchonly': False, 'type': 'default'} + Package: lockdev-devel: {'basearchonly': False, 'type': 'default'} + Package: openldap-devel: {'basearchonly': False, 'type': 'default'} + Package: openssl-devel: {'basearchonly': False, 'type': 'default'} + Package: pciutils-devel: {'basearchonly': False, 'type': 'default'} + Package: pcsc-lite-devel: {'basearchonly': False, 'type': 'default'} + Package: perl-devel: {'basearchonly': False, 'type': 'default'} + Package: python-devel: {'basearchonly': False, 'type': 'default'} + Package: python-ldap: {'basearchonly': False, 'type': 'default'} + Package: rpm-devel: {'basearchonly': False, 'type': 'default'} + Package: slang-devel: {'basearchonly': False, 'type': 'default'} + Package: check-devel: {'basearchonly': False, 'type': 'optional'} + Package: coolkey-devel: {'basearchonly': False, 'type': 'optional'} + Package: DSDP-devel: {'basearchonly': False, 'type': 'optional'} + Package: expat-devel: {'basearchonly': False, 'type': 'optional'} + Package: ffcall: {'basearchonly': False, 'type': 'optional'} + Package: gdbm-devel: {'basearchonly': False, 'type': 'optional'} + Package: geoclue-devel: {'basearchonly': False, 'type': 'optional'} + Package: gf2x-devel: {'basearchonly': False, 'type': 'optional'} + Package: givaro-devel: {'basearchonly': False, 'type': 'optional'} + Package: gmp-ecm-devel: {'basearchonly': False, 'type': 'optional'} + Package: gpm-devel: {'basearchonly': False, 'type': 'optional'} + Package: gssdp-devel: {'basearchonly': False, 'type': 'optional'} + Package: gupnp-devel: {'basearchonly': False, 'type': 'optional'} + Package: gypsy-devel: {'basearchonly': False, 'type': 'optional'} + Package: iml-devel: {'basearchonly': False, 'type': 'optional'} + Package: lexertl-devel: {'basearchonly': False, 'type': 'optional'} + Package: libdwarf-devel: {'basearchonly': False, 'type': 'optional'} + Package: libedit-devel: {'basearchonly': False, 'type': 'optional'} + Package: libusbx-devel: {'basearchonly': False, 'type': 'optional'} + Package: linbox-devel: {'basearchonly': False, 'type': 'optional'} + Package: m4ri-devel: {'basearchonly': False, 'type': 'optional'} + Package: m4rie-devel: {'basearchonly': False, 'type': 'optional'} + Package: mpir-devel: {'basearchonly': False, 'type': 'optional'} + Package: newt-devel: {'basearchonly': False, 'type': 'optional'} + Package: poco-devel: {'basearchonly': False, 'type': 'optional'} + Package: poco-doc: {'basearchonly': False, 'type': 'optional'} + Package: python-ZODB3-devel: {'basearchonly': False, 'type': 'optional'} Group: development-tools (Development Tools) - Package: gettext: {'type': 'mandatory', 'basearchonly': False} - Package: cvs: {'type': 'default', 'basearchonly': False} - Package: diffstat: {'type': 'default', 'basearchonly': False} - Package: doxygen: {'type': 'default', 'basearchonly': False} - Package: git: {'type': 'default', 'basearchonly': False} - Package: patch: {'type': 'default', 'basearchonly': False} - Package: patchutils: {'type': 'default', 'basearchonly': False} - Package: rcs: {'type': 'default', 'basearchonly': False} - Package: subversion: {'type': 'default', 'basearchonly': False} - Package: systemtap: {'type': 'default', 'basearchonly': False} - Package: archmage: {'type': 'optional', 'basearchonly': False} - Package: buildbot: {'type': 'optional', 'basearchonly': False} - Package: bzr: {'type': 'optional', 'basearchonly': False} - Package: colordiff: {'type': 'optional', 'basearchonly': False} - Package: cvs2cl: {'type': 'optional', 'basearchonly': False} - Package: cvsgraph: {'type': 'optional', 'basearchonly': False} - Package: cvsps: {'type': 'optional', 'basearchonly': False} - Package: darcs: {'type': 'optional', 'basearchonly': False} - Package: dejagnu: {'type': 'optional', 'basearchonly': False} - Package: expect: {'type': 'optional', 'basearchonly': False} - Package: gambas3-ide: {'type': 'optional', 'basearchonly': False} - Package: giggle: {'type': 'optional', 'basearchonly': False} - Package: git-annex: {'type': 'optional', 'basearchonly': False} - Package: git-cola: {'type': 'optional', 'basearchonly': False} - Package: git2cl: {'type': 'optional', 'basearchonly': False} - Package: gitg: {'type': 'optional', 'basearchonly': False} - Package: gtranslator: {'type': 'optional', 'basearchonly': False} - Package: highlight: {'type': 'optional', 'basearchonly': False} - Package: lcov: {'type': 'optional', 'basearchonly': False} - Package: manedit: {'type': 'optional', 'basearchonly': False} - Package: meld: {'type': 'optional', 'basearchonly': False} - Package: mercurial: {'type': 'optional', 'basearchonly': False} - Package: monotone: {'type': 'optional', 'basearchonly': False} - Package: mr: {'type': 'optional', 'basearchonly': False} - Package: nemiver: {'type': 'optional', 'basearchonly': False} - Package: qgit: {'type': 'optional', 'basearchonly': False} - Package: quilt: {'type': 'optional', 'basearchonly': False} - Package: rapidsvn: {'type': 'optional', 'basearchonly': False} - Package: robodoc: {'type': 'optional', 'basearchonly': False} - Package: scanmem: {'type': 'optional', 'basearchonly': False} - Package: subunit: {'type': 'optional', 'basearchonly': False} - Package: svn2cl: {'type': 'optional', 'basearchonly': False} - Package: tailor: {'type': 'optional', 'basearchonly': False} - Package: tig: {'type': 'optional', 'basearchonly': False} - Package: tkcvs: {'type': 'optional', 'basearchonly': False} - Package: tortoisehg: {'type': 'optional', 'basearchonly': False} - Package: translate-toolkit: {'type': 'optional', 'basearchonly': False} - Package: utrac: {'type': 'optional', 'basearchonly': False} + Package: gettext: {'basearchonly': False, 'type': 'mandatory'} + Package: cvs: {'basearchonly': False, 'type': 'default'} + Package: diffstat: {'basearchonly': False, 'type': 'default'} + Package: doxygen: {'basearchonly': False, 'type': 'default'} + Package: git: {'basearchonly': False, 'type': 'default'} + Package: patch: {'basearchonly': False, 'type': 'default'} + Package: patchutils: {'basearchonly': False, 'type': 'default'} + Package: rcs: {'basearchonly': False, 'type': 'default'} + Package: subversion: {'basearchonly': False, 'type': 'default'} + Package: systemtap: {'basearchonly': False, 'type': 'default'} + Package: archmage: {'basearchonly': False, 'type': 'optional'} + Package: buildbot: {'basearchonly': False, 'type': 'optional'} + Package: bzr: {'basearchonly': False, 'type': 'optional'} + Package: colordiff: {'basearchonly': False, 'type': 'optional'} + Package: cvs2cl: {'basearchonly': False, 'type': 'optional'} + Package: cvsgraph: {'basearchonly': False, 'type': 'optional'} + Package: cvsps: {'basearchonly': False, 'type': 'optional'} + Package: darcs: {'basearchonly': False, 'type': 'optional'} + Package: dejagnu: {'basearchonly': False, 'type': 'optional'} + Package: expect: {'basearchonly': False, 'type': 'optional'} + Package: gambas3-ide: {'basearchonly': False, 'type': 'optional'} + Package: giggle: {'basearchonly': False, 'type': 'optional'} + Package: git-annex: {'basearchonly': False, 'type': 'optional'} + Package: git-cola: {'basearchonly': False, 'type': 'optional'} + Package: git2cl: {'basearchonly': False, 'type': 'optional'} + Package: gitg: {'basearchonly': False, 'type': 'optional'} + Package: gtranslator: {'basearchonly': False, 'type': 'optional'} + Package: highlight: {'basearchonly': False, 'type': 'optional'} + Package: lcov: {'basearchonly': False, 'type': 'optional'} + Package: manedit: {'basearchonly': False, 'type': 'optional'} + Package: meld: {'basearchonly': False, 'type': 'optional'} + Package: mercurial: {'basearchonly': False, 'type': 'optional'} + Package: monotone: {'basearchonly': False, 'type': 'optional'} + Package: mr: {'basearchonly': False, 'type': 'optional'} + Package: nemiver: {'basearchonly': False, 'type': 'optional'} + Package: qgit: {'basearchonly': False, 'type': 'optional'} + Package: quilt: {'basearchonly': False, 'type': 'optional'} + Package: rapidsvn: {'basearchonly': False, 'type': 'optional'} + Package: robodoc: {'basearchonly': False, 'type': 'optional'} + Package: scanmem: {'basearchonly': False, 'type': 'optional'} + Package: subunit: {'basearchonly': False, 'type': 'optional'} + Package: svn2cl: {'basearchonly': False, 'type': 'optional'} + Package: tailor: {'basearchonly': False, 'type': 'optional'} + Package: tig: {'basearchonly': False, 'type': 'optional'} + Package: tkcvs: {'basearchonly': False, 'type': 'optional'} + Package: tortoisehg: {'basearchonly': False, 'type': 'optional'} + Package: translate-toolkit: {'basearchonly': False, 'type': 'optional'} + Package: utrac: {'basearchonly': False, 'type': 'optional'} Group: dial-up (Dial-up Networking Support) - Package: ppp: {'type': 'mandatory', 'basearchonly': False} - Package: isdn4k-utils: {'type': 'default', 'basearchonly': False} - Package: linux-atm: {'type': 'default', 'basearchonly': False} - Package: lrzsz: {'type': 'default', 'basearchonly': False} - Package: minicom: {'type': 'default', 'basearchonly': False} - Package: ModemManager: {'type': 'default', 'basearchonly': False} - Package: NetworkManager-adsl: {'type': 'default', 'basearchonly': False} - Package: rp-pppoe: {'type': 'default', 'basearchonly': False} - Package: wvdial: {'type': 'default', 'basearchonly': False} - Package: efax: {'type': 'optional', 'basearchonly': False} - Package: pptp: {'type': 'optional', 'basearchonly': False} - Package: statserial: {'type': 'optional', 'basearchonly': False} + Package: ppp: {'basearchonly': False, 'type': 'mandatory'} + Package: isdn4k-utils: {'basearchonly': False, 'type': 'default'} + Package: linux-atm: {'basearchonly': False, 'type': 'default'} + Package: lrzsz: {'basearchonly': False, 'type': 'default'} + Package: minicom: {'basearchonly': False, 'type': 'default'} + Package: ModemManager: {'basearchonly': False, 'type': 'default'} + Package: NetworkManager-adsl: {'basearchonly': False, 'type': 'default'} + Package: rp-pppoe: {'basearchonly': False, 'type': 'default'} + Package: wvdial: {'basearchonly': False, 'type': 'default'} + Package: efax: {'basearchonly': False, 'type': 'optional'} + Package: pptp: {'basearchonly': False, 'type': 'optional'} + Package: statserial: {'basearchonly': False, 'type': 'optional'} Group: directory-server (Directory Server) - Package: 389-admin-console: {'type': 'optional', 'basearchonly': False} - Package: 389-console: {'type': 'optional', 'basearchonly': False} - Package: 389-ds-base: {'type': 'optional', 'basearchonly': False} - Package: 389-ds-console: {'type': 'optional', 'basearchonly': False} - Package: 389-dsgw: {'type': 'optional', 'basearchonly': False} - Package: idm-console-framework: {'type': 'optional', 'basearchonly': False} - Package: krb5-server: {'type': 'optional', 'basearchonly': False} - Package: migrationtools: {'type': 'optional', 'basearchonly': False} - Package: openldap-servers: {'type': 'optional', 'basearchonly': False} - Package: samba: {'type': 'optional', 'basearchonly': False} - Package: ypserv: {'type': 'optional', 'basearchonly': False} + Package: 389-admin-console: {'basearchonly': False, 'type': 'optional'} + Package: 389-console: {'basearchonly': False, 'type': 'optional'} + Package: 389-ds-base: {'basearchonly': False, 'type': 'optional'} + Package: 389-ds-console: {'basearchonly': False, 'type': 'optional'} + Package: 389-dsgw: {'basearchonly': False, 'type': 'optional'} + Package: idm-console-framework: {'basearchonly': False, 'type': 'optional'} + Package: krb5-server: {'basearchonly': False, 'type': 'optional'} + Package: migrationtools: {'basearchonly': False, 'type': 'optional'} + Package: openldap-servers: {'basearchonly': False, 'type': 'optional'} + Package: samba: {'basearchonly': False, 'type': 'optional'} + Package: ypserv: {'basearchonly': False, 'type': 'optional'} Group: dns-server (DNS Name Server) - Package: bind-chroot: {'type': 'default', 'basearchonly': False} - Package: bind: {'type': 'optional', 'basearchonly': False} - Package: dnsperf: {'type': 'optional', 'basearchonly': False} - Package: ldns: {'type': 'optional', 'basearchonly': False} - Package: nsd: {'type': 'optional', 'basearchonly': False} - Package: pdns: {'type': 'optional', 'basearchonly': False} - Package: pdns-recursor: {'type': 'optional', 'basearchonly': False} - Package: rbldnsd: {'type': 'optional', 'basearchonly': False} - Package: unbound: {'type': 'optional', 'basearchonly': False} + Package: bind-chroot: {'basearchonly': False, 'type': 'default'} + Package: bind: {'basearchonly': False, 'type': 'optional'} + Package: dnsperf: {'basearchonly': False, 'type': 'optional'} + Package: ldns: {'basearchonly': False, 'type': 'optional'} + Package: nsd: {'basearchonly': False, 'type': 'optional'} + Package: pdns: {'basearchonly': False, 'type': 'optional'} + Package: pdns-recursor: {'basearchonly': False, 'type': 'optional'} + Package: rbldnsd: {'basearchonly': False, 'type': 'optional'} + Package: unbound: {'basearchonly': False, 'type': 'optional'} Group: dogri-support (Dogri Support) - Package: lohit-devanagari-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: samyak-devanagari-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: samyak-devanagari-fonts: {'basearchonly': False, 'type': 'default'} Group: dogtag (Dogtag Certificate System) - Package: pki-ca: {'type': 'mandatory', 'basearchonly': False} - Package: pki-console: {'type': 'default', 'basearchonly': False} - Package: pki-kra: {'type': 'default', 'basearchonly': False} - Package: pki-ocsp: {'type': 'default', 'basearchonly': False} - Package: pki-javadoc: {'type': 'optional', 'basearchonly': False} - Package: pki-tks: {'type': 'optional', 'basearchonly': False} - Package: pki-tps: {'type': 'optional', 'basearchonly': False} + Package: pki-ca: {'basearchonly': False, 'type': 'mandatory'} + Package: pki-console: {'basearchonly': False, 'type': 'default'} + Package: pki-kra: {'basearchonly': False, 'type': 'default'} + Package: pki-ocsp: {'basearchonly': False, 'type': 'default'} + Package: pki-javadoc: {'basearchonly': False, 'type': 'optional'} + Package: pki-tks: {'basearchonly': False, 'type': 'optional'} + Package: pki-tps: {'basearchonly': False, 'type': 'optional'} Group: domain-client (Domain Membership) - Package: adcli: {'type': 'mandatory', 'basearchonly': False} - Package: freeipa-client: {'type': 'mandatory', 'basearchonly': False} - Package: oddjob-mkhomedir: {'type': 'mandatory', 'basearchonly': False} - Package: samba-common-tools: {'type': 'mandatory', 'basearchonly': False} - Package: samba-winbind: {'type': 'mandatory', 'basearchonly': False} - Package: sssd: {'type': 'mandatory', 'basearchonly': False} + Package: adcli: {'basearchonly': False, 'type': 'mandatory'} + Package: freeipa-client: {'basearchonly': False, 'type': 'mandatory'} + Package: oddjob-mkhomedir: {'basearchonly': False, 'type': 'mandatory'} + Package: samba-common-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: samba-winbind: {'basearchonly': False, 'type': 'mandatory'} + Package: sssd: {'basearchonly': False, 'type': 'mandatory'} Group: eclipse (Fedora Eclipse) - Package: eclipse-cdt: {'type': 'mandatory', 'basearchonly': False} - Package: eclipse-jdt: {'type': 'mandatory', 'basearchonly': False} - Package: eclipse-changelog: {'type': 'default', 'basearchonly': False} - Package: eclipse-collabnet-merge: {'type': 'default', 'basearchonly': False} - Package: eclipse-dtp: {'type': 'default', 'basearchonly': False} - Package: eclipse-egit: {'type': 'default', 'basearchonly': False} - Package: eclipse-fedorapackager: {'type': 'default', 'basearchonly': False} - Package: eclipse-mpc: {'type': 'default', 'basearchonly': False} - Package: eclipse-mylyn: {'type': 'default', 'basearchonly': False} - Package: eclipse-mylyn-context-cdt: {'type': 'default', 'basearchonly': False} - Package: eclipse-mylyn-context-java: {'type': 'default', 'basearchonly': False} - Package: eclipse-mylyn-tasks-bugzilla: {'type': 'default', 'basearchonly': False} - Package: eclipse-mylyn-tasks-trac: {'type': 'default', 'basearchonly': False} - Package: eclipse-mylyn-tasks-web: {'type': 'default', 'basearchonly': False} - Package: eclipse-oprofile: {'type': 'default', 'basearchonly': False} - Package: eclipse-packagekit: {'type': 'default', 'basearchonly': False} - Package: eclipse-pde: {'type': 'default', 'basearchonly': False} - Package: eclipse-pydev: {'type': 'default', 'basearchonly': False} - Package: eclipse-rpm-editor: {'type': 'default', 'basearchonly': False} - Package: eclipse-subclipse: {'type': 'default', 'basearchonly': False} - Package: eclipse-valgrind: {'type': 'default', 'basearchonly': False} - Package: eclipse-dltk-ruby: {'type': 'optional', 'basearchonly': False} - Package: eclipse-dltk-tcl: {'type': 'optional', 'basearchonly': False} - Package: eclipse-eclemma: {'type': 'optional', 'basearchonly': False} - Package: eclipse-epic: {'type': 'optional', 'basearchonly': False} - Package: eclipse-findbugs: {'type': 'optional', 'basearchonly': False} - Package: eclipse-moreunit: {'type': 'optional', 'basearchonly': False} - Package: eclipse-mylyn-fedora-integration: {'type': 'optional', 'basearchonly': False} - Package: eclipse-photran: {'type': 'optional', 'basearchonly': False} - Package: eclipse-quickrex: {'type': 'optional', 'basearchonly': False} - Package: eclipse-rpmstubby: {'type': 'optional', 'basearchonly': False} - Package: eclipse-shelled: {'type': 'optional', 'basearchonly': False} - Package: eclipse-texlipse: {'type': 'optional', 'basearchonly': False} - Package: eclipse-veditor: {'type': 'optional', 'basearchonly': False} + Package: eclipse-cdt: {'basearchonly': False, 'type': 'mandatory'} + Package: eclipse-jdt: {'basearchonly': False, 'type': 'mandatory'} + Package: eclipse-changelog: {'basearchonly': False, 'type': 'default'} + Package: eclipse-collabnet-merge: {'basearchonly': False, 'type': 'default'} + Package: eclipse-dtp: {'basearchonly': False, 'type': 'default'} + Package: eclipse-egit: {'basearchonly': False, 'type': 'default'} + Package: eclipse-fedorapackager: {'basearchonly': False, 'type': 'default'} + Package: eclipse-mpc: {'basearchonly': False, 'type': 'default'} + Package: eclipse-mylyn: {'basearchonly': False, 'type': 'default'} + Package: eclipse-mylyn-context-cdt: {'basearchonly': False, 'type': 'default'} + Package: eclipse-mylyn-context-java: {'basearchonly': False, 'type': 'default'} + Package: eclipse-mylyn-tasks-bugzilla: {'basearchonly': False, 'type': 'default'} + Package: eclipse-mylyn-tasks-trac: {'basearchonly': False, 'type': 'default'} + Package: eclipse-mylyn-tasks-web: {'basearchonly': False, 'type': 'default'} + Package: eclipse-oprofile: {'basearchonly': False, 'type': 'default'} + Package: eclipse-packagekit: {'basearchonly': False, 'type': 'default'} + Package: eclipse-pde: {'basearchonly': False, 'type': 'default'} + Package: eclipse-pydev: {'basearchonly': False, 'type': 'default'} + Package: eclipse-rpm-editor: {'basearchonly': False, 'type': 'default'} + Package: eclipse-subclipse: {'basearchonly': False, 'type': 'default'} + Package: eclipse-valgrind: {'basearchonly': False, 'type': 'default'} + Package: eclipse-dltk-ruby: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-dltk-tcl: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-eclemma: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-epic: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-findbugs: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-moreunit: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-mylyn-fedora-integration: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-photran: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-quickrex: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-rpmstubby: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-shelled: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-texlipse: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-veditor: {'basearchonly': False, 'type': 'optional'} Group: editors (Editors) - Package: code-editor: {'type': 'optional', 'basearchonly': False} - Package: cssed: {'type': 'optional', 'basearchonly': False} - Package: emacs: {'type': 'optional', 'basearchonly': False} - Package: emacs-auctex: {'type': 'optional', 'basearchonly': False} - Package: emacs-bbdb: {'type': 'optional', 'basearchonly': False} - Package: emacs-ess: {'type': 'optional', 'basearchonly': False} - Package: emacs-vm: {'type': 'optional', 'basearchonly': False} - Package: geany: {'type': 'optional', 'basearchonly': False} - Package: gobby: {'type': 'optional', 'basearchonly': False} - Package: jed: {'type': 'optional', 'basearchonly': False} - Package: joe: {'type': 'optional', 'basearchonly': False} - Package: leafpad: {'type': 'optional', 'basearchonly': False} - Package: nedit: {'type': 'optional', 'basearchonly': False} - Package: poedit: {'type': 'optional', 'basearchonly': False} - Package: psgml: {'type': 'optional', 'basearchonly': False} - Package: vim-enhanced: {'type': 'optional', 'basearchonly': False} - Package: vim-X11: {'type': 'optional', 'basearchonly': False} - Package: xemacs: {'type': 'optional', 'basearchonly': False} - Package: xemacs-packages-base: {'type': 'optional', 'basearchonly': False} - Package: xemacs-packages-extra: {'type': 'optional', 'basearchonly': False} - Package: xemacs-xft: {'type': 'optional', 'basearchonly': False} - Package: xmlcopyeditor: {'type': 'optional', 'basearchonly': False} - Package: zile: {'type': 'optional', 'basearchonly': False} + Package: code-editor: {'basearchonly': False, 'type': 'optional'} + Package: cssed: {'basearchonly': False, 'type': 'optional'} + Package: emacs: {'basearchonly': False, 'type': 'optional'} + Package: emacs-auctex: {'basearchonly': False, 'type': 'optional'} + Package: emacs-bbdb: {'basearchonly': False, 'type': 'optional'} + Package: emacs-ess: {'basearchonly': False, 'type': 'optional'} + Package: emacs-vm: {'basearchonly': False, 'type': 'optional'} + Package: geany: {'basearchonly': False, 'type': 'optional'} + Package: gobby: {'basearchonly': False, 'type': 'optional'} + Package: jed: {'basearchonly': False, 'type': 'optional'} + Package: joe: {'basearchonly': False, 'type': 'optional'} + Package: leafpad: {'basearchonly': False, 'type': 'optional'} + Package: nedit: {'basearchonly': False, 'type': 'optional'} + Package: poedit: {'basearchonly': False, 'type': 'optional'} + Package: psgml: {'basearchonly': False, 'type': 'optional'} + Package: vim-enhanced: {'basearchonly': False, 'type': 'optional'} + Package: vim-X11: {'basearchonly': False, 'type': 'optional'} + Package: xemacs: {'basearchonly': False, 'type': 'optional'} + Package: xemacs-packages-base: {'basearchonly': False, 'type': 'optional'} + Package: xemacs-packages-extra: {'basearchonly': False, 'type': 'optional'} + Package: xemacs-xft: {'basearchonly': False, 'type': 'optional'} + Package: xmlcopyeditor: {'basearchonly': False, 'type': 'optional'} + Package: zile: {'basearchonly': False, 'type': 'optional'} Group: education (Educational Software) - Package: anki: {'type': 'optional', 'basearchonly': False} - Package: blinken: {'type': 'optional', 'basearchonly': False} - Package: cantor: {'type': 'optional', 'basearchonly': False} - Package: childsplay: {'type': 'optional', 'basearchonly': False} - Package: corrida: {'type': 'optional', 'basearchonly': False} - Package: drgeo: {'type': 'optional', 'basearchonly': False} - Package: drgeo-doc: {'type': 'optional', 'basearchonly': False} - Package: fantasdic: {'type': 'optional', 'basearchonly': False} - Package: gcompris: {'type': 'optional', 'basearchonly': False} - Package: genchemlab: {'type': 'optional', 'basearchonly': False} - Package: glglobe: {'type': 'optional', 'basearchonly': False} - Package: gtypist: {'type': 'optional', 'basearchonly': False} - Package: kalgebra: {'type': 'optional', 'basearchonly': False} - Package: kalzium: {'type': 'optional', 'basearchonly': False} - Package: kanagram: {'type': 'optional', 'basearchonly': False} - Package: kbruch: {'type': 'optional', 'basearchonly': False} - Package: kgeography: {'type': 'optional', 'basearchonly': False} - Package: khangman: {'type': 'optional', 'basearchonly': False} - Package: kig: {'type': 'optional', 'basearchonly': False} - Package: kiten: {'type': 'optional', 'basearchonly': False} - Package: klettres: {'type': 'optional', 'basearchonly': False} - Package: kmplot: {'type': 'optional', 'basearchonly': False} - Package: kstars: {'type': 'optional', 'basearchonly': False} - Package: ktouch: {'type': 'optional', 'basearchonly': False} - Package: kturtle: {'type': 'optional', 'basearchonly': False} - Package: kwordquiz: {'type': 'optional', 'basearchonly': False} - Package: marble: {'type': 'optional', 'basearchonly': False} - Package: mnemosyne: {'type': 'optional', 'basearchonly': False} - Package: moodle: {'type': 'optional', 'basearchonly': False} - Package: nightview: {'type': 'optional', 'basearchonly': False} - Package: pairs: {'type': 'optional', 'basearchonly': False} - Package: parley: {'type': 'optional', 'basearchonly': False} - Package: rocs: {'type': 'optional', 'basearchonly': False} - Package: saoimage: {'type': 'optional', 'basearchonly': False} - Package: skychart: {'type': 'optional', 'basearchonly': False} - Package: stellarium: {'type': 'optional', 'basearchonly': False} - Package: step: {'type': 'optional', 'basearchonly': False} - Package: tuxtype2: {'type': 'optional', 'basearchonly': False} - Package: vmpk: {'type': 'optional', 'basearchonly': False} + Package: anki: {'basearchonly': False, 'type': 'optional'} + Package: blinken: {'basearchonly': False, 'type': 'optional'} + Package: cantor: {'basearchonly': False, 'type': 'optional'} + Package: childsplay: {'basearchonly': False, 'type': 'optional'} + Package: corrida: {'basearchonly': False, 'type': 'optional'} + Package: drgeo: {'basearchonly': False, 'type': 'optional'} + Package: drgeo-doc: {'basearchonly': False, 'type': 'optional'} + Package: fantasdic: {'basearchonly': False, 'type': 'optional'} + Package: gcompris: {'basearchonly': False, 'type': 'optional'} + Package: genchemlab: {'basearchonly': False, 'type': 'optional'} + Package: glglobe: {'basearchonly': False, 'type': 'optional'} + Package: gtypist: {'basearchonly': False, 'type': 'optional'} + Package: kalgebra: {'basearchonly': False, 'type': 'optional'} + Package: kalzium: {'basearchonly': False, 'type': 'optional'} + Package: kanagram: {'basearchonly': False, 'type': 'optional'} + Package: kbruch: {'basearchonly': False, 'type': 'optional'} + Package: kgeography: {'basearchonly': False, 'type': 'optional'} + Package: khangman: {'basearchonly': False, 'type': 'optional'} + Package: kig: {'basearchonly': False, 'type': 'optional'} + Package: kiten: {'basearchonly': False, 'type': 'optional'} + Package: klettres: {'basearchonly': False, 'type': 'optional'} + Package: kmplot: {'basearchonly': False, 'type': 'optional'} + Package: kstars: {'basearchonly': False, 'type': 'optional'} + Package: ktouch: {'basearchonly': False, 'type': 'optional'} + Package: kturtle: {'basearchonly': False, 'type': 'optional'} + Package: kwordquiz: {'basearchonly': False, 'type': 'optional'} + Package: marble: {'basearchonly': False, 'type': 'optional'} + Package: mnemosyne: {'basearchonly': False, 'type': 'optional'} + Package: moodle: {'basearchonly': False, 'type': 'optional'} + Package: nightview: {'basearchonly': False, 'type': 'optional'} + Package: pairs: {'basearchonly': False, 'type': 'optional'} + Package: parley: {'basearchonly': False, 'type': 'optional'} + Package: rocs: {'basearchonly': False, 'type': 'optional'} + Package: saoimage: {'basearchonly': False, 'type': 'optional'} + Package: skychart: {'basearchonly': False, 'type': 'optional'} + Package: stellarium: {'basearchonly': False, 'type': 'optional'} + Package: step: {'basearchonly': False, 'type': 'optional'} + Package: tuxtype2: {'basearchonly': False, 'type': 'optional'} + Package: vmpk: {'basearchonly': False, 'type': 'optional'} Group: electronic-lab (Electronic Lab) - Package: acpica-tools: {'type': 'default', 'basearchonly': False} - Package: alliance: {'type': 'default', 'basearchonly': False} - Package: archimedes: {'type': 'default', 'basearchonly': False} - Package: arduino: {'type': 'default', 'basearchonly': False} - Package: avarice: {'type': 'default', 'basearchonly': False} - Package: avr-binutils: {'type': 'default', 'basearchonly': False} - Package: avr-gcc: {'type': 'default', 'basearchonly': False} - Package: avr-gcc-c++: {'type': 'default', 'basearchonly': False} - Package: avr-gdb: {'type': 'default', 'basearchonly': False} - Package: avra: {'type': 'default', 'basearchonly': False} - Package: avrdude: {'type': 'default', 'basearchonly': False} - Package: cgnslib: {'type': 'default', 'basearchonly': False} - Package: covered: {'type': 'default', 'basearchonly': False} - Package: CUnit: {'type': 'default', 'basearchonly': False} - Package: dfu-programmer: {'type': 'default', 'basearchonly': False} - Package: dgc: {'type': 'default', 'basearchonly': False} - Package: dia-CMOS: {'type': 'default', 'basearchonly': False} - Package: dia-Digital: {'type': 'default', 'basearchonly': False} - Package: dia-electric2: {'type': 'default', 'basearchonly': False} - Package: dia-electronic: {'type': 'default', 'basearchonly': False} - Package: dinotrace: {'type': 'default', 'basearchonly': False} - Package: drawtiming: {'type': 'default', 'basearchonly': False} - Package: eclipse-cdt: {'type': 'default', 'basearchonly': False} - Package: eclipse-dltk-tcl: {'type': 'default', 'basearchonly': False} - Package: eclipse-eclox: {'type': 'default', 'basearchonly': False} - Package: eclipse-epic: {'type': 'default', 'basearchonly': False} - Package: eclipse-subclipse: {'type': 'default', 'basearchonly': False} - Package: eclipse-texlipse: {'type': 'default', 'basearchonly': False} - Package: eclipse-veditor: {'type': 'default', 'basearchonly': False} - Package: electric: {'type': 'default', 'basearchonly': False} - Package: emacs-dinotrace: {'type': 'default', 'basearchonly': False} - Package: emacs-verilog-mode: {'type': 'default', 'basearchonly': False} - Package: emacs-vregs-mode: {'type': 'default', 'basearchonly': False} - Package: eqntott: {'type': 'default', 'basearchonly': False} - Package: espresso-ab: {'type': 'default', 'basearchonly': False} - Package: flterm: {'type': 'default', 'basearchonly': False} - Package: fped: {'type': 'default', 'basearchonly': False} - Package: freeDiameter: {'type': 'default', 'basearchonly': False} - Package: fritzing: {'type': 'default', 'basearchonly': False} - Package: gds2pov: {'type': 'default', 'basearchonly': False} - Package: geda-gaf: {'type': 'default', 'basearchonly': False} - Package: gerbv: {'type': 'default', 'basearchonly': False} - Package: ghc-chalmers-lava2000-devel: {'type': 'default', 'basearchonly': False} - Package: ghdl: {'type': 'default', 'basearchonly': False} - Package: gnucap: {'type': 'default', 'basearchonly': False} - Package: gnuradio: {'type': 'default', 'basearchonly': False} - Package: gnusim8085: {'type': 'default', 'basearchonly': False} - Package: gplcver: {'type': 'default', 'basearchonly': False} - Package: gpsim: {'type': 'default', 'basearchonly': False} - Package: gputils: {'type': 'default', 'basearchonly': False} - Package: gresistor: {'type': 'default', 'basearchonly': False} - Package: gr-osmosdr: {'type': 'default', 'basearchonly': False} - Package: gsim85: {'type': 'default', 'basearchonly': False} - Package: gspiceui: {'type': 'default', 'basearchonly': False} - Package: gtkterm: {'type': 'default', 'basearchonly': False} - Package: gtkwave: {'type': 'default', 'basearchonly': False} - Package: hct: {'type': 'default', 'basearchonly': False} - Package: hiredis: {'type': 'default', 'basearchonly': False} - Package: icaro: {'type': 'default', 'basearchonly': False} - Package: irsim: {'type': 'default', 'basearchonly': False} - Package: iverilog: {'type': 'default', 'basearchonly': False} - Package: kicad: {'type': 'default', 'basearchonly': False} - Package: ktechlab: {'type': 'default', 'basearchonly': False} - Package: LabPlot: {'type': 'default', 'basearchonly': False} - Package: linsmith: {'type': 'default', 'basearchonly': False} - Package: magic: {'type': 'default', 'basearchonly': False} - Package: magic-doc: {'type': 'default', 'basearchonly': False} - Package: mcu8051ide: {'type': 'default', 'basearchonly': False} - Package: mot-adms: {'type': 'default', 'basearchonly': False} - Package: nesc: {'type': 'default', 'basearchonly': False} - Package: netgen: {'type': 'default', 'basearchonly': False} - Package: ngspice: {'type': 'default', 'basearchonly': False} - Package: openocd: {'type': 'default', 'basearchonly': False} - Package: pcb: {'type': 'default', 'basearchonly': False} - Package: perl-Hardware-Verilog-Parser: {'type': 'default', 'basearchonly': False} - Package: perl-Hardware-Vhdl-Lexer: {'type': 'default', 'basearchonly': False} - Package: perl-Hardware-Vhdl-Parser: {'type': 'default', 'basearchonly': False} - Package: perl-Hardware-Vhdl-Tidy: {'type': 'default', 'basearchonly': False} - Package: perl-ModelSim-List: {'type': 'default', 'basearchonly': False} - Package: perl-Perlilog: {'type': 'default', 'basearchonly': False} - Package: perl-SystemC-Vregs: {'type': 'default', 'basearchonly': False} - Package: perl-SystemPerl: {'type': 'default', 'basearchonly': False} - Package: perl-Verilog-CodeGen: {'type': 'default', 'basearchonly': False} - Package: perl-Verilog-Perl: {'type': 'default', 'basearchonly': False} - Package: perl-Verilog-Readmem: {'type': 'default', 'basearchonly': False} - Package: pharosc: {'type': 'default', 'basearchonly': False} - Package: pharosc-alliance: {'type': 'default', 'basearchonly': False} - Package: pharosc-magic: {'type': 'default', 'basearchonly': False} - Package: pharosc-synopsys: {'type': 'default', 'basearchonly': False} - Package: pharosc-xcircuit: {'type': 'default', 'basearchonly': False} - Package: picocom: {'type': 'default', 'basearchonly': False} - Package: picprog: {'type': 'default', 'basearchonly': False} - Package: pikdev: {'type': 'default', 'basearchonly': False} - Package: piklab: {'type': 'default', 'basearchonly': False} - Package: pikloops: {'type': 'default', 'basearchonly': False} - Package: pulseview: {'type': 'default', 'basearchonly': False} - Package: python-myhdl: {'type': 'default', 'basearchonly': False} - Package: qtoctave: {'type': 'default', 'basearchonly': False} - Package: qucs: {'type': 'default', 'basearchonly': False} - Package: rtl-sdr: {'type': 'default', 'basearchonly': False} - Package: sdcc: {'type': 'default', 'basearchonly': False} - Package: sigrok-cli: {'type': 'default', 'basearchonly': False} - Package: sigrok-firmware-fx2lafw: {'type': 'default', 'basearchonly': False} - Package: sk2py: {'type': 'default', 'basearchonly': False} - Package: smartsim: {'type': 'default', 'basearchonly': False} - Package: srecord: {'type': 'default', 'basearchonly': False} - Package: tclspice: {'type': 'default', 'basearchonly': False} - Package: teal: {'type': 'default', 'basearchonly': False} - Package: tetex-IEEEtran: {'type': 'default', 'basearchonly': False} - Package: tkcvs: {'type': 'default', 'basearchonly': False} - Package: tkgate: {'type': 'default', 'basearchonly': False} - Package: toped: {'type': 'default', 'basearchonly': False} - Package: uisp: {'type': 'default', 'basearchonly': False} - Package: verilator: {'type': 'default', 'basearchonly': False} - Package: vhd2vl: {'type': 'default', 'basearchonly': False} - Package: vrq: {'type': 'default', 'basearchonly': False} - Package: xcircuit: {'type': 'default', 'basearchonly': False} - Package: xorg-x11-fonts-100dpi: {'type': 'default', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-1-100dpi: {'type': 'default', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-9-100dpi: {'type': 'default', 'basearchonly': False} - Package: xorg-x11-fonts-Type1: {'type': 'default', 'basearchonly': False} - Package: freehdl: {'type': 'optional', 'basearchonly': False} - Package: kdesvn: {'type': 'optional', 'basearchonly': False} - Package: minicom: {'type': 'optional', 'basearchonly': False} - Package: rfdump: {'type': 'optional', 'basearchonly': False} + Package: acpica-tools: {'basearchonly': False, 'type': 'default'} + Package: alliance: {'basearchonly': False, 'type': 'default'} + Package: archimedes: {'basearchonly': False, 'type': 'default'} + Package: arduino: {'basearchonly': False, 'type': 'default'} + Package: avarice: {'basearchonly': False, 'type': 'default'} + Package: avr-binutils: {'basearchonly': False, 'type': 'default'} + Package: avr-gcc: {'basearchonly': False, 'type': 'default'} + Package: avr-gcc-c++: {'basearchonly': False, 'type': 'default'} + Package: avr-gdb: {'basearchonly': False, 'type': 'default'} + Package: avra: {'basearchonly': False, 'type': 'default'} + Package: avrdude: {'basearchonly': False, 'type': 'default'} + Package: cgnslib: {'basearchonly': False, 'type': 'default'} + Package: covered: {'basearchonly': False, 'type': 'default'} + Package: CUnit: {'basearchonly': False, 'type': 'default'} + Package: dfu-programmer: {'basearchonly': False, 'type': 'default'} + Package: dgc: {'basearchonly': False, 'type': 'default'} + Package: dia-CMOS: {'basearchonly': False, 'type': 'default'} + Package: dia-Digital: {'basearchonly': False, 'type': 'default'} + Package: dia-electric2: {'basearchonly': False, 'type': 'default'} + Package: dia-electronic: {'basearchonly': False, 'type': 'default'} + Package: dinotrace: {'basearchonly': False, 'type': 'default'} + Package: drawtiming: {'basearchonly': False, 'type': 'default'} + Package: eclipse-cdt: {'basearchonly': False, 'type': 'default'} + Package: eclipse-dltk-tcl: {'basearchonly': False, 'type': 'default'} + Package: eclipse-eclox: {'basearchonly': False, 'type': 'default'} + Package: eclipse-epic: {'basearchonly': False, 'type': 'default'} + Package: eclipse-subclipse: {'basearchonly': False, 'type': 'default'} + Package: eclipse-texlipse: {'basearchonly': False, 'type': 'default'} + Package: eclipse-veditor: {'basearchonly': False, 'type': 'default'} + Package: electric: {'basearchonly': False, 'type': 'default'} + Package: emacs-dinotrace: {'basearchonly': False, 'type': 'default'} + Package: emacs-verilog-mode: {'basearchonly': False, 'type': 'default'} + Package: emacs-vregs-mode: {'basearchonly': False, 'type': 'default'} + Package: eqntott: {'basearchonly': False, 'type': 'default'} + Package: espresso-ab: {'basearchonly': False, 'type': 'default'} + Package: flterm: {'basearchonly': False, 'type': 'default'} + Package: fped: {'basearchonly': False, 'type': 'default'} + Package: freeDiameter: {'basearchonly': False, 'type': 'default'} + Package: fritzing: {'basearchonly': False, 'type': 'default'} + Package: gds2pov: {'basearchonly': False, 'type': 'default'} + Package: geda-gaf: {'basearchonly': False, 'type': 'default'} + Package: gerbv: {'basearchonly': False, 'type': 'default'} + Package: ghc-chalmers-lava2000-devel: {'basearchonly': False, 'type': 'default'} + Package: ghdl: {'basearchonly': False, 'type': 'default'} + Package: gnucap: {'basearchonly': False, 'type': 'default'} + Package: gnuradio: {'basearchonly': False, 'type': 'default'} + Package: gnusim8085: {'basearchonly': False, 'type': 'default'} + Package: gplcver: {'basearchonly': False, 'type': 'default'} + Package: gpsim: {'basearchonly': False, 'type': 'default'} + Package: gputils: {'basearchonly': False, 'type': 'default'} + Package: gresistor: {'basearchonly': False, 'type': 'default'} + Package: gr-osmosdr: {'basearchonly': False, 'type': 'default'} + Package: gsim85: {'basearchonly': False, 'type': 'default'} + Package: gspiceui: {'basearchonly': False, 'type': 'default'} + Package: gtkterm: {'basearchonly': False, 'type': 'default'} + Package: gtkwave: {'basearchonly': False, 'type': 'default'} + Package: hct: {'basearchonly': False, 'type': 'default'} + Package: hiredis: {'basearchonly': False, 'type': 'default'} + Package: icaro: {'basearchonly': False, 'type': 'default'} + Package: irsim: {'basearchonly': False, 'type': 'default'} + Package: iverilog: {'basearchonly': False, 'type': 'default'} + Package: kicad: {'basearchonly': False, 'type': 'default'} + Package: ktechlab: {'basearchonly': False, 'type': 'default'} + Package: LabPlot: {'basearchonly': False, 'type': 'default'} + Package: linsmith: {'basearchonly': False, 'type': 'default'} + Package: magic: {'basearchonly': False, 'type': 'default'} + Package: magic-doc: {'basearchonly': False, 'type': 'default'} + Package: mcu8051ide: {'basearchonly': False, 'type': 'default'} + Package: mot-adms: {'basearchonly': False, 'type': 'default'} + Package: nesc: {'basearchonly': False, 'type': 'default'} + Package: netgen: {'basearchonly': False, 'type': 'default'} + Package: ngspice: {'basearchonly': False, 'type': 'default'} + Package: openocd: {'basearchonly': False, 'type': 'default'} + Package: pcb: {'basearchonly': False, 'type': 'default'} + Package: perl-Hardware-Verilog-Parser: {'basearchonly': False, 'type': 'default'} + Package: perl-Hardware-Vhdl-Lexer: {'basearchonly': False, 'type': 'default'} + Package: perl-Hardware-Vhdl-Parser: {'basearchonly': False, 'type': 'default'} + Package: perl-Hardware-Vhdl-Tidy: {'basearchonly': False, 'type': 'default'} + Package: perl-ModelSim-List: {'basearchonly': False, 'type': 'default'} + Package: perl-Perlilog: {'basearchonly': False, 'type': 'default'} + Package: perl-SystemC-Vregs: {'basearchonly': False, 'type': 'default'} + Package: perl-SystemPerl: {'basearchonly': False, 'type': 'default'} + Package: perl-Verilog-CodeGen: {'basearchonly': False, 'type': 'default'} + Package: perl-Verilog-Perl: {'basearchonly': False, 'type': 'default'} + Package: perl-Verilog-Readmem: {'basearchonly': False, 'type': 'default'} + Package: pharosc: {'basearchonly': False, 'type': 'default'} + Package: pharosc-alliance: {'basearchonly': False, 'type': 'default'} + Package: pharosc-magic: {'basearchonly': False, 'type': 'default'} + Package: pharosc-synopsys: {'basearchonly': False, 'type': 'default'} + Package: pharosc-xcircuit: {'basearchonly': False, 'type': 'default'} + Package: picocom: {'basearchonly': False, 'type': 'default'} + Package: picprog: {'basearchonly': False, 'type': 'default'} + Package: pikdev: {'basearchonly': False, 'type': 'default'} + Package: piklab: {'basearchonly': False, 'type': 'default'} + Package: pikloops: {'basearchonly': False, 'type': 'default'} + Package: pulseview: {'basearchonly': False, 'type': 'default'} + Package: python-myhdl: {'basearchonly': False, 'type': 'default'} + Package: qtoctave: {'basearchonly': False, 'type': 'default'} + Package: qucs: {'basearchonly': False, 'type': 'default'} + Package: rtl-sdr: {'basearchonly': False, 'type': 'default'} + Package: sdcc: {'basearchonly': False, 'type': 'default'} + Package: sigrok-cli: {'basearchonly': False, 'type': 'default'} + Package: sigrok-firmware-fx2lafw: {'basearchonly': False, 'type': 'default'} + Package: sk2py: {'basearchonly': False, 'type': 'default'} + Package: smartsim: {'basearchonly': False, 'type': 'default'} + Package: srecord: {'basearchonly': False, 'type': 'default'} + Package: tclspice: {'basearchonly': False, 'type': 'default'} + Package: teal: {'basearchonly': False, 'type': 'default'} + Package: tetex-IEEEtran: {'basearchonly': False, 'type': 'default'} + Package: tkcvs: {'basearchonly': False, 'type': 'default'} + Package: tkgate: {'basearchonly': False, 'type': 'default'} + Package: toped: {'basearchonly': False, 'type': 'default'} + Package: uisp: {'basearchonly': False, 'type': 'default'} + Package: verilator: {'basearchonly': False, 'type': 'default'} + Package: vhd2vl: {'basearchonly': False, 'type': 'default'} + Package: vrq: {'basearchonly': False, 'type': 'default'} + Package: xcircuit: {'basearchonly': False, 'type': 'default'} + Package: xorg-x11-fonts-100dpi: {'basearchonly': False, 'type': 'default'} + Package: xorg-x11-fonts-ISO8859-1-100dpi: {'basearchonly': False, 'type': 'default'} + Package: xorg-x11-fonts-ISO8859-9-100dpi: {'basearchonly': False, 'type': 'default'} + Package: xorg-x11-fonts-Type1: {'basearchonly': False, 'type': 'default'} + Package: freehdl: {'basearchonly': False, 'type': 'optional'} + Package: kdesvn: {'basearchonly': False, 'type': 'optional'} + Package: minicom: {'basearchonly': False, 'type': 'optional'} + Package: rfdump: {'basearchonly': False, 'type': 'optional'} Group: engineering-and-scientific (Engineering and Scientific) - Package: gnuplot: {'type': 'mandatory', 'basearchonly': False} - Package: gsl: {'type': 'mandatory', 'basearchonly': False} - Package: gsl-devel: {'type': 'mandatory', 'basearchonly': False} - Package: maxima: {'type': 'mandatory', 'basearchonly': False} - Package: octave: {'type': 'mandatory', 'basearchonly': False} - Package: python2-matplotlib: {'type': 'mandatory', 'basearchonly': False} - Package: python2-scipy: {'type': 'mandatory', 'basearchonly': False} - Package: R: {'type': 'mandatory', 'basearchonly': False} - Package: speedcrunch: {'type': 'mandatory', 'basearchonly': False} - Package: texmaker: {'type': 'mandatory', 'basearchonly': False} - Package: transfig: {'type': 'mandatory', 'basearchonly': False} - Package: units: {'type': 'mandatory', 'basearchonly': False} - Package: wxMaxima: {'type': 'mandatory', 'basearchonly': False} - Package: xfig: {'type': 'mandatory', 'basearchonly': False} - Package: 4ti2: {'type': 'optional', 'basearchonly': False} - Package: alt-ergo: {'type': 'optional', 'basearchonly': False} - Package: alt-ergo-gui: {'type': 'optional', 'basearchonly': False} - Package: atlas: {'type': 'optional', 'basearchonly': False} - Package: automaton: {'type': 'optional', 'basearchonly': False} - Package: automaton-javadoc: {'type': 'optional', 'basearchonly': False} - Package: azove: {'type': 'optional', 'basearchonly': False} - Package: blas: {'type': 'optional', 'basearchonly': False} - Package: bliss: {'type': 'optional', 'basearchonly': False} - Package: bowtie: {'type': 'optional', 'basearchonly': False} - Package: brial: {'type': 'optional', 'basearchonly': False} - Package: bwa: {'type': 'optional', 'basearchonly': False} - Package: cantor: {'type': 'optional', 'basearchonly': False} - Package: cantor-R: {'type': 'optional', 'basearchonly': False} - Package: cddlib: {'type': 'optional', 'basearchonly': False} - Package: chemtool: {'type': 'optional', 'basearchonly': False} - Package: coq: {'type': 'optional', 'basearchonly': False} - Package: coq-coqide: {'type': 'optional', 'basearchonly': False} - Package: coq-doc: {'type': 'optional', 'basearchonly': False} - Package: coq-emacs: {'type': 'optional', 'basearchonly': False} - Package: cryptominisat: {'type': 'optional', 'basearchonly': False} - Package: csdp: {'type': 'optional', 'basearchonly': False} - Package: csdp-tools: {'type': 'optional', 'basearchonly': False} - Package: cudd: {'type': 'optional', 'basearchonly': False} - Package: cudd-devel: {'type': 'optional', 'basearchonly': False} - Package: cvc3: {'type': 'optional', 'basearchonly': False} - Package: cvc3-devel: {'type': 'optional', 'basearchonly': False} - Package: cvc3-doc: {'type': 'optional', 'basearchonly': False} - Package: cvc3-emacs: {'type': 'optional', 'basearchonly': False} - Package: cvc3-xemacs: {'type': 'optional', 'basearchonly': False} - Package: cvc4: {'type': 'optional', 'basearchonly': False} - Package: dx: {'type': 'optional', 'basearchonly': False} - Package: dx-samples: {'type': 'optional', 'basearchonly': False} - Package: E: {'type': 'optional', 'basearchonly': False} - Package: eclib: {'type': 'optional', 'basearchonly': False} - Package: EMBOSS: {'type': 'optional', 'basearchonly': False} - Package: fastx_toolkit: {'type': 'optional', 'basearchonly': False} - Package: fflas-ffpack-devel: {'type': 'optional', 'basearchonly': False} - Package: flint: {'type': 'optional', 'basearchonly': False} - Package: flocq: {'type': 'optional', 'basearchonly': False} - Package: frama-c: {'type': 'optional', 'basearchonly': False} - Package: freefem++: {'type': 'optional', 'basearchonly': False} - Package: gabedit: {'type': 'optional', 'basearchonly': False} - Package: galculator: {'type': 'optional', 'basearchonly': False} - Package: gap: {'type': 'optional', 'basearchonly': False} - Package: gappa: {'type': 'optional', 'basearchonly': False} - Package: gappalib-coq: {'type': 'optional', 'basearchonly': False} - Package: gdl: {'type': 'optional', 'basearchonly': False} - Package: genius: {'type': 'optional', 'basearchonly': False} - Package: genus2reduction: {'type': 'optional', 'basearchonly': False} - Package: geomview: {'type': 'optional', 'basearchonly': False} - Package: gfan: {'type': 'optional', 'basearchonly': False} - Package: ginac: {'type': 'optional', 'basearchonly': False} - Package: glimmer: {'type': 'optional', 'basearchonly': False} - Package: GMT: {'type': 'optional', 'basearchonly': False} - Package: GMT-coastlines-full: {'type': 'optional', 'basearchonly': False} - Package: GMT-coastlines-high: {'type': 'optional', 'basearchonly': False} - Package: GMT-doc: {'type': 'optional', 'basearchonly': False} - Package: gnome-chemistry-utils: {'type': 'optional', 'basearchonly': False} - Package: gpredict: {'type': 'optional', 'basearchonly': False} - Package: grace: {'type': 'optional', 'basearchonly': False} - Package: grads: {'type': 'optional', 'basearchonly': False} - Package: gridengine: {'type': 'optional', 'basearchonly': False} - Package: gromacs: {'type': 'optional', 'basearchonly': False} - Package: gromacs-openmpi: {'type': 'optional', 'basearchonly': False} - Package: gts: {'type': 'optional', 'basearchonly': False} - Package: hdf: {'type': 'optional', 'basearchonly': False} - Package: hdf5: {'type': 'optional', 'basearchonly': False} - Package: hmmer: {'type': 'optional', 'basearchonly': False} - Package: jmol: {'type': 'optional', 'basearchonly': False} - Package: jnormaliz: {'type': 'optional', 'basearchonly': False} - Package: kpolynome: {'type': 'optional', 'basearchonly': False} - Package: kst: {'type': 'optional', 'basearchonly': False} - Package: lagan: {'type': 'optional', 'basearchonly': False} - Package: lapack: {'type': 'optional', 'basearchonly': False} - Package: latte-integrale: {'type': 'optional', 'basearchonly': False} - Package: libctl: {'type': 'optional', 'basearchonly': False} - Package: libmatheval: {'type': 'optional', 'basearchonly': False} - Package: libtcd: {'type': 'optional', 'basearchonly': False} - Package: linbox: {'type': 'optional', 'basearchonly': False} - Package: ltl2ba: {'type': 'optional', 'basearchonly': False} - Package: Macaulay2: {'type': 'optional', 'basearchonly': False} - Package: malaga: {'type': 'optional', 'basearchonly': False} - Package: maxima-gui: {'type': 'optional', 'basearchonly': False} - Package: meataxe: {'type': 'optional', 'basearchonly': False} - Package: minisat2: {'type': 'optional', 'basearchonly': False} - Package: mona: {'type': 'optional', 'basearchonly': False} - Package: mona-devel: {'type': 'optional', 'basearchonly': False} - Package: mona-emacs: {'type': 'optional', 'basearchonly': False} - Package: mona-examples: {'type': 'optional', 'basearchonly': False} - Package: mona-xemacs: {'type': 'optional', 'basearchonly': False} - Package: mpfi: {'type': 'optional', 'basearchonly': False} - Package: ncl: {'type': 'optional', 'basearchonly': False} - Package: nco: {'type': 'optional', 'basearchonly': False} - Package: ncview: {'type': 'optional', 'basearchonly': False} - Package: netcdf: {'type': 'optional', 'basearchonly': False} - Package: normaliz: {'type': 'optional', 'basearchonly': False} - Package: openbabel: {'type': 'optional', 'basearchonly': False} - Package: opencv: {'type': 'optional', 'basearchonly': False} - Package: paraview: {'type': 'optional', 'basearchonly': False} - Package: picosat: {'type': 'optional', 'basearchonly': False} - Package: picosat-devel: {'type': 'optional', 'basearchonly': False} - Package: plotutils: {'type': 'optional', 'basearchonly': False} - Package: polybori: {'type': 'optional', 'basearchonly': False} - Package: polybori-gui: {'type': 'optional', 'basearchonly': False} - Package: polybori-ipbori: {'type': 'optional', 'basearchonly': False} - Package: polymake: {'type': 'optional', 'basearchonly': False} - Package: pvs-sbcl: {'type': 'optional', 'basearchonly': False} - Package: pypop: {'type': 'optional', 'basearchonly': False} - Package: python2-biopython: {'type': 'optional', 'basearchonly': False} - Package: python2-cvxopt: {'type': 'optional', 'basearchonly': False} - Package: python2-networkx: {'type': 'optional', 'basearchonly': False} - Package: python2-theano: {'type': 'optional', 'basearchonly': False} - Package: qalculate-gtk: {'type': 'optional', 'basearchonly': False} - Package: qalculate-kde: {'type': 'optional', 'basearchonly': False} - Package: qepcad-B: {'type': 'optional', 'basearchonly': False} - Package: qtoctave: {'type': 'optional', 'basearchonly': False} - Package: root: {'type': 'optional', 'basearchonly': False} - Package: routino: {'type': 'optional', 'basearchonly': False} - Package: rrdtool: {'type': 'optional', 'basearchonly': False} - Package: seaview: {'type': 'optional', 'basearchonly': False} - Package: sextractor: {'type': 'optional', 'basearchonly': False} - Package: SIBsim4: {'type': 'optional', 'basearchonly': False} - Package: stix-math-fonts: {'type': 'optional', 'basearchonly': False} - Package: stp: {'type': 'optional', 'basearchonly': False} - Package: symmetrica: {'type': 'optional', 'basearchonly': False} - Package: sympy: {'type': 'optional', 'basearchonly': False} - Package: tcd-utils: {'type': 'optional', 'basearchonly': False} - Package: TeXmacs: {'type': 'optional', 'basearchonly': False} - Package: tgif: {'type': 'optional', 'basearchonly': False} - Package: tideEditor: {'type': 'optional', 'basearchonly': False} - Package: TOPCOM: {'type': 'optional', 'basearchonly': False} - Package: vaspview: {'type': 'optional', 'basearchonly': False} - Package: veusz: {'type': 'optional', 'basearchonly': False} - Package: vinci: {'type': 'optional', 'basearchonly': False} - Package: wgrib: {'type': 'optional', 'basearchonly': False} - Package: wgrib2: {'type': 'optional', 'basearchonly': False} - Package: why: {'type': 'optional', 'basearchonly': False} - Package: why3: {'type': 'optional', 'basearchonly': False} - Package: wise2: {'type': 'optional', 'basearchonly': False} - Package: wvs-data: {'type': 'optional', 'basearchonly': False} - Package: xdrawchem: {'type': 'optional', 'basearchonly': False} - Package: xgap: {'type': 'optional', 'basearchonly': False} - Package: xtide: {'type': 'optional', 'basearchonly': False} - Package: zenon: {'type': 'optional', 'basearchonly': False} + Package: gnuplot: {'basearchonly': False, 'type': 'mandatory'} + Package: gsl: {'basearchonly': False, 'type': 'mandatory'} + Package: gsl-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: maxima: {'basearchonly': False, 'type': 'mandatory'} + Package: octave: {'basearchonly': False, 'type': 'mandatory'} + Package: python2-matplotlib: {'basearchonly': False, 'type': 'mandatory'} + Package: python2-scipy: {'basearchonly': False, 'type': 'mandatory'} + Package: R: {'basearchonly': False, 'type': 'mandatory'} + Package: speedcrunch: {'basearchonly': False, 'type': 'mandatory'} + Package: texmaker: {'basearchonly': False, 'type': 'mandatory'} + Package: transfig: {'basearchonly': False, 'type': 'mandatory'} + Package: units: {'basearchonly': False, 'type': 'mandatory'} + Package: wxMaxima: {'basearchonly': False, 'type': 'mandatory'} + Package: xfig: {'basearchonly': False, 'type': 'mandatory'} + Package: 4ti2: {'basearchonly': False, 'type': 'optional'} + Package: alt-ergo: {'basearchonly': False, 'type': 'optional'} + Package: alt-ergo-gui: {'basearchonly': False, 'type': 'optional'} + Package: atlas: {'basearchonly': False, 'type': 'optional'} + Package: automaton: {'basearchonly': False, 'type': 'optional'} + Package: automaton-javadoc: {'basearchonly': False, 'type': 'optional'} + Package: azove: {'basearchonly': False, 'type': 'optional'} + Package: blas: {'basearchonly': False, 'type': 'optional'} + Package: bliss: {'basearchonly': False, 'type': 'optional'} + Package: bowtie: {'basearchonly': False, 'type': 'optional'} + Package: brial: {'basearchonly': False, 'type': 'optional'} + Package: bwa: {'basearchonly': False, 'type': 'optional'} + Package: cantor: {'basearchonly': False, 'type': 'optional'} + Package: cantor-R: {'basearchonly': False, 'type': 'optional'} + Package: cddlib: {'basearchonly': False, 'type': 'optional'} + Package: chemtool: {'basearchonly': False, 'type': 'optional'} + Package: coq: {'basearchonly': False, 'type': 'optional'} + Package: coq-coqide: {'basearchonly': False, 'type': 'optional'} + Package: coq-doc: {'basearchonly': False, 'type': 'optional'} + Package: coq-emacs: {'basearchonly': False, 'type': 'optional'} + Package: cryptominisat: {'basearchonly': False, 'type': 'optional'} + Package: csdp: {'basearchonly': False, 'type': 'optional'} + Package: csdp-tools: {'basearchonly': False, 'type': 'optional'} + Package: cudd: {'basearchonly': False, 'type': 'optional'} + Package: cudd-devel: {'basearchonly': False, 'type': 'optional'} + Package: cvc3: {'basearchonly': False, 'type': 'optional'} + Package: cvc3-devel: {'basearchonly': False, 'type': 'optional'} + Package: cvc3-doc: {'basearchonly': False, 'type': 'optional'} + Package: cvc3-emacs: {'basearchonly': False, 'type': 'optional'} + Package: cvc3-xemacs: {'basearchonly': False, 'type': 'optional'} + Package: cvc4: {'basearchonly': False, 'type': 'optional'} + Package: dx: {'basearchonly': False, 'type': 'optional'} + Package: dx-samples: {'basearchonly': False, 'type': 'optional'} + Package: E: {'basearchonly': False, 'type': 'optional'} + Package: eclib: {'basearchonly': False, 'type': 'optional'} + Package: EMBOSS: {'basearchonly': False, 'type': 'optional'} + Package: fastx_toolkit: {'basearchonly': False, 'type': 'optional'} + Package: fflas-ffpack-devel: {'basearchonly': False, 'type': 'optional'} + Package: flint: {'basearchonly': False, 'type': 'optional'} + Package: flocq: {'basearchonly': False, 'type': 'optional'} + Package: frama-c: {'basearchonly': False, 'type': 'optional'} + Package: freefem++: {'basearchonly': False, 'type': 'optional'} + Package: gabedit: {'basearchonly': False, 'type': 'optional'} + Package: galculator: {'basearchonly': False, 'type': 'optional'} + Package: gap: {'basearchonly': False, 'type': 'optional'} + Package: gappa: {'basearchonly': False, 'type': 'optional'} + Package: gappalib-coq: {'basearchonly': False, 'type': 'optional'} + Package: gdl: {'basearchonly': False, 'type': 'optional'} + Package: genius: {'basearchonly': False, 'type': 'optional'} + Package: genus2reduction: {'basearchonly': False, 'type': 'optional'} + Package: geomview: {'basearchonly': False, 'type': 'optional'} + Package: gfan: {'basearchonly': False, 'type': 'optional'} + Package: ginac: {'basearchonly': False, 'type': 'optional'} + Package: glimmer: {'basearchonly': False, 'type': 'optional'} + Package: GMT: {'basearchonly': False, 'type': 'optional'} + Package: GMT-coastlines-full: {'basearchonly': False, 'type': 'optional'} + Package: GMT-coastlines-high: {'basearchonly': False, 'type': 'optional'} + Package: GMT-doc: {'basearchonly': False, 'type': 'optional'} + Package: gnome-chemistry-utils: {'basearchonly': False, 'type': 'optional'} + Package: gpredict: {'basearchonly': False, 'type': 'optional'} + Package: grace: {'basearchonly': False, 'type': 'optional'} + Package: grads: {'basearchonly': False, 'type': 'optional'} + Package: gridengine: {'basearchonly': False, 'type': 'optional'} + Package: gromacs: {'basearchonly': False, 'type': 'optional'} + Package: gromacs-openmpi: {'basearchonly': False, 'type': 'optional'} + Package: gts: {'basearchonly': False, 'type': 'optional'} + Package: hdf: {'basearchonly': False, 'type': 'optional'} + Package: hdf5: {'basearchonly': False, 'type': 'optional'} + Package: hmmer: {'basearchonly': False, 'type': 'optional'} + Package: jmol: {'basearchonly': False, 'type': 'optional'} + Package: jnormaliz: {'basearchonly': False, 'type': 'optional'} + Package: kpolynome: {'basearchonly': False, 'type': 'optional'} + Package: kst: {'basearchonly': False, 'type': 'optional'} + Package: lagan: {'basearchonly': False, 'type': 'optional'} + Package: lapack: {'basearchonly': False, 'type': 'optional'} + Package: latte-integrale: {'basearchonly': False, 'type': 'optional'} + Package: libctl: {'basearchonly': False, 'type': 'optional'} + Package: libmatheval: {'basearchonly': False, 'type': 'optional'} + Package: libtcd: {'basearchonly': False, 'type': 'optional'} + Package: linbox: {'basearchonly': False, 'type': 'optional'} + Package: ltl2ba: {'basearchonly': False, 'type': 'optional'} + Package: Macaulay2: {'basearchonly': False, 'type': 'optional'} + Package: malaga: {'basearchonly': False, 'type': 'optional'} + Package: maxima-gui: {'basearchonly': False, 'type': 'optional'} + Package: meataxe: {'basearchonly': False, 'type': 'optional'} + Package: minisat2: {'basearchonly': False, 'type': 'optional'} + Package: mona: {'basearchonly': False, 'type': 'optional'} + Package: mona-devel: {'basearchonly': False, 'type': 'optional'} + Package: mona-emacs: {'basearchonly': False, 'type': 'optional'} + Package: mona-examples: {'basearchonly': False, 'type': 'optional'} + Package: mona-xemacs: {'basearchonly': False, 'type': 'optional'} + Package: mpfi: {'basearchonly': False, 'type': 'optional'} + Package: ncl: {'basearchonly': False, 'type': 'optional'} + Package: nco: {'basearchonly': False, 'type': 'optional'} + Package: ncview: {'basearchonly': False, 'type': 'optional'} + Package: netcdf: {'basearchonly': False, 'type': 'optional'} + Package: normaliz: {'basearchonly': False, 'type': 'optional'} + Package: openbabel: {'basearchonly': False, 'type': 'optional'} + Package: opencv: {'basearchonly': False, 'type': 'optional'} + Package: paraview: {'basearchonly': False, 'type': 'optional'} + Package: picosat: {'basearchonly': False, 'type': 'optional'} + Package: picosat-devel: {'basearchonly': False, 'type': 'optional'} + Package: plotutils: {'basearchonly': False, 'type': 'optional'} + Package: polybori: {'basearchonly': False, 'type': 'optional'} + Package: polybori-gui: {'basearchonly': False, 'type': 'optional'} + Package: polybori-ipbori: {'basearchonly': False, 'type': 'optional'} + Package: polymake: {'basearchonly': False, 'type': 'optional'} + Package: pvs-sbcl: {'basearchonly': False, 'type': 'optional'} + Package: pypop: {'basearchonly': False, 'type': 'optional'} + Package: python2-biopython: {'basearchonly': False, 'type': 'optional'} + Package: python2-cvxopt: {'basearchonly': False, 'type': 'optional'} + Package: python2-networkx: {'basearchonly': False, 'type': 'optional'} + Package: python2-theano: {'basearchonly': False, 'type': 'optional'} + Package: qalculate-gtk: {'basearchonly': False, 'type': 'optional'} + Package: qalculate-kde: {'basearchonly': False, 'type': 'optional'} + Package: qepcad-B: {'basearchonly': False, 'type': 'optional'} + Package: qtoctave: {'basearchonly': False, 'type': 'optional'} + Package: root: {'basearchonly': False, 'type': 'optional'} + Package: routino: {'basearchonly': False, 'type': 'optional'} + Package: rrdtool: {'basearchonly': False, 'type': 'optional'} + Package: seaview: {'basearchonly': False, 'type': 'optional'} + Package: sextractor: {'basearchonly': False, 'type': 'optional'} + Package: SIBsim4: {'basearchonly': False, 'type': 'optional'} + Package: stix-math-fonts: {'basearchonly': False, 'type': 'optional'} + Package: stp: {'basearchonly': False, 'type': 'optional'} + Package: symmetrica: {'basearchonly': False, 'type': 'optional'} + Package: sympy: {'basearchonly': False, 'type': 'optional'} + Package: tcd-utils: {'basearchonly': False, 'type': 'optional'} + Package: TeXmacs: {'basearchonly': False, 'type': 'optional'} + Package: tgif: {'basearchonly': False, 'type': 'optional'} + Package: tideEditor: {'basearchonly': False, 'type': 'optional'} + Package: TOPCOM: {'basearchonly': False, 'type': 'optional'} + Package: vaspview: {'basearchonly': False, 'type': 'optional'} + Package: veusz: {'basearchonly': False, 'type': 'optional'} + Package: vinci: {'basearchonly': False, 'type': 'optional'} + Package: wgrib: {'basearchonly': False, 'type': 'optional'} + Package: wgrib2: {'basearchonly': False, 'type': 'optional'} + Package: why: {'basearchonly': False, 'type': 'optional'} + Package: why3: {'basearchonly': False, 'type': 'optional'} + Package: wise2: {'basearchonly': False, 'type': 'optional'} + Package: wvs-data: {'basearchonly': False, 'type': 'optional'} + Package: xdrawchem: {'basearchonly': False, 'type': 'optional'} + Package: xgap: {'basearchonly': False, 'type': 'optional'} + Package: xtide: {'basearchonly': False, 'type': 'optional'} + Package: zenon: {'basearchonly': False, 'type': 'optional'} Group: enlightenment-desktop (Enlightenment) - Package: efl: {'type': 'mandatory', 'basearchonly': False} - Package: elementary: {'type': 'mandatory', 'basearchonly': False} - Package: enlightenment: {'type': 'mandatory', 'basearchonly': False} - Package: evas-generic-loaders: {'type': 'mandatory', 'basearchonly': False} - Package: terminology: {'type': 'mandatory', 'basearchonly': False} + Package: efl: {'basearchonly': False, 'type': 'mandatory'} + Package: elementary: {'basearchonly': False, 'type': 'mandatory'} + Package: enlightenment: {'basearchonly': False, 'type': 'mandatory'} + Package: evas-generic-loaders: {'basearchonly': False, 'type': 'mandatory'} + Package: terminology: {'basearchonly': False, 'type': 'mandatory'} Group: epiphany (Epiphany Web Browser) - Package: epiphany: {'type': 'mandatory', 'basearchonly': False} + Package: epiphany: {'basearchonly': False, 'type': 'mandatory'} Group: ethiopic-support (Ethiopic Support) - Package: google-noto-sans-ethiopic-fonts: {'type': 'default', 'basearchonly': False} - Package: sil-abyssinica-fonts: {'type': 'default', 'basearchonly': False} - Package: scim-tables-amharic: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-fantuwua-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-hiwua-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-jiret-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-tint-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-wookianos-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-yebse-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-yigezu-bisrat-goffer-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-yigezu-bisrat-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-zelan-fonts: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ethiopic: {'type': 'optional', 'basearchonly': False} + Package: google-noto-sans-ethiopic-fonts: {'basearchonly': False, 'type': 'default'} + Package: sil-abyssinica-fonts: {'basearchonly': False, 'type': 'default'} + Package: scim-tables-amharic: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-fantuwua-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-hiwua-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-jiret-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-tint-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-wookianos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-yebse-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-yigezu-bisrat-goffer-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-yigezu-bisrat-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-zelan-fonts: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ethiopic: {'basearchonly': False, 'type': 'optional'} Group: fedora-packager (Fedora Packager) - Package: bodhi-client: {'type': 'mandatory', 'basearchonly': False} - Package: curl: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-easy-karma: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-packager: {'type': 'mandatory', 'basearchonly': False} - Package: git: {'type': 'mandatory', 'basearchonly': False} - Package: koji: {'type': 'mandatory', 'basearchonly': False} - Package: make: {'type': 'mandatory', 'basearchonly': False} - Package: mock: {'type': 'mandatory', 'basearchonly': False} - Package: redhat-rpm-config: {'type': 'mandatory', 'basearchonly': False} - Package: rpm-build: {'type': 'mandatory', 'basearchonly': False} - Package: rpmdevtools: {'type': 'mandatory', 'basearchonly': False} - Package: bzr: {'type': 'default', 'basearchonly': False} - Package: mercurial: {'type': 'default', 'basearchonly': False} - Package: auto-destdir: {'type': 'optional', 'basearchonly': False} - Package: cpanspec: {'type': 'optional', 'basearchonly': False} - Package: cvs: {'type': 'optional', 'basearchonly': False} - Package: plague-client: {'type': 'optional', 'basearchonly': False} + Package: bodhi-client: {'basearchonly': False, 'type': 'mandatory'} + Package: curl: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-easy-karma: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-packager: {'basearchonly': False, 'type': 'mandatory'} + Package: git: {'basearchonly': False, 'type': 'mandatory'} + Package: koji: {'basearchonly': False, 'type': 'mandatory'} + Package: make: {'basearchonly': False, 'type': 'mandatory'} + Package: mock: {'basearchonly': False, 'type': 'mandatory'} + Package: redhat-rpm-config: {'basearchonly': False, 'type': 'mandatory'} + Package: rpm-build: {'basearchonly': False, 'type': 'mandatory'} + Package: rpmdevtools: {'basearchonly': False, 'type': 'mandatory'} + Package: bzr: {'basearchonly': False, 'type': 'default'} + Package: mercurial: {'basearchonly': False, 'type': 'default'} + Package: auto-destdir: {'basearchonly': False, 'type': 'optional'} + Package: cpanspec: {'basearchonly': False, 'type': 'optional'} + Package: cvs: {'basearchonly': False, 'type': 'optional'} + Package: plague-client: {'basearchonly': False, 'type': 'optional'} Group: finnish-support (Finnish Support) - Package: mozvoikko: {'requires': u'firefox', 'type': 'conditional', 'basearchonly': False} - Package: enchant-voikko: {'type': 'default', 'basearchonly': False} - Package: tmispell-voikko: {'type': 'optional', 'basearchonly': False} + Package: mozvoikko: {'basearchonly': False, 'requires': 'firefox', 'type': 'conditional'} + Package: enchant-voikko: {'basearchonly': False, 'type': 'default'} + Package: tmispell-voikko: {'basearchonly': False, 'type': 'optional'} Group: firefox (Firefox Web Browser) - Package: firefox: {'type': 'mandatory', 'basearchonly': False} + Package: firefox: {'basearchonly': False, 'type': 'mandatory'} Group: font-design (Font design and packaging) - Package: fontforge: {'type': 'mandatory', 'basearchonly': False} - Package: xgridfit: {'type': 'mandatory', 'basearchonly': False} - Package: fontaine: {'type': 'default', 'basearchonly': False} - Package: fontmatrix: {'type': 'default', 'basearchonly': False} - Package: fontpackages-devel: {'type': 'default', 'basearchonly': False} - Package: fonttools: {'type': 'default', 'basearchonly': False} - Package: ghostscript: {'type': 'default', 'basearchonly': False} - Package: gimp: {'type': 'default', 'basearchonly': False} - Package: gimp-data-extras: {'type': 'default', 'basearchonly': False} - Package: gimp-help: {'type': 'default', 'basearchonly': False} - Package: gimp-help-browser: {'type': 'default', 'basearchonly': False} - Package: gucharmap: {'type': 'default', 'basearchonly': False} - Package: inkscape: {'type': 'default', 'basearchonly': False} - Package: perl-Font-TTF: {'type': 'default', 'basearchonly': False} - Package: poppler-utils: {'type': 'default', 'basearchonly': False} - Package: texlive-lcdftypetools: {'type': 'default', 'basearchonly': False} - Package: xgridfit-doc: {'type': 'default', 'basearchonly': False} - Package: bzr: {'type': 'optional', 'basearchonly': False} - Package: cube2font: {'type': 'optional', 'basearchonly': False} - Package: cvs: {'type': 'optional', 'basearchonly': False} - Package: darcs: {'type': 'optional', 'basearchonly': False} - Package: fontpackages-tools: {'type': 'optional', 'basearchonly': False} - Package: freetype-demos: {'type': 'optional', 'basearchonly': False} - Package: gbdfed: {'type': 'optional', 'basearchonly': False} - Package: ghostscript-doc: {'type': 'optional', 'basearchonly': False} - Package: ghostscript-gtk: {'type': 'optional', 'basearchonly': False} - Package: giggle: {'type': 'optional', 'basearchonly': False} - Package: git: {'type': 'optional', 'basearchonly': False} - Package: meld: {'type': 'optional', 'basearchonly': False} - Package: mercurial: {'type': 'optional', 'basearchonly': False} - Package: python-compositor: {'type': 'optional', 'basearchonly': False} - Package: python-fontMath: {'type': 'optional', 'basearchonly': False} - Package: python-robofab: {'type': 'optional', 'basearchonly': False} - Package: python-ufo2fdk: {'type': 'optional', 'basearchonly': False} - Package: qgit: {'type': 'optional', 'basearchonly': False} - Package: quilt: {'type': 'optional', 'basearchonly': False} - Package: scribus: {'type': 'optional', 'basearchonly': False} - Package: subversion: {'type': 'optional', 'basearchonly': False} - Package: woff: {'type': 'optional', 'basearchonly': False} - Package: woffTools: {'type': 'optional', 'basearchonly': False} - Package: xmbdfed: {'type': 'optional', 'basearchonly': False} + Package: fontforge: {'basearchonly': False, 'type': 'mandatory'} + Package: xgridfit: {'basearchonly': False, 'type': 'mandatory'} + Package: fontaine: {'basearchonly': False, 'type': 'default'} + Package: fontmatrix: {'basearchonly': False, 'type': 'default'} + Package: fontpackages-devel: {'basearchonly': False, 'type': 'default'} + Package: fonttools: {'basearchonly': False, 'type': 'default'} + Package: ghostscript: {'basearchonly': False, 'type': 'default'} + Package: gimp: {'basearchonly': False, 'type': 'default'} + Package: gimp-data-extras: {'basearchonly': False, 'type': 'default'} + Package: gimp-help: {'basearchonly': False, 'type': 'default'} + Package: gimp-help-browser: {'basearchonly': False, 'type': 'default'} + Package: gucharmap: {'basearchonly': False, 'type': 'default'} + Package: inkscape: {'basearchonly': False, 'type': 'default'} + Package: perl-Font-TTF: {'basearchonly': False, 'type': 'default'} + Package: poppler-utils: {'basearchonly': False, 'type': 'default'} + Package: texlive-lcdftypetools: {'basearchonly': False, 'type': 'default'} + Package: xgridfit-doc: {'basearchonly': False, 'type': 'default'} + Package: bzr: {'basearchonly': False, 'type': 'optional'} + Package: cube2font: {'basearchonly': False, 'type': 'optional'} + Package: cvs: {'basearchonly': False, 'type': 'optional'} + Package: darcs: {'basearchonly': False, 'type': 'optional'} + Package: fontpackages-tools: {'basearchonly': False, 'type': 'optional'} + Package: freetype-demos: {'basearchonly': False, 'type': 'optional'} + Package: gbdfed: {'basearchonly': False, 'type': 'optional'} + Package: ghostscript-doc: {'basearchonly': False, 'type': 'optional'} + Package: ghostscript-gtk: {'basearchonly': False, 'type': 'optional'} + Package: giggle: {'basearchonly': False, 'type': 'optional'} + Package: git: {'basearchonly': False, 'type': 'optional'} + Package: meld: {'basearchonly': False, 'type': 'optional'} + Package: mercurial: {'basearchonly': False, 'type': 'optional'} + Package: python-compositor: {'basearchonly': False, 'type': 'optional'} + Package: python-fontMath: {'basearchonly': False, 'type': 'optional'} + Package: python-robofab: {'basearchonly': False, 'type': 'optional'} + Package: python-ufo2fdk: {'basearchonly': False, 'type': 'optional'} + Package: qgit: {'basearchonly': False, 'type': 'optional'} + Package: quilt: {'basearchonly': False, 'type': 'optional'} + Package: scribus: {'basearchonly': False, 'type': 'optional'} + Package: subversion: {'basearchonly': False, 'type': 'optional'} + Package: woff: {'basearchonly': False, 'type': 'optional'} + Package: woffTools: {'basearchonly': False, 'type': 'optional'} + Package: xmbdfed: {'basearchonly': False, 'type': 'optional'} Group: fonts (Fonts) - Package: aajohan-comfortaa-fonts: {'type': 'default', 'basearchonly': False} - Package: abattis-cantarell-fonts: {'type': 'default', 'basearchonly': False} - Package: adobe-source-han-sans-cn-fonts: {'type': 'default', 'basearchonly': False} - Package: adobe-source-han-sans-tw-fonts: {'type': 'default', 'basearchonly': False} - Package: dejavu-sans-fonts: {'type': 'default', 'basearchonly': False} - Package: dejavu-sans-mono-fonts: {'type': 'default', 'basearchonly': False} - Package: dejavu-serif-fonts: {'type': 'default', 'basearchonly': False} - Package: gnu-free-mono-fonts: {'type': 'default', 'basearchonly': False} - Package: gnu-free-sans-fonts: {'type': 'default', 'basearchonly': False} - Package: gnu-free-serif-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-lisu-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-mandaic-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-meetei-mayek-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-tagalog-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-tai-tham-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-tai-viet-fonts: {'type': 'default', 'basearchonly': False} - Package: jomolhari-fonts: {'type': 'default', 'basearchonly': False} - Package: julietaula-montserrat-fonts: {'type': 'default', 'basearchonly': False} - Package: khmeros-base-fonts: {'type': 'default', 'basearchonly': False} - Package: liberation-mono-fonts: {'type': 'default', 'basearchonly': False} - Package: liberation-sans-fonts: {'type': 'default', 'basearchonly': False} - Package: liberation-serif-fonts: {'type': 'default', 'basearchonly': False} - Package: lklug-fonts: {'type': 'default', 'basearchonly': False} - Package: lohit-assamese-fonts: {'type': 'default', 'basearchonly': False} - Package: lohit-bengali-fonts: {'type': 'default', 'basearchonly': False} - Package: lohit-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: lohit-gujarati-fonts: {'type': 'default', 'basearchonly': False} - Package: lohit-gurmukhi-fonts: {'type': 'default', 'basearchonly': False} - Package: lohit-kannada-fonts: {'type': 'default', 'basearchonly': False} - Package: lohit-odia-fonts: {'type': 'default', 'basearchonly': False} - Package: lohit-tamil-fonts: {'type': 'default', 'basearchonly': False} - Package: lohit-telugu-fonts: {'type': 'default', 'basearchonly': False} - Package: naver-nanum-gothic-fonts: {'type': 'default', 'basearchonly': False} - Package: paktype-naskh-basic-fonts: {'type': 'default', 'basearchonly': False} - Package: paratype-pt-sans-fonts: {'type': 'default', 'basearchonly': False} - Package: sil-abyssinica-fonts: {'type': 'default', 'basearchonly': False} - Package: sil-mingzat-fonts: {'type': 'default', 'basearchonly': False} - Package: sil-nuosu-fonts: {'type': 'default', 'basearchonly': False} - Package: sil-padauk-fonts: {'type': 'default', 'basearchonly': False} - Package: smc-meera-fonts: {'type': 'default', 'basearchonly': False} - Package: stix-fonts: {'type': 'default', 'basearchonly': False} - Package: tabish-eeyek-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-waree-fonts: {'type': 'default', 'basearchonly': False} - Package: vlgothic-fonts: {'type': 'default', 'basearchonly': False} - Package: adf-accanthis-2-fonts: {'type': 'optional', 'basearchonly': False} - Package: adf-accanthis-3-fonts: {'type': 'optional', 'basearchonly': False} - Package: adf-accanthis-fonts: {'type': 'optional', 'basearchonly': False} - Package: adf-gillius-2-fonts: {'type': 'optional', 'basearchonly': False} - Package: adf-gillius-fonts: {'type': 'optional', 'basearchonly': False} - Package: adf-tribun-fonts: {'type': 'optional', 'basearchonly': False} - Package: aldusleaf-crimson-text-fonts: {'type': 'optional', 'basearchonly': False} - Package: allgeyer-musiqwik-fonts: {'type': 'optional', 'basearchonly': False} - Package: allgeyer-musisync-fonts: {'type': 'optional', 'basearchonly': False} - Package: apa-new-athena-unicode-fonts: {'type': 'optional', 'basearchonly': False} - Package: apanov-edrip-fonts: {'type': 'optional', 'basearchonly': False} - Package: apanov-heuristica-fonts: {'type': 'optional', 'basearchonly': False} - Package: baekmuk-ttf-batang-fonts: {'type': 'optional', 'basearchonly': False} - Package: baekmuk-ttf-dotum-fonts: {'type': 'optional', 'basearchonly': False} - Package: baekmuk-ttf-gulim-fonts: {'type': 'optional', 'basearchonly': False} - Package: baekmuk-ttf-hline-fonts: {'type': 'optional', 'basearchonly': False} - Package: beteckna-fonts: {'type': 'optional', 'basearchonly': False} - Package: beteckna-lower-case-fonts: {'type': 'optional', 'basearchonly': False} - Package: beteckna-small-caps-fonts: {'type': 'optional', 'basearchonly': False} - Package: bitstream-vera-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: bitstream-vera-sans-mono-fonts: {'type': 'optional', 'basearchonly': False} - Package: bitstream-vera-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-algeti-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-chveulebrivi-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-courier-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-courier-s-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-elite-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-excelsior-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-glaho-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-ingiri-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-nino-medium-cond-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-nino-medium-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-sans-medium-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-sans-modern-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-sans-regular-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-serif-modern-fonts: {'type': 'optional', 'basearchonly': False} - Package: campivisivi-titillium-fonts: {'type': 'optional', 'basearchonly': False} - Package: cave9-mutante-fonts: {'type': 'optional', 'basearchonly': False} - Package: cf-bonveno-fonts: {'type': 'optional', 'basearchonly': False} - Package: cf-sorts-mill-goudy-fonts: {'type': 'optional', 'basearchonly': False} - Package: chisholm-letterslaughing-fonts: {'type': 'optional', 'basearchonly': False} - Package: chisholm-to-be-continued-fonts: {'type': 'optional', 'basearchonly': False} - Package: cjkuni-ukai-fonts: {'type': 'optional', 'basearchonly': False} - Package: cjkuni-uming-fonts: {'type': 'optional', 'basearchonly': False} - Package: comic-neue-fonts: {'type': 'optional', 'basearchonly': False} - Package: conakry-fonts: {'type': 'optional', 'basearchonly': False} - Package: ctan-cm-lgc-roman-fonts: {'type': 'optional', 'basearchonly': False} - Package: ctan-cm-lgc-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: ctan-cm-lgc-typewriter-fonts: {'type': 'optional', 'basearchonly': False} - Package: ctan-kerkis-calligraphic-fonts: {'type': 'optional', 'basearchonly': False} - Package: ctan-kerkis-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: ctan-kerkis-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: darkgarden-fonts: {'type': 'optional', 'basearchonly': False} - Package: dejavu-lgc-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: dejavu-lgc-sans-mono-fonts: {'type': 'optional', 'basearchonly': False} - Package: dejavu-lgc-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: denemo-emmentaler-fonts: {'type': 'optional', 'basearchonly': False} - Package: denemo-feta-fonts: {'type': 'optional', 'basearchonly': False} - Package: denemo-music-fonts: {'type': 'optional', 'basearchonly': False} - Package: drehatlas-warender-bibliothek-fonts: {'type': 'optional', 'basearchonly': False} - Package: drehatlas-widelands-fonts: {'type': 'optional', 'basearchonly': False} - Package: drehatlas-xaporho-fonts: {'type': 'optional', 'basearchonly': False} - Package: dustin-domestic-manners-fonts: {'type': 'optional', 'basearchonly': False} - Package: dustin-dustismo-roman-fonts: {'type': 'optional', 'basearchonly': False} - Package: dustin-dustismo-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: ecolier-court-fonts: {'type': 'optional', 'basearchonly': False} - Package: ecolier-court-lignes-fonts: {'type': 'optional', 'basearchonly': False} - Package: extremetuxracer-papercuts-fonts: {'type': 'optional', 'basearchonly': False} - Package: extremetuxracer-papercuts-outline-fonts: {'type': 'optional', 'basearchonly': False} - Package: fontawesome-fonts: {'type': 'optional', 'basearchonly': False} - Package: freecol-imperator-fonts: {'type': 'optional', 'basearchonly': False} - Package: freecol-shadowedblack-fonts: {'type': 'optional', 'basearchonly': False} - Package: gargi-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-aegean-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-aegyptus-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-akkadian-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-alexander-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-anaktoria-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-analecta-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-aroania-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-asea-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-avdira-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-musica-fonts: {'type': 'optional', 'basearchonly': False} - Package: gdouros-symbola-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-ambrosia-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-artemisia-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-baskerville-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-bodoni-classic-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-bodoni-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-complutum-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-decker-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-didot-classic-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-didot-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-eustace-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-fleischman-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-garaldus-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-gazis-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-goschen-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-ignacio-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-jackson-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-neohellenic-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-nicefore-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-olga-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-philostratos-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-porson-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-pyrsos-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-solomos-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-theokritos-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-croscore-arimo-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-croscore-cousine-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-croscore-symbolneu-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-croscore-tinos-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-droid-kufi-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-droid-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-droid-sans-mono-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-droid-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-armenian-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-avestan-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-bengali-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-bengali-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-brahmi-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-carian-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-cherokee-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-coptic-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-deseret-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-egyptian-hieroglyphs-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-ethiopic-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-georgian-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-glagolitic-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-gujarati-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-gujarati-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-hebrew-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-imperial-aramaic-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-kaithi-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-kannada-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-kannada-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-kayah-li-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-kharoshthi-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-khmer-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-khmer-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-lao-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-lao-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-lycian-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-lydian-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-malayalam-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-malayalam-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-nko-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-old-south-arabian-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-old-turkic-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-osmanya-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-phoenician-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-shavian-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-symbols-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-tamil-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-tamil-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-telugu-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-telugu-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-thaana-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-thai-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-thai-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-ugaritic-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-ui-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-sans-vai-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-serif-armenian-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-serif-georgian-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-serif-khmer-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-serif-lao-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-noto-serif-thai-fonts: {'type': 'optional', 'basearchonly': False} - Package: grimmer-proggy-tinysz-fonts: {'type': 'optional', 'basearchonly': False} - Package: gubbi-fonts: {'type': 'optional', 'basearchonly': False} - Package: hanazono-fonts: {'type': 'optional', 'basearchonly': False} - Package: hiran-perizia-fonts: {'type': 'optional', 'basearchonly': False} - Package: horai-ume-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: horai-ume-mincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: horai-ume-pgothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: horai-ume-pmincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: horai-ume-uigothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: impallari-lobster-fonts: {'type': 'optional', 'basearchonly': False} - Package: inkboy-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-ex-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-ex-mincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-mincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-pgothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-pmincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: jsmath-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-art-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-book-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-decorative-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-digital-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-farsi-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-letter-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-office-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-one-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-pen-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-poster-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-qurn-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-screen-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-title-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-titlel-fonts: {'type': 'optional', 'basearchonly': False} - Package: kalapi-fonts: {'type': 'optional', 'basearchonly': False} - Package: kanjistrokeorders-fonts: {'type': 'optional', 'basearchonly': False} - Package: kanotf-fonts: {'type': 'optional', 'basearchonly': False} - Package: khmeros-battambang-fonts: {'type': 'optional', 'basearchonly': False} - Package: khmeros-bokor-fonts: {'type': 'optional', 'basearchonly': False} - Package: khmeros-handwritten-fonts: {'type': 'optional', 'basearchonly': False} - Package: khmeros-metal-chrieng-fonts: {'type': 'optional', 'basearchonly': False} - Package: khmeros-muol-fonts: {'type': 'optional', 'basearchonly': False} - Package: khmeros-siemreap-fonts: {'type': 'optional', 'basearchonly': False} - Package: kurdit-unikurd-web-fonts: {'type': 'optional', 'basearchonly': False} - Package: lato-fonts: {'type': 'optional', 'basearchonly': False} - Package: levien-inconsolata-fonts: {'type': 'optional', 'basearchonly': False} - Package: levien-museum-fonts: {'type': 'optional', 'basearchonly': False} - Package: liberation-narrow-fonts: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-opensymbol-fonts: {'type': 'optional', 'basearchonly': False} - Package: lilypond-emmentaler-fonts: {'type': 'optional', 'basearchonly': False} - Package: linux-libertine-biolinum-fonts: {'type': 'optional', 'basearchonly': False} - Package: linux-libertine-fonts: {'type': 'optional', 'basearchonly': False} - Package: lohit-malayalam-fonts: {'type': 'optional', 'basearchonly': False} - Package: lohit-marathi-fonts: {'type': 'optional', 'basearchonly': False} - Package: lohit-nepali-fonts: {'type': 'optional', 'basearchonly': False} - Package: lohit-tamil-classical-fonts: {'type': 'optional', 'basearchonly': False} - Package: madan-fonts: {'type': 'optional', 'basearchonly': False} - Package: manchu-fonts: {'type': 'optional', 'basearchonly': False} - Package: mgopen-canonica-fonts: {'type': 'optional', 'basearchonly': False} - Package: mgopen-cosmetica-fonts: {'type': 'optional', 'basearchonly': False} - Package: mgopen-modata-fonts: {'type': 'optional', 'basearchonly': False} - Package: mgopen-moderna-fonts: {'type': 'optional', 'basearchonly': False} - Package: mona-sazanami-fonts: {'type': 'optional', 'basearchonly': False} - Package: mona-vlgothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: motoya-lcedar-fonts: {'type': 'optional', 'basearchonly': False} - Package: motoya-lmaru-fonts: {'type': 'optional', 'basearchonly': False} - Package: moyogo-molengo-fonts: {'type': 'optional', 'basearchonly': False} - Package: mph-2b-damase-fonts: {'type': 'optional', 'basearchonly': False} - Package: mplus-1c-fonts: {'type': 'optional', 'basearchonly': False} - Package: mplus-1m-fonts: {'type': 'optional', 'basearchonly': False} - Package: mplus-1mn-fonts: {'type': 'optional', 'basearchonly': False} - Package: mplus-1p-fonts: {'type': 'optional', 'basearchonly': False} - Package: mplus-2c-fonts: {'type': 'optional', 'basearchonly': False} - Package: mplus-2m-fonts: {'type': 'optional', 'basearchonly': False} - Package: mplus-2p-fonts: {'type': 'optional', 'basearchonly': False} - Package: mscore-fonts: {'type': 'optional', 'basearchonly': False} - Package: msimonson-anonymouspro-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-nastaleeq-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-pakistani-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-pakistani-web-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-riqa-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-tehreer-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-web-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: naver-nanum-barun-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: naver-nanum-brush-fonts: {'type': 'optional', 'basearchonly': False} - Package: naver-nanum-myeongjo-fonts: {'type': 'optional', 'basearchonly': False} - Package: naver-nanum-pen-fonts: {'type': 'optional', 'basearchonly': False} - Package: navilu-fonts: {'type': 'optional', 'basearchonly': False} - Package: nhn-nanum-gothic-coding-fonts: {'type': 'optional', 'basearchonly': False} - Package: ns-bola-fonts: {'type': 'optional', 'basearchonly': False} - Package: ns-tiza-chalk-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-asana-math-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-brett-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-goudy-bookletter-1911-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-icelandic-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-notcouriersans-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-prociono-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-riordonfancy-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-roadstencil-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-smonohand-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-sportrop-fonts: {'type': 'optional', 'basearchonly': False} - Package: oldstandard-sfd-fonts: {'type': 'optional', 'basearchonly': False} - Package: open-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: overpass-fonts: {'type': 'optional', 'basearchonly': False} - Package: pagul-fonts: {'type': 'optional', 'basearchonly': False} - Package: paktype-ajrak-fonts: {'type': 'optional', 'basearchonly': False} - Package: paktype-naqsh-fonts: {'type': 'optional', 'basearchonly': False} - Package: paktype-tehreer-fonts: {'type': 'optional', 'basearchonly': False} - Package: paratype-pt-mono-fonts: {'type': 'optional', 'basearchonly': False} - Package: paratype-pt-sans-caption-fonts: {'type': 'optional', 'basearchonly': False} - Package: paratype-pt-serif-caption-fonts: {'type': 'optional', 'basearchonly': False} - Package: paratype-pt-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: pothana2000-fonts: {'type': 'optional', 'basearchonly': False} - Package: saab-fonts: {'type': 'optional', 'basearchonly': False} - Package: samyak-devanagari-fonts: {'type': 'optional', 'basearchonly': False} - Package: samyak-gujarati-fonts: {'type': 'optional', 'basearchonly': False} - Package: samyak-malayalam-fonts: {'type': 'optional', 'basearchonly': False} - Package: samyak-odia-fonts: {'type': 'optional', 'basearchonly': False} - Package: samyak-tamil-fonts: {'type': 'optional', 'basearchonly': False} - Package: sarai-fonts: {'type': 'optional', 'basearchonly': False} - Package: sazanami-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: sazanami-mincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: scholarsfonts-cardo-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-fantuwua-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-hiwua-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-jiret-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-tint-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-wookianos-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-yebse-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-yigezu-bisrat-goffer-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-yigezu-bisrat-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: senamirmir-washra-zelan-fonts: {'type': 'optional', 'basearchonly': False} - Package: serafettin-cartoon-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-andika-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-charis-compact-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-charis-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-doulos-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-gentium-alt-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-gentium-basic-book-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-gentium-basic-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-gentium-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-lateef-fonts: {'type': 'optional', 'basearchonly': False} - Package: sil-scheherazade-fonts: {'type': 'optional', 'basearchonly': False} - Package: silkscreen-expanded-fonts: {'type': 'optional', 'basearchonly': False} - Package: silkscreen-fonts: {'type': 'optional', 'basearchonly': False} - Package: sj-delphine-fonts: {'type': 'optional', 'basearchonly': False} - Package: sj-stevehand-fonts: {'type': 'optional', 'basearchonly': False} - Package: smc-anjalioldlipi-fonts: {'type': 'optional', 'basearchonly': False} - Package: smc-dyuthi-fonts: {'type': 'optional', 'basearchonly': False} - Package: smc-kalyani-fonts: {'type': 'optional', 'basearchonly': False} - Package: smc-rachana-fonts: {'type': 'optional', 'basearchonly': False} - Package: smc-raghumalayalam-fonts: {'type': 'optional', 'basearchonly': False} - Package: smc-suruma-fonts: {'type': 'optional', 'basearchonly': False} - Package: stix-math-fonts: {'type': 'optional', 'basearchonly': False} - Package: tangerine-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-arundina-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-arundina-sans-mono-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-arundina-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-garuda-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-kinnari-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-loma-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-norasi-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-purisa-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-sawasdee-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-tlwgmono-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-tlwgtypewriter-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-tlwgtypist-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-tlwgtypo-fonts: {'type': 'optional', 'basearchonly': False} - Package: thai-scalable-umpush-fonts: {'type': 'optional', 'basearchonly': False} - Package: thibault-essays1743-fonts: {'type': 'optional', 'basearchonly': False} - Package: thibault-isabella-fonts: {'type': 'optional', 'basearchonly': False} - Package: thibault-rockets-fonts: {'type': 'optional', 'basearchonly': False} - Package: thibault-staypuft-fonts: {'type': 'optional', 'basearchonly': False} - Package: tibetan-machine-uni-fonts: {'type': 'optional', 'basearchonly': False} - Package: tiresias-info-fonts: {'type': 'optional', 'basearchonly': False} - Package: tiresias-info-z-fonts: {'type': 'optional', 'basearchonly': False} - Package: tiresias-key-v2-fonts: {'type': 'optional', 'basearchonly': False} - Package: tiresias-lp-fonts: {'type': 'optional', 'basearchonly': False} - Package: tiresias-pc-fonts: {'type': 'optional', 'basearchonly': False} - Package: tiresias-pc-z-fonts: {'type': 'optional', 'basearchonly': False} - Package: tiresias-sign-fonts: {'type': 'optional', 'basearchonly': False} - Package: tiresias-sign-z-fonts: {'type': 'optional', 'basearchonly': False} - Package: tlomt-junction-fonts: {'type': 'optional', 'basearchonly': False} - Package: tlomt-league-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: tlomt-orbitron-fonts: {'type': 'optional', 'basearchonly': False} - Package: tlomt-sniglet-fonts: {'type': 'optional', 'basearchonly': False} - Package: trabajo-fonts: {'type': 'optional', 'basearchonly': False} - Package: tulrich-tuffy-fonts: {'type': 'optional', 'basearchonly': False} - Package: typemade-josefinsansstd-light-fonts: {'type': 'optional', 'basearchonly': False} - Package: ubuntu-title-fonts: {'type': 'optional', 'basearchonly': False} - Package: ukij-tuz-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-batang-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-dinaru-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-dotum-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-graphic-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-gungseo-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-pilgi-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-bom-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-jamobatang-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-jamodotum-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-jamonovel-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-jamosora-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-pen-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-penheulim-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-pilgia-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-shinmun-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-taza-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-vada-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-yetgul-fonts: {'type': 'optional', 'basearchonly': False} - Package: vdrsymbol-fonts: {'type': 'optional', 'basearchonly': False} - Package: vemana2000-fonts: {'type': 'optional', 'basearchonly': False} - Package: vlgothic-p-fonts: {'type': 'optional', 'basearchonly': False} - Package: vollkorn-fonts: {'type': 'optional', 'basearchonly': False} - Package: wine-marlett-fonts: {'type': 'optional', 'basearchonly': False} - Package: wine-symbol-fonts: {'type': 'optional', 'basearchonly': False} - Package: woodardworks-laconic-fonts: {'type': 'optional', 'basearchonly': False} - Package: woodardworks-laconic-shadow-fonts: {'type': 'optional', 'basearchonly': False} - Package: wqy-microhei-fonts: {'type': 'optional', 'basearchonly': False} - Package: wqy-zenhei-fonts: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ethiopic: {'type': 'optional', 'basearchonly': False} - Package: yanone-kaffeesatz-fonts: {'type': 'optional', 'basearchonly': False} - Package: yanone-tagesschrift-fonts: {'type': 'optional', 'basearchonly': False} + Package: aajohan-comfortaa-fonts: {'basearchonly': False, 'type': 'default'} + Package: abattis-cantarell-fonts: {'basearchonly': False, 'type': 'default'} + Package: adobe-source-han-sans-cn-fonts: {'basearchonly': False, 'type': 'default'} + Package: adobe-source-han-sans-tw-fonts: {'basearchonly': False, 'type': 'default'} + Package: dejavu-sans-fonts: {'basearchonly': False, 'type': 'default'} + Package: dejavu-sans-mono-fonts: {'basearchonly': False, 'type': 'default'} + Package: dejavu-serif-fonts: {'basearchonly': False, 'type': 'default'} + Package: gnu-free-mono-fonts: {'basearchonly': False, 'type': 'default'} + Package: gnu-free-sans-fonts: {'basearchonly': False, 'type': 'default'} + Package: gnu-free-serif-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-lisu-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-mandaic-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-meetei-mayek-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-tagalog-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-tai-tham-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-tai-viet-fonts: {'basearchonly': False, 'type': 'default'} + Package: jomolhari-fonts: {'basearchonly': False, 'type': 'default'} + Package: julietaula-montserrat-fonts: {'basearchonly': False, 'type': 'default'} + Package: khmeros-base-fonts: {'basearchonly': False, 'type': 'default'} + Package: liberation-mono-fonts: {'basearchonly': False, 'type': 'default'} + Package: liberation-sans-fonts: {'basearchonly': False, 'type': 'default'} + Package: liberation-serif-fonts: {'basearchonly': False, 'type': 'default'} + Package: lklug-fonts: {'basearchonly': False, 'type': 'default'} + Package: lohit-assamese-fonts: {'basearchonly': False, 'type': 'default'} + Package: lohit-bengali-fonts: {'basearchonly': False, 'type': 'default'} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: lohit-gujarati-fonts: {'basearchonly': False, 'type': 'default'} + Package: lohit-gurmukhi-fonts: {'basearchonly': False, 'type': 'default'} + Package: lohit-kannada-fonts: {'basearchonly': False, 'type': 'default'} + Package: lohit-odia-fonts: {'basearchonly': False, 'type': 'default'} + Package: lohit-tamil-fonts: {'basearchonly': False, 'type': 'default'} + Package: lohit-telugu-fonts: {'basearchonly': False, 'type': 'default'} + Package: naver-nanum-gothic-fonts: {'basearchonly': False, 'type': 'default'} + Package: paktype-naskh-basic-fonts: {'basearchonly': False, 'type': 'default'} + Package: paratype-pt-sans-fonts: {'basearchonly': False, 'type': 'default'} + Package: sil-abyssinica-fonts: {'basearchonly': False, 'type': 'default'} + Package: sil-mingzat-fonts: {'basearchonly': False, 'type': 'default'} + Package: sil-nuosu-fonts: {'basearchonly': False, 'type': 'default'} + Package: sil-padauk-fonts: {'basearchonly': False, 'type': 'default'} + Package: smc-meera-fonts: {'basearchonly': False, 'type': 'default'} + Package: stix-fonts: {'basearchonly': False, 'type': 'default'} + Package: tabish-eeyek-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-waree-fonts: {'basearchonly': False, 'type': 'default'} + Package: vlgothic-fonts: {'basearchonly': False, 'type': 'default'} + Package: adf-accanthis-2-fonts: {'basearchonly': False, 'type': 'optional'} + Package: adf-accanthis-3-fonts: {'basearchonly': False, 'type': 'optional'} + Package: adf-accanthis-fonts: {'basearchonly': False, 'type': 'optional'} + Package: adf-gillius-2-fonts: {'basearchonly': False, 'type': 'optional'} + Package: adf-gillius-fonts: {'basearchonly': False, 'type': 'optional'} + Package: adf-tribun-fonts: {'basearchonly': False, 'type': 'optional'} + Package: aldusleaf-crimson-text-fonts: {'basearchonly': False, 'type': 'optional'} + Package: allgeyer-musiqwik-fonts: {'basearchonly': False, 'type': 'optional'} + Package: allgeyer-musisync-fonts: {'basearchonly': False, 'type': 'optional'} + Package: apa-new-athena-unicode-fonts: {'basearchonly': False, 'type': 'optional'} + Package: apanov-edrip-fonts: {'basearchonly': False, 'type': 'optional'} + Package: apanov-heuristica-fonts: {'basearchonly': False, 'type': 'optional'} + Package: baekmuk-ttf-batang-fonts: {'basearchonly': False, 'type': 'optional'} + Package: baekmuk-ttf-dotum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: baekmuk-ttf-gulim-fonts: {'basearchonly': False, 'type': 'optional'} + Package: baekmuk-ttf-hline-fonts: {'basearchonly': False, 'type': 'optional'} + Package: beteckna-fonts: {'basearchonly': False, 'type': 'optional'} + Package: beteckna-lower-case-fonts: {'basearchonly': False, 'type': 'optional'} + Package: beteckna-small-caps-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bitstream-vera-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bitstream-vera-sans-mono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bitstream-vera-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-algeti-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-chveulebrivi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-courier-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-courier-s-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-elite-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-excelsior-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-glaho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-ingiri-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-nino-medium-cond-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-nino-medium-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-sans-medium-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-sans-modern-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-sans-regular-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-serif-modern-fonts: {'basearchonly': False, 'type': 'optional'} + Package: campivisivi-titillium-fonts: {'basearchonly': False, 'type': 'optional'} + Package: cave9-mutante-fonts: {'basearchonly': False, 'type': 'optional'} + Package: cf-bonveno-fonts: {'basearchonly': False, 'type': 'optional'} + Package: cf-sorts-mill-goudy-fonts: {'basearchonly': False, 'type': 'optional'} + Package: chisholm-letterslaughing-fonts: {'basearchonly': False, 'type': 'optional'} + Package: chisholm-to-be-continued-fonts: {'basearchonly': False, 'type': 'optional'} + Package: cjkuni-ukai-fonts: {'basearchonly': False, 'type': 'optional'} + Package: cjkuni-uming-fonts: {'basearchonly': False, 'type': 'optional'} + Package: comic-neue-fonts: {'basearchonly': False, 'type': 'optional'} + Package: conakry-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ctan-cm-lgc-roman-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ctan-cm-lgc-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ctan-cm-lgc-typewriter-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ctan-kerkis-calligraphic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ctan-kerkis-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ctan-kerkis-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: darkgarden-fonts: {'basearchonly': False, 'type': 'optional'} + Package: dejavu-lgc-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: dejavu-lgc-sans-mono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: dejavu-lgc-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: denemo-emmentaler-fonts: {'basearchonly': False, 'type': 'optional'} + Package: denemo-feta-fonts: {'basearchonly': False, 'type': 'optional'} + Package: denemo-music-fonts: {'basearchonly': False, 'type': 'optional'} + Package: drehatlas-warender-bibliothek-fonts: {'basearchonly': False, 'type': 'optional'} + Package: drehatlas-widelands-fonts: {'basearchonly': False, 'type': 'optional'} + Package: drehatlas-xaporho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: dustin-domestic-manners-fonts: {'basearchonly': False, 'type': 'optional'} + Package: dustin-dustismo-roman-fonts: {'basearchonly': False, 'type': 'optional'} + Package: dustin-dustismo-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ecolier-court-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ecolier-court-lignes-fonts: {'basearchonly': False, 'type': 'optional'} + Package: extremetuxracer-papercuts-fonts: {'basearchonly': False, 'type': 'optional'} + Package: extremetuxracer-papercuts-outline-fonts: {'basearchonly': False, 'type': 'optional'} + Package: fontawesome-fonts: {'basearchonly': False, 'type': 'optional'} + Package: freecol-imperator-fonts: {'basearchonly': False, 'type': 'optional'} + Package: freecol-shadowedblack-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gargi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-aegean-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-aegyptus-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-akkadian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-alexander-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-anaktoria-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-analecta-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-aroania-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-asea-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-avdira-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-musica-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gdouros-symbola-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-ambrosia-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-artemisia-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-baskerville-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-bodoni-classic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-bodoni-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-complutum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-decker-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-didot-classic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-didot-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-eustace-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-fleischman-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-garaldus-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-gazis-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-goschen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-ignacio-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-jackson-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-neohellenic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-nicefore-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-olga-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-philostratos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-porson-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-pyrsos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-solomos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-theokritos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-croscore-arimo-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-croscore-cousine-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-croscore-symbolneu-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-croscore-tinos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-droid-kufi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-droid-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-droid-sans-mono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-droid-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-armenian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-avestan-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-bengali-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-bengali-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-brahmi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-carian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-cherokee-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-coptic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-deseret-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-egyptian-hieroglyphs-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-ethiopic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-georgian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-glagolitic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-gujarati-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-gujarati-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-hebrew-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-imperial-aramaic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-kaithi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-kannada-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-kannada-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-kayah-li-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-kharoshthi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-khmer-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-khmer-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-lao-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-lao-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-lycian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-lydian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-malayalam-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-malayalam-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-nko-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-old-south-arabian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-old-turkic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-osmanya-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-phoenician-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-shavian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-symbols-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-tamil-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-tamil-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-telugu-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-telugu-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-thaana-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-thai-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-thai-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-ugaritic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-ui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-sans-vai-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-serif-armenian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-serif-georgian-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-serif-khmer-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-serif-lao-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-noto-serif-thai-fonts: {'basearchonly': False, 'type': 'optional'} + Package: grimmer-proggy-tinysz-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gubbi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: hanazono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: hiran-perizia-fonts: {'basearchonly': False, 'type': 'optional'} + Package: horai-ume-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: horai-ume-mincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: horai-ume-pgothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: horai-ume-pmincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: horai-ume-uigothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: impallari-lobster-fonts: {'basearchonly': False, 'type': 'optional'} + Package: inkboy-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-ex-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-ex-mincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-mincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-pgothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-pmincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: jsmath-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-art-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-book-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-decorative-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-digital-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-farsi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-letter-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-office-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-one-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-pen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-poster-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-qurn-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-screen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-title-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-titlel-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kalapi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kanjistrokeorders-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kanotf-fonts: {'basearchonly': False, 'type': 'optional'} + Package: khmeros-battambang-fonts: {'basearchonly': False, 'type': 'optional'} + Package: khmeros-bokor-fonts: {'basearchonly': False, 'type': 'optional'} + Package: khmeros-handwritten-fonts: {'basearchonly': False, 'type': 'optional'} + Package: khmeros-metal-chrieng-fonts: {'basearchonly': False, 'type': 'optional'} + Package: khmeros-muol-fonts: {'basearchonly': False, 'type': 'optional'} + Package: khmeros-siemreap-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kurdit-unikurd-web-fonts: {'basearchonly': False, 'type': 'optional'} + Package: lato-fonts: {'basearchonly': False, 'type': 'optional'} + Package: levien-inconsolata-fonts: {'basearchonly': False, 'type': 'optional'} + Package: levien-museum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: liberation-narrow-fonts: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-opensymbol-fonts: {'basearchonly': False, 'type': 'optional'} + Package: lilypond-emmentaler-fonts: {'basearchonly': False, 'type': 'optional'} + Package: linux-libertine-biolinum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: linux-libertine-fonts: {'basearchonly': False, 'type': 'optional'} + Package: lohit-malayalam-fonts: {'basearchonly': False, 'type': 'optional'} + Package: lohit-marathi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: lohit-nepali-fonts: {'basearchonly': False, 'type': 'optional'} + Package: lohit-tamil-classical-fonts: {'basearchonly': False, 'type': 'optional'} + Package: madan-fonts: {'basearchonly': False, 'type': 'optional'} + Package: manchu-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mgopen-canonica-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mgopen-cosmetica-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mgopen-modata-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mgopen-moderna-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mona-sazanami-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mona-vlgothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: motoya-lcedar-fonts: {'basearchonly': False, 'type': 'optional'} + Package: motoya-lmaru-fonts: {'basearchonly': False, 'type': 'optional'} + Package: moyogo-molengo-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mph-2b-damase-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mplus-1c-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mplus-1m-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mplus-1mn-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mplus-1p-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mplus-2c-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mplus-2m-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mplus-2p-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mscore-fonts: {'basearchonly': False, 'type': 'optional'} + Package: msimonson-anonymouspro-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-nastaleeq-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-pakistani-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-pakistani-web-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-riqa-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-tehreer-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-web-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: naver-nanum-barun-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: naver-nanum-brush-fonts: {'basearchonly': False, 'type': 'optional'} + Package: naver-nanum-myeongjo-fonts: {'basearchonly': False, 'type': 'optional'} + Package: naver-nanum-pen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: navilu-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nhn-nanum-gothic-coding-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ns-bola-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ns-tiza-chalk-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-asana-math-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-brett-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-goudy-bookletter-1911-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-icelandic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-notcouriersans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-prociono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-riordonfancy-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-roadstencil-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-smonohand-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-sportrop-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oldstandard-sfd-fonts: {'basearchonly': False, 'type': 'optional'} + Package: open-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: overpass-fonts: {'basearchonly': False, 'type': 'optional'} + Package: pagul-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paktype-ajrak-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paktype-naqsh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paktype-tehreer-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paratype-pt-mono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paratype-pt-sans-caption-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paratype-pt-serif-caption-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paratype-pt-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: pothana2000-fonts: {'basearchonly': False, 'type': 'optional'} + Package: saab-fonts: {'basearchonly': False, 'type': 'optional'} + Package: samyak-devanagari-fonts: {'basearchonly': False, 'type': 'optional'} + Package: samyak-gujarati-fonts: {'basearchonly': False, 'type': 'optional'} + Package: samyak-malayalam-fonts: {'basearchonly': False, 'type': 'optional'} + Package: samyak-odia-fonts: {'basearchonly': False, 'type': 'optional'} + Package: samyak-tamil-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sarai-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sazanami-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sazanami-mincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: scholarsfonts-cardo-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-fantuwua-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-hiwua-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-jiret-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-tint-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-wookianos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-yebse-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-yigezu-bisrat-goffer-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-yigezu-bisrat-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: senamirmir-washra-zelan-fonts: {'basearchonly': False, 'type': 'optional'} + Package: serafettin-cartoon-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-andika-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-charis-compact-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-charis-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-doulos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-gentium-alt-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-gentium-basic-book-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-gentium-basic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-gentium-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-lateef-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sil-scheherazade-fonts: {'basearchonly': False, 'type': 'optional'} + Package: silkscreen-expanded-fonts: {'basearchonly': False, 'type': 'optional'} + Package: silkscreen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sj-delphine-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sj-stevehand-fonts: {'basearchonly': False, 'type': 'optional'} + Package: smc-anjalioldlipi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: smc-dyuthi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: smc-kalyani-fonts: {'basearchonly': False, 'type': 'optional'} + Package: smc-rachana-fonts: {'basearchonly': False, 'type': 'optional'} + Package: smc-raghumalayalam-fonts: {'basearchonly': False, 'type': 'optional'} + Package: smc-suruma-fonts: {'basearchonly': False, 'type': 'optional'} + Package: stix-math-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tangerine-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-arundina-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-arundina-sans-mono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-arundina-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-garuda-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-kinnari-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-loma-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-norasi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-purisa-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-sawasdee-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-tlwgmono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-tlwgtypewriter-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-tlwgtypist-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-tlwgtypo-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thai-scalable-umpush-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thibault-essays1743-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thibault-isabella-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thibault-rockets-fonts: {'basearchonly': False, 'type': 'optional'} + Package: thibault-staypuft-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tibetan-machine-uni-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tiresias-info-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tiresias-info-z-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tiresias-key-v2-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tiresias-lp-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tiresias-pc-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tiresias-pc-z-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tiresias-sign-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tiresias-sign-z-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tlomt-junction-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tlomt-league-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tlomt-orbitron-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tlomt-sniglet-fonts: {'basearchonly': False, 'type': 'optional'} + Package: trabajo-fonts: {'basearchonly': False, 'type': 'optional'} + Package: tulrich-tuffy-fonts: {'basearchonly': False, 'type': 'optional'} + Package: typemade-josefinsansstd-light-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ubuntu-title-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ukij-tuz-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-batang-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-dinaru-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-dotum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-graphic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-gungseo-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-pilgi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-bom-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-jamobatang-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-jamodotum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-jamonovel-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-jamosora-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-pen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-penheulim-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-pilgia-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-shinmun-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-taza-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-vada-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-yetgul-fonts: {'basearchonly': False, 'type': 'optional'} + Package: vdrsymbol-fonts: {'basearchonly': False, 'type': 'optional'} + Package: vemana2000-fonts: {'basearchonly': False, 'type': 'optional'} + Package: vlgothic-p-fonts: {'basearchonly': False, 'type': 'optional'} + Package: vollkorn-fonts: {'basearchonly': False, 'type': 'optional'} + Package: wine-marlett-fonts: {'basearchonly': False, 'type': 'optional'} + Package: wine-symbol-fonts: {'basearchonly': False, 'type': 'optional'} + Package: woodardworks-laconic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: woodardworks-laconic-shadow-fonts: {'basearchonly': False, 'type': 'optional'} + Package: wqy-microhei-fonts: {'basearchonly': False, 'type': 'optional'} + Package: wqy-zenhei-fonts: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ethiopic: {'basearchonly': False, 'type': 'optional'} + Package: yanone-kaffeesatz-fonts: {'basearchonly': False, 'type': 'optional'} + Package: yanone-tagesschrift-fonts: {'basearchonly': False, 'type': 'optional'} Group: freeipa-server (FreeIPA Server) - Package: freeipa-server: {'type': 'mandatory', 'basearchonly': False} - Package: bind-dyndb-ldap: {'type': 'default', 'basearchonly': False} - Package: freeipa-server-dns: {'type': 'default', 'basearchonly': False} - Package: freeipa-server-trust-ad: {'type': 'default', 'basearchonly': False} - Package: opendnssec: {'type': 'default', 'basearchonly': False} + Package: freeipa-server: {'basearchonly': False, 'type': 'mandatory'} + Package: bind-dyndb-ldap: {'basearchonly': False, 'type': 'default'} + Package: freeipa-server-dns: {'basearchonly': False, 'type': 'default'} + Package: freeipa-server-trust-ad: {'basearchonly': False, 'type': 'default'} + Package: opendnssec: {'basearchonly': False, 'type': 'default'} Group: ftp-server (FTP Server) - Package: vsftpd: {'type': 'mandatory', 'basearchonly': False} - Package: proftpd: {'type': 'optional', 'basearchonly': False} - Package: pure-ftpd: {'type': 'optional', 'basearchonly': False} + Package: vsftpd: {'basearchonly': False, 'type': 'mandatory'} + Package: proftpd: {'basearchonly': False, 'type': 'optional'} + Package: pure-ftpd: {'basearchonly': False, 'type': 'optional'} Group: games (Games and Entertainment) - Package: 0ad: {'type': 'optional', 'basearchonly': False} - Package: abe: {'type': 'optional', 'basearchonly': False} - Package: adanaxisgpl: {'type': 'optional', 'basearchonly': False} - Package: agistudio: {'type': 'optional', 'basearchonly': False} - Package: alex4: {'type': 'optional', 'basearchonly': False} - Package: alienarena: {'type': 'optional', 'basearchonly': False} - Package: alienblaster: {'type': 'optional', 'basearchonly': False} - Package: alphabet-soup: {'type': 'optional', 'basearchonly': False} - Package: amoebax: {'type': 'optional', 'basearchonly': False} - Package: angrydd: {'type': 'optional', 'basearchonly': False} - Package: ants: {'type': 'optional', 'basearchonly': False} - Package: apricots: {'type': 'optional', 'basearchonly': False} - Package: armacycles-ad: {'type': 'optional', 'basearchonly': False} - Package: arrows: {'type': 'optional', 'basearchonly': False} - Package: asc: {'type': 'optional', 'basearchonly': False} - Package: asc-music: {'type': 'optional', 'basearchonly': False} - Package: astromenace: {'type': 'optional', 'basearchonly': False} - Package: asylum: {'type': 'optional', 'basearchonly': False} - Package: atanks: {'type': 'optional', 'basearchonly': False} - Package: atomix: {'type': 'optional', 'basearchonly': False} - Package: atomorun: {'type': 'optional', 'basearchonly': False} - Package: auriferous: {'type': 'optional', 'basearchonly': False} - Package: avoision: {'type': 'optional', 'basearchonly': False} - Package: ballbuster: {'type': 'optional', 'basearchonly': False} - Package: ballz: {'type': 'optional', 'basearchonly': False} - Package: barrage: {'type': 'optional', 'basearchonly': False} - Package: bastet: {'type': 'optional', 'basearchonly': False} - Package: beneath-a-steel-sky: {'type': 'optional', 'basearchonly': False} - Package: beneath-a-steel-sky-cd: {'type': 'optional', 'basearchonly': False} - Package: berusky: {'type': 'optional', 'basearchonly': False} - Package: berusky2: {'type': 'optional', 'basearchonly': False} - Package: billiards: {'type': 'optional', 'basearchonly': False} - Package: biloba: {'type': 'optional', 'basearchonly': False} - Package: biniax: {'type': 'optional', 'basearchonly': False} - Package: blobby: {'type': 'optional', 'basearchonly': False} - Package: blobwars: {'type': 'optional', 'basearchonly': False} - Package: BlockOutII: {'type': 'optional', 'basearchonly': False} - Package: bolzplatz2006: {'type': 'optional', 'basearchonly': False} - Package: bombardier: {'type': 'optional', 'basearchonly': False} - Package: boswars: {'type': 'optional', 'basearchonly': False} - Package: boswars-addons: {'type': 'optional', 'basearchonly': False} - Package: bsd-games: {'type': 'optional', 'basearchonly': False} - Package: bsp: {'type': 'optional', 'basearchonly': False} - Package: btanks: {'type': 'optional', 'basearchonly': False} - Package: bygfoot: {'type': 'optional', 'basearchonly': False} - Package: bzflag: {'type': 'optional', 'basearchonly': False} - Package: CardManager: {'type': 'optional', 'basearchonly': False} - Package: cave9: {'type': 'optional', 'basearchonly': False} - Package: ccgo: {'type': 'optional', 'basearchonly': False} - Package: cdogs-sdl: {'type': 'optional', 'basearchonly': False} - Package: celestia: {'type': 'optional', 'basearchonly': False} - Package: chocolate-doom: {'type': 'optional', 'basearchonly': False} - Package: chromium-bsu: {'type': 'optional', 'basearchonly': False} - Package: clanbomber: {'type': 'optional', 'basearchonly': False} - Package: clonekeen: {'type': 'optional', 'basearchonly': False} - Package: coco-coq: {'type': 'optional', 'basearchonly': False} - Package: colossus: {'type': 'optional', 'basearchonly': False} - Package: crack-attack: {'type': 'optional', 'basearchonly': False} - Package: CriticalMass: {'type': 'optional', 'basearchonly': False} - Package: crossfire: {'type': 'optional', 'basearchonly': False} - Package: crossfire-client: {'type': 'optional', 'basearchonly': False} - Package: crystal-stacker: {'type': 'optional', 'basearchonly': False} - Package: crystal-stacker-themes: {'type': 'optional', 'basearchonly': False} - Package: csmash: {'type': 'optional', 'basearchonly': False} - Package: curblaster: {'type': 'optional', 'basearchonly': False} - Package: cylindrix: {'type': 'optional', 'basearchonly': False} - Package: cyphesis: {'type': 'optional', 'basearchonly': False} - Package: darkplaces-quake: {'type': 'optional', 'basearchonly': False} - Package: dd2: {'type': 'optional', 'basearchonly': False} - Package: dgae: {'type': 'optional', 'basearchonly': False} - Package: dopewars: {'type': 'optional', 'basearchonly': False} - Package: drascula: {'type': 'optional', 'basearchonly': False} - Package: drascula-music: {'type': 'optional', 'basearchonly': False} - Package: dsi: {'type': 'optional', 'basearchonly': False} - Package: duel3: {'type': 'optional', 'basearchonly': False} - Package: ember: {'type': 'optional', 'basearchonly': False} - Package: enigma: {'type': 'optional', 'basearchonly': False} - Package: escape: {'type': 'optional', 'basearchonly': False} - Package: extremetuxracer: {'type': 'optional', 'basearchonly': False} - Package: fbg2: {'type': 'optional', 'basearchonly': False} - Package: fgrun: {'type': 'optional', 'basearchonly': False} - Package: fillets-ng: {'type': 'optional', 'basearchonly': False} - Package: findthatword: {'type': 'optional', 'basearchonly': False} - Package: five-or-more: {'type': 'optional', 'basearchonly': False} - Package: flare: {'type': 'optional', 'basearchonly': False} - Package: flight-of-the-amazon-queen: {'type': 'optional', 'basearchonly': False} - Package: flight-of-the-amazon-queen-cd: {'type': 'optional', 'basearchonly': False} - Package: FlightGear: {'type': 'optional', 'basearchonly': False} - Package: flobopuyo: {'type': 'optional', 'basearchonly': False} - Package: foobillard: {'type': 'optional', 'basearchonly': False} - Package: fortune-mod: {'type': 'optional', 'basearchonly': False} - Package: four-in-a-row: {'type': 'optional', 'basearchonly': False} - Package: freeciv: {'type': 'optional', 'basearchonly': False} - Package: freecol: {'type': 'optional', 'basearchonly': False} - Package: freedink: {'type': 'optional', 'basearchonly': False} - Package: freedoom: {'type': 'optional', 'basearchonly': False} - Package: freedoom-freedm: {'type': 'optional', 'basearchonly': False} - Package: freedroid: {'type': 'optional', 'basearchonly': False} - Package: freedroidrpg: {'type': 'optional', 'basearchonly': False} - Package: freetennis: {'type': 'optional', 'basearchonly': False} - Package: frozen-bubble: {'type': 'optional', 'basearchonly': False} - Package: funguloids: {'type': 'optional', 'basearchonly': False} - Package: gamazons: {'type': 'optional', 'basearchonly': False} - Package: games-menus: {'type': 'optional', 'basearchonly': False} - Package: gbrainy: {'type': 'optional', 'basearchonly': False} - Package: gemdropx: {'type': 'optional', 'basearchonly': False} - Package: gl-117: {'type': 'optional', 'basearchonly': False} - Package: glaxium: {'type': 'optional', 'basearchonly': False} - Package: glob2: {'type': 'optional', 'basearchonly': False} - Package: gnome-chess: {'type': 'optional', 'basearchonly': False} - Package: gnome-hearts: {'type': 'optional', 'basearchonly': False} - Package: gnome-klotski: {'type': 'optional', 'basearchonly': False} - Package: gnome-mahjongg: {'type': 'optional', 'basearchonly': False} - Package: gnome-mines: {'type': 'optional', 'basearchonly': False} - Package: gnome-mud: {'type': 'optional', 'basearchonly': False} - Package: gnome-nibbles: {'type': 'optional', 'basearchonly': False} - Package: gnome-robots: {'type': 'optional', 'basearchonly': False} - Package: gnome-sudoku: {'type': 'optional', 'basearchonly': False} - Package: gnome-tetravex: {'type': 'optional', 'basearchonly': False} - Package: gnubg: {'type': 'optional', 'basearchonly': False} - Package: gnubik: {'type': 'optional', 'basearchonly': False} - Package: gnuchess: {'type': 'optional', 'basearchonly': False} - Package: gnugo: {'type': 'optional', 'basearchonly': False} - Package: gnujump: {'type': 'optional', 'basearchonly': False} - Package: greyhounds: {'type': 'optional', 'basearchonly': False} - Package: grhino: {'type': 'optional', 'basearchonly': False} - Package: gweled: {'type': 'optional', 'basearchonly': False} - Package: haxima: {'type': 'optional', 'basearchonly': False} - Package: hedgewars: {'type': 'optional', 'basearchonly': False} - Package: hexglass: {'type': 'optional', 'basearchonly': False} - Package: hitori: {'type': 'optional', 'basearchonly': False} - Package: iagno: {'type': 'optional', 'basearchonly': False} - Package: iapetal: {'type': 'optional', 'basearchonly': False} - Package: joystick: {'type': 'optional', 'basearchonly': False} - Package: kbilliards: {'type': 'optional', 'basearchonly': False} - Package: kcheckers: {'type': 'optional', 'basearchonly': False} - Package: kdeaddons-atlantikdesigner: {'type': 'optional', 'basearchonly': False} - Package: kdegames: {'type': 'optional', 'basearchonly': False} - Package: kdegames3: {'type': 'optional', 'basearchonly': False} - Package: kitsune: {'type': 'optional', 'basearchonly': False} - Package: knights: {'type': 'optional', 'basearchonly': False} - Package: KoboDeluxe: {'type': 'optional', 'basearchonly': False} - Package: koules: {'type': 'optional', 'basearchonly': False} - Package: lacewing: {'type': 'optional', 'basearchonly': False} - Package: lbrickbuster2: {'type': 'optional', 'basearchonly': False} - Package: lightsoff: {'type': 'optional', 'basearchonly': False} - Package: lincity-ng: {'type': 'optional', 'basearchonly': False} - Package: liquidwar: {'type': 'optional', 'basearchonly': False} - Package: lmarbles: {'type': 'optional', 'basearchonly': False} - Package: londonlaw: {'type': 'optional', 'basearchonly': False} - Package: lordsawar: {'type': 'optional', 'basearchonly': False} - Package: lpairs: {'type': 'optional', 'basearchonly': False} - Package: lucidlife: {'type': 'optional', 'basearchonly': False} - Package: lure: {'type': 'optional', 'basearchonly': False} - Package: machineball: {'type': 'optional', 'basearchonly': False} - Package: Maelstrom: {'type': 'optional', 'basearchonly': False} - Package: magicmaze: {'type': 'optional', 'basearchonly': False} - Package: magicor: {'type': 'optional', 'basearchonly': False} - Package: maniadrive: {'type': 'optional', 'basearchonly': False} - Package: maniadrive-music: {'type': 'optional', 'basearchonly': False} - Package: megaglest: {'type': 'optional', 'basearchonly': False} - Package: methane: {'type': 'optional', 'basearchonly': False} - Package: mindless: {'type': 'optional', 'basearchonly': False} - Package: minetest: {'type': 'optional', 'basearchonly': False} - Package: mine_detector: {'type': 'optional', 'basearchonly': False} - Package: mirrormagic: {'type': 'optional', 'basearchonly': False} - Package: mj: {'type': 'optional', 'basearchonly': False} - Package: monsterz: {'type': 'optional', 'basearchonly': False} - Package: naev: {'type': 'optional', 'basearchonly': False} - Package: nagi: {'type': 'optional', 'basearchonly': False} - Package: naturette: {'type': 'optional', 'basearchonly': False} - Package: nazghul: {'type': 'optional', 'basearchonly': False} - Package: nethack: {'type': 'optional', 'basearchonly': False} - Package: nethack-vultures: {'type': 'optional', 'basearchonly': False} - Package: netpanzer: {'type': 'optional', 'basearchonly': False} - Package: neverball: {'type': 'optional', 'basearchonly': False} - Package: njam: {'type': 'optional', 'basearchonly': False} - Package: nogravity: {'type': 'optional', 'basearchonly': False} - Package: oneko: {'type': 'optional', 'basearchonly': False} - Package: openalchemist: {'type': 'optional', 'basearchonly': False} - Package: openarena: {'type': 'optional', 'basearchonly': False} - Package: openlierox: {'type': 'optional', 'basearchonly': False} - Package: overgod: {'type': 'optional', 'basearchonly': False} - Package: pachi: {'type': 'optional', 'basearchonly': False} - Package: penguin-command: {'type': 'optional', 'basearchonly': False} - Package: pengupop: {'type': 'optional', 'basearchonly': False} - Package: pinball: {'type': 'optional', 'basearchonly': False} - Package: pingus: {'type': 'optional', 'basearchonly': False} - Package: pioneers: {'type': 'optional', 'basearchonly': False} - Package: pipenightdreams: {'type': 'optional', 'basearchonly': False} - Package: pipepanic: {'type': 'optional', 'basearchonly': False} - Package: planets: {'type': 'optional', 'basearchonly': False} - Package: plee-the-bear: {'type': 'optional', 'basearchonly': False} - Package: pokerth: {'type': 'optional', 'basearchonly': False} - Package: powermanga: {'type': 'optional', 'basearchonly': False} - Package: prboom: {'type': 'optional', 'basearchonly': False} - Package: professor-is-missing: {'type': 'optional', 'basearchonly': False} - Package: puzzle-master: {'type': 'optional', 'basearchonly': False} - Package: puzzles: {'type': 'optional', 'basearchonly': False} - Package: pychess: {'type': 'optional', 'basearchonly': False} - Package: PySolFC: {'type': 'optional', 'basearchonly': False} - Package: PySolFC-cardsets: {'type': 'optional', 'basearchonly': False} - Package: PySolFC-music: {'type': 'optional', 'basearchonly': False} - Package: qascade: {'type': 'optional', 'basearchonly': False} - Package: qstars: {'type': 'optional', 'basearchonly': False} - Package: quadrapassel: {'type': 'optional', 'basearchonly': False} - Package: quake3: {'type': 'optional', 'basearchonly': False} - Package: quake3-demo: {'type': 'optional', 'basearchonly': False} - Package: quarry: {'type': 'optional', 'basearchonly': False} - Package: rafkill: {'type': 'optional', 'basearchonly': False} - Package: raidem: {'type': 'optional', 'basearchonly': False} - Package: raidem-music: {'type': 'optional', 'basearchonly': False} - Package: redeclipse: {'type': 'optional', 'basearchonly': False} - Package: redeclipse-data: {'type': 'optional', 'basearchonly': False} - Package: redeclipse-server: {'type': 'optional', 'basearchonly': False} - Package: Ri-li: {'type': 'optional', 'basearchonly': False} - Package: rocksndiamonds: {'type': 'optional', 'basearchonly': False} - Package: rogue: {'type': 'optional', 'basearchonly': False} - Package: rott-shareware: {'type': 'optional', 'basearchonly': False} - Package: sar2: {'type': 'optional', 'basearchonly': False} - Package: scorched3d: {'type': 'optional', 'basearchonly': False} - Package: scorchwentbonkers: {'type': 'optional', 'basearchonly': False} - Package: scummvm: {'type': 'optional', 'basearchonly': False} - Package: seahorse-adventures: {'type': 'optional', 'basearchonly': False} - Package: sergueis-destiny: {'type': 'optional', 'basearchonly': False} - Package: shippy: {'type': 'optional', 'basearchonly': False} - Package: sirius: {'type': 'optional', 'basearchonly': False} - Package: six: {'type': 'optional', 'basearchonly': False} - Package: slashem: {'type': 'optional', 'basearchonly': False} - Package: slingshot: {'type': 'optional', 'basearchonly': False} - Package: solarwolf: {'type': 'optional', 'basearchonly': False} - Package: sopwith: {'type': 'optional', 'basearchonly': False} - Package: spring: {'type': 'optional', 'basearchonly': False} - Package: stormbaancoureur: {'type': 'optional', 'basearchonly': False} - Package: sudoku-savant: {'type': 'optional', 'basearchonly': False} - Package: sumwars: {'type': 'optional', 'basearchonly': False} - Package: supertux: {'type': 'optional', 'basearchonly': False} - Package: supertuxkart: {'type': 'optional', 'basearchonly': False} - Package: swell-foop: {'type': 'optional', 'basearchonly': False} - Package: taggle: {'type': 'optional', 'basearchonly': False} - Package: tali: {'type': 'optional', 'basearchonly': False} - Package: taxipilot: {'type': 'optional', 'basearchonly': False} - Package: tecnoballz: {'type': 'optional', 'basearchonly': False} - Package: teeworlds: {'type': 'optional', 'basearchonly': False} - Package: tennix: {'type': 'optional', 'basearchonly': False} - Package: tong: {'type': 'optional', 'basearchonly': False} - Package: toppler: {'type': 'optional', 'basearchonly': False} - Package: torcs: {'type': 'optional', 'basearchonly': False} - Package: torcs-data: {'type': 'optional', 'basearchonly': False} - Package: trackballs: {'type': 'optional', 'basearchonly': False} - Package: trackballs-music: {'type': 'optional', 'basearchonly': False} - Package: tremulous: {'type': 'optional', 'basearchonly': False} - Package: trophy: {'type': 'optional', 'basearchonly': False} - Package: tunneler: {'type': 'optional', 'basearchonly': False} - Package: tuxmath: {'type': 'optional', 'basearchonly': False} - Package: tuxpuck: {'type': 'optional', 'basearchonly': False} - Package: typespeed: {'type': 'optional', 'basearchonly': False} - Package: ularn: {'type': 'optional', 'basearchonly': False} - Package: ultimatestunts: {'type': 'optional', 'basearchonly': False} - Package: uqm: {'type': 'optional', 'basearchonly': False} - Package: urbanterror: {'type': 'optional', 'basearchonly': False} - Package: vavoom: {'type': 'optional', 'basearchonly': False} - Package: vdr-sudoku: {'type': 'optional', 'basearchonly': False} - Package: vdrift: {'type': 'optional', 'basearchonly': False} - Package: vegastrike: {'type': 'optional', 'basearchonly': False} - Package: vegastrike-extra: {'type': 'optional', 'basearchonly': False} - Package: vegastrike-music: {'type': 'optional', 'basearchonly': False} - Package: vegastrike-speech: {'type': 'optional', 'basearchonly': False} - Package: vodovod: {'type': 'optional', 'basearchonly': False} - Package: warmux: {'type': 'optional', 'basearchonly': False} - Package: warzone2100: {'type': 'optional', 'basearchonly': False} - Package: warzone2100-sequences: {'type': 'optional', 'basearchonly': False} - Package: wastesedge: {'type': 'optional', 'basearchonly': False} - Package: wesnoth: {'type': 'optional', 'basearchonly': False} - Package: widelands: {'type': 'optional', 'basearchonly': False} - Package: wordwarvi: {'type': 'optional', 'basearchonly': False} - Package: worldofpadman: {'type': 'optional', 'basearchonly': False} - Package: worminator: {'type': 'optional', 'basearchonly': False} - Package: xaos: {'type': 'optional', 'basearchonly': False} - Package: xarchon: {'type': 'optional', 'basearchonly': False} - Package: xblast: {'type': 'optional', 'basearchonly': False} - Package: xboard: {'type': 'optional', 'basearchonly': False} - Package: xgalaxy: {'type': 'optional', 'basearchonly': False} - Package: xgrav: {'type': 'optional', 'basearchonly': False} - Package: xmoto: {'type': 'optional', 'basearchonly': False} - Package: xonotic: {'type': 'optional', 'basearchonly': False} - Package: xpenguins: {'type': 'optional', 'basearchonly': False} - Package: xpilot-ng: {'type': 'optional', 'basearchonly': False} - Package: xpilot-ng-server: {'type': 'optional', 'basearchonly': False} - Package: xplanet: {'type': 'optional', 'basearchonly': False} - Package: xscorch: {'type': 'optional', 'basearchonly': False} - Package: xskat: {'type': 'optional', 'basearchonly': False} - Package: xstar: {'type': 'optional', 'basearchonly': False} - Package: xteddy: {'type': 'optional', 'basearchonly': False} - Package: xu4: {'type': 'optional', 'basearchonly': False} - Package: xword: {'type': 'optional', 'basearchonly': False} - Package: zasx: {'type': 'optional', 'basearchonly': False} - Package: zaz: {'type': 'optional', 'basearchonly': False} + Package: 0ad: {'basearchonly': False, 'type': 'optional'} + Package: abe: {'basearchonly': False, 'type': 'optional'} + Package: adanaxisgpl: {'basearchonly': False, 'type': 'optional'} + Package: agistudio: {'basearchonly': False, 'type': 'optional'} + Package: alex4: {'basearchonly': False, 'type': 'optional'} + Package: alienarena: {'basearchonly': False, 'type': 'optional'} + Package: alienblaster: {'basearchonly': False, 'type': 'optional'} + Package: alphabet-soup: {'basearchonly': False, 'type': 'optional'} + Package: amoebax: {'basearchonly': False, 'type': 'optional'} + Package: angrydd: {'basearchonly': False, 'type': 'optional'} + Package: ants: {'basearchonly': False, 'type': 'optional'} + Package: apricots: {'basearchonly': False, 'type': 'optional'} + Package: armacycles-ad: {'basearchonly': False, 'type': 'optional'} + Package: arrows: {'basearchonly': False, 'type': 'optional'} + Package: asc: {'basearchonly': False, 'type': 'optional'} + Package: asc-music: {'basearchonly': False, 'type': 'optional'} + Package: astromenace: {'basearchonly': False, 'type': 'optional'} + Package: asylum: {'basearchonly': False, 'type': 'optional'} + Package: atanks: {'basearchonly': False, 'type': 'optional'} + Package: atomix: {'basearchonly': False, 'type': 'optional'} + Package: atomorun: {'basearchonly': False, 'type': 'optional'} + Package: auriferous: {'basearchonly': False, 'type': 'optional'} + Package: avoision: {'basearchonly': False, 'type': 'optional'} + Package: ballbuster: {'basearchonly': False, 'type': 'optional'} + Package: ballz: {'basearchonly': False, 'type': 'optional'} + Package: barrage: {'basearchonly': False, 'type': 'optional'} + Package: bastet: {'basearchonly': False, 'type': 'optional'} + Package: beneath-a-steel-sky: {'basearchonly': False, 'type': 'optional'} + Package: beneath-a-steel-sky-cd: {'basearchonly': False, 'type': 'optional'} + Package: berusky: {'basearchonly': False, 'type': 'optional'} + Package: berusky2: {'basearchonly': False, 'type': 'optional'} + Package: billiards: {'basearchonly': False, 'type': 'optional'} + Package: biloba: {'basearchonly': False, 'type': 'optional'} + Package: biniax: {'basearchonly': False, 'type': 'optional'} + Package: blobby: {'basearchonly': False, 'type': 'optional'} + Package: blobwars: {'basearchonly': False, 'type': 'optional'} + Package: BlockOutII: {'basearchonly': False, 'type': 'optional'} + Package: bolzplatz2006: {'basearchonly': False, 'type': 'optional'} + Package: bombardier: {'basearchonly': False, 'type': 'optional'} + Package: boswars: {'basearchonly': False, 'type': 'optional'} + Package: boswars-addons: {'basearchonly': False, 'type': 'optional'} + Package: bsd-games: {'basearchonly': False, 'type': 'optional'} + Package: bsp: {'basearchonly': False, 'type': 'optional'} + Package: btanks: {'basearchonly': False, 'type': 'optional'} + Package: bygfoot: {'basearchonly': False, 'type': 'optional'} + Package: bzflag: {'basearchonly': False, 'type': 'optional'} + Package: CardManager: {'basearchonly': False, 'type': 'optional'} + Package: cave9: {'basearchonly': False, 'type': 'optional'} + Package: ccgo: {'basearchonly': False, 'type': 'optional'} + Package: cdogs-sdl: {'basearchonly': False, 'type': 'optional'} + Package: celestia: {'basearchonly': False, 'type': 'optional'} + Package: chocolate-doom: {'basearchonly': False, 'type': 'optional'} + Package: chromium-bsu: {'basearchonly': False, 'type': 'optional'} + Package: clanbomber: {'basearchonly': False, 'type': 'optional'} + Package: clonekeen: {'basearchonly': False, 'type': 'optional'} + Package: coco-coq: {'basearchonly': False, 'type': 'optional'} + Package: colossus: {'basearchonly': False, 'type': 'optional'} + Package: crack-attack: {'basearchonly': False, 'type': 'optional'} + Package: CriticalMass: {'basearchonly': False, 'type': 'optional'} + Package: crossfire: {'basearchonly': False, 'type': 'optional'} + Package: crossfire-client: {'basearchonly': False, 'type': 'optional'} + Package: crystal-stacker: {'basearchonly': False, 'type': 'optional'} + Package: crystal-stacker-themes: {'basearchonly': False, 'type': 'optional'} + Package: csmash: {'basearchonly': False, 'type': 'optional'} + Package: curblaster: {'basearchonly': False, 'type': 'optional'} + Package: cylindrix: {'basearchonly': False, 'type': 'optional'} + Package: cyphesis: {'basearchonly': False, 'type': 'optional'} + Package: darkplaces-quake: {'basearchonly': False, 'type': 'optional'} + Package: dd2: {'basearchonly': False, 'type': 'optional'} + Package: dgae: {'basearchonly': False, 'type': 'optional'} + Package: dopewars: {'basearchonly': False, 'type': 'optional'} + Package: drascula: {'basearchonly': False, 'type': 'optional'} + Package: drascula-music: {'basearchonly': False, 'type': 'optional'} + Package: dsi: {'basearchonly': False, 'type': 'optional'} + Package: duel3: {'basearchonly': False, 'type': 'optional'} + Package: ember: {'basearchonly': False, 'type': 'optional'} + Package: enigma: {'basearchonly': False, 'type': 'optional'} + Package: escape: {'basearchonly': False, 'type': 'optional'} + Package: extremetuxracer: {'basearchonly': False, 'type': 'optional'} + Package: fbg2: {'basearchonly': False, 'type': 'optional'} + Package: fgrun: {'basearchonly': False, 'type': 'optional'} + Package: fillets-ng: {'basearchonly': False, 'type': 'optional'} + Package: findthatword: {'basearchonly': False, 'type': 'optional'} + Package: five-or-more: {'basearchonly': False, 'type': 'optional'} + Package: flare: {'basearchonly': False, 'type': 'optional'} + Package: flight-of-the-amazon-queen: {'basearchonly': False, 'type': 'optional'} + Package: flight-of-the-amazon-queen-cd: {'basearchonly': False, 'type': 'optional'} + Package: FlightGear: {'basearchonly': False, 'type': 'optional'} + Package: flobopuyo: {'basearchonly': False, 'type': 'optional'} + Package: foobillard: {'basearchonly': False, 'type': 'optional'} + Package: fortune-mod: {'basearchonly': False, 'type': 'optional'} + Package: four-in-a-row: {'basearchonly': False, 'type': 'optional'} + Package: freeciv: {'basearchonly': False, 'type': 'optional'} + Package: freecol: {'basearchonly': False, 'type': 'optional'} + Package: freedink: {'basearchonly': False, 'type': 'optional'} + Package: freedoom: {'basearchonly': False, 'type': 'optional'} + Package: freedoom-freedm: {'basearchonly': False, 'type': 'optional'} + Package: freedroid: {'basearchonly': False, 'type': 'optional'} + Package: freedroidrpg: {'basearchonly': False, 'type': 'optional'} + Package: freetennis: {'basearchonly': False, 'type': 'optional'} + Package: frozen-bubble: {'basearchonly': False, 'type': 'optional'} + Package: funguloids: {'basearchonly': False, 'type': 'optional'} + Package: gamazons: {'basearchonly': False, 'type': 'optional'} + Package: games-menus: {'basearchonly': False, 'type': 'optional'} + Package: gbrainy: {'basearchonly': False, 'type': 'optional'} + Package: gemdropx: {'basearchonly': False, 'type': 'optional'} + Package: gl-117: {'basearchonly': False, 'type': 'optional'} + Package: glaxium: {'basearchonly': False, 'type': 'optional'} + Package: glob2: {'basearchonly': False, 'type': 'optional'} + Package: gnome-chess: {'basearchonly': False, 'type': 'optional'} + Package: gnome-hearts: {'basearchonly': False, 'type': 'optional'} + Package: gnome-klotski: {'basearchonly': False, 'type': 'optional'} + Package: gnome-mahjongg: {'basearchonly': False, 'type': 'optional'} + Package: gnome-mines: {'basearchonly': False, 'type': 'optional'} + Package: gnome-mud: {'basearchonly': False, 'type': 'optional'} + Package: gnome-nibbles: {'basearchonly': False, 'type': 'optional'} + Package: gnome-robots: {'basearchonly': False, 'type': 'optional'} + Package: gnome-sudoku: {'basearchonly': False, 'type': 'optional'} + Package: gnome-tetravex: {'basearchonly': False, 'type': 'optional'} + Package: gnubg: {'basearchonly': False, 'type': 'optional'} + Package: gnubik: {'basearchonly': False, 'type': 'optional'} + Package: gnuchess: {'basearchonly': False, 'type': 'optional'} + Package: gnugo: {'basearchonly': False, 'type': 'optional'} + Package: gnujump: {'basearchonly': False, 'type': 'optional'} + Package: greyhounds: {'basearchonly': False, 'type': 'optional'} + Package: grhino: {'basearchonly': False, 'type': 'optional'} + Package: gweled: {'basearchonly': False, 'type': 'optional'} + Package: haxima: {'basearchonly': False, 'type': 'optional'} + Package: hedgewars: {'basearchonly': False, 'type': 'optional'} + Package: hexglass: {'basearchonly': False, 'type': 'optional'} + Package: hitori: {'basearchonly': False, 'type': 'optional'} + Package: iagno: {'basearchonly': False, 'type': 'optional'} + Package: iapetal: {'basearchonly': False, 'type': 'optional'} + Package: joystick: {'basearchonly': False, 'type': 'optional'} + Package: kbilliards: {'basearchonly': False, 'type': 'optional'} + Package: kcheckers: {'basearchonly': False, 'type': 'optional'} + Package: kdeaddons-atlantikdesigner: {'basearchonly': False, 'type': 'optional'} + Package: kdegames: {'basearchonly': False, 'type': 'optional'} + Package: kdegames3: {'basearchonly': False, 'type': 'optional'} + Package: kitsune: {'basearchonly': False, 'type': 'optional'} + Package: knights: {'basearchonly': False, 'type': 'optional'} + Package: KoboDeluxe: {'basearchonly': False, 'type': 'optional'} + Package: koules: {'basearchonly': False, 'type': 'optional'} + Package: lacewing: {'basearchonly': False, 'type': 'optional'} + Package: lbrickbuster2: {'basearchonly': False, 'type': 'optional'} + Package: lightsoff: {'basearchonly': False, 'type': 'optional'} + Package: lincity-ng: {'basearchonly': False, 'type': 'optional'} + Package: liquidwar: {'basearchonly': False, 'type': 'optional'} + Package: lmarbles: {'basearchonly': False, 'type': 'optional'} + Package: londonlaw: {'basearchonly': False, 'type': 'optional'} + Package: lordsawar: {'basearchonly': False, 'type': 'optional'} + Package: lpairs: {'basearchonly': False, 'type': 'optional'} + Package: lucidlife: {'basearchonly': False, 'type': 'optional'} + Package: lure: {'basearchonly': False, 'type': 'optional'} + Package: machineball: {'basearchonly': False, 'type': 'optional'} + Package: Maelstrom: {'basearchonly': False, 'type': 'optional'} + Package: magicmaze: {'basearchonly': False, 'type': 'optional'} + Package: magicor: {'basearchonly': False, 'type': 'optional'} + Package: maniadrive: {'basearchonly': False, 'type': 'optional'} + Package: maniadrive-music: {'basearchonly': False, 'type': 'optional'} + Package: megaglest: {'basearchonly': False, 'type': 'optional'} + Package: methane: {'basearchonly': False, 'type': 'optional'} + Package: mindless: {'basearchonly': False, 'type': 'optional'} + Package: minetest: {'basearchonly': False, 'type': 'optional'} + Package: mine_detector: {'basearchonly': False, 'type': 'optional'} + Package: mirrormagic: {'basearchonly': False, 'type': 'optional'} + Package: mj: {'basearchonly': False, 'type': 'optional'} + Package: monsterz: {'basearchonly': False, 'type': 'optional'} + Package: naev: {'basearchonly': False, 'type': 'optional'} + Package: nagi: {'basearchonly': False, 'type': 'optional'} + Package: naturette: {'basearchonly': False, 'type': 'optional'} + Package: nazghul: {'basearchonly': False, 'type': 'optional'} + Package: nethack: {'basearchonly': False, 'type': 'optional'} + Package: nethack-vultures: {'basearchonly': False, 'type': 'optional'} + Package: netpanzer: {'basearchonly': False, 'type': 'optional'} + Package: neverball: {'basearchonly': False, 'type': 'optional'} + Package: njam: {'basearchonly': False, 'type': 'optional'} + Package: nogravity: {'basearchonly': False, 'type': 'optional'} + Package: oneko: {'basearchonly': False, 'type': 'optional'} + Package: openalchemist: {'basearchonly': False, 'type': 'optional'} + Package: openarena: {'basearchonly': False, 'type': 'optional'} + Package: openlierox: {'basearchonly': False, 'type': 'optional'} + Package: overgod: {'basearchonly': False, 'type': 'optional'} + Package: pachi: {'basearchonly': False, 'type': 'optional'} + Package: penguin-command: {'basearchonly': False, 'type': 'optional'} + Package: pengupop: {'basearchonly': False, 'type': 'optional'} + Package: pinball: {'basearchonly': False, 'type': 'optional'} + Package: pingus: {'basearchonly': False, 'type': 'optional'} + Package: pioneers: {'basearchonly': False, 'type': 'optional'} + Package: pipenightdreams: {'basearchonly': False, 'type': 'optional'} + Package: pipepanic: {'basearchonly': False, 'type': 'optional'} + Package: planets: {'basearchonly': False, 'type': 'optional'} + Package: plee-the-bear: {'basearchonly': False, 'type': 'optional'} + Package: pokerth: {'basearchonly': False, 'type': 'optional'} + Package: powermanga: {'basearchonly': False, 'type': 'optional'} + Package: prboom: {'basearchonly': False, 'type': 'optional'} + Package: professor-is-missing: {'basearchonly': False, 'type': 'optional'} + Package: puzzle-master: {'basearchonly': False, 'type': 'optional'} + Package: puzzles: {'basearchonly': False, 'type': 'optional'} + Package: pychess: {'basearchonly': False, 'type': 'optional'} + Package: PySolFC: {'basearchonly': False, 'type': 'optional'} + Package: PySolFC-cardsets: {'basearchonly': False, 'type': 'optional'} + Package: PySolFC-music: {'basearchonly': False, 'type': 'optional'} + Package: qascade: {'basearchonly': False, 'type': 'optional'} + Package: qstars: {'basearchonly': False, 'type': 'optional'} + Package: quadrapassel: {'basearchonly': False, 'type': 'optional'} + Package: quake3: {'basearchonly': False, 'type': 'optional'} + Package: quake3-demo: {'basearchonly': False, 'type': 'optional'} + Package: quarry: {'basearchonly': False, 'type': 'optional'} + Package: rafkill: {'basearchonly': False, 'type': 'optional'} + Package: raidem: {'basearchonly': False, 'type': 'optional'} + Package: raidem-music: {'basearchonly': False, 'type': 'optional'} + Package: redeclipse: {'basearchonly': False, 'type': 'optional'} + Package: redeclipse-data: {'basearchonly': False, 'type': 'optional'} + Package: redeclipse-server: {'basearchonly': False, 'type': 'optional'} + Package: Ri-li: {'basearchonly': False, 'type': 'optional'} + Package: rocksndiamonds: {'basearchonly': False, 'type': 'optional'} + Package: rogue: {'basearchonly': False, 'type': 'optional'} + Package: rott-shareware: {'basearchonly': False, 'type': 'optional'} + Package: sar2: {'basearchonly': False, 'type': 'optional'} + Package: scorched3d: {'basearchonly': False, 'type': 'optional'} + Package: scorchwentbonkers: {'basearchonly': False, 'type': 'optional'} + Package: scummvm: {'basearchonly': False, 'type': 'optional'} + Package: seahorse-adventures: {'basearchonly': False, 'type': 'optional'} + Package: sergueis-destiny: {'basearchonly': False, 'type': 'optional'} + Package: shippy: {'basearchonly': False, 'type': 'optional'} + Package: sirius: {'basearchonly': False, 'type': 'optional'} + Package: six: {'basearchonly': False, 'type': 'optional'} + Package: slashem: {'basearchonly': False, 'type': 'optional'} + Package: slingshot: {'basearchonly': False, 'type': 'optional'} + Package: solarwolf: {'basearchonly': False, 'type': 'optional'} + Package: sopwith: {'basearchonly': False, 'type': 'optional'} + Package: spring: {'basearchonly': False, 'type': 'optional'} + Package: stormbaancoureur: {'basearchonly': False, 'type': 'optional'} + Package: sudoku-savant: {'basearchonly': False, 'type': 'optional'} + Package: sumwars: {'basearchonly': False, 'type': 'optional'} + Package: supertux: {'basearchonly': False, 'type': 'optional'} + Package: supertuxkart: {'basearchonly': False, 'type': 'optional'} + Package: swell-foop: {'basearchonly': False, 'type': 'optional'} + Package: taggle: {'basearchonly': False, 'type': 'optional'} + Package: tali: {'basearchonly': False, 'type': 'optional'} + Package: taxipilot: {'basearchonly': False, 'type': 'optional'} + Package: tecnoballz: {'basearchonly': False, 'type': 'optional'} + Package: teeworlds: {'basearchonly': False, 'type': 'optional'} + Package: tennix: {'basearchonly': False, 'type': 'optional'} + Package: tong: {'basearchonly': False, 'type': 'optional'} + Package: toppler: {'basearchonly': False, 'type': 'optional'} + Package: torcs: {'basearchonly': False, 'type': 'optional'} + Package: torcs-data: {'basearchonly': False, 'type': 'optional'} + Package: trackballs: {'basearchonly': False, 'type': 'optional'} + Package: trackballs-music: {'basearchonly': False, 'type': 'optional'} + Package: tremulous: {'basearchonly': False, 'type': 'optional'} + Package: trophy: {'basearchonly': False, 'type': 'optional'} + Package: tunneler: {'basearchonly': False, 'type': 'optional'} + Package: tuxmath: {'basearchonly': False, 'type': 'optional'} + Package: tuxpuck: {'basearchonly': False, 'type': 'optional'} + Package: typespeed: {'basearchonly': False, 'type': 'optional'} + Package: ularn: {'basearchonly': False, 'type': 'optional'} + Package: ultimatestunts: {'basearchonly': False, 'type': 'optional'} + Package: uqm: {'basearchonly': False, 'type': 'optional'} + Package: urbanterror: {'basearchonly': False, 'type': 'optional'} + Package: vavoom: {'basearchonly': False, 'type': 'optional'} + Package: vdr-sudoku: {'basearchonly': False, 'type': 'optional'} + Package: vdrift: {'basearchonly': False, 'type': 'optional'} + Package: vegastrike: {'basearchonly': False, 'type': 'optional'} + Package: vegastrike-extra: {'basearchonly': False, 'type': 'optional'} + Package: vegastrike-music: {'basearchonly': False, 'type': 'optional'} + Package: vegastrike-speech: {'basearchonly': False, 'type': 'optional'} + Package: vodovod: {'basearchonly': False, 'type': 'optional'} + Package: warmux: {'basearchonly': False, 'type': 'optional'} + Package: warzone2100: {'basearchonly': False, 'type': 'optional'} + Package: warzone2100-sequences: {'basearchonly': False, 'type': 'optional'} + Package: wastesedge: {'basearchonly': False, 'type': 'optional'} + Package: wesnoth: {'basearchonly': False, 'type': 'optional'} + Package: widelands: {'basearchonly': False, 'type': 'optional'} + Package: wordwarvi: {'basearchonly': False, 'type': 'optional'} + Package: worldofpadman: {'basearchonly': False, 'type': 'optional'} + Package: worminator: {'basearchonly': False, 'type': 'optional'} + Package: xaos: {'basearchonly': False, 'type': 'optional'} + Package: xarchon: {'basearchonly': False, 'type': 'optional'} + Package: xblast: {'basearchonly': False, 'type': 'optional'} + Package: xboard: {'basearchonly': False, 'type': 'optional'} + Package: xgalaxy: {'basearchonly': False, 'type': 'optional'} + Package: xgrav: {'basearchonly': False, 'type': 'optional'} + Package: xmoto: {'basearchonly': False, 'type': 'optional'} + Package: xonotic: {'basearchonly': False, 'type': 'optional'} + Package: xpenguins: {'basearchonly': False, 'type': 'optional'} + Package: xpilot-ng: {'basearchonly': False, 'type': 'optional'} + Package: xpilot-ng-server: {'basearchonly': False, 'type': 'optional'} + Package: xplanet: {'basearchonly': False, 'type': 'optional'} + Package: xscorch: {'basearchonly': False, 'type': 'optional'} + Package: xskat: {'basearchonly': False, 'type': 'optional'} + Package: xstar: {'basearchonly': False, 'type': 'optional'} + Package: xteddy: {'basearchonly': False, 'type': 'optional'} + Package: xu4: {'basearchonly': False, 'type': 'optional'} + Package: xword: {'basearchonly': False, 'type': 'optional'} + Package: zasx: {'basearchonly': False, 'type': 'optional'} + Package: zaz: {'basearchonly': False, 'type': 'optional'} Group: georgian-support (Georgian Support) - Package: dejavu-sans-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: bpg-chveulebrivi-fonts: {'type': 'default', 'basearchonly': False} - Package: bpg-courier-fonts: {'type': 'default', 'basearchonly': False} - Package: bpg-glaho-fonts: {'type': 'default', 'basearchonly': False} - Package: dejavu-sans-mono-fonts: {'type': 'default', 'basearchonly': False} - Package: dejavu-serif-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-georgian-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-serif-georgian-fonts: {'type': 'default', 'basearchonly': False} - Package: bpg-algeti-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-courier-s-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-elite-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-excelsior-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-ingiri-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-nino-medium-cond-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-nino-medium-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-sans-medium-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-sans-modern-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-sans-regular-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: bpg-serif-modern-fonts: {'type': 'optional', 'basearchonly': False} + Package: dejavu-sans-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: bpg-chveulebrivi-fonts: {'basearchonly': False, 'type': 'default'} + Package: bpg-courier-fonts: {'basearchonly': False, 'type': 'default'} + Package: bpg-glaho-fonts: {'basearchonly': False, 'type': 'default'} + Package: dejavu-sans-mono-fonts: {'basearchonly': False, 'type': 'default'} + Package: dejavu-serif-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-georgian-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-serif-georgian-fonts: {'basearchonly': False, 'type': 'default'} + Package: bpg-algeti-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-courier-s-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-elite-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-excelsior-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-ingiri-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-nino-medium-cond-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-nino-medium-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-sans-medium-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-sans-modern-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-sans-regular-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bpg-serif-modern-fonts: {'basearchonly': False, 'type': 'optional'} Group: gnome-desktop (GNOME) - Package: at-spi2-atk: {'type': 'mandatory', 'basearchonly': False} - Package: at-spi2-core: {'type': 'mandatory', 'basearchonly': False} - Package: avahi: {'type': 'mandatory', 'basearchonly': False} - Package: baobab: {'type': 'mandatory', 'basearchonly': False} - Package: caribou: {'type': 'mandatory', 'basearchonly': False} - Package: caribou-gtk2-module: {'type': 'mandatory', 'basearchonly': False} - Package: caribou-gtk3-module: {'type': 'mandatory', 'basearchonly': False} - Package: cheese: {'type': 'mandatory', 'basearchonly': False} - Package: control-center: {'type': 'mandatory', 'basearchonly': False} - Package: dconf: {'type': 'mandatory', 'basearchonly': False} - Package: eog: {'type': 'mandatory', 'basearchonly': False} - Package: evince: {'type': 'mandatory', 'basearchonly': False} - Package: evince-djvu: {'type': 'mandatory', 'basearchonly': False} - Package: evince-nautilus: {'type': 'mandatory', 'basearchonly': False} - Package: file-roller: {'type': 'mandatory', 'basearchonly': False} - Package: file-roller-nautilus: {'type': 'mandatory', 'basearchonly': False} - Package: fprintd-pam: {'type': 'mandatory', 'basearchonly': False} - Package: gdm: {'type': 'mandatory', 'basearchonly': False} - Package: gedit: {'type': 'mandatory', 'basearchonly': False} - Package: glib-networking: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-backgrounds: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-bluetooth: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-boxes: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-calculator: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-calendar: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-characters: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-classic-session: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-clocks: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-color-manager: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-contacts: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-disk-utility: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-documents: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-font-viewer: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-getting-started-docs: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-initial-setup: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-logs: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-maps: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-screenshot: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-session-wayland-session: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-session-xsession: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-settings-daemon: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-shell: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-software: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-system-monitor: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-terminal: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-themes-standard: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-user-docs: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-user-share: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-weather: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-afc: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-afp: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-archive: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-fuse: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-goa: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-gphoto2: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-mtp: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-smb: {'type': 'mandatory', 'basearchonly': False} - Package: libcanberra-gtk2: {'type': 'mandatory', 'basearchonly': False} - Package: libcanberra-gtk3: {'type': 'mandatory', 'basearchonly': False} - Package: libproxy-mozjs: {'type': 'mandatory', 'basearchonly': False} - Package: librsvg2: {'type': 'mandatory', 'basearchonly': False} - Package: libsane-hpaio: {'type': 'mandatory', 'basearchonly': False} - Package: ModemManager: {'type': 'mandatory', 'basearchonly': False} - Package: mousetweaks: {'type': 'mandatory', 'basearchonly': False} - Package: nautilus: {'type': 'mandatory', 'basearchonly': False} - Package: nautilus-sendto: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-adsl: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-openconnect: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-openvpn-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-pptp-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-vpnc-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: orca: {'type': 'mandatory', 'basearchonly': False} - Package: PackageKit-command-not-found: {'type': 'mandatory', 'basearchonly': False} - Package: PackageKit-gtk3-module: {'type': 'mandatory', 'basearchonly': False} - Package: polkit: {'type': 'mandatory', 'basearchonly': False} - Package: rygel: {'type': 'mandatory', 'basearchonly': False} - Package: sane-backends-drivers-scanners: {'type': 'mandatory', 'basearchonly': False} - Package: sushi: {'type': 'mandatory', 'basearchonly': False} - Package: totem: {'type': 'mandatory', 'basearchonly': False} - Package: totem-nautilus: {'type': 'mandatory', 'basearchonly': False} - Package: xdg-user-dirs-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: yelp: {'type': 'mandatory', 'basearchonly': False} + Package: at-spi2-atk: {'basearchonly': False, 'type': 'mandatory'} + Package: at-spi2-core: {'basearchonly': False, 'type': 'mandatory'} + Package: avahi: {'basearchonly': False, 'type': 'mandatory'} + Package: baobab: {'basearchonly': False, 'type': 'mandatory'} + Package: caribou: {'basearchonly': False, 'type': 'mandatory'} + Package: caribou-gtk2-module: {'basearchonly': False, 'type': 'mandatory'} + Package: caribou-gtk3-module: {'basearchonly': False, 'type': 'mandatory'} + Package: cheese: {'basearchonly': False, 'type': 'mandatory'} + Package: control-center: {'basearchonly': False, 'type': 'mandatory'} + Package: dconf: {'basearchonly': False, 'type': 'mandatory'} + Package: eog: {'basearchonly': False, 'type': 'mandatory'} + Package: evince: {'basearchonly': False, 'type': 'mandatory'} + Package: evince-djvu: {'basearchonly': False, 'type': 'mandatory'} + Package: evince-nautilus: {'basearchonly': False, 'type': 'mandatory'} + Package: file-roller: {'basearchonly': False, 'type': 'mandatory'} + Package: file-roller-nautilus: {'basearchonly': False, 'type': 'mandatory'} + Package: fprintd-pam: {'basearchonly': False, 'type': 'mandatory'} + Package: gdm: {'basearchonly': False, 'type': 'mandatory'} + Package: gedit: {'basearchonly': False, 'type': 'mandatory'} + Package: glib-networking: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-backgrounds: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-bluetooth: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-boxes: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-calculator: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-calendar: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-characters: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-classic-session: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-clocks: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-color-manager: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-contacts: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-disk-utility: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-documents: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-font-viewer: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-getting-started-docs: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-initial-setup: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-logs: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-maps: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-screenshot: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-session-wayland-session: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-session-xsession: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-settings-daemon: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-shell: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-software: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-system-monitor: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-terminal: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-themes-standard: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-user-docs: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-user-share: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-weather: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-afc: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-afp: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-archive: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-fuse: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-goa: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-gphoto2: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-mtp: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-smb: {'basearchonly': False, 'type': 'mandatory'} + Package: libcanberra-gtk2: {'basearchonly': False, 'type': 'mandatory'} + Package: libcanberra-gtk3: {'basearchonly': False, 'type': 'mandatory'} + Package: libproxy-mozjs: {'basearchonly': False, 'type': 'mandatory'} + Package: librsvg2: {'basearchonly': False, 'type': 'mandatory'} + Package: libsane-hpaio: {'basearchonly': False, 'type': 'mandatory'} + Package: ModemManager: {'basearchonly': False, 'type': 'mandatory'} + Package: mousetweaks: {'basearchonly': False, 'type': 'mandatory'} + Package: nautilus: {'basearchonly': False, 'type': 'mandatory'} + Package: nautilus-sendto: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-adsl: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-openconnect: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-openvpn-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-pptp-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-vpnc-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: orca: {'basearchonly': False, 'type': 'mandatory'} + Package: PackageKit-command-not-found: {'basearchonly': False, 'type': 'mandatory'} + Package: PackageKit-gtk3-module: {'basearchonly': False, 'type': 'mandatory'} + Package: polkit: {'basearchonly': False, 'type': 'mandatory'} + Package: rygel: {'basearchonly': False, 'type': 'mandatory'} + Package: sane-backends-drivers-scanners: {'basearchonly': False, 'type': 'mandatory'} + Package: sushi: {'basearchonly': False, 'type': 'mandatory'} + Package: totem: {'basearchonly': False, 'type': 'mandatory'} + Package: totem-nautilus: {'basearchonly': False, 'type': 'mandatory'} + Package: xdg-user-dirs-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: yelp: {'basearchonly': False, 'type': 'mandatory'} Group: gnome-games (Extra games for the GNOME Desktop) - Package: five-or-more: {'type': 'mandatory', 'basearchonly': False} - Package: four-in-a-row: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-chess: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-klotski: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-mahjongg: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-mines: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-nibbles: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-robots: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-sudoku: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-taquin: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-tetravex: {'type': 'mandatory', 'basearchonly': False} - Package: hitori: {'type': 'mandatory', 'basearchonly': False} - Package: iagno: {'type': 'mandatory', 'basearchonly': False} - Package: lightsoff: {'type': 'mandatory', 'basearchonly': False} - Package: quadrapassel: {'type': 'mandatory', 'basearchonly': False} - Package: swell-foop: {'type': 'mandatory', 'basearchonly': False} - Package: tali: {'type': 'mandatory', 'basearchonly': False} + Package: five-or-more: {'basearchonly': False, 'type': 'mandatory'} + Package: four-in-a-row: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-chess: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-klotski: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-mahjongg: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-mines: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-nibbles: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-robots: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-sudoku: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-taquin: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-tetravex: {'basearchonly': False, 'type': 'mandatory'} + Package: hitori: {'basearchonly': False, 'type': 'mandatory'} + Package: iagno: {'basearchonly': False, 'type': 'mandatory'} + Package: lightsoff: {'basearchonly': False, 'type': 'mandatory'} + Package: quadrapassel: {'basearchonly': False, 'type': 'mandatory'} + Package: swell-foop: {'basearchonly': False, 'type': 'mandatory'} + Package: tali: {'basearchonly': False, 'type': 'mandatory'} Group: gnome-software-development (GNOME Software Development) - Package: atk-devel: {'type': 'mandatory', 'basearchonly': False} - Package: clutter-devel: {'type': 'mandatory', 'basearchonly': False} - Package: dbus-devel: {'type': 'mandatory', 'basearchonly': False} - Package: glib2-devel: {'type': 'mandatory', 'basearchonly': False} - Package: gstreamer-devel: {'type': 'mandatory', 'basearchonly': False} - Package: gtk3-devel: {'type': 'mandatory', 'basearchonly': False} - Package: gtk3-devel-docs: {'type': 'mandatory', 'basearchonly': False} - Package: intltool: {'type': 'mandatory', 'basearchonly': False} - Package: pango-devel: {'type': 'mandatory', 'basearchonly': False} - Package: at-spi2-core-devel: {'type': 'default', 'basearchonly': False} - Package: clutter-gtk-devel: {'type': 'default', 'basearchonly': False} - Package: devhelp: {'type': 'default', 'basearchonly': False} - Package: evolution-data-server-devel: {'type': 'default', 'basearchonly': False} - Package: git: {'type': 'default', 'basearchonly': False} - Package: glib2-doc: {'type': 'default', 'basearchonly': False} - Package: gnome-common: {'type': 'default', 'basearchonly': False} - Package: gnome-desktop3-devel: {'type': 'default', 'basearchonly': False} - Package: gnome-devel-docs: {'type': 'default', 'basearchonly': False} - Package: gobject-introspection: {'type': 'default', 'basearchonly': False} - Package: gobject-introspection-devel: {'type': 'default', 'basearchonly': False} - Package: gtk-doc: {'type': 'default', 'basearchonly': False} - Package: libcanberra-devel: {'type': 'default', 'basearchonly': False} - Package: libgda-devel: {'type': 'default', 'basearchonly': False} - Package: libgnome-keyring-devel: {'type': 'default', 'basearchonly': False} - Package: libnotify-devel: {'type': 'default', 'basearchonly': False} - Package: webkitgtk4-devel: {'type': 'default', 'basearchonly': False} - Package: cairomm-devel: {'type': 'optional', 'basearchonly': False} - Package: cairomm-doc: {'type': 'optional', 'basearchonly': False} - Package: clutter-gst-devel: {'type': 'optional', 'basearchonly': False} - Package: glade3: {'type': 'optional', 'basearchonly': False} - Package: glibmm24-devel: {'type': 'optional', 'basearchonly': False} - Package: gnome-builder: {'type': 'optional', 'basearchonly': False} - Package: gtkmm30-devel: {'type': 'optional', 'basearchonly': False} - Package: libgtop2-devel: {'type': 'optional', 'basearchonly': False} - Package: libsigc++20-devel: {'type': 'optional', 'basearchonly': False} - Package: vala: {'type': 'optional', 'basearchonly': False} + Package: atk-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: clutter-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: dbus-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: glib2-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: gstreamer-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: gtk3-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: gtk3-devel-docs: {'basearchonly': False, 'type': 'mandatory'} + Package: intltool: {'basearchonly': False, 'type': 'mandatory'} + Package: pango-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: at-spi2-core-devel: {'basearchonly': False, 'type': 'default'} + Package: clutter-gtk-devel: {'basearchonly': False, 'type': 'default'} + Package: devhelp: {'basearchonly': False, 'type': 'default'} + Package: evolution-data-server-devel: {'basearchonly': False, 'type': 'default'} + Package: git: {'basearchonly': False, 'type': 'default'} + Package: glib2-doc: {'basearchonly': False, 'type': 'default'} + Package: gnome-common: {'basearchonly': False, 'type': 'default'} + Package: gnome-desktop3-devel: {'basearchonly': False, 'type': 'default'} + Package: gnome-devel-docs: {'basearchonly': False, 'type': 'default'} + Package: gobject-introspection: {'basearchonly': False, 'type': 'default'} + Package: gobject-introspection-devel: {'basearchonly': False, 'type': 'default'} + Package: gtk-doc: {'basearchonly': False, 'type': 'default'} + Package: libcanberra-devel: {'basearchonly': False, 'type': 'default'} + Package: libgda-devel: {'basearchonly': False, 'type': 'default'} + Package: libgnome-keyring-devel: {'basearchonly': False, 'type': 'default'} + Package: libnotify-devel: {'basearchonly': False, 'type': 'default'} + Package: webkitgtk4-devel: {'basearchonly': False, 'type': 'default'} + Package: cairomm-devel: {'basearchonly': False, 'type': 'optional'} + Package: cairomm-doc: {'basearchonly': False, 'type': 'optional'} + Package: clutter-gst-devel: {'basearchonly': False, 'type': 'optional'} + Package: glade3: {'basearchonly': False, 'type': 'optional'} + Package: glibmm24-devel: {'basearchonly': False, 'type': 'optional'} + Package: gnome-builder: {'basearchonly': False, 'type': 'optional'} + Package: gtkmm30-devel: {'basearchonly': False, 'type': 'optional'} + Package: libgtop2-devel: {'basearchonly': False, 'type': 'optional'} + Package: libsigc++20-devel: {'basearchonly': False, 'type': 'optional'} + Package: vala: {'basearchonly': False, 'type': 'optional'} Group: graphical-internet (Graphical Internet) - Package: arora: {'type': 'optional', 'basearchonly': False} - Package: azureus: {'type': 'optional', 'basearchonly': False} - Package: balsa: {'type': 'optional', 'basearchonly': False} - Package: bluefish: {'type': 'optional', 'basearchonly': False} - Package: choqok: {'type': 'optional', 'basearchonly': False} - Package: claws-mail: {'type': 'optional', 'basearchonly': False} - Package: deluge: {'type': 'optional', 'basearchonly': False} - Package: dillo: {'type': 'optional', 'basearchonly': False} - Package: ekiga: {'type': 'optional', 'basearchonly': False} - Package: empathy: {'type': 'optional', 'basearchonly': False} - Package: epiphany: {'type': 'optional', 'basearchonly': False} - Package: evolution: {'type': 'optional', 'basearchonly': False} - Package: evolution-bogofilter: {'type': 'optional', 'basearchonly': False} - Package: evolution-help: {'type': 'optional', 'basearchonly': False} - Package: evolution-perl: {'type': 'optional', 'basearchonly': False} - Package: filezilla: {'type': 'optional', 'basearchonly': False} - Package: firefox: {'type': 'optional', 'basearchonly': False} - Package: gajim: {'type': 'optional', 'basearchonly': False} - Package: gftp: {'type': 'optional', 'basearchonly': False} - Package: gnash-plugin: {'type': 'optional', 'basearchonly': False} - Package: gnome-translate: {'type': 'optional', 'basearchonly': False} - Package: gtk-gnutella: {'type': 'optional', 'basearchonly': False} - Package: gtorrentviewer: {'type': 'optional', 'basearchonly': False} - Package: gwget: {'type': 'optional', 'basearchonly': False} - Package: gyachi: {'type': 'optional', 'basearchonly': False} - Package: icedtea-web: {'type': 'optional', 'basearchonly': False} - Package: jd: {'type': 'optional', 'basearchonly': False} - Package: kazehakase: {'type': 'optional', 'basearchonly': False} - Package: kdepim: {'type': 'optional', 'basearchonly': False} - Package: kdewebdev: {'type': 'optional', 'basearchonly': False} - Package: kita: {'type': 'optional', 'basearchonly': False} - Package: knetstats: {'type': 'optional', 'basearchonly': False} - Package: konversation: {'type': 'optional', 'basearchonly': False} - Package: kvirc: {'type': 'optional', 'basearchonly': False} - Package: licq: {'type': 'optional', 'basearchonly': False} - Package: liferea: {'type': 'optional', 'basearchonly': False} - Package: linphone: {'type': 'optional', 'basearchonly': False} - Package: logjam: {'type': 'optional', 'basearchonly': False} - Package: mail-notification: {'type': 'optional', 'basearchonly': False} - Package: meiga: {'type': 'optional', 'basearchonly': False} - Package: mitter: {'type': 'optional', 'basearchonly': False} - Package: mtr-gtk: {'type': 'optional', 'basearchonly': False} - Package: nicotine+: {'type': 'optional', 'basearchonly': False} - Package: nntpgrab-gui: {'type': 'optional', 'basearchonly': False} - Package: ochusha: {'type': 'optional', 'basearchonly': False} - Package: pan: {'type': 'optional', 'basearchonly': False} - Package: pcmanx-gtk2: {'type': 'optional', 'basearchonly': False} - Package: pidgin: {'type': 'optional', 'basearchonly': False} - Package: pidgin-libnotify: {'type': 'optional', 'basearchonly': False} - Package: prozilla: {'type': 'optional', 'basearchonly': False} - Package: psi: {'type': 'optional', 'basearchonly': False} - Package: psimedia: {'type': 'optional', 'basearchonly': False} - Package: qbittorrent: {'type': 'optional', 'basearchonly': False} - Package: qterm: {'type': 'optional', 'basearchonly': False} - Package: rekonq: {'type': 'optional', 'basearchonly': False} - Package: seamonkey: {'type': 'optional', 'basearchonly': False} - Package: streamtuner: {'type': 'optional', 'basearchonly': False} - Package: sylpheed: {'type': 'optional', 'basearchonly': False} - Package: thunderbird: {'type': 'optional', 'basearchonly': False} - Package: transmission-gtk: {'type': 'optional', 'basearchonly': False} - Package: transmission-qt: {'type': 'optional', 'basearchonly': False} - Package: uget: {'type': 'optional', 'basearchonly': False} - Package: valknut: {'type': 'optional', 'basearchonly': False} - Package: x3270-x11: {'type': 'optional', 'basearchonly': False} - Package: xchat: {'type': 'optional', 'basearchonly': False} - Package: xchat-gnome: {'type': 'optional', 'basearchonly': False} - Package: xchat-ruby: {'type': 'optional', 'basearchonly': False} - Package: xchat-tcl: {'type': 'optional', 'basearchonly': False} + Package: arora: {'basearchonly': False, 'type': 'optional'} + Package: azureus: {'basearchonly': False, 'type': 'optional'} + Package: balsa: {'basearchonly': False, 'type': 'optional'} + Package: bluefish: {'basearchonly': False, 'type': 'optional'} + Package: choqok: {'basearchonly': False, 'type': 'optional'} + Package: claws-mail: {'basearchonly': False, 'type': 'optional'} + Package: deluge: {'basearchonly': False, 'type': 'optional'} + Package: dillo: {'basearchonly': False, 'type': 'optional'} + Package: ekiga: {'basearchonly': False, 'type': 'optional'} + Package: empathy: {'basearchonly': False, 'type': 'optional'} + Package: epiphany: {'basearchonly': False, 'type': 'optional'} + Package: evolution: {'basearchonly': False, 'type': 'optional'} + Package: evolution-bogofilter: {'basearchonly': False, 'type': 'optional'} + Package: evolution-help: {'basearchonly': False, 'type': 'optional'} + Package: evolution-perl: {'basearchonly': False, 'type': 'optional'} + Package: filezilla: {'basearchonly': False, 'type': 'optional'} + Package: firefox: {'basearchonly': False, 'type': 'optional'} + Package: gajim: {'basearchonly': False, 'type': 'optional'} + Package: gftp: {'basearchonly': False, 'type': 'optional'} + Package: gnash-plugin: {'basearchonly': False, 'type': 'optional'} + Package: gnome-translate: {'basearchonly': False, 'type': 'optional'} + Package: gtk-gnutella: {'basearchonly': False, 'type': 'optional'} + Package: gtorrentviewer: {'basearchonly': False, 'type': 'optional'} + Package: gwget: {'basearchonly': False, 'type': 'optional'} + Package: gyachi: {'basearchonly': False, 'type': 'optional'} + Package: icedtea-web: {'basearchonly': False, 'type': 'optional'} + Package: jd: {'basearchonly': False, 'type': 'optional'} + Package: kazehakase: {'basearchonly': False, 'type': 'optional'} + Package: kdepim: {'basearchonly': False, 'type': 'optional'} + Package: kdewebdev: {'basearchonly': False, 'type': 'optional'} + Package: kita: {'basearchonly': False, 'type': 'optional'} + Package: knetstats: {'basearchonly': False, 'type': 'optional'} + Package: konversation: {'basearchonly': False, 'type': 'optional'} + Package: kvirc: {'basearchonly': False, 'type': 'optional'} + Package: licq: {'basearchonly': False, 'type': 'optional'} + Package: liferea: {'basearchonly': False, 'type': 'optional'} + Package: linphone: {'basearchonly': False, 'type': 'optional'} + Package: logjam: {'basearchonly': False, 'type': 'optional'} + Package: mail-notification: {'basearchonly': False, 'type': 'optional'} + Package: meiga: {'basearchonly': False, 'type': 'optional'} + Package: mitter: {'basearchonly': False, 'type': 'optional'} + Package: mtr-gtk: {'basearchonly': False, 'type': 'optional'} + Package: nicotine+: {'basearchonly': False, 'type': 'optional'} + Package: nntpgrab-gui: {'basearchonly': False, 'type': 'optional'} + Package: ochusha: {'basearchonly': False, 'type': 'optional'} + Package: pan: {'basearchonly': False, 'type': 'optional'} + Package: pcmanx-gtk2: {'basearchonly': False, 'type': 'optional'} + Package: pidgin: {'basearchonly': False, 'type': 'optional'} + Package: pidgin-libnotify: {'basearchonly': False, 'type': 'optional'} + Package: prozilla: {'basearchonly': False, 'type': 'optional'} + Package: psi: {'basearchonly': False, 'type': 'optional'} + Package: psimedia: {'basearchonly': False, 'type': 'optional'} + Package: qbittorrent: {'basearchonly': False, 'type': 'optional'} + Package: qterm: {'basearchonly': False, 'type': 'optional'} + Package: rekonq: {'basearchonly': False, 'type': 'optional'} + Package: seamonkey: {'basearchonly': False, 'type': 'optional'} + Package: streamtuner: {'basearchonly': False, 'type': 'optional'} + Package: sylpheed: {'basearchonly': False, 'type': 'optional'} + Package: thunderbird: {'basearchonly': False, 'type': 'optional'} + Package: transmission-gtk: {'basearchonly': False, 'type': 'optional'} + Package: transmission-qt: {'basearchonly': False, 'type': 'optional'} + Package: uget: {'basearchonly': False, 'type': 'optional'} + Package: valknut: {'basearchonly': False, 'type': 'optional'} + Package: x3270-x11: {'basearchonly': False, 'type': 'optional'} + Package: xchat: {'basearchonly': False, 'type': 'optional'} + Package: xchat-gnome: {'basearchonly': False, 'type': 'optional'} + Package: xchat-ruby: {'basearchonly': False, 'type': 'optional'} + Package: xchat-tcl: {'basearchonly': False, 'type': 'optional'} Group: graphics (Graphics) - Package: xsane-gimp: {'requires': u'gimp', 'type': 'conditional', 'basearchonly': False} - Package: argyllcms: {'type': 'optional', 'basearchonly': False} - Package: asciio: {'type': 'optional', 'basearchonly': False} - Package: asymptote: {'type': 'optional', 'basearchonly': False} - Package: blender: {'type': 'optional', 'basearchonly': False} - Package: calligra-krita: {'type': 'optional', 'basearchonly': False} - Package: cbrpager: {'type': 'optional', 'basearchonly': False} - Package: cinepaint: {'type': 'optional', 'basearchonly': False} - Package: comix: {'type': 'optional', 'basearchonly': False} - Package: dcraw: {'type': 'optional', 'basearchonly': False} - Package: digikam: {'type': 'optional', 'basearchonly': False} - Package: gcolor2: {'type': 'optional', 'basearchonly': False} - Package: geeqie: {'type': 'optional', 'basearchonly': False} - Package: gifsicle: {'type': 'optional', 'basearchonly': False} - Package: gifview: {'type': 'optional', 'basearchonly': False} - Package: gimp: {'type': 'optional', 'basearchonly': False} - Package: gimp-data-extras: {'type': 'optional', 'basearchonly': False} - Package: gimp-help: {'type': 'optional', 'basearchonly': False} - Package: gimp-help-browser: {'type': 'optional', 'basearchonly': False} - Package: gipfel: {'type': 'optional', 'basearchonly': False} - Package: gnofract4d: {'type': 'optional', 'basearchonly': False} - Package: graphviz: {'type': 'optional', 'basearchonly': False} - Package: gutenprint-plugin: {'type': 'optional', 'basearchonly': False} - Package: gv: {'type': 'optional', 'basearchonly': False} - Package: gwenview: {'type': 'optional', 'basearchonly': False} - Package: hugin: {'type': 'optional', 'basearchonly': False} - Package: ImageMagick: {'type': 'optional', 'basearchonly': False} - Package: inkscape: {'type': 'optional', 'basearchonly': False} - Package: ipe: {'type': 'optional', 'basearchonly': False} - Package: k3d: {'type': 'optional', 'basearchonly': False} - Package: kf5-kipi-plugins: {'type': 'optional', 'basearchonly': False} - Package: kolourpaint: {'type': 'optional', 'basearchonly': False} - Package: kphotoalbum: {'type': 'optional', 'basearchonly': False} - Package: ksnapshot: {'type': 'optional', 'basearchonly': False} - Package: libsane-hpaio: {'type': 'optional', 'basearchonly': False} - Package: mirage: {'type': 'optional', 'basearchonly': False} - Package: netpbm-progs: {'type': 'optional', 'basearchonly': False} - Package: nip2: {'type': 'optional', 'basearchonly': False} - Package: optipng: {'type': 'optional', 'basearchonly': False} - Package: Panini: {'type': 'optional', 'basearchonly': False} - Package: pstoedit: {'type': 'optional', 'basearchonly': False} - Package: pydot: {'type': 'optional', 'basearchonly': False} - Package: qiv: {'type': 'optional', 'basearchonly': False} - Package: rawstudio: {'type': 'optional', 'basearchonly': False} - Package: renrot: {'type': 'optional', 'basearchonly': False} - Package: sane-backends-drivers-cameras: {'type': 'optional', 'basearchonly': False} - Package: sane-backends-drivers-scanners: {'type': 'optional', 'basearchonly': False} - Package: sane-frontends: {'type': 'optional', 'basearchonly': False} - Package: shotwell: {'type': 'optional', 'basearchonly': False} - Package: simple-scan: {'type': 'optional', 'basearchonly': False} - Package: tachyon: {'type': 'optional', 'basearchonly': False} - Package: tuxpaint: {'type': 'optional', 'basearchonly': False} - Package: tzclock: {'type': 'optional', 'basearchonly': False} - Package: ufraw: {'type': 'optional', 'basearchonly': False} - Package: uniconvertor: {'type': 'optional', 'basearchonly': False} - Package: viewnior: {'type': 'optional', 'basearchonly': False} - Package: wings: {'type': 'optional', 'basearchonly': False} - Package: xfig: {'type': 'optional', 'basearchonly': False} - Package: xpaint: {'type': 'optional', 'basearchonly': False} - Package: xsane: {'type': 'optional', 'basearchonly': False} + Package: xsane-gimp: {'basearchonly': False, 'requires': 'gimp', 'type': 'conditional'} + Package: argyllcms: {'basearchonly': False, 'type': 'optional'} + Package: asciio: {'basearchonly': False, 'type': 'optional'} + Package: asymptote: {'basearchonly': False, 'type': 'optional'} + Package: blender: {'basearchonly': False, 'type': 'optional'} + Package: calligra-krita: {'basearchonly': False, 'type': 'optional'} + Package: cbrpager: {'basearchonly': False, 'type': 'optional'} + Package: cinepaint: {'basearchonly': False, 'type': 'optional'} + Package: comix: {'basearchonly': False, 'type': 'optional'} + Package: dcraw: {'basearchonly': False, 'type': 'optional'} + Package: digikam: {'basearchonly': False, 'type': 'optional'} + Package: gcolor2: {'basearchonly': False, 'type': 'optional'} + Package: geeqie: {'basearchonly': False, 'type': 'optional'} + Package: gifsicle: {'basearchonly': False, 'type': 'optional'} + Package: gifview: {'basearchonly': False, 'type': 'optional'} + Package: gimp: {'basearchonly': False, 'type': 'optional'} + Package: gimp-data-extras: {'basearchonly': False, 'type': 'optional'} + Package: gimp-help: {'basearchonly': False, 'type': 'optional'} + Package: gimp-help-browser: {'basearchonly': False, 'type': 'optional'} + Package: gipfel: {'basearchonly': False, 'type': 'optional'} + Package: gnofract4d: {'basearchonly': False, 'type': 'optional'} + Package: graphviz: {'basearchonly': False, 'type': 'optional'} + Package: gutenprint-plugin: {'basearchonly': False, 'type': 'optional'} + Package: gv: {'basearchonly': False, 'type': 'optional'} + Package: gwenview: {'basearchonly': False, 'type': 'optional'} + Package: hugin: {'basearchonly': False, 'type': 'optional'} + Package: ImageMagick: {'basearchonly': False, 'type': 'optional'} + Package: inkscape: {'basearchonly': False, 'type': 'optional'} + Package: ipe: {'basearchonly': False, 'type': 'optional'} + Package: k3d: {'basearchonly': False, 'type': 'optional'} + Package: kf5-kipi-plugins: {'basearchonly': False, 'type': 'optional'} + Package: kolourpaint: {'basearchonly': False, 'type': 'optional'} + Package: kphotoalbum: {'basearchonly': False, 'type': 'optional'} + Package: ksnapshot: {'basearchonly': False, 'type': 'optional'} + Package: libsane-hpaio: {'basearchonly': False, 'type': 'optional'} + Package: mirage: {'basearchonly': False, 'type': 'optional'} + Package: netpbm-progs: {'basearchonly': False, 'type': 'optional'} + Package: nip2: {'basearchonly': False, 'type': 'optional'} + Package: optipng: {'basearchonly': False, 'type': 'optional'} + Package: Panini: {'basearchonly': False, 'type': 'optional'} + Package: pstoedit: {'basearchonly': False, 'type': 'optional'} + Package: pydot: {'basearchonly': False, 'type': 'optional'} + Package: qiv: {'basearchonly': False, 'type': 'optional'} + Package: rawstudio: {'basearchonly': False, 'type': 'optional'} + Package: renrot: {'basearchonly': False, 'type': 'optional'} + Package: sane-backends-drivers-cameras: {'basearchonly': False, 'type': 'optional'} + Package: sane-backends-drivers-scanners: {'basearchonly': False, 'type': 'optional'} + Package: sane-frontends: {'basearchonly': False, 'type': 'optional'} + Package: shotwell: {'basearchonly': False, 'type': 'optional'} + Package: simple-scan: {'basearchonly': False, 'type': 'optional'} + Package: tachyon: {'basearchonly': False, 'type': 'optional'} + Package: tuxpaint: {'basearchonly': False, 'type': 'optional'} + Package: tzclock: {'basearchonly': False, 'type': 'optional'} + Package: ufraw: {'basearchonly': False, 'type': 'optional'} + Package: uniconvertor: {'basearchonly': False, 'type': 'optional'} + Package: viewnior: {'basearchonly': False, 'type': 'optional'} + Package: wings: {'basearchonly': False, 'type': 'optional'} + Package: xfig: {'basearchonly': False, 'type': 'optional'} + Package: xpaint: {'basearchonly': False, 'type': 'optional'} + Package: xsane: {'basearchonly': False, 'type': 'optional'} Group: greek-support (Greek Support) - Package: ctan-kerkis-calligraphic-fonts: {'type': 'optional', 'basearchonly': False} - Package: ctan-kerkis-sans-fonts: {'type': 'optional', 'basearchonly': False} - Package: ctan-kerkis-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-ambrosia-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-artemisia-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-baskerville-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-bodoni-classic-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-bodoni-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-complutum-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-decker-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-didot-classic-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-didot-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-eustace-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-fleischman-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-garaldus-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-gazis-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-goschen-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-ignacio-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-jackson-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-neohellenic-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-nicefore-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-olga-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-philostratos-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-porson-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-pyrsos-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-solomos-fonts: {'type': 'optional', 'basearchonly': False} - Package: gfs-theokritos-fonts: {'type': 'optional', 'basearchonly': False} - Package: mgopen-canonica-fonts: {'type': 'optional', 'basearchonly': False} - Package: mgopen-cosmetica-fonts: {'type': 'optional', 'basearchonly': False} - Package: mgopen-modata-fonts: {'type': 'optional', 'basearchonly': False} - Package: mgopen-moderna-fonts: {'type': 'optional', 'basearchonly': False} + Package: ctan-kerkis-calligraphic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ctan-kerkis-sans-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ctan-kerkis-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-ambrosia-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-artemisia-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-baskerville-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-bodoni-classic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-bodoni-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-complutum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-decker-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-didot-classic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-didot-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-eustace-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-fleischman-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-garaldus-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-gazis-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-goschen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-ignacio-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-jackson-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-neohellenic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-nicefore-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-olga-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-philostratos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-porson-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-pyrsos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-solomos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gfs-theokritos-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mgopen-canonica-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mgopen-cosmetica-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mgopen-modata-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mgopen-moderna-fonts: {'basearchonly': False, 'type': 'optional'} Group: guest-agents (Guest Agents) - Package: open-vm-tools: {'type': 'mandatory', 'basearchonly': False} - Package: qemu-guest-agent: {'type': 'mandatory', 'basearchonly': False} + Package: open-vm-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: qemu-guest-agent: {'basearchonly': False, 'type': 'mandatory'} Group: guest-desktop-agents (Guest Desktop Agents) - Package: hyperv-daemons: {'type': 'mandatory', 'basearchonly': False} - Package: open-vm-tools-desktop: {'type': 'mandatory', 'basearchonly': False} - Package: qemu-guest-agent: {'type': 'mandatory', 'basearchonly': False} - Package: spice-vdagent: {'type': 'mandatory', 'basearchonly': False} + Package: hyperv-daemons: {'basearchonly': False, 'type': 'mandatory'} + Package: open-vm-tools-desktop: {'basearchonly': False, 'type': 'mandatory'} + Package: qemu-guest-agent: {'basearchonly': False, 'type': 'mandatory'} + Package: spice-vdagent: {'basearchonly': False, 'type': 'mandatory'} Group: gujarati-support (Gujarati Support) - Package: lohit-gujarati-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-gujarati-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-gujarati-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: samyak-gujarati-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-gujarati-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-gujarati-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-gujarati-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: samyak-gujarati-fonts: {'basearchonly': False, 'type': 'default'} Group: ha (High Availability) - Package: fence-agents-all: {'type': 'mandatory', 'basearchonly': False} - Package: omping: {'type': 'mandatory', 'basearchonly': False} - Package: pacemaker: {'type': 'mandatory', 'basearchonly': False} - Package: pcs: {'type': 'mandatory', 'basearchonly': False} - Package: clufter: {'type': 'optional', 'basearchonly': False} + Package: fence-agents-all: {'basearchonly': False, 'type': 'mandatory'} + Package: omping: {'basearchonly': False, 'type': 'mandatory'} + Package: pacemaker: {'basearchonly': False, 'type': 'mandatory'} + Package: pcs: {'basearchonly': False, 'type': 'mandatory'} + Package: clufter: {'basearchonly': False, 'type': 'optional'} Group: haproxy (HAProxy) - Package: haproxy: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-abrt: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-daemons: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-rest-client: {'type': 'mandatory', 'basearchonly': False} + Package: haproxy: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-abrt: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-daemons: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-rest-client: {'basearchonly': False, 'type': 'mandatory'} Group: hardware-support (Hardware Support) - Package: atmel-firmware: {'type': 'default', 'basearchonly': False} - Package: b43-fwcutter: {'type': 'default', 'basearchonly': False} - Package: b43-openfwwf: {'type': 'default', 'basearchonly': False} - Package: ipw2100-firmware: {'type': 'default', 'basearchonly': False} - Package: ipw2200-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl100-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl1000-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl105-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl135-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl2000-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl2030-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl3160-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl3945-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl4965-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl5000-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl5150-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl6000-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl6000g2a-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl6000g2b-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl6050-firmware: {'type': 'default', 'basearchonly': False} - Package: iwl7260-firmware: {'type': 'default', 'basearchonly': False} - Package: libertas-usb8388-firmware: {'type': 'default', 'basearchonly': False} - Package: usb_modeswitch: {'type': 'default', 'basearchonly': False} - Package: zd1211-firmware: {'type': 'default', 'basearchonly': False} - Package: acpi: {'type': 'optional', 'basearchonly': False} - Package: acpitool: {'type': 'optional', 'basearchonly': False} - Package: alsa-firmware: {'type': 'optional', 'basearchonly': False} - Package: bcm283x-firmware: {'type': 'optional', 'basearchonly': False} - Package: cmospwd: {'type': 'optional', 'basearchonly': False} - Package: firmware-addon-dell: {'type': 'optional', 'basearchonly': False} - Package: gpsd: {'type': 'optional', 'basearchonly': False} - Package: gpsd-clients: {'type': 'optional', 'basearchonly': False} - Package: gypsy: {'type': 'optional', 'basearchonly': False} - Package: hddtemp: {'type': 'optional', 'basearchonly': False} - Package: hdparm: {'type': 'optional', 'basearchonly': False} - Package: i8kutils: {'type': 'optional', 'basearchonly': False} - Package: iscan-firmware: {'type': 'optional', 'basearchonly': False} - Package: isight-firmware-tools: {'type': 'optional', 'basearchonly': False} - Package: libifp: {'type': 'optional', 'basearchonly': False} - Package: lsscsi: {'type': 'optional', 'basearchonly': False} - Package: multican: {'type': 'optional', 'basearchonly': False} - Package: openct: {'type': 'optional', 'basearchonly': False} - Package: opensc: {'type': 'optional', 'basearchonly': False} - Package: pcsc-lite: {'type': 'optional', 'basearchonly': False} - Package: pcsc-lite-ccid: {'type': 'optional', 'basearchonly': False} - Package: radeontop: {'type': 'optional', 'basearchonly': False} - Package: wpan-tools: {'type': 'optional', 'basearchonly': False} + Package: atmel-firmware: {'basearchonly': False, 'type': 'default'} + Package: b43-fwcutter: {'basearchonly': False, 'type': 'default'} + Package: b43-openfwwf: {'basearchonly': False, 'type': 'default'} + Package: ipw2100-firmware: {'basearchonly': False, 'type': 'default'} + Package: ipw2200-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl100-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl1000-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl105-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl135-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl2000-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl2030-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl3160-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl3945-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl4965-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl5000-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl5150-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl6000-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl6000g2a-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl6000g2b-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl6050-firmware: {'basearchonly': False, 'type': 'default'} + Package: iwl7260-firmware: {'basearchonly': False, 'type': 'default'} + Package: libertas-usb8388-firmware: {'basearchonly': False, 'type': 'default'} + Package: usb_modeswitch: {'basearchonly': False, 'type': 'default'} + Package: zd1211-firmware: {'basearchonly': False, 'type': 'default'} + Package: acpi: {'basearchonly': False, 'type': 'optional'} + Package: acpitool: {'basearchonly': False, 'type': 'optional'} + Package: alsa-firmware: {'basearchonly': False, 'type': 'optional'} + Package: bcm283x-firmware: {'basearchonly': False, 'type': 'optional'} + Package: cmospwd: {'basearchonly': False, 'type': 'optional'} + Package: firmware-addon-dell: {'basearchonly': False, 'type': 'optional'} + Package: gpsd: {'basearchonly': False, 'type': 'optional'} + Package: gpsd-clients: {'basearchonly': False, 'type': 'optional'} + Package: gypsy: {'basearchonly': False, 'type': 'optional'} + Package: hddtemp: {'basearchonly': False, 'type': 'optional'} + Package: hdparm: {'basearchonly': False, 'type': 'optional'} + Package: i8kutils: {'basearchonly': False, 'type': 'optional'} + Package: iscan-firmware: {'basearchonly': False, 'type': 'optional'} + Package: isight-firmware-tools: {'basearchonly': False, 'type': 'optional'} + Package: libifp: {'basearchonly': False, 'type': 'optional'} + Package: lsscsi: {'basearchonly': False, 'type': 'optional'} + Package: multican: {'basearchonly': False, 'type': 'optional'} + Package: openct: {'basearchonly': False, 'type': 'optional'} + Package: opensc: {'basearchonly': False, 'type': 'optional'} + Package: pcsc-lite: {'basearchonly': False, 'type': 'optional'} + Package: pcsc-lite-ccid: {'basearchonly': False, 'type': 'optional'} + Package: radeontop: {'basearchonly': False, 'type': 'optional'} + Package: wpan-tools: {'basearchonly': False, 'type': 'optional'} Group: haskell (Haskell) - Package: cabal-rpm: {'type': 'mandatory', 'basearchonly': False} - Package: darcs: {'type': 'mandatory', 'basearchonly': False} - Package: ghc: {'type': 'mandatory', 'basearchonly': False} - Package: ghc-rpm-macros: {'type': 'mandatory', 'basearchonly': False} - Package: haskell-platform: {'type': 'mandatory', 'basearchonly': False} - Package: hlint: {'type': 'mandatory', 'basearchonly': False} - Package: hscolour: {'type': 'mandatory', 'basearchonly': False} - Package: emacs-haskell-mode: {'requires': u'emacs', 'type': 'conditional', 'basearchonly': False} + Package: cabal-rpm: {'basearchonly': False, 'type': 'mandatory'} + Package: darcs: {'basearchonly': False, 'type': 'mandatory'} + Package: ghc: {'basearchonly': False, 'type': 'mandatory'} + Package: ghc-rpm-macros: {'basearchonly': False, 'type': 'mandatory'} + Package: haskell-platform: {'basearchonly': False, 'type': 'mandatory'} + Package: hlint: {'basearchonly': False, 'type': 'mandatory'} + Package: hscolour: {'basearchonly': False, 'type': 'mandatory'} + Package: emacs-haskell-mode: {'basearchonly': False, 'requires': 'emacs', 'type': 'conditional'} Group: hawaii-apps (Applications for the Hawaii Desktop) - Package: eyesight: {'type': 'mandatory', 'basearchonly': False} - Package: transmission-qt: {'type': 'mandatory', 'basearchonly': False} + Package: eyesight: {'basearchonly': False, 'type': 'mandatory'} + Package: transmission-qt: {'basearchonly': False, 'type': 'mandatory'} Group: hawaii-desktop (Hawaii) - Package: firewall-config: {'type': 'mandatory', 'basearchonly': False} - Package: hawaii-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: hawaii-shell: {'type': 'mandatory', 'basearchonly': False} - Package: hawaii-system-preferences: {'type': 'mandatory', 'basearchonly': False} - Package: hawaii-widget-styles: {'type': 'mandatory', 'basearchonly': False} - Package: hawaii-workspace: {'type': 'mandatory', 'basearchonly': False} - Package: initial-setup-gui: {'type': 'mandatory', 'basearchonly': False} - Package: mesa-dri-drivers: {'type': 'mandatory', 'basearchonly': False} - Package: pcmanfm-qt: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qdbusviewer: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtbase-gui: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtdeclarative: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtwayland: {'type': 'mandatory', 'basearchonly': False} - Package: qterminal-qt5: {'type': 'mandatory', 'basearchonly': False} - Package: otter-browser: {'type': 'mandatory', 'basearchonly': False} - Package: sddm: {'type': 'mandatory', 'basearchonly': False} - Package: sddm-theme-hawaii: {'type': 'mandatory', 'basearchonly': False} - Package: upower: {'type': 'mandatory', 'basearchonly': False} - Package: xdg-user-dirs: {'type': 'mandatory', 'basearchonly': False} + Package: firewall-config: {'basearchonly': False, 'type': 'mandatory'} + Package: hawaii-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: hawaii-shell: {'basearchonly': False, 'type': 'mandatory'} + Package: hawaii-system-preferences: {'basearchonly': False, 'type': 'mandatory'} + Package: hawaii-widget-styles: {'basearchonly': False, 'type': 'mandatory'} + Package: hawaii-workspace: {'basearchonly': False, 'type': 'mandatory'} + Package: initial-setup-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: mesa-dri-drivers: {'basearchonly': False, 'type': 'mandatory'} + Package: pcmanfm-qt: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qdbusviewer: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtbase-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtdeclarative: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtwayland: {'basearchonly': False, 'type': 'mandatory'} + Package: qterminal-qt5: {'basearchonly': False, 'type': 'mandatory'} + Package: otter-browser: {'basearchonly': False, 'type': 'mandatory'} + Package: sddm: {'basearchonly': False, 'type': 'mandatory'} + Package: sddm-theme-hawaii: {'basearchonly': False, 'type': 'mandatory'} + Package: upower: {'basearchonly': False, 'type': 'mandatory'} + Package: xdg-user-dirs: {'basearchonly': False, 'type': 'mandatory'} Group: hawaii-media (Multimedia support for Hawaii) - Package: pavucontrol: {'type': 'mandatory', 'basearchonly': False} + Package: pavucontrol: {'basearchonly': False, 'type': 'mandatory'} Group: hawaii-office (Hawaii Office) - Package: libreoffice-calc: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-impress: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-writer: {'type': 'mandatory', 'basearchonly': False} + Package: libreoffice-calc: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-impress: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-writer: {'basearchonly': False, 'type': 'mandatory'} Group: headless-management (Headless Management) - Package: cockpit-bridge: {'type': 'mandatory', 'basearchonly': False} - Package: cockpit-networkmanager: {'type': 'mandatory', 'basearchonly': False} - Package: cockpit-shell: {'type': 'mandatory', 'basearchonly': False} - Package: cockpit-storaged: {'type': 'mandatory', 'basearchonly': False} - Package: cockpit-ws: {'type': 'mandatory', 'basearchonly': False} - Package: openssh-server: {'type': 'mandatory', 'basearchonly': False} - Package: PackageKit: {'type': 'mandatory', 'basearchonly': False} - Package: rolekit: {'type': 'mandatory', 'basearchonly': False} - Package: cockpit-kubernetes: {'type': 'optional', 'basearchonly': False} - Package: cockpit-pcp: {'type': 'optional', 'basearchonly': False} + Package: cockpit-bridge: {'basearchonly': False, 'type': 'mandatory'} + Package: cockpit-networkmanager: {'basearchonly': False, 'type': 'mandatory'} + Package: cockpit-shell: {'basearchonly': False, 'type': 'mandatory'} + Package: cockpit-storaged: {'basearchonly': False, 'type': 'mandatory'} + Package: cockpit-ws: {'basearchonly': False, 'type': 'mandatory'} + Package: openssh-server: {'basearchonly': False, 'type': 'mandatory'} + Package: PackageKit: {'basearchonly': False, 'type': 'mandatory'} + Package: rolekit: {'basearchonly': False, 'type': 'mandatory'} + Package: cockpit-kubernetes: {'basearchonly': False, 'type': 'optional'} + Package: cockpit-pcp: {'basearchonly': False, 'type': 'optional'} Group: hebrew-support (Hebrew Support) - Package: dejavu-sans-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: culmus-aharoni-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-caladings-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-david-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-drugulin-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-ellinia-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-frank-ruehl-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-hadasim-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-keteryg-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-miriam-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-miriam-mono-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-nachlieli-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-simple-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-stamashkenaz-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-stamsefarad-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-yehuda-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-hebrew-fonts: {'type': 'default', 'basearchonly': False} + Package: dejavu-sans-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: culmus-aharoni-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-caladings-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-david-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-drugulin-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-ellinia-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-frank-ruehl-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-hadasim-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-keteryg-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-miriam-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-miriam-mono-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-nachlieli-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-simple-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-stamashkenaz-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-stamsefarad-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-yehuda-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-hebrew-fonts: {'basearchonly': False, 'type': 'default'} Group: hindi-support (Hindi Support) - Package: lohit-devanagari-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: samyak-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: sarai-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: samyak-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: sarai-fonts: {'basearchonly': False, 'type': 'default'} Group: input-methods (Input Methods) - Package: gtk2-immodule-xim: {'requires': u'gtk2', 'type': 'conditional', 'basearchonly': False} - Package: gtk3-immodule-xim: {'requires': u'gtk3', 'type': 'conditional', 'basearchonly': False} - Package: ibus-gtk2: {'requires': u'gtk2', 'type': 'conditional', 'basearchonly': False} - Package: ibus-gtk3: {'requires': u'gtk3', 'type': 'conditional', 'basearchonly': False} - Package: ibus-qt: {'requires': u'qt', 'type': 'conditional', 'basearchonly': False} - Package: im-chooser-xfce: {'requires': u'xfce4-panel', 'type': 'conditional', 'basearchonly': False} - Package: imsettings-cinnamon: {'requires': u'cinnamon', 'type': 'conditional', 'basearchonly': False} - Package: imsettings-gsettings: {'requires': u'gnome-settings-daemon', 'type': 'conditional', 'basearchonly': False} - Package: imsettings-lxde: {'requires': u'lxde-common', 'type': 'conditional', 'basearchonly': False} - Package: imsettings-mate: {'requires': u'mate-settings-daemon', 'type': 'conditional', 'basearchonly': False} - Package: imsettings-qt: {'requires': u'qt', 'type': 'conditional', 'basearchonly': False} - Package: imsettings-xfce: {'requires': u'xfce4-panel', 'type': 'conditional', 'basearchonly': False} - Package: ibus-hangul: {'type': 'default', 'basearchonly': False} - Package: ibus-kkc: {'type': 'default', 'basearchonly': False} - Package: ibus-libpinyin: {'type': 'default', 'basearchonly': False} - Package: ibus-libzhuyin: {'type': 'default', 'basearchonly': False} - Package: ibus-m17n: {'type': 'default', 'basearchonly': False} - Package: ibus-rawcode: {'type': 'default', 'basearchonly': False} - Package: ibus-typing-booster: {'type': 'default', 'basearchonly': False} - Package: im-chooser: {'type': 'default', 'basearchonly': False} - Package: imsettings: {'type': 'default', 'basearchonly': False} - Package: cellwriter: {'type': 'optional', 'basearchonly': False} - Package: eekboard: {'type': 'optional', 'basearchonly': False} - Package: fcitx: {'type': 'optional', 'basearchonly': False} - Package: gcin: {'type': 'optional', 'basearchonly': False} - Package: ibus-anthy: {'type': 'optional', 'basearchonly': False} - Package: ibus-bogo: {'type': 'optional', 'basearchonly': False} - Package: ibus-fbterm: {'type': 'optional', 'basearchonly': False} - Package: ibus-gucharmap: {'type': 'optional', 'basearchonly': False} - Package: ibus-handwrite: {'type': 'optional', 'basearchonly': False} - Package: ibus-input-pad: {'type': 'optional', 'basearchonly': False} - Package: ibus-mozc: {'type': 'optional', 'basearchonly': False} - Package: ibus-sayura: {'type': 'optional', 'basearchonly': False} - Package: ibus-skk: {'type': 'optional', 'basearchonly': False} - Package: ibus-table: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-array30: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-cyrillic: {'type': 'optional', 'basearchonly': False} - Package: ibus-xkbc: {'type': 'optional', 'basearchonly': False} - Package: input-pad: {'type': 'optional', 'basearchonly': False} - Package: iok: {'type': 'optional', 'basearchonly': False} - Package: kinput2: {'type': 'optional', 'basearchonly': False} - Package: scim-anthy: {'type': 'optional', 'basearchonly': False} - Package: scim-array: {'type': 'optional', 'basearchonly': False} - Package: scim-bridge-gtk: {'type': 'optional', 'basearchonly': False} - Package: scim-bridge-qt: {'type': 'optional', 'basearchonly': False} - Package: scim-bridge-qt3: {'type': 'optional', 'basearchonly': False} - Package: scim-chewing: {'type': 'optional', 'basearchonly': False} - Package: scim-fcitx: {'type': 'optional', 'basearchonly': False} - Package: scim-gtk: {'type': 'optional', 'basearchonly': False} - Package: scim-hangul: {'type': 'optional', 'basearchonly': False} - Package: scim-m17n: {'type': 'optional', 'basearchonly': False} - Package: scim-pinyin: {'type': 'optional', 'basearchonly': False} - Package: scim-rawcode: {'type': 'optional', 'basearchonly': False} - Package: scim-sayura: {'type': 'optional', 'basearchonly': False} - Package: scim-tables-additional: {'type': 'optional', 'basearchonly': False} - Package: scim-tables-chinese: {'type': 'optional', 'basearchonly': False} - Package: scim-tables-chinese-extra: {'type': 'optional', 'basearchonly': False} - Package: scim-thai: {'type': 'optional', 'basearchonly': False} - Package: uim: {'type': 'optional', 'basearchonly': False} - Package: uim-anthy: {'type': 'optional', 'basearchonly': False} - Package: uim-canna: {'type': 'optional', 'basearchonly': False} - Package: uim-gtk2: {'type': 'optional', 'basearchonly': False} - Package: uim-gtk3: {'type': 'optional', 'basearchonly': False} - Package: uim-m17n: {'type': 'optional', 'basearchonly': False} - Package: uim-qt3: {'type': 'optional', 'basearchonly': False} - Package: uim-skk: {'type': 'optional', 'basearchonly': False} - Package: WritRecogn: {'type': 'optional', 'basearchonly': False} + Package: gtk2-immodule-xim: {'basearchonly': False, 'requires': 'gtk2', 'type': 'conditional'} + Package: gtk3-immodule-xim: {'basearchonly': False, 'requires': 'gtk3', 'type': 'conditional'} + Package: ibus-gtk2: {'basearchonly': False, 'requires': 'gtk2', 'type': 'conditional'} + Package: ibus-gtk3: {'basearchonly': False, 'requires': 'gtk3', 'type': 'conditional'} + Package: ibus-qt: {'basearchonly': False, 'requires': 'qt', 'type': 'conditional'} + Package: im-chooser-xfce: {'basearchonly': False, 'requires': 'xfce4-panel', 'type': 'conditional'} + Package: imsettings-cinnamon: {'basearchonly': False, 'requires': 'cinnamon', 'type': 'conditional'} + Package: imsettings-gsettings: {'basearchonly': False, 'requires': 'gnome-settings-daemon', 'type': 'conditional'} + Package: imsettings-lxde: {'basearchonly': False, 'requires': 'lxde-common', 'type': 'conditional'} + Package: imsettings-mate: {'basearchonly': False, 'requires': 'mate-settings-daemon', 'type': 'conditional'} + Package: imsettings-qt: {'basearchonly': False, 'requires': 'qt', 'type': 'conditional'} + Package: imsettings-xfce: {'basearchonly': False, 'requires': 'xfce4-panel', 'type': 'conditional'} + Package: ibus-hangul: {'basearchonly': False, 'type': 'default'} + Package: ibus-kkc: {'basearchonly': False, 'type': 'default'} + Package: ibus-libpinyin: {'basearchonly': False, 'type': 'default'} + Package: ibus-libzhuyin: {'basearchonly': False, 'type': 'default'} + Package: ibus-m17n: {'basearchonly': False, 'type': 'default'} + Package: ibus-rawcode: {'basearchonly': False, 'type': 'default'} + Package: ibus-typing-booster: {'basearchonly': False, 'type': 'default'} + Package: im-chooser: {'basearchonly': False, 'type': 'default'} + Package: imsettings: {'basearchonly': False, 'type': 'default'} + Package: cellwriter: {'basearchonly': False, 'type': 'optional'} + Package: eekboard: {'basearchonly': False, 'type': 'optional'} + Package: fcitx: {'basearchonly': False, 'type': 'optional'} + Package: gcin: {'basearchonly': False, 'type': 'optional'} + Package: ibus-anthy: {'basearchonly': False, 'type': 'optional'} + Package: ibus-bogo: {'basearchonly': False, 'type': 'optional'} + Package: ibus-fbterm: {'basearchonly': False, 'type': 'optional'} + Package: ibus-gucharmap: {'basearchonly': False, 'type': 'optional'} + Package: ibus-handwrite: {'basearchonly': False, 'type': 'optional'} + Package: ibus-input-pad: {'basearchonly': False, 'type': 'optional'} + Package: ibus-mozc: {'basearchonly': False, 'type': 'optional'} + Package: ibus-sayura: {'basearchonly': False, 'type': 'optional'} + Package: ibus-skk: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-array30: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-cyrillic: {'basearchonly': False, 'type': 'optional'} + Package: ibus-xkbc: {'basearchonly': False, 'type': 'optional'} + Package: input-pad: {'basearchonly': False, 'type': 'optional'} + Package: iok: {'basearchonly': False, 'type': 'optional'} + Package: kinput2: {'basearchonly': False, 'type': 'optional'} + Package: scim-anthy: {'basearchonly': False, 'type': 'optional'} + Package: scim-array: {'basearchonly': False, 'type': 'optional'} + Package: scim-bridge-gtk: {'basearchonly': False, 'type': 'optional'} + Package: scim-bridge-qt: {'basearchonly': False, 'type': 'optional'} + Package: scim-bridge-qt3: {'basearchonly': False, 'type': 'optional'} + Package: scim-chewing: {'basearchonly': False, 'type': 'optional'} + Package: scim-fcitx: {'basearchonly': False, 'type': 'optional'} + Package: scim-gtk: {'basearchonly': False, 'type': 'optional'} + Package: scim-hangul: {'basearchonly': False, 'type': 'optional'} + Package: scim-m17n: {'basearchonly': False, 'type': 'optional'} + Package: scim-pinyin: {'basearchonly': False, 'type': 'optional'} + Package: scim-rawcode: {'basearchonly': False, 'type': 'optional'} + Package: scim-sayura: {'basearchonly': False, 'type': 'optional'} + Package: scim-tables-additional: {'basearchonly': False, 'type': 'optional'} + Package: scim-tables-chinese: {'basearchonly': False, 'type': 'optional'} + Package: scim-tables-chinese-extra: {'basearchonly': False, 'type': 'optional'} + Package: scim-thai: {'basearchonly': False, 'type': 'optional'} + Package: uim: {'basearchonly': False, 'type': 'optional'} + Package: uim-anthy: {'basearchonly': False, 'type': 'optional'} + Package: uim-canna: {'basearchonly': False, 'type': 'optional'} + Package: uim-gtk2: {'basearchonly': False, 'type': 'optional'} + Package: uim-gtk3: {'basearchonly': False, 'type': 'optional'} + Package: uim-m17n: {'basearchonly': False, 'type': 'optional'} + Package: uim-qt3: {'basearchonly': False, 'type': 'optional'} + Package: uim-skk: {'basearchonly': False, 'type': 'optional'} + Package: WritRecogn: {'basearchonly': False, 'type': 'optional'} Group: japanese-support (Japanese Support) - Package: ibus-kkc: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: uim-anthy: {'requires': u'uim', 'type': 'conditional', 'basearchonly': False} - Package: vlgothic-fonts: {'type': 'default', 'basearchonly': False} - Package: vlgothic-p-fonts: {'type': 'default', 'basearchonly': False} - Package: cmigemo: {'type': 'optional', 'basearchonly': False} - Package: eblook: {'type': 'optional', 'basearchonly': False} - Package: ebview: {'type': 'optional', 'basearchonly': False} - Package: emacs-common-ddskk: {'type': 'optional', 'basearchonly': False} - Package: hanazono-fonts: {'type': 'optional', 'basearchonly': False} - Package: ibus-mozc: {'type': 'optional', 'basearchonly': False} - Package: ipa-ex-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-ex-mincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-mincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-pgothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: ipa-pmincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: japanese-bitmap-fonts: {'type': 'optional', 'basearchonly': False} - Package: jfbterm: {'type': 'optional', 'basearchonly': False} - Package: jisksp16-1990-fonts: {'type': 'optional', 'basearchonly': False} - Package: kcc: {'type': 'optional', 'basearchonly': False} - Package: kinput2: {'type': 'optional', 'basearchonly': False} - Package: lv: {'type': 'optional', 'basearchonly': False} - Package: m17n-db-extras: {'type': 'optional', 'basearchonly': False} - Package: mecab: {'type': 'optional', 'basearchonly': False} - Package: mecab-ipadic: {'type': 'optional', 'basearchonly': False} - Package: mecab-jumandic: {'type': 'optional', 'basearchonly': False} - Package: mfiler3: {'type': 'optional', 'basearchonly': False} - Package: migemo: {'type': 'optional', 'basearchonly': False} - Package: mona-bitmap-fonts: {'type': 'optional', 'basearchonly': False} - Package: mona-sazanami-fonts: {'type': 'optional', 'basearchonly': False} - Package: mona-vlgothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: motoya-lcedar-fonts: {'type': 'optional', 'basearchonly': False} - Package: motoya-lmaru-fonts: {'type': 'optional', 'basearchonly': False} - Package: nkf: {'type': 'optional', 'basearchonly': False} - Package: oniguruma: {'type': 'optional', 'basearchonly': False} - Package: perl-NKF: {'type': 'optional', 'basearchonly': False} - Package: sazanami-gothic-fonts: {'type': 'optional', 'basearchonly': False} - Package: sazanami-mincho-fonts: {'type': 'optional', 'basearchonly': False} - Package: scim-anthy: {'type': 'optional', 'basearchonly': False} - Package: stardict-dic-ja: {'type': 'optional', 'basearchonly': False} - Package: uim-canna: {'type': 'optional', 'basearchonly': False} - Package: uim-skk: {'type': 'optional', 'basearchonly': False} + Package: ibus-kkc: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: uim-anthy: {'basearchonly': False, 'requires': 'uim', 'type': 'conditional'} + Package: vlgothic-fonts: {'basearchonly': False, 'type': 'default'} + Package: vlgothic-p-fonts: {'basearchonly': False, 'type': 'default'} + Package: cmigemo: {'basearchonly': False, 'type': 'optional'} + Package: eblook: {'basearchonly': False, 'type': 'optional'} + Package: ebview: {'basearchonly': False, 'type': 'optional'} + Package: emacs-common-ddskk: {'basearchonly': False, 'type': 'optional'} + Package: hanazono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ibus-mozc: {'basearchonly': False, 'type': 'optional'} + Package: ipa-ex-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-ex-mincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-mincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-pgothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ipa-pmincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: japanese-bitmap-fonts: {'basearchonly': False, 'type': 'optional'} + Package: jfbterm: {'basearchonly': False, 'type': 'optional'} + Package: jisksp16-1990-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kcc: {'basearchonly': False, 'type': 'optional'} + Package: kinput2: {'basearchonly': False, 'type': 'optional'} + Package: lv: {'basearchonly': False, 'type': 'optional'} + Package: m17n-db-extras: {'basearchonly': False, 'type': 'optional'} + Package: mecab: {'basearchonly': False, 'type': 'optional'} + Package: mecab-ipadic: {'basearchonly': False, 'type': 'optional'} + Package: mecab-jumandic: {'basearchonly': False, 'type': 'optional'} + Package: mfiler3: {'basearchonly': False, 'type': 'optional'} + Package: migemo: {'basearchonly': False, 'type': 'optional'} + Package: mona-bitmap-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mona-sazanami-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mona-vlgothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: motoya-lcedar-fonts: {'basearchonly': False, 'type': 'optional'} + Package: motoya-lmaru-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nkf: {'basearchonly': False, 'type': 'optional'} + Package: oniguruma: {'basearchonly': False, 'type': 'optional'} + Package: perl-NKF: {'basearchonly': False, 'type': 'optional'} + Package: sazanami-gothic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: sazanami-mincho-fonts: {'basearchonly': False, 'type': 'optional'} + Package: scim-anthy: {'basearchonly': False, 'type': 'optional'} + Package: stardict-dic-ja: {'basearchonly': False, 'type': 'optional'} + Package: uim-canna: {'basearchonly': False, 'type': 'optional'} + Package: uim-skk: {'basearchonly': False, 'type': 'optional'} Group: java (Java) - Package: java-1.8.0-openjdk: {'type': 'mandatory', 'basearchonly': False} - Package: abrt-java-connector: {'type': 'default', 'basearchonly': False} - Package: icedtea-web: {'type': 'default', 'basearchonly': False} + Package: java-1.8.0-openjdk: {'basearchonly': False, 'type': 'mandatory'} + Package: abrt-java-connector: {'basearchonly': False, 'type': 'default'} + Package: icedtea-web: {'basearchonly': False, 'type': 'default'} Group: java-development (Java Development) - Package: ant: {'type': 'mandatory', 'basearchonly': False} - Package: ecj: {'type': 'mandatory', 'basearchonly': False} - Package: java-1.8.0-openjdk-devel: {'type': 'mandatory', 'basearchonly': False} - Package: abrt-java-connector: {'type': 'default', 'basearchonly': False} - Package: ant-antlr: {'type': 'default', 'basearchonly': False} - Package: ant-apache-bcel: {'type': 'default', 'basearchonly': False} - Package: ant-apache-log4j: {'type': 'default', 'basearchonly': False} - Package: ant-apache-oro: {'type': 'default', 'basearchonly': False} - Package: ant-apache-regexp: {'type': 'default', 'basearchonly': False} - Package: ant-apache-resolver: {'type': 'default', 'basearchonly': False} - Package: ant-commons-logging: {'type': 'default', 'basearchonly': False} - Package: ant-javamail: {'type': 'default', 'basearchonly': False} - Package: ant-jdepend: {'type': 'default', 'basearchonly': False} - Package: ant-junit: {'type': 'default', 'basearchonly': False} - Package: ant-swing: {'type': 'default', 'basearchonly': False} - Package: apache-commons-beanutils: {'type': 'default', 'basearchonly': False} - Package: apache-commons-codec: {'type': 'default', 'basearchonly': False} - Package: apache-commons-collections: {'type': 'default', 'basearchonly': False} - Package: apache-commons-compress: {'type': 'default', 'basearchonly': False} - Package: apache-commons-configuration: {'type': 'default', 'basearchonly': False} - Package: apache-commons-daemon: {'type': 'default', 'basearchonly': False} - Package: apache-commons-dbcp: {'type': 'default', 'basearchonly': False} - Package: apache-commons-digester: {'type': 'default', 'basearchonly': False} - Package: apache-commons-discovery: {'type': 'default', 'basearchonly': False} - Package: apache-commons-el: {'type': 'default', 'basearchonly': False} - Package: apache-commons-exec: {'type': 'default', 'basearchonly': False} - Package: apache-commons-fileupload: {'type': 'default', 'basearchonly': False} - Package: apache-commons-io: {'type': 'default', 'basearchonly': False} - Package: apache-commons-lang: {'type': 'default', 'basearchonly': False} - Package: apache-commons-launcher: {'type': 'default', 'basearchonly': False} - Package: apache-commons-logging: {'type': 'default', 'basearchonly': False} - Package: apache-commons-math: {'type': 'default', 'basearchonly': False} - Package: apache-commons-modeler: {'type': 'default', 'basearchonly': False} - Package: apache-commons-net: {'type': 'default', 'basearchonly': False} - Package: apache-commons-pool: {'type': 'default', 'basearchonly': False} - Package: apache-commons-validator: {'type': 'default', 'basearchonly': False} - Package: avalon-framework: {'type': 'default', 'basearchonly': False} - Package: avalon-logkit: {'type': 'default', 'basearchonly': False} - Package: bcel: {'type': 'default', 'basearchonly': False} - Package: gnu-getopt: {'type': 'default', 'basearchonly': False} - Package: jakarta-oro: {'type': 'default', 'basearchonly': False} - Package: java-1.8.0-openjdk-demo: {'type': 'default', 'basearchonly': False} - Package: java-1.8.0-openjdk-javadoc: {'type': 'default', 'basearchonly': False} - Package: java-1.8.0-openjdk-src: {'type': 'default', 'basearchonly': False} - Package: javamail: {'type': 'default', 'basearchonly': False} - Package: java_cup: {'type': 'default', 'basearchonly': False} - Package: jdepend: {'type': 'default', 'basearchonly': False} - Package: jflex: {'type': 'default', 'basearchonly': False} - Package: junit: {'type': 'default', 'basearchonly': False} - Package: ldapjdk: {'type': 'default', 'basearchonly': False} - Package: log4j: {'type': 'default', 'basearchonly': False} - Package: maven: {'type': 'default', 'basearchonly': False} - Package: mx4j: {'type': 'default', 'basearchonly': False} - Package: regexp: {'type': 'default', 'basearchonly': False} - Package: xalan-j2: {'type': 'default', 'basearchonly': False} - Package: xalan-j2-xsltc: {'type': 'default', 'basearchonly': False} - Package: xerces-j2: {'type': 'default', 'basearchonly': False} - Package: xml-commons-apis: {'type': 'default', 'basearchonly': False} - Package: xml-commons-resolver: {'type': 'default', 'basearchonly': False} - Package: ant-findbugs: {'type': 'optional', 'basearchonly': False} - Package: findbugs: {'type': 'optional', 'basearchonly': False} - Package: findbugs-tools: {'type': 'optional', 'basearchonly': False} - Package: jcip-annotations: {'type': 'optional', 'basearchonly': False} - Package: jinput: {'type': 'optional', 'basearchonly': False} - Package: jsr-305: {'type': 'optional', 'basearchonly': False} - Package: pmd: {'type': 'optional', 'basearchonly': False} + Package: ant: {'basearchonly': False, 'type': 'mandatory'} + Package: ecj: {'basearchonly': False, 'type': 'mandatory'} + Package: java-1.8.0-openjdk-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: abrt-java-connector: {'basearchonly': False, 'type': 'default'} + Package: ant-antlr: {'basearchonly': False, 'type': 'default'} + Package: ant-apache-bcel: {'basearchonly': False, 'type': 'default'} + Package: ant-apache-log4j: {'basearchonly': False, 'type': 'default'} + Package: ant-apache-oro: {'basearchonly': False, 'type': 'default'} + Package: ant-apache-regexp: {'basearchonly': False, 'type': 'default'} + Package: ant-apache-resolver: {'basearchonly': False, 'type': 'default'} + Package: ant-commons-logging: {'basearchonly': False, 'type': 'default'} + Package: ant-javamail: {'basearchonly': False, 'type': 'default'} + Package: ant-jdepend: {'basearchonly': False, 'type': 'default'} + Package: ant-junit: {'basearchonly': False, 'type': 'default'} + Package: ant-swing: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-beanutils: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-codec: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-collections: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-compress: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-configuration: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-daemon: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-dbcp: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-digester: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-discovery: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-el: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-exec: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-fileupload: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-io: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-lang: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-launcher: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-logging: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-math: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-modeler: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-net: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-pool: {'basearchonly': False, 'type': 'default'} + Package: apache-commons-validator: {'basearchonly': False, 'type': 'default'} + Package: avalon-framework: {'basearchonly': False, 'type': 'default'} + Package: avalon-logkit: {'basearchonly': False, 'type': 'default'} + Package: bcel: {'basearchonly': False, 'type': 'default'} + Package: gnu-getopt: {'basearchonly': False, 'type': 'default'} + Package: jakarta-oro: {'basearchonly': False, 'type': 'default'} + Package: java-1.8.0-openjdk-demo: {'basearchonly': False, 'type': 'default'} + Package: java-1.8.0-openjdk-javadoc: {'basearchonly': False, 'type': 'default'} + Package: java-1.8.0-openjdk-src: {'basearchonly': False, 'type': 'default'} + Package: javamail: {'basearchonly': False, 'type': 'default'} + Package: java_cup: {'basearchonly': False, 'type': 'default'} + Package: jdepend: {'basearchonly': False, 'type': 'default'} + Package: jflex: {'basearchonly': False, 'type': 'default'} + Package: junit: {'basearchonly': False, 'type': 'default'} + Package: ldapjdk: {'basearchonly': False, 'type': 'default'} + Package: log4j: {'basearchonly': False, 'type': 'default'} + Package: maven: {'basearchonly': False, 'type': 'default'} + Package: mx4j: {'basearchonly': False, 'type': 'default'} + Package: regexp: {'basearchonly': False, 'type': 'default'} + Package: xalan-j2: {'basearchonly': False, 'type': 'default'} + Package: xalan-j2-xsltc: {'basearchonly': False, 'type': 'default'} + Package: xerces-j2: {'basearchonly': False, 'type': 'default'} + Package: xml-commons-apis: {'basearchonly': False, 'type': 'default'} + Package: xml-commons-resolver: {'basearchonly': False, 'type': 'default'} + Package: ant-findbugs: {'basearchonly': False, 'type': 'optional'} + Package: findbugs: {'basearchonly': False, 'type': 'optional'} + Package: findbugs-tools: {'basearchonly': False, 'type': 'optional'} + Package: jcip-annotations: {'basearchonly': False, 'type': 'optional'} + Package: jinput: {'basearchonly': False, 'type': 'optional'} + Package: jsr-305: {'basearchonly': False, 'type': 'optional'} + Package: pmd: {'basearchonly': False, 'type': 'optional'} Group: javaenterprise (Java Application Server) - Package: abrt-java-connector: {'type': 'mandatory', 'basearchonly': False} - Package: java-1.8.0-openjdk: {'type': 'mandatory', 'basearchonly': False} - Package: java-1.8.0-openjdk-devel: {'type': 'mandatory', 'basearchonly': False} - Package: jboss-modules: {'type': 'mandatory', 'basearchonly': False} - Package: maven: {'type': 'mandatory', 'basearchonly': False} - Package: wildfly: {'type': 'mandatory', 'basearchonly': False} + Package: abrt-java-connector: {'basearchonly': False, 'type': 'mandatory'} + Package: java-1.8.0-openjdk: {'basearchonly': False, 'type': 'mandatory'} + Package: java-1.8.0-openjdk-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: jboss-modules: {'basearchonly': False, 'type': 'mandatory'} + Package: maven: {'basearchonly': False, 'type': 'mandatory'} + Package: wildfly: {'basearchonly': False, 'type': 'mandatory'} Group: kannada-support (Kannada Support) - Package: lohit-kannada-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-kannada-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-kannada-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: gubbi-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: navilu-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-kannada-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-kannada-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-kannada-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: gubbi-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: navilu-fonts: {'basearchonly': False, 'type': 'default'} Group: kashmiri-support (Kashmiri Support) - Package: lohit-devanagari-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} Group: kde-apps (KDE Applications) - Package: ark: {'type': 'mandatory', 'basearchonly': False} - Package: digikam: {'type': 'mandatory', 'basearchonly': False} - Package: kde-connect: {'type': 'mandatory', 'basearchonly': False} - Package: kdegames-minimal: {'type': 'mandatory', 'basearchonly': False} - Package: kolourpaint: {'type': 'mandatory', 'basearchonly': False} - Package: konversation: {'type': 'mandatory', 'basearchonly': False} - Package: krdc: {'type': 'mandatory', 'basearchonly': False} - Package: krfb: {'type': 'mandatory', 'basearchonly': False} - Package: krusader: {'type': 'mandatory', 'basearchonly': False} - Package: ktorrent: {'type': 'mandatory', 'basearchonly': False} + Package: ark: {'basearchonly': False, 'type': 'mandatory'} + Package: digikam: {'basearchonly': False, 'type': 'mandatory'} + Package: kde-connect: {'basearchonly': False, 'type': 'mandatory'} + Package: kdegames-minimal: {'basearchonly': False, 'type': 'mandatory'} + Package: kolourpaint: {'basearchonly': False, 'type': 'mandatory'} + Package: konversation: {'basearchonly': False, 'type': 'mandatory'} + Package: krdc: {'basearchonly': False, 'type': 'mandatory'} + Package: krfb: {'basearchonly': False, 'type': 'mandatory'} + Package: krusader: {'basearchonly': False, 'type': 'mandatory'} + Package: ktorrent: {'basearchonly': False, 'type': 'mandatory'} Group: kde-desktop (KDE) - Package: abrt-desktop: {'type': 'mandatory', 'basearchonly': False} - Package: adwaita-gtk2-theme: {'type': 'mandatory', 'basearchonly': False} - Package: akregator: {'type': 'mandatory', 'basearchonly': False} - Package: apper: {'type': 'mandatory', 'basearchonly': False} - Package: bluedevil: {'type': 'mandatory', 'basearchonly': False} - Package: breeze-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: cagibi: {'type': 'mandatory', 'basearchonly': False} - Package: colord-kde: {'type': 'mandatory', 'basearchonly': False} - Package: cups-pk-helper: {'type': 'mandatory', 'basearchonly': False} - Package: dolphin: {'type': 'mandatory', 'basearchonly': False} - Package: firewall-config: {'type': 'mandatory', 'basearchonly': False} - Package: glibc-all-langpacks: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-keyring-pam: {'type': 'mandatory', 'basearchonly': False} - Package: gwenview: {'type': 'mandatory', 'basearchonly': False} - Package: initial-setup-gui: {'type': 'mandatory', 'basearchonly': False} - Package: kaddressbook: {'type': 'mandatory', 'basearchonly': False} - Package: kamera: {'type': 'mandatory', 'basearchonly': False} - Package: kcalc: {'type': 'mandatory', 'basearchonly': False} - Package: kcharselect: {'type': 'mandatory', 'basearchonly': False} - Package: kcm_systemd: {'type': 'mandatory', 'basearchonly': False} - Package: kcolorchooser: {'type': 'mandatory', 'basearchonly': False} - Package: kde-gtk-config: {'type': 'mandatory', 'basearchonly': False} - Package: kde-partitionmanager: {'type': 'mandatory', 'basearchonly': False} - Package: kde-platform-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: kde-print-manager: {'type': 'mandatory', 'basearchonly': False} - Package: kde-runtime: {'type': 'mandatory', 'basearchonly': False} - Package: kde-settings-pulseaudio: {'type': 'mandatory', 'basearchonly': False} - Package: kde-style-breeze: {'type': 'mandatory', 'basearchonly': False} - Package: kdeaccessibility: {'type': 'mandatory', 'basearchonly': False} - Package: kdegames-minimal: {'type': 'mandatory', 'basearchonly': False} - Package: kdegraphics-thumbnailers: {'type': 'mandatory', 'basearchonly': False} - Package: kdelibs: {'type': 'mandatory', 'basearchonly': False} - Package: kdepasswd: {'type': 'mandatory', 'basearchonly': False} - Package: kdeplasma-addons: {'type': 'mandatory', 'basearchonly': False} - Package: kdialog: {'type': 'mandatory', 'basearchonly': False} - Package: kdnssd: {'type': 'mandatory', 'basearchonly': False} - Package: keditbookmarks: {'type': 'mandatory', 'basearchonly': False} - Package: kf5-akonadi-server: {'type': 'mandatory', 'basearchonly': False} - Package: kf5-akonadi-server-mysql: {'type': 'mandatory', 'basearchonly': False} - Package: kf5-baloo-file: {'type': 'mandatory', 'basearchonly': False} - Package: kf5-kipi-plugins: {'type': 'mandatory', 'basearchonly': False} - Package: kfind: {'type': 'mandatory', 'basearchonly': False} - Package: kget: {'type': 'mandatory', 'basearchonly': False} - Package: kgpg: {'type': 'mandatory', 'basearchonly': False} - Package: khelpcenter: {'type': 'mandatory', 'basearchonly': False} - Package: khotkeys: {'type': 'mandatory', 'basearchonly': False} - Package: kinfocenter: {'type': 'mandatory', 'basearchonly': False} - Package: kmail: {'type': 'mandatory', 'basearchonly': False} - Package: kmenuedit: {'type': 'mandatory', 'basearchonly': False} - Package: knode: {'type': 'mandatory', 'basearchonly': False} - Package: konqueror: {'type': 'mandatory', 'basearchonly': False} - Package: konsole5: {'type': 'mandatory', 'basearchonly': False} - Package: kontact: {'type': 'mandatory', 'basearchonly': False} - Package: korganizer: {'type': 'mandatory', 'basearchonly': False} - Package: kruler: {'type': 'mandatory', 'basearchonly': False} - Package: kscreen: {'type': 'mandatory', 'basearchonly': False} - Package: kscreenlocker: {'type': 'mandatory', 'basearchonly': False} - Package: ksshaskpass: {'type': 'mandatory', 'basearchonly': False} - Package: ksysguard: {'type': 'mandatory', 'basearchonly': False} - Package: kuser: {'type': 'mandatory', 'basearchonly': False} - Package: kwalletmanager: {'type': 'mandatory', 'basearchonly': False} - Package: kwalletmanager5: {'type': 'mandatory', 'basearchonly': False} - Package: kwebkitpart: {'type': 'mandatory', 'basearchonly': False} - Package: kwin: {'type': 'mandatory', 'basearchonly': False} - Package: kwrite: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-config-connectivity-fedora: {'type': 'mandatory', 'basearchonly': False} - Package: pam-kwallet: {'type': 'mandatory', 'basearchonly': False} - Package: phonon-backend-gstreamer: {'type': 'mandatory', 'basearchonly': False} - Package: phonon-qt5-backend-gstreamer: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-breeze: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-desktop: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-desktop-doc: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-nm: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-nm-l2tp: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-nm-openconnect: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-nm-openswan: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-nm-openvpn: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-nm-pptp: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-nm-vpnc: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-pa: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-pk-updates: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-user-manager: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-workspace: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-workspace-drkonqi: {'type': 'mandatory', 'basearchonly': False} - Package: plasma-workspace-geolocation: {'type': 'mandatory', 'basearchonly': False} - Package: polkit-kde: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qdbusviewer: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtbase-gui: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtdeclarative: {'type': 'mandatory', 'basearchonly': False} - Package: sddm: {'type': 'mandatory', 'basearchonly': False} - Package: sddm-breeze: {'type': 'mandatory', 'basearchonly': False} - Package: sddm-kcm: {'type': 'mandatory', 'basearchonly': False} - Package: sni-qt: {'type': 'mandatory', 'basearchonly': False} - Package: spectacle: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-libinput: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-kde: {'requires': u'libreoffice-core', 'type': 'conditional', 'basearchonly': False} - Package: pinentry-qt: {'requires': u'pinentry', 'type': 'conditional', 'basearchonly': False} - Package: qt-at-spi: {'requires': u'at-spi2-core', 'type': 'conditional', 'basearchonly': False} - Package: socat: {'requires': u'pam_kwallet', 'type': 'conditional', 'basearchonly': False} + Package: abrt-desktop: {'basearchonly': False, 'type': 'mandatory'} + Package: adwaita-gtk2-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: akregator: {'basearchonly': False, 'type': 'mandatory'} + Package: apper: {'basearchonly': False, 'type': 'mandatory'} + Package: bluedevil: {'basearchonly': False, 'type': 'mandatory'} + Package: breeze-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: cagibi: {'basearchonly': False, 'type': 'mandatory'} + Package: colord-kde: {'basearchonly': False, 'type': 'mandatory'} + Package: cups-pk-helper: {'basearchonly': False, 'type': 'mandatory'} + Package: dolphin: {'basearchonly': False, 'type': 'mandatory'} + Package: firewall-config: {'basearchonly': False, 'type': 'mandatory'} + Package: glibc-all-langpacks: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-keyring-pam: {'basearchonly': False, 'type': 'mandatory'} + Package: gwenview: {'basearchonly': False, 'type': 'mandatory'} + Package: initial-setup-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: kaddressbook: {'basearchonly': False, 'type': 'mandatory'} + Package: kamera: {'basearchonly': False, 'type': 'mandatory'} + Package: kcalc: {'basearchonly': False, 'type': 'mandatory'} + Package: kcharselect: {'basearchonly': False, 'type': 'mandatory'} + Package: kcm_systemd: {'basearchonly': False, 'type': 'mandatory'} + Package: kcolorchooser: {'basearchonly': False, 'type': 'mandatory'} + Package: kde-gtk-config: {'basearchonly': False, 'type': 'mandatory'} + Package: kde-partitionmanager: {'basearchonly': False, 'type': 'mandatory'} + Package: kde-platform-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: kde-print-manager: {'basearchonly': False, 'type': 'mandatory'} + Package: kde-runtime: {'basearchonly': False, 'type': 'mandatory'} + Package: kde-settings-pulseaudio: {'basearchonly': False, 'type': 'mandatory'} + Package: kde-style-breeze: {'basearchonly': False, 'type': 'mandatory'} + Package: kdeaccessibility: {'basearchonly': False, 'type': 'mandatory'} + Package: kdegames-minimal: {'basearchonly': False, 'type': 'mandatory'} + Package: kdegraphics-thumbnailers: {'basearchonly': False, 'type': 'mandatory'} + Package: kdelibs: {'basearchonly': False, 'type': 'mandatory'} + Package: kdepasswd: {'basearchonly': False, 'type': 'mandatory'} + Package: kdeplasma-addons: {'basearchonly': False, 'type': 'mandatory'} + Package: kdialog: {'basearchonly': False, 'type': 'mandatory'} + Package: kdnssd: {'basearchonly': False, 'type': 'mandatory'} + Package: keditbookmarks: {'basearchonly': False, 'type': 'mandatory'} + Package: kf5-akonadi-server: {'basearchonly': False, 'type': 'mandatory'} + Package: kf5-akonadi-server-mysql: {'basearchonly': False, 'type': 'mandatory'} + Package: kf5-baloo-file: {'basearchonly': False, 'type': 'mandatory'} + Package: kf5-kipi-plugins: {'basearchonly': False, 'type': 'mandatory'} + Package: kfind: {'basearchonly': False, 'type': 'mandatory'} + Package: kget: {'basearchonly': False, 'type': 'mandatory'} + Package: kgpg: {'basearchonly': False, 'type': 'mandatory'} + Package: khelpcenter: {'basearchonly': False, 'type': 'mandatory'} + Package: khotkeys: {'basearchonly': False, 'type': 'mandatory'} + Package: kinfocenter: {'basearchonly': False, 'type': 'mandatory'} + Package: kmail: {'basearchonly': False, 'type': 'mandatory'} + Package: kmenuedit: {'basearchonly': False, 'type': 'mandatory'} + Package: knode: {'basearchonly': False, 'type': 'mandatory'} + Package: konqueror: {'basearchonly': False, 'type': 'mandatory'} + Package: konsole5: {'basearchonly': False, 'type': 'mandatory'} + Package: kontact: {'basearchonly': False, 'type': 'mandatory'} + Package: korganizer: {'basearchonly': False, 'type': 'mandatory'} + Package: kruler: {'basearchonly': False, 'type': 'mandatory'} + Package: kscreen: {'basearchonly': False, 'type': 'mandatory'} + Package: kscreenlocker: {'basearchonly': False, 'type': 'mandatory'} + Package: ksshaskpass: {'basearchonly': False, 'type': 'mandatory'} + Package: ksysguard: {'basearchonly': False, 'type': 'mandatory'} + Package: kuser: {'basearchonly': False, 'type': 'mandatory'} + Package: kwalletmanager: {'basearchonly': False, 'type': 'mandatory'} + Package: kwalletmanager5: {'basearchonly': False, 'type': 'mandatory'} + Package: kwebkitpart: {'basearchonly': False, 'type': 'mandatory'} + Package: kwin: {'basearchonly': False, 'type': 'mandatory'} + Package: kwrite: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-config-connectivity-fedora: {'basearchonly': False, 'type': 'mandatory'} + Package: pam-kwallet: {'basearchonly': False, 'type': 'mandatory'} + Package: phonon-backend-gstreamer: {'basearchonly': False, 'type': 'mandatory'} + Package: phonon-qt5-backend-gstreamer: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-breeze: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-desktop: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-desktop-doc: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-nm: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-nm-l2tp: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-nm-openconnect: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-nm-openswan: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-nm-openvpn: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-nm-pptp: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-nm-vpnc: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-pa: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-pk-updates: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-user-manager: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-workspace: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-workspace-drkonqi: {'basearchonly': False, 'type': 'mandatory'} + Package: plasma-workspace-geolocation: {'basearchonly': False, 'type': 'mandatory'} + Package: polkit-kde: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qdbusviewer: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtbase-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtdeclarative: {'basearchonly': False, 'type': 'mandatory'} + Package: sddm: {'basearchonly': False, 'type': 'mandatory'} + Package: sddm-breeze: {'basearchonly': False, 'type': 'mandatory'} + Package: sddm-kcm: {'basearchonly': False, 'type': 'mandatory'} + Package: sni-qt: {'basearchonly': False, 'type': 'mandatory'} + Package: spectacle: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-libinput: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-kde: {'basearchonly': False, 'requires': 'libreoffice-core', 'type': 'conditional'} + Package: pinentry-qt: {'basearchonly': False, 'requires': 'pinentry', 'type': 'conditional'} + Package: qt-at-spi: {'basearchonly': False, 'requires': 'at-spi2-core', 'type': 'conditional'} + Package: socat: {'basearchonly': False, 'requires': 'pam_kwallet', 'type': 'conditional'} Group: kde-education (KDE Educational applications) - Package: blinken: {'type': 'mandatory', 'basearchonly': False} - Package: cantor: {'type': 'mandatory', 'basearchonly': False} - Package: kalgebra: {'type': 'mandatory', 'basearchonly': False} - Package: kalzium: {'type': 'mandatory', 'basearchonly': False} - Package: kanagram: {'type': 'mandatory', 'basearchonly': False} - Package: kbruch: {'type': 'mandatory', 'basearchonly': False} - Package: kgeography: {'type': 'mandatory', 'basearchonly': False} - Package: khangman: {'type': 'mandatory', 'basearchonly': False} - Package: kig: {'type': 'mandatory', 'basearchonly': False} - Package: kiten: {'type': 'mandatory', 'basearchonly': False} - Package: klettres: {'type': 'mandatory', 'basearchonly': False} - Package: kmplot: {'type': 'mandatory', 'basearchonly': False} - Package: kstars: {'type': 'mandatory', 'basearchonly': False} - Package: ktouch: {'type': 'mandatory', 'basearchonly': False} - Package: kturtle: {'type': 'mandatory', 'basearchonly': False} - Package: kwordquiz: {'type': 'mandatory', 'basearchonly': False} - Package: marble: {'type': 'mandatory', 'basearchonly': False} - Package: parley: {'type': 'mandatory', 'basearchonly': False} - Package: rocs: {'type': 'mandatory', 'basearchonly': False} - Package: step: {'type': 'mandatory', 'basearchonly': False} + Package: blinken: {'basearchonly': False, 'type': 'mandatory'} + Package: cantor: {'basearchonly': False, 'type': 'mandatory'} + Package: kalgebra: {'basearchonly': False, 'type': 'mandatory'} + Package: kalzium: {'basearchonly': False, 'type': 'mandatory'} + Package: kanagram: {'basearchonly': False, 'type': 'mandatory'} + Package: kbruch: {'basearchonly': False, 'type': 'mandatory'} + Package: kgeography: {'basearchonly': False, 'type': 'mandatory'} + Package: khangman: {'basearchonly': False, 'type': 'mandatory'} + Package: kig: {'basearchonly': False, 'type': 'mandatory'} + Package: kiten: {'basearchonly': False, 'type': 'mandatory'} + Package: klettres: {'basearchonly': False, 'type': 'mandatory'} + Package: kmplot: {'basearchonly': False, 'type': 'mandatory'} + Package: kstars: {'basearchonly': False, 'type': 'mandatory'} + Package: ktouch: {'basearchonly': False, 'type': 'mandatory'} + Package: kturtle: {'basearchonly': False, 'type': 'mandatory'} + Package: kwordquiz: {'basearchonly': False, 'type': 'mandatory'} + Package: marble: {'basearchonly': False, 'type': 'mandatory'} + Package: parley: {'basearchonly': False, 'type': 'mandatory'} + Package: rocs: {'basearchonly': False, 'type': 'mandatory'} + Package: step: {'basearchonly': False, 'type': 'mandatory'} Group: kde-media (KDE Multimedia support) - Package: amarok: {'type': 'mandatory', 'basearchonly': False} - Package: dragon: {'type': 'mandatory', 'basearchonly': False} - Package: k3b: {'type': 'mandatory', 'basearchonly': False} - Package: kamoso: {'type': 'mandatory', 'basearchonly': False} + Package: amarok: {'basearchonly': False, 'type': 'mandatory'} + Package: dragon: {'basearchonly': False, 'type': 'mandatory'} + Package: k3b: {'basearchonly': False, 'type': 'mandatory'} + Package: kamoso: {'basearchonly': False, 'type': 'mandatory'} Group: kde-office (KDE Office) - Package: calligra-sheets: {'type': 'mandatory', 'basearchonly': False} - Package: calligra-stage: {'type': 'mandatory', 'basearchonly': False} - Package: calligra-words: {'type': 'mandatory', 'basearchonly': False} - Package: okular: {'type': 'mandatory', 'basearchonly': False} + Package: calligra-sheets: {'basearchonly': False, 'type': 'mandatory'} + Package: calligra-stage: {'basearchonly': False, 'type': 'mandatory'} + Package: calligra-words: {'basearchonly': False, 'type': 'mandatory'} + Package: okular: {'basearchonly': False, 'type': 'mandatory'} Group: kde-software-development (KDE Software Development) - Package: cmake: {'type': 'mandatory', 'basearchonly': False} - Package: kdelibs-devel: {'type': 'mandatory', 'basearchonly': False} - Package: qt-devel: {'type': 'mandatory', 'basearchonly': False} - Package: kate: {'type': 'default', 'basearchonly': False} - Package: kdelibs-webkit-devel: {'type': 'default', 'basearchonly': False} - Package: kdepimlibs-devel: {'type': 'default', 'basearchonly': False} - Package: kdesdk-cervisia: {'type': 'default', 'basearchonly': False} - Package: kdesdk-dolphin-plugins: {'type': 'default', 'basearchonly': False} - Package: kdesdk-kapptemplate: {'type': 'default', 'basearchonly': False} - Package: kdesdk-kcachegrind: {'type': 'default', 'basearchonly': False} - Package: kdesdk-kioslave: {'type': 'default', 'basearchonly': False} - Package: kdesdk-kmtrace: {'type': 'default', 'basearchonly': False} - Package: kdesdk-kompare: {'type': 'default', 'basearchonly': False} - Package: kdesdk-kpartloader: {'type': 'default', 'basearchonly': False} - Package: kdesdk-kstartperf: {'type': 'default', 'basearchonly': False} - Package: kdesdk-kuiviewer: {'type': 'default', 'basearchonly': False} - Package: kdesdk-okteta: {'type': 'default', 'basearchonly': False} - Package: kdesdk-poxml: {'type': 'default', 'basearchonly': False} - Package: kdesdk-scripts: {'type': 'default', 'basearchonly': False} - Package: kdesdk-thumbnailers: {'type': 'default', 'basearchonly': False} - Package: kdesdk-umbrello: {'type': 'default', 'basearchonly': False} - Package: kdevelop: {'type': 'default', 'basearchonly': False} - Package: pykde4-devel: {'type': 'default', 'basearchonly': False} - Package: PyQt4-devel: {'type': 'default', 'basearchonly': False} - Package: audiocd-kio-devel: {'type': 'optional', 'basearchonly': False} - Package: cantor-devel: {'type': 'optional', 'basearchonly': False} - Package: gambas3-runtime: {'type': 'optional', 'basearchonly': False} - Package: kate-devel: {'type': 'optional', 'basearchonly': False} - Package: kdbg: {'type': 'optional', 'basearchonly': False} - Package: kde-baseapps-devel: {'type': 'optional', 'basearchonly': False} - Package: kdebindings-devel: {'type': 'optional', 'basearchonly': False} - Package: kdegraphics-devel: {'type': 'optional', 'basearchonly': False} - Package: kdelibs3-devel: {'type': 'optional', 'basearchonly': False} - Package: kdenetwork-devel: {'type': 'optional', 'basearchonly': False} - Package: kdepim-devel: {'type': 'optional', 'basearchonly': False} - Package: kdesvn: {'type': 'optional', 'basearchonly': False} - Package: kdewebdev-devel: {'type': 'optional', 'basearchonly': False} - Package: kiten-devel: {'type': 'optional', 'basearchonly': False} - Package: krazy2: {'type': 'optional', 'basearchonly': False} - Package: ktp-common-internals-devel: {'type': 'optional', 'basearchonly': False} - Package: libkcddb-devel: {'type': 'optional', 'basearchonly': False} - Package: libkcompactdisc-devel: {'type': 'optional', 'basearchonly': False} - Package: libkdeedu-devel: {'type': 'optional', 'basearchonly': False} - Package: libkdegames-devel: {'type': 'optional', 'basearchonly': False} - Package: marble-devel: {'type': 'optional', 'basearchonly': False} - Package: PyKDE-devel: {'type': 'optional', 'basearchonly': False} - Package: PyQt-devel: {'type': 'optional', 'basearchonly': False} - Package: qt-creator: {'type': 'optional', 'basearchonly': False} - Package: qt-mobility-devel: {'type': 'optional', 'basearchonly': False} - Package: qt3-designer: {'type': 'optional', 'basearchonly': False} - Package: qt3-devel: {'type': 'optional', 'basearchonly': False} - Package: qtwebkit-devel: {'type': 'optional', 'basearchonly': False} - Package: rocs-devel: {'type': 'optional', 'basearchonly': False} - Package: telepathy-qt4-devel: {'type': 'optional', 'basearchonly': False} + Package: cmake: {'basearchonly': False, 'type': 'mandatory'} + Package: kdelibs-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: qt-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: kate: {'basearchonly': False, 'type': 'default'} + Package: kdelibs-webkit-devel: {'basearchonly': False, 'type': 'default'} + Package: kdepimlibs-devel: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-cervisia: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-dolphin-plugins: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-kapptemplate: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-kcachegrind: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-kioslave: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-kmtrace: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-kompare: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-kpartloader: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-kstartperf: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-kuiviewer: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-okteta: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-poxml: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-scripts: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-thumbnailers: {'basearchonly': False, 'type': 'default'} + Package: kdesdk-umbrello: {'basearchonly': False, 'type': 'default'} + Package: kdevelop: {'basearchonly': False, 'type': 'default'} + Package: pykde4-devel: {'basearchonly': False, 'type': 'default'} + Package: PyQt4-devel: {'basearchonly': False, 'type': 'default'} + Package: audiocd-kio-devel: {'basearchonly': False, 'type': 'optional'} + Package: cantor-devel: {'basearchonly': False, 'type': 'optional'} + Package: gambas3-runtime: {'basearchonly': False, 'type': 'optional'} + Package: kate-devel: {'basearchonly': False, 'type': 'optional'} + Package: kdbg: {'basearchonly': False, 'type': 'optional'} + Package: kde-baseapps-devel: {'basearchonly': False, 'type': 'optional'} + Package: kdebindings-devel: {'basearchonly': False, 'type': 'optional'} + Package: kdegraphics-devel: {'basearchonly': False, 'type': 'optional'} + Package: kdelibs3-devel: {'basearchonly': False, 'type': 'optional'} + Package: kdenetwork-devel: {'basearchonly': False, 'type': 'optional'} + Package: kdepim-devel: {'basearchonly': False, 'type': 'optional'} + Package: kdesvn: {'basearchonly': False, 'type': 'optional'} + Package: kdewebdev-devel: {'basearchonly': False, 'type': 'optional'} + Package: kiten-devel: {'basearchonly': False, 'type': 'optional'} + Package: krazy2: {'basearchonly': False, 'type': 'optional'} + Package: ktp-common-internals-devel: {'basearchonly': False, 'type': 'optional'} + Package: libkcddb-devel: {'basearchonly': False, 'type': 'optional'} + Package: libkcompactdisc-devel: {'basearchonly': False, 'type': 'optional'} + Package: libkdeedu-devel: {'basearchonly': False, 'type': 'optional'} + Package: libkdegames-devel: {'basearchonly': False, 'type': 'optional'} + Package: marble-devel: {'basearchonly': False, 'type': 'optional'} + Package: PyKDE-devel: {'basearchonly': False, 'type': 'optional'} + Package: PyQt-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt-creator: {'basearchonly': False, 'type': 'optional'} + Package: qt-mobility-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt3-designer: {'basearchonly': False, 'type': 'optional'} + Package: qt3-devel: {'basearchonly': False, 'type': 'optional'} + Package: qtwebkit-devel: {'basearchonly': False, 'type': 'optional'} + Package: rocs-devel: {'basearchonly': False, 'type': 'optional'} + Package: telepathy-qt4-devel: {'basearchonly': False, 'type': 'optional'} Group: kde-telepathy (KDE Telepathy) - Package: kaccounts-integration: {'type': 'mandatory', 'basearchonly': False} - Package: kaccounts-providers: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-accounts-kcm: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-approver: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-auth-handler: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-contact-list: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-contact-runner: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-desktop-applets: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-filetransfer-handler: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-kded-integration-module: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-send-file: {'type': 'mandatory', 'basearchonly': False} - Package: ktp-text-ui: {'type': 'mandatory', 'basearchonly': False} - Package: signon-kwallet-extension: {'type': 'mandatory', 'basearchonly': False} + Package: kaccounts-integration: {'basearchonly': False, 'type': 'mandatory'} + Package: kaccounts-providers: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-accounts-kcm: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-approver: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-auth-handler: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-contact-list: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-contact-runner: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-desktop-applets: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-filetransfer-handler: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-kded-integration-module: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-send-file: {'basearchonly': False, 'type': 'mandatory'} + Package: ktp-text-ui: {'basearchonly': False, 'type': 'mandatory'} + Package: signon-kwallet-extension: {'basearchonly': False, 'type': 'mandatory'} Group: kf5-software-development (KDE Frameworks 5 Software Development) - Package: cmake: {'type': 'mandatory', 'basearchonly': False} - Package: extra-cmake-modules: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtdeclarative-devel: {'type': 'default', 'basearchonly': False} - Package: qt5-qtquickcontrols: {'type': 'default', 'basearchonly': False} - Package: qt5-qttools-devel: {'type': 'default', 'basearchonly': False} - Package: qt5-qtwebkit-devel: {'type': 'default', 'basearchonly': False} - Package: qt-creator: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtconnectivity-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtimageformats-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtlocation-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtmultimedia-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtquick1-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtscript-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtsensors-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtserialport-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtsvg-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtwayland-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtx11extras-devel: {'type': 'optional', 'basearchonly': False} - Package: qt5-qtxmlpatterns-devel: {'type': 'optional', 'basearchonly': False} + Package: cmake: {'basearchonly': False, 'type': 'mandatory'} + Package: extra-cmake-modules: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtdeclarative-devel: {'basearchonly': False, 'type': 'default'} + Package: qt5-qtquickcontrols: {'basearchonly': False, 'type': 'default'} + Package: qt5-qttools-devel: {'basearchonly': False, 'type': 'default'} + Package: qt5-qtwebkit-devel: {'basearchonly': False, 'type': 'default'} + Package: qt-creator: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtconnectivity-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtimageformats-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtlocation-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtmultimedia-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtquick1-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtscript-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtsensors-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtserialport-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtsvg-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtwayland-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtx11extras-devel: {'basearchonly': False, 'type': 'optional'} + Package: qt5-qtxmlpatterns-devel: {'basearchonly': False, 'type': 'optional'} Group: khmer-support (Khmer Support) - Package: khmeros-base-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: google-noto-sans-khmer-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-khmer-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: khmeros-battambang-fonts: {'type': 'default', 'basearchonly': False} - Package: khmeros-bokor-fonts: {'type': 'default', 'basearchonly': False} - Package: khmeros-handwritten-fonts: {'type': 'default', 'basearchonly': False} - Package: khmeros-metal-chrieng-fonts: {'type': 'default', 'basearchonly': False} - Package: khmeros-muol-fonts: {'type': 'default', 'basearchonly': False} - Package: khmeros-siemreap-fonts: {'type': 'default', 'basearchonly': False} + Package: khmeros-base-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: google-noto-sans-khmer-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-khmer-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: khmeros-battambang-fonts: {'basearchonly': False, 'type': 'default'} + Package: khmeros-bokor-fonts: {'basearchonly': False, 'type': 'default'} + Package: khmeros-handwritten-fonts: {'basearchonly': False, 'type': 'default'} + Package: khmeros-metal-chrieng-fonts: {'basearchonly': False, 'type': 'default'} + Package: khmeros-muol-fonts: {'basearchonly': False, 'type': 'default'} + Package: khmeros-siemreap-fonts: {'basearchonly': False, 'type': 'default'} Group: konkani-support (Konkani Support) - Package: lohit-devanagari-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} Group: korean-support (Korean Support) - Package: ibus-hangul: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: naver-nanum-barun-gothic-fonts: {'type': 'default', 'basearchonly': False} - Package: naver-nanum-brush-fonts: {'type': 'default', 'basearchonly': False} - Package: naver-nanum-gothic-fonts: {'type': 'default', 'basearchonly': False} - Package: naver-nanum-myeongjo-fonts: {'type': 'default', 'basearchonly': False} - Package: naver-nanum-pen-fonts: {'type': 'default', 'basearchonly': False} - Package: baekmuk-bdf-fonts: {'type': 'optional', 'basearchonly': False} - Package: baekmuk-ttf-batang-fonts: {'type': 'optional', 'basearchonly': False} - Package: baekmuk-ttf-dotum-fonts: {'type': 'optional', 'basearchonly': False} - Package: baekmuk-ttf-gulim-fonts: {'type': 'optional', 'basearchonly': False} - Package: baekmuk-ttf-hline-fonts: {'type': 'optional', 'basearchonly': False} - Package: lv: {'type': 'optional', 'basearchonly': False} - Package: nhn-nanum-gothic-coding-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-batang-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-dinaru-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-dotum-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-graphic-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-gungseo-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-core-pilgi-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-bom-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-jamobatang-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-jamodotum-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-jamonovel-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-jamosora-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-pen-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-penheulim-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-pilgia-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-shinmun-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-taza-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-vada-fonts: {'type': 'optional', 'basearchonly': False} - Package: un-extra-yetgul-fonts: {'type': 'optional', 'basearchonly': False} + Package: ibus-hangul: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: naver-nanum-barun-gothic-fonts: {'basearchonly': False, 'type': 'default'} + Package: naver-nanum-brush-fonts: {'basearchonly': False, 'type': 'default'} + Package: naver-nanum-gothic-fonts: {'basearchonly': False, 'type': 'default'} + Package: naver-nanum-myeongjo-fonts: {'basearchonly': False, 'type': 'default'} + Package: naver-nanum-pen-fonts: {'basearchonly': False, 'type': 'default'} + Package: baekmuk-bdf-fonts: {'basearchonly': False, 'type': 'optional'} + Package: baekmuk-ttf-batang-fonts: {'basearchonly': False, 'type': 'optional'} + Package: baekmuk-ttf-dotum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: baekmuk-ttf-gulim-fonts: {'basearchonly': False, 'type': 'optional'} + Package: baekmuk-ttf-hline-fonts: {'basearchonly': False, 'type': 'optional'} + Package: lv: {'basearchonly': False, 'type': 'optional'} + Package: nhn-nanum-gothic-coding-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-batang-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-dinaru-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-dotum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-graphic-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-gungseo-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-core-pilgi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-bom-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-jamobatang-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-jamodotum-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-jamonovel-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-jamosora-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-pen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-penheulim-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-pilgia-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-shinmun-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-taza-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-vada-fonts: {'basearchonly': False, 'type': 'optional'} + Package: un-extra-yetgul-fonts: {'basearchonly': False, 'type': 'optional'} Group: kurdish-support (Kurdish Support) - Package: kurdit-unikurd-web-fonts: {'type': 'default', 'basearchonly': False} + Package: kurdit-unikurd-web-fonts: {'basearchonly': False, 'type': 'default'} Group: legacy-fonts (Legacy Fonts) - Package: xorg-x11-fonts-100dpi: {'type': 'default', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-15-100dpi: {'type': 'default', 'basearchonly': False} - Package: xorg-x11-fonts-misc: {'type': 'default', 'basearchonly': False} - Package: xorg-x11-fonts-Type1: {'type': 'default', 'basearchonly': False} - Package: artwiz-aleczapka-anorexia-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-aqui-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-cure-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-drift-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-edges-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-fkp-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-gelly-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-glisp-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-kates-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-lime-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-mints-mild-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-mints-strong-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-nu-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-smoothansi-fonts: {'type': 'optional', 'basearchonly': False} - Package: artwiz-aleczapka-snap-fonts: {'type': 'optional', 'basearchonly': False} - Package: baekmuk-bdf-fonts: {'type': 'optional', 'basearchonly': False} - Package: bitmap-console-fonts: {'type': 'optional', 'basearchonly': False} - Package: bitmap-fangsongti-fonts: {'type': 'optional', 'basearchonly': False} - Package: bitmap-fixed-fonts: {'type': 'optional', 'basearchonly': False} - Package: bitmap-lucida-typewriter-fonts: {'type': 'optional', 'basearchonly': False} - Package: ctan-musixtex-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-aharoni-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-caladings-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-david-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-drugulin-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-ellinia-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-frank-ruehl-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-hadasim-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-keteryg-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-miriam-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-miriam-mono-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-nachlieli-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-simple-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-stamashkenaz-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-stamsefarad-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: culmus-yehuda-clm-fonts: {'type': 'optional', 'basearchonly': False} - Package: efont-unicode-bdf: {'type': 'optional', 'basearchonly': False} - Package: fonts-KOI8-R: {'type': 'optional', 'basearchonly': False} - Package: fonts-KOI8-R-100dpi: {'type': 'optional', 'basearchonly': False} - Package: fonts-KOI8-R-75dpi: {'type': 'optional', 'basearchonly': False} - Package: ghostscript-fonts: {'type': 'optional', 'basearchonly': False} - Package: google-android-emoji-fonts: {'type': 'optional', 'basearchonly': False} - Package: iso8859-2-100dpi-fonts: {'type': 'optional', 'basearchonly': False} - Package: iso8859-2-75dpi-fonts: {'type': 'optional', 'basearchonly': False} - Package: iso8859-2-misc-fonts: {'type': 'optional', 'basearchonly': False} - Package: japanese-bitmap-fonts: {'type': 'optional', 'basearchonly': False} - Package: jisksp16-1990-fonts: {'type': 'optional', 'basearchonly': False} - Package: knm-new-fixed-fonts: {'type': 'optional', 'basearchonly': False} - Package: libdockapp-fonts: {'type': 'optional', 'basearchonly': False} - Package: lyx-fonts: {'type': 'optional', 'basearchonly': False} - Package: mona-bitmap-fonts: {'type': 'optional', 'basearchonly': False} - Package: nethack-bitmap-fonts: {'type': 'optional', 'basearchonly': False} - Package: oflb-dignas-handwriting-fonts: {'type': 'optional', 'basearchonly': False} - Package: rosegarden4-feta-fonts: {'type': 'optional', 'basearchonly': False} - Package: rosegarden4-parmesan-fonts: {'type': 'optional', 'basearchonly': False} - Package: taipeifonts: {'type': 'optional', 'basearchonly': False} - Package: terminus-fonts: {'type': 'optional', 'basearchonly': False} - Package: terminus-fonts-console: {'type': 'optional', 'basearchonly': False} - Package: texmacs-fedora-fonts: {'type': 'optional', 'basearchonly': False} - Package: ucs-miscfixed-fonts: {'type': 'optional', 'basearchonly': False} - Package: urw-fonts: {'type': 'optional', 'basearchonly': False} - Package: wqy-bitmap-fonts: {'type': 'optional', 'basearchonly': False} - Package: wqy-unibit-fonts: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-75dpi: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-cyrillic: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ethiopic: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-1-100dpi: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-1-75dpi: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-14-100dpi: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-14-75dpi: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-15-75dpi: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-2-100dpi: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-2-75dpi: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-9-100dpi: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-ISO8859-9-75dpi: {'type': 'optional', 'basearchonly': False} - Package: zvbi-fonts: {'type': 'optional', 'basearchonly': False} + Package: xorg-x11-fonts-100dpi: {'basearchonly': False, 'type': 'default'} + Package: xorg-x11-fonts-ISO8859-15-100dpi: {'basearchonly': False, 'type': 'default'} + Package: xorg-x11-fonts-misc: {'basearchonly': False, 'type': 'default'} + Package: xorg-x11-fonts-Type1: {'basearchonly': False, 'type': 'default'} + Package: artwiz-aleczapka-anorexia-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-aqui-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-cure-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-drift-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-edges-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-fkp-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-gelly-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-glisp-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-kates-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-lime-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-mints-mild-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-mints-strong-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-nu-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-smoothansi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: artwiz-aleczapka-snap-fonts: {'basearchonly': False, 'type': 'optional'} + Package: baekmuk-bdf-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bitmap-console-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bitmap-fangsongti-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bitmap-fixed-fonts: {'basearchonly': False, 'type': 'optional'} + Package: bitmap-lucida-typewriter-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ctan-musixtex-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-aharoni-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-caladings-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-david-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-drugulin-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-ellinia-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-frank-ruehl-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-hadasim-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-keteryg-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-miriam-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-miriam-mono-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-nachlieli-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-simple-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-stamashkenaz-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-stamsefarad-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: culmus-yehuda-clm-fonts: {'basearchonly': False, 'type': 'optional'} + Package: efont-unicode-bdf: {'basearchonly': False, 'type': 'optional'} + Package: fonts-KOI8-R: {'basearchonly': False, 'type': 'optional'} + Package: fonts-KOI8-R-100dpi: {'basearchonly': False, 'type': 'optional'} + Package: fonts-KOI8-R-75dpi: {'basearchonly': False, 'type': 'optional'} + Package: ghostscript-fonts: {'basearchonly': False, 'type': 'optional'} + Package: google-android-emoji-fonts: {'basearchonly': False, 'type': 'optional'} + Package: iso8859-2-100dpi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: iso8859-2-75dpi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: iso8859-2-misc-fonts: {'basearchonly': False, 'type': 'optional'} + Package: japanese-bitmap-fonts: {'basearchonly': False, 'type': 'optional'} + Package: jisksp16-1990-fonts: {'basearchonly': False, 'type': 'optional'} + Package: knm-new-fixed-fonts: {'basearchonly': False, 'type': 'optional'} + Package: libdockapp-fonts: {'basearchonly': False, 'type': 'optional'} + Package: lyx-fonts: {'basearchonly': False, 'type': 'optional'} + Package: mona-bitmap-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nethack-bitmap-fonts: {'basearchonly': False, 'type': 'optional'} + Package: oflb-dignas-handwriting-fonts: {'basearchonly': False, 'type': 'optional'} + Package: rosegarden4-feta-fonts: {'basearchonly': False, 'type': 'optional'} + Package: rosegarden4-parmesan-fonts: {'basearchonly': False, 'type': 'optional'} + Package: taipeifonts: {'basearchonly': False, 'type': 'optional'} + Package: terminus-fonts: {'basearchonly': False, 'type': 'optional'} + Package: terminus-fonts-console: {'basearchonly': False, 'type': 'optional'} + Package: texmacs-fedora-fonts: {'basearchonly': False, 'type': 'optional'} + Package: ucs-miscfixed-fonts: {'basearchonly': False, 'type': 'optional'} + Package: urw-fonts: {'basearchonly': False, 'type': 'optional'} + Package: wqy-bitmap-fonts: {'basearchonly': False, 'type': 'optional'} + Package: wqy-unibit-fonts: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-75dpi: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-cyrillic: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ethiopic: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ISO8859-1-100dpi: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ISO8859-1-75dpi: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ISO8859-14-100dpi: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ISO8859-14-75dpi: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ISO8859-15-75dpi: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ISO8859-2-100dpi: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ISO8859-2-75dpi: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ISO8859-9-100dpi: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-ISO8859-9-75dpi: {'basearchonly': False, 'type': 'optional'} + Package: zvbi-fonts: {'basearchonly': False, 'type': 'optional'} Group: legacy-network-server (Legacy Network Server) - Package: bootparamd: {'type': 'optional', 'basearchonly': False} - Package: rarpd: {'type': 'optional', 'basearchonly': False} - Package: rsh-server: {'type': 'optional', 'basearchonly': False} - Package: rusers: {'type': 'optional', 'basearchonly': False} - Package: rusers-server: {'type': 'optional', 'basearchonly': False} - Package: rwho: {'type': 'optional', 'basearchonly': False} - Package: talk-server: {'type': 'optional', 'basearchonly': False} - Package: telnet-server: {'type': 'optional', 'basearchonly': False} - Package: tftp-server: {'type': 'optional', 'basearchonly': False} + Package: bootparamd: {'basearchonly': False, 'type': 'optional'} + Package: rarpd: {'basearchonly': False, 'type': 'optional'} + Package: rsh-server: {'basearchonly': False, 'type': 'optional'} + Package: rusers: {'basearchonly': False, 'type': 'optional'} + Package: rusers-server: {'basearchonly': False, 'type': 'optional'} + Package: rwho: {'basearchonly': False, 'type': 'optional'} + Package: talk-server: {'basearchonly': False, 'type': 'optional'} + Package: telnet-server: {'basearchonly': False, 'type': 'optional'} + Package: tftp-server: {'basearchonly': False, 'type': 'optional'} Group: legacy-software-development (Legacy Software Development) - Package: compat-gcc-34: {'type': 'default', 'basearchonly': True} - Package: compat-gcc-34-c++: {'type': 'default', 'basearchonly': True} - Package: compat-gcc-34-g77: {'type': 'default', 'basearchonly': True} - Package: compat-libstdc++-296: {'type': 'default', 'basearchonly': True} - Package: compat-libstdc++-33: {'type': 'default', 'basearchonly': True} + Package: compat-gcc-34: {'basearchonly': True, 'type': 'default'} + Package: compat-gcc-34-c++: {'basearchonly': True, 'type': 'default'} + Package: compat-gcc-34-g77: {'basearchonly': True, 'type': 'default'} + Package: compat-libstdc++-296: {'basearchonly': True, 'type': 'default'} + Package: compat-libstdc++-33: {'basearchonly': True, 'type': 'default'} Group: legacy-software-support (Legacy Software Support) - Package: compat-libstdc++-296: {'type': 'default', 'basearchonly': False} - Package: compat-libstdc++-33: {'type': 'default', 'basearchonly': False} + Package: compat-libstdc++-296: {'basearchonly': False, 'type': 'default'} + Package: compat-libstdc++-33: {'basearchonly': False, 'type': 'default'} Group: lepcha-support (Lepcha Support) - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: sil-mingzat-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: sil-mingzat-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: iok: {'basearchonly': False, 'type': 'default'} Group: libreoffice (LibreOffice) - Package: libreoffice-calc: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-draw: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-emailmerge: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-graphicfilter: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-impress: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-math: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-writer: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-base: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-pyuno: {'type': 'optional', 'basearchonly': False} + Package: libreoffice-calc: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-draw: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-emailmerge: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-graphicfilter: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-impress: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-math: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-writer: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-base: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-pyuno: {'basearchonly': False, 'type': 'optional'} Group: libreoffice-development (LibreOffice Development) - Package: libreoffice-sdk: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-sdk-doc: {'type': 'optional', 'basearchonly': False} + Package: libreoffice-sdk: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-sdk-doc: {'basearchonly': False, 'type': 'optional'} Group: livecd-tools (LiveCD Tools) - Package: dracut-config-generic: {'type': 'mandatory', 'basearchonly': False} - Package: dracut-live: {'type': 'mandatory', 'basearchonly': False} - Package: grub2-efi: {'type': 'mandatory', 'basearchonly': False} - Package: kernel: {'type': 'mandatory', 'basearchonly': False} - Package: kernel-modules: {'type': 'mandatory', 'basearchonly': False} - Package: kernel-modules-extra: {'type': 'mandatory', 'basearchonly': False} - Package: syslinux: {'type': 'mandatory', 'basearchonly': False} + Package: dracut-config-generic: {'basearchonly': False, 'type': 'mandatory'} + Package: dracut-live: {'basearchonly': False, 'type': 'mandatory'} + Package: grub2-efi: {'basearchonly': False, 'type': 'mandatory'} + Package: kernel: {'basearchonly': False, 'type': 'mandatory'} + Package: kernel-modules: {'basearchonly': False, 'type': 'mandatory'} + Package: kernel-modules-extra: {'basearchonly': False, 'type': 'mandatory'} + Package: syslinux: {'basearchonly': False, 'type': 'mandatory'} Group: load-balancer (Load Balancer) - Package: ipvsadm: {'type': 'mandatory', 'basearchonly': False} - Package: keepalived: {'type': 'mandatory', 'basearchonly': False} + Package: ipvsadm: {'basearchonly': False, 'type': 'mandatory'} + Package: keepalived: {'basearchonly': False, 'type': 'mandatory'} Group: lxde-apps (Applications for the LXDE Desktop) - Package: midori: {'type': 'mandatory', 'basearchonly': False} - Package: pidgin: {'type': 'mandatory', 'basearchonly': False} - Package: sylpheed: {'type': 'mandatory', 'basearchonly': False} - Package: transmission: {'type': 'mandatory', 'basearchonly': False} + Package: midori: {'basearchonly': False, 'type': 'mandatory'} + Package: pidgin: {'basearchonly': False, 'type': 'mandatory'} + Package: sylpheed: {'basearchonly': False, 'type': 'mandatory'} + Package: transmission: {'basearchonly': False, 'type': 'mandatory'} Group: lxde-desktop (LXDE) - Package: adwaita-gtk2-theme: {'type': 'mandatory', 'basearchonly': False} - Package: adwaita-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: clipit: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: firewall-config: {'type': 'mandatory', 'basearchonly': False} - Package: galculator: {'type': 'mandatory', 'basearchonly': False} - Package: gigolo: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-keyring-pam: {'type': 'mandatory', 'basearchonly': False} - Package: gpicview: {'type': 'mandatory', 'basearchonly': False} - Package: initial-setup-gui: {'type': 'mandatory', 'basearchonly': False} - Package: leafpad: {'type': 'mandatory', 'basearchonly': False} - Package: lxappearance: {'type': 'mandatory', 'basearchonly': False} - Package: lxappearance-obconf: {'type': 'mandatory', 'basearchonly': False} - Package: lxde-common: {'type': 'mandatory', 'basearchonly': False} - Package: lxdm: {'type': 'mandatory', 'basearchonly': False} - Package: lxinput: {'type': 'mandatory', 'basearchonly': False} - Package: lxlauncher: {'type': 'mandatory', 'basearchonly': False} - Package: lxmenu-data: {'type': 'mandatory', 'basearchonly': False} - Package: lxpanel: {'type': 'mandatory', 'basearchonly': False} - Package: lxpolkit: {'type': 'mandatory', 'basearchonly': False} - Package: lxrandr: {'type': 'mandatory', 'basearchonly': False} - Package: lxsession: {'type': 'mandatory', 'basearchonly': False} - Package: lxsession-edit: {'type': 'mandatory', 'basearchonly': False} - Package: lxtask: {'type': 'mandatory', 'basearchonly': False} - Package: lxterminal: {'type': 'mandatory', 'basearchonly': False} - Package: network-manager-applet: {'type': 'mandatory', 'basearchonly': False} - Package: nm-connection-editor: {'type': 'mandatory', 'basearchonly': False} - Package: notification-daemon: {'type': 'mandatory', 'basearchonly': False} - Package: obconf: {'type': 'mandatory', 'basearchonly': False} - Package: openbox: {'type': 'mandatory', 'basearchonly': False} - Package: openssh-askpass: {'type': 'mandatory', 'basearchonly': False} - Package: pcmanfm: {'type': 'mandatory', 'basearchonly': False} - Package: perl-File-MimeInfo: {'type': 'mandatory', 'basearchonly': False} - Package: upower: {'type': 'mandatory', 'basearchonly': False} - Package: xarchiver: {'type': 'mandatory', 'basearchonly': False} - Package: xcompmgr: {'type': 'mandatory', 'basearchonly': False} - Package: xdg-user-dirs-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: xpad: {'type': 'mandatory', 'basearchonly': False} - Package: xscreensaver-base: {'type': 'mandatory', 'basearchonly': False} - Package: xscreensaver-extras: {'type': 'mandatory', 'basearchonly': False} - Package: yumex-dnf: {'type': 'mandatory', 'basearchonly': False} + Package: adwaita-gtk2-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: adwaita-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: clipit: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: firewall-config: {'basearchonly': False, 'type': 'mandatory'} + Package: galculator: {'basearchonly': False, 'type': 'mandatory'} + Package: gigolo: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-keyring-pam: {'basearchonly': False, 'type': 'mandatory'} + Package: gpicview: {'basearchonly': False, 'type': 'mandatory'} + Package: initial-setup-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: leafpad: {'basearchonly': False, 'type': 'mandatory'} + Package: lxappearance: {'basearchonly': False, 'type': 'mandatory'} + Package: lxappearance-obconf: {'basearchonly': False, 'type': 'mandatory'} + Package: lxde-common: {'basearchonly': False, 'type': 'mandatory'} + Package: lxdm: {'basearchonly': False, 'type': 'mandatory'} + Package: lxinput: {'basearchonly': False, 'type': 'mandatory'} + Package: lxlauncher: {'basearchonly': False, 'type': 'mandatory'} + Package: lxmenu-data: {'basearchonly': False, 'type': 'mandatory'} + Package: lxpanel: {'basearchonly': False, 'type': 'mandatory'} + Package: lxpolkit: {'basearchonly': False, 'type': 'mandatory'} + Package: lxrandr: {'basearchonly': False, 'type': 'mandatory'} + Package: lxsession: {'basearchonly': False, 'type': 'mandatory'} + Package: lxsession-edit: {'basearchonly': False, 'type': 'mandatory'} + Package: lxtask: {'basearchonly': False, 'type': 'mandatory'} + Package: lxterminal: {'basearchonly': False, 'type': 'mandatory'} + Package: network-manager-applet: {'basearchonly': False, 'type': 'mandatory'} + Package: nm-connection-editor: {'basearchonly': False, 'type': 'mandatory'} + Package: notification-daemon: {'basearchonly': False, 'type': 'mandatory'} + Package: obconf: {'basearchonly': False, 'type': 'mandatory'} + Package: openbox: {'basearchonly': False, 'type': 'mandatory'} + Package: openssh-askpass: {'basearchonly': False, 'type': 'mandatory'} + Package: pcmanfm: {'basearchonly': False, 'type': 'mandatory'} + Package: perl-File-MimeInfo: {'basearchonly': False, 'type': 'mandatory'} + Package: upower: {'basearchonly': False, 'type': 'mandatory'} + Package: xarchiver: {'basearchonly': False, 'type': 'mandatory'} + Package: xcompmgr: {'basearchonly': False, 'type': 'mandatory'} + Package: xdg-user-dirs-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: xpad: {'basearchonly': False, 'type': 'mandatory'} + Package: xscreensaver-base: {'basearchonly': False, 'type': 'mandatory'} + Package: xscreensaver-extras: {'basearchonly': False, 'type': 'mandatory'} + Package: yumex-dnf: {'basearchonly': False, 'type': 'mandatory'} Group: lxde-media (Multimedia support for LXDE) - Package: asunder: {'type': 'mandatory', 'basearchonly': False} - Package: gnomebaker: {'type': 'mandatory', 'basearchonly': False} - Package: lxmusic: {'type': 'mandatory', 'basearchonly': False} - Package: pavucontrol: {'type': 'mandatory', 'basearchonly': False} - Package: pnmixer: {'type': 'mandatory', 'basearchonly': False} + Package: asunder: {'basearchonly': False, 'type': 'mandatory'} + Package: gnomebaker: {'basearchonly': False, 'type': 'mandatory'} + Package: lxmusic: {'basearchonly': False, 'type': 'mandatory'} + Package: pavucontrol: {'basearchonly': False, 'type': 'mandatory'} + Package: pnmixer: {'basearchonly': False, 'type': 'mandatory'} Group: lxde-office (LXDE Office) - Package: abiword: {'type': 'mandatory', 'basearchonly': False} - Package: gnumeric: {'type': 'mandatory', 'basearchonly': False} - Package: osmo: {'type': 'mandatory', 'basearchonly': False} + Package: abiword: {'basearchonly': False, 'type': 'mandatory'} + Package: gnumeric: {'basearchonly': False, 'type': 'mandatory'} + Package: osmo: {'basearchonly': False, 'type': 'mandatory'} Group: lxqt-apps (Applications for the LXQt Desktop) - Package: transmission-qt: {'type': 'mandatory', 'basearchonly': False} + Package: transmission-qt: {'basearchonly': False, 'type': 'mandatory'} Group: lxqt-desktop (LXQt) - Package: ark: {'type': 'mandatory', 'basearchonly': False} - Package: breeze-cursor-theme: {'type': 'mandatory', 'basearchonly': False} - Package: breeze-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: breeze-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: firewall-config: {'type': 'mandatory', 'basearchonly': False} - Package: initial-setup-gui: {'type': 'mandatory', 'basearchonly': False} - Package: kwin: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-about: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-common: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-config: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-globalkeys: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-notificationd: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-openssh-askpass: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-panel: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-policykit: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-powermanagement: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-qtplugin: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-runner: {'type': 'mandatory', 'basearchonly': False} - Package: lxqt-session: {'type': 'mandatory', 'basearchonly': False} - Package: network-manager-applet: {'type': 'mandatory', 'basearchonly': False} - Package: nm-connection-editor: {'type': 'mandatory', 'basearchonly': False} - Package: notification-daemon: {'type': 'mandatory', 'basearchonly': False} - Package: obconf: {'type': 'mandatory', 'basearchonly': False} - Package: openbox: {'type': 'mandatory', 'basearchonly': False} - Package: pcmanfm-qt: {'type': 'mandatory', 'basearchonly': False} - Package: perl-File-MimeInfo: {'type': 'mandatory', 'basearchonly': False} - Package: qterminal-qt5: {'type': 'mandatory', 'basearchonly': False} - Package: qupzilla: {'type': 'mandatory', 'basearchonly': False} - Package: qupzilla-kwallet: {'type': 'mandatory', 'basearchonly': False} - Package: sddm: {'type': 'mandatory', 'basearchonly': False} - Package: sddm-breeze: {'type': 'mandatory', 'basearchonly': False} - Package: upower: {'type': 'mandatory', 'basearchonly': False} - Package: xdg-user-dirs: {'type': 'mandatory', 'basearchonly': False} + Package: ark: {'basearchonly': False, 'type': 'mandatory'} + Package: breeze-cursor-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: breeze-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: breeze-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: firewall-config: {'basearchonly': False, 'type': 'mandatory'} + Package: initial-setup-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: kwin: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-about: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-common: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-config: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-globalkeys: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-notificationd: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-openssh-askpass: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-panel: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-policykit: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-powermanagement: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-qtplugin: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-runner: {'basearchonly': False, 'type': 'mandatory'} + Package: lxqt-session: {'basearchonly': False, 'type': 'mandatory'} + Package: network-manager-applet: {'basearchonly': False, 'type': 'mandatory'} + Package: nm-connection-editor: {'basearchonly': False, 'type': 'mandatory'} + Package: notification-daemon: {'basearchonly': False, 'type': 'mandatory'} + Package: obconf: {'basearchonly': False, 'type': 'mandatory'} + Package: openbox: {'basearchonly': False, 'type': 'mandatory'} + Package: pcmanfm-qt: {'basearchonly': False, 'type': 'mandatory'} + Package: perl-File-MimeInfo: {'basearchonly': False, 'type': 'mandatory'} + Package: qterminal-qt5: {'basearchonly': False, 'type': 'mandatory'} + Package: qupzilla: {'basearchonly': False, 'type': 'mandatory'} + Package: qupzilla-kwallet: {'basearchonly': False, 'type': 'mandatory'} + Package: sddm: {'basearchonly': False, 'type': 'mandatory'} + Package: sddm-breeze: {'basearchonly': False, 'type': 'mandatory'} + Package: upower: {'basearchonly': False, 'type': 'mandatory'} + Package: xdg-user-dirs: {'basearchonly': False, 'type': 'mandatory'} Group: lxqt-media (Multimedia support for LXQt) - Package: pavucontrol: {'type': 'mandatory', 'basearchonly': False} - Package: pnmixer: {'type': 'mandatory', 'basearchonly': False} + Package: pavucontrol: {'basearchonly': False, 'type': 'mandatory'} + Package: pnmixer: {'basearchonly': False, 'type': 'mandatory'} Group: lxqt-office (LXQt Office) - Package: libreoffice-calc: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-impress: {'type': 'mandatory', 'basearchonly': False} - Package: libreoffice-writer: {'type': 'mandatory', 'basearchonly': False} + Package: libreoffice-calc: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-impress: {'basearchonly': False, 'type': 'mandatory'} + Package: libreoffice-writer: {'basearchonly': False, 'type': 'mandatory'} Group: mail-server (Mail Server) - Package: cyrus-sasl: {'type': 'default', 'basearchonly': False} - Package: dovecot: {'type': 'default', 'basearchonly': False} - Package: sendmail: {'type': 'default', 'basearchonly': False} - Package: sendmail-cf: {'type': 'default', 'basearchonly': False} - Package: spamassassin: {'type': 'default', 'basearchonly': False} - Package: amavisd-new: {'type': 'optional', 'basearchonly': False} - Package: clamav: {'type': 'optional', 'basearchonly': False} - Package: clamav-data: {'type': 'optional', 'basearchonly': False} - Package: clamav-milter: {'type': 'optional', 'basearchonly': False} - Package: crm114: {'type': 'optional', 'basearchonly': False} - Package: cyrus-imapd: {'type': 'optional', 'basearchonly': False} - Package: dbmail: {'type': 'optional', 'basearchonly': False} - Package: enemies-of-carlotta: {'type': 'optional', 'basearchonly': False} - Package: esmtp: {'type': 'optional', 'basearchonly': False} - Package: exim: {'type': 'optional', 'basearchonly': False} - Package: exim-clamav: {'type': 'optional', 'basearchonly': False} - Package: exim-doc: {'type': 'optional', 'basearchonly': False} - Package: imp: {'type': 'optional', 'basearchonly': False} - Package: mailman: {'type': 'optional', 'basearchonly': False} - Package: milter-regex: {'type': 'optional', 'basearchonly': False} - Package: opendkim: {'type': 'optional', 'basearchonly': False} - Package: postfix: {'type': 'optional', 'basearchonly': False} - Package: pyzor: {'type': 'optional', 'basearchonly': False} - Package: roundcubemail: {'type': 'optional', 'basearchonly': False} - Package: spamass-milter: {'type': 'optional', 'basearchonly': False} - Package: spambayes: {'type': 'optional', 'basearchonly': False} - Package: sqlgrey: {'type': 'optional', 'basearchonly': False} - Package: squirrelmail: {'type': 'optional', 'basearchonly': False} - Package: up-imapproxy: {'type': 'optional', 'basearchonly': False} - Package: uw-imap: {'type': 'optional', 'basearchonly': False} + Package: cyrus-sasl: {'basearchonly': False, 'type': 'default'} + Package: dovecot: {'basearchonly': False, 'type': 'default'} + Package: sendmail: {'basearchonly': False, 'type': 'default'} + Package: sendmail-cf: {'basearchonly': False, 'type': 'default'} + Package: spamassassin: {'basearchonly': False, 'type': 'default'} + Package: amavisd-new: {'basearchonly': False, 'type': 'optional'} + Package: clamav: {'basearchonly': False, 'type': 'optional'} + Package: clamav-data: {'basearchonly': False, 'type': 'optional'} + Package: clamav-milter: {'basearchonly': False, 'type': 'optional'} + Package: crm114: {'basearchonly': False, 'type': 'optional'} + Package: cyrus-imapd: {'basearchonly': False, 'type': 'optional'} + Package: dbmail: {'basearchonly': False, 'type': 'optional'} + Package: enemies-of-carlotta: {'basearchonly': False, 'type': 'optional'} + Package: esmtp: {'basearchonly': False, 'type': 'optional'} + Package: exim: {'basearchonly': False, 'type': 'optional'} + Package: exim-clamav: {'basearchonly': False, 'type': 'optional'} + Package: exim-doc: {'basearchonly': False, 'type': 'optional'} + Package: imp: {'basearchonly': False, 'type': 'optional'} + Package: mailman: {'basearchonly': False, 'type': 'optional'} + Package: milter-regex: {'basearchonly': False, 'type': 'optional'} + Package: opendkim: {'basearchonly': False, 'type': 'optional'} + Package: postfix: {'basearchonly': False, 'type': 'optional'} + Package: pyzor: {'basearchonly': False, 'type': 'optional'} + Package: roundcubemail: {'basearchonly': False, 'type': 'optional'} + Package: spamass-milter: {'basearchonly': False, 'type': 'optional'} + Package: spambayes: {'basearchonly': False, 'type': 'optional'} + Package: sqlgrey: {'basearchonly': False, 'type': 'optional'} + Package: squirrelmail: {'basearchonly': False, 'type': 'optional'} + Package: up-imapproxy: {'basearchonly': False, 'type': 'optional'} + Package: uw-imap: {'basearchonly': False, 'type': 'optional'} Group: maithili-support (Maithili Support) - Package: lohit-devanagari-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} Group: malayalam-support (Malayalam Support) - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: smc-meera-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-malayalam-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-malayalam-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: lohit-malayalam-fonts: {'type': 'default', 'basearchonly': False} - Package: samyak-malayalam-fonts: {'type': 'default', 'basearchonly': False} - Package: smc-anjalioldlipi-fonts: {'type': 'default', 'basearchonly': False} - Package: smc-dyuthi-fonts: {'type': 'default', 'basearchonly': False} - Package: smc-kalyani-fonts: {'type': 'default', 'basearchonly': False} - Package: smc-rachana-fonts: {'type': 'default', 'basearchonly': False} - Package: smc-raghumalayalam-fonts: {'type': 'default', 'basearchonly': False} - Package: smc-suruma-fonts: {'type': 'default', 'basearchonly': False} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: smc-meera-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-malayalam-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-malayalam-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: lohit-malayalam-fonts: {'basearchonly': False, 'type': 'default'} + Package: samyak-malayalam-fonts: {'basearchonly': False, 'type': 'default'} + Package: smc-anjalioldlipi-fonts: {'basearchonly': False, 'type': 'default'} + Package: smc-dyuthi-fonts: {'basearchonly': False, 'type': 'default'} + Package: smc-kalyani-fonts: {'basearchonly': False, 'type': 'default'} + Package: smc-rachana-fonts: {'basearchonly': False, 'type': 'default'} + Package: smc-raghumalayalam-fonts: {'basearchonly': False, 'type': 'default'} + Package: smc-suruma-fonts: {'basearchonly': False, 'type': 'default'} Group: manipuri-support (Manipuri Support) - Package: lohit-bengali-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} + Package: lohit-bengali-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: iok: {'basearchonly': False, 'type': 'default'} Group: marathi-support (Marathi Support) - Package: lohit-marathi-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: samyak-devanagari-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-marathi-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: samyak-devanagari-fonts: {'basearchonly': False, 'type': 'default'} Group: mate-applications (MATE Applications) - Package: atril-thumbnailer: {'type': 'mandatory', 'basearchonly': False} - Package: caja-actions: {'type': 'mandatory', 'basearchonly': False} - Package: caja-beesu: {'type': 'mandatory', 'basearchonly': False} - Package: caja-beesu-manager: {'type': 'mandatory', 'basearchonly': False} - Package: caja-share: {'type': 'mandatory', 'basearchonly': False} - Package: firewall-applet: {'type': 'mandatory', 'basearchonly': False} - Package: mate-applet-softupd: {'type': 'mandatory', 'basearchonly': False} - Package: mate-icon-theme-faenza: {'type': 'mandatory', 'basearchonly': False} - Package: mate-sensors-applet: {'type': 'mandatory', 'basearchonly': False} - Package: mate-utils: {'type': 'mandatory', 'basearchonly': False} - Package: mintmenu: {'type': 'mandatory', 'basearchonly': False} - Package: pidgin: {'type': 'mandatory', 'basearchonly': False} - Package: pluma-beesu-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: python-caja: {'type': 'mandatory', 'basearchonly': False} - Package: tigervnc: {'type': 'mandatory', 'basearchonly': False} + Package: atril-thumbnailer: {'basearchonly': False, 'type': 'mandatory'} + Package: caja-actions: {'basearchonly': False, 'type': 'mandatory'} + Package: caja-beesu: {'basearchonly': False, 'type': 'mandatory'} + Package: caja-beesu-manager: {'basearchonly': False, 'type': 'mandatory'} + Package: caja-share: {'basearchonly': False, 'type': 'mandatory'} + Package: firewall-applet: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-applet-softupd: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-icon-theme-faenza: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-sensors-applet: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: mintmenu: {'basearchonly': False, 'type': 'mandatory'} + Package: pidgin: {'basearchonly': False, 'type': 'mandatory'} + Package: pluma-beesu-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: python-caja: {'basearchonly': False, 'type': 'mandatory'} + Package: tigervnc: {'basearchonly': False, 'type': 'mandatory'} Group: mate-compiz (MATE Compiz) - Package: ccsm: {'type': 'mandatory', 'basearchonly': False} - Package: compiz: {'type': 'mandatory', 'basearchonly': False} - Package: compiz-bcop: {'type': 'mandatory', 'basearchonly': False} - Package: compiz-manager: {'type': 'mandatory', 'basearchonly': False} - Package: compiz-plugins-experimental: {'type': 'mandatory', 'basearchonly': False} - Package: compiz-plugins-extra: {'type': 'mandatory', 'basearchonly': False} - Package: compiz-plugins-main: {'type': 'mandatory', 'basearchonly': False} - Package: compizconfig-python: {'type': 'mandatory', 'basearchonly': False} - Package: emerald: {'type': 'mandatory', 'basearchonly': False} - Package: emerald-themes: {'type': 'mandatory', 'basearchonly': False} - Package: fusion-icon: {'type': 'mandatory', 'basearchonly': False} - Package: libcompizconfig: {'type': 'mandatory', 'basearchonly': False} - Package: simple-ccsm: {'type': 'mandatory', 'basearchonly': False} + Package: ccsm: {'basearchonly': False, 'type': 'mandatory'} + Package: compiz: {'basearchonly': False, 'type': 'mandatory'} + Package: compiz-bcop: {'basearchonly': False, 'type': 'mandatory'} + Package: compiz-manager: {'basearchonly': False, 'type': 'mandatory'} + Package: compiz-plugins-experimental: {'basearchonly': False, 'type': 'mandatory'} + Package: compiz-plugins-extra: {'basearchonly': False, 'type': 'mandatory'} + Package: compiz-plugins-main: {'basearchonly': False, 'type': 'mandatory'} + Package: compizconfig-python: {'basearchonly': False, 'type': 'mandatory'} + Package: emerald: {'basearchonly': False, 'type': 'mandatory'} + Package: emerald-themes: {'basearchonly': False, 'type': 'mandatory'} + Package: fusion-icon: {'basearchonly': False, 'type': 'mandatory'} + Package: libcompizconfig: {'basearchonly': False, 'type': 'mandatory'} + Package: simple-ccsm: {'basearchonly': False, 'type': 'mandatory'} Group: mate-desktop (MATE) - Package: abrt-desktop: {'type': 'mandatory', 'basearchonly': False} - Package: abrt-java-connector: {'type': 'mandatory', 'basearchonly': False} - Package: atril: {'type': 'mandatory', 'basearchonly': False} - Package: atril-caja: {'type': 'mandatory', 'basearchonly': False} - Package: blueman: {'type': 'mandatory', 'basearchonly': False} - Package: caja: {'type': 'mandatory', 'basearchonly': False} - Package: caja-image-converter: {'type': 'mandatory', 'basearchonly': False} - Package: caja-open-terminal: {'type': 'mandatory', 'basearchonly': False} - Package: caja-sendto: {'type': 'mandatory', 'basearchonly': False} - Package: caja-wallpaper: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail: {'type': 'mandatory', 'basearchonly': False} - Package: dconf-editor: {'type': 'mandatory', 'basearchonly': False} - Package: engrampa: {'type': 'mandatory', 'basearchonly': False} - Package: eom: {'type': 'mandatory', 'basearchonly': False} - Package: exaile: {'type': 'mandatory', 'basearchonly': False} - Package: f24-backgrounds-base: {'type': 'mandatory', 'basearchonly': False} - Package: f24-backgrounds-extras-base: {'type': 'mandatory', 'basearchonly': False} - Package: f24-backgrounds-mate: {'type': 'mandatory', 'basearchonly': False} - Package: filezilla: {'type': 'mandatory', 'basearchonly': False} - Package: firefox: {'type': 'mandatory', 'basearchonly': False} - Package: firewall-config: {'type': 'mandatory', 'basearchonly': False} - Package: fros-recordmydesktop: {'type': 'mandatory', 'basearchonly': False} - Package: gnote: {'type': 'mandatory', 'basearchonly': False} - Package: gparted: {'type': 'mandatory', 'basearchonly': False} - Package: gtk2-engines: {'type': 'mandatory', 'basearchonly': False} - Package: gucharmap: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-afc: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-archive: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-fuse: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-gphoto2: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-mtp: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-smb: {'type': 'mandatory', 'basearchonly': False} - Package: hexchat: {'type': 'mandatory', 'basearchonly': False} - Package: initial-setup-gui: {'type': 'mandatory', 'basearchonly': False} - Package: libmatekbd: {'type': 'mandatory', 'basearchonly': False} - Package: libmatemixer: {'type': 'mandatory', 'basearchonly': False} - Package: libmateweather: {'type': 'mandatory', 'basearchonly': False} - Package: libsecret: {'type': 'mandatory', 'basearchonly': False} - Package: lightdm: {'type': 'mandatory', 'basearchonly': False} - Package: lightdm-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: lightdm-gtk-greeter-settings: {'type': 'mandatory', 'basearchonly': False} - Package: marco: {'type': 'mandatory', 'basearchonly': False} - Package: mate-applets: {'type': 'mandatory', 'basearchonly': False} - Package: mate-backgrounds: {'type': 'mandatory', 'basearchonly': False} - Package: mate-calc: {'type': 'mandatory', 'basearchonly': False} - Package: mate-control-center: {'type': 'mandatory', 'basearchonly': False} - Package: mate-desktop: {'type': 'mandatory', 'basearchonly': False} - Package: mate-dictionary: {'type': 'mandatory', 'basearchonly': False} - Package: mate-disk-usage-analyzer: {'type': 'mandatory', 'basearchonly': False} - Package: mate-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: mate-media: {'type': 'mandatory', 'basearchonly': False} - Package: mate-menus: {'type': 'mandatory', 'basearchonly': False} - Package: mate-menus-preferences-category-menu: {'type': 'mandatory', 'basearchonly': False} - Package: mate-notification-daemon: {'type': 'mandatory', 'basearchonly': False} - Package: mate-panel: {'type': 'mandatory', 'basearchonly': False} - Package: mate-polkit: {'type': 'mandatory', 'basearchonly': False} - Package: mate-power-manager: {'type': 'mandatory', 'basearchonly': False} - Package: mate-screensaver: {'type': 'mandatory', 'basearchonly': False} - Package: mate-screenshot: {'type': 'mandatory', 'basearchonly': False} - Package: mate-search-tool: {'type': 'mandatory', 'basearchonly': False} - Package: mate-session-manager: {'type': 'mandatory', 'basearchonly': False} - Package: mate-settings-daemon: {'type': 'mandatory', 'basearchonly': False} - Package: mate-system-log: {'type': 'mandatory', 'basearchonly': False} - Package: mate-system-monitor: {'type': 'mandatory', 'basearchonly': False} - Package: mate-terminal: {'type': 'mandatory', 'basearchonly': False} - Package: mate-themes: {'type': 'mandatory', 'basearchonly': False} - Package: mate-user-guide: {'type': 'mandatory', 'basearchonly': False} - Package: mozo: {'type': 'mandatory', 'basearchonly': False} - Package: network-manager-applet: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-adsl: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-bluetooth: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-iodine-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-l2tp: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-libreswan-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-openconnect: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-openvpn-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-pptp-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-vpnc-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: p7zip: {'type': 'mandatory', 'basearchonly': False} - Package: p7zip-plugins: {'type': 'mandatory', 'basearchonly': False} - Package: parole: {'type': 'mandatory', 'basearchonly': False} - Package: pluma: {'type': 'mandatory', 'basearchonly': False} - Package: seahorse: {'type': 'mandatory', 'basearchonly': False} - Package: setroubleshoot: {'type': 'mandatory', 'basearchonly': False} - Package: simple-scan: {'type': 'mandatory', 'basearchonly': False} - Package: system-config-date: {'type': 'mandatory', 'basearchonly': False} - Package: system-config-language: {'type': 'mandatory', 'basearchonly': False} - Package: system-config-printer: {'type': 'mandatory', 'basearchonly': False} - Package: system-config-users: {'type': 'mandatory', 'basearchonly': False} - Package: transmission-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: vim-enhanced: {'type': 'mandatory', 'basearchonly': False} - Package: xdg-user-dirs-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: xfburn: {'type': 'mandatory', 'basearchonly': False} - Package: yelp: {'type': 'mandatory', 'basearchonly': False} - Package: yumex-dnf: {'type': 'mandatory', 'basearchonly': False} + Package: abrt-desktop: {'basearchonly': False, 'type': 'mandatory'} + Package: abrt-java-connector: {'basearchonly': False, 'type': 'mandatory'} + Package: atril: {'basearchonly': False, 'type': 'mandatory'} + Package: atril-caja: {'basearchonly': False, 'type': 'mandatory'} + Package: blueman: {'basearchonly': False, 'type': 'mandatory'} + Package: caja: {'basearchonly': False, 'type': 'mandatory'} + Package: caja-image-converter: {'basearchonly': False, 'type': 'mandatory'} + Package: caja-open-terminal: {'basearchonly': False, 'type': 'mandatory'} + Package: caja-sendto: {'basearchonly': False, 'type': 'mandatory'} + Package: caja-wallpaper: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail: {'basearchonly': False, 'type': 'mandatory'} + Package: dconf-editor: {'basearchonly': False, 'type': 'mandatory'} + Package: engrampa: {'basearchonly': False, 'type': 'mandatory'} + Package: eom: {'basearchonly': False, 'type': 'mandatory'} + Package: exaile: {'basearchonly': False, 'type': 'mandatory'} + Package: f24-backgrounds-base: {'basearchonly': False, 'type': 'mandatory'} + Package: f24-backgrounds-extras-base: {'basearchonly': False, 'type': 'mandatory'} + Package: f24-backgrounds-mate: {'basearchonly': False, 'type': 'mandatory'} + Package: filezilla: {'basearchonly': False, 'type': 'mandatory'} + Package: firefox: {'basearchonly': False, 'type': 'mandatory'} + Package: firewall-config: {'basearchonly': False, 'type': 'mandatory'} + Package: fros-recordmydesktop: {'basearchonly': False, 'type': 'mandatory'} + Package: gnote: {'basearchonly': False, 'type': 'mandatory'} + Package: gparted: {'basearchonly': False, 'type': 'mandatory'} + Package: gtk2-engines: {'basearchonly': False, 'type': 'mandatory'} + Package: gucharmap: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-afc: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-archive: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-fuse: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-gphoto2: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-mtp: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-smb: {'basearchonly': False, 'type': 'mandatory'} + Package: hexchat: {'basearchonly': False, 'type': 'mandatory'} + Package: initial-setup-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: libmatekbd: {'basearchonly': False, 'type': 'mandatory'} + Package: libmatemixer: {'basearchonly': False, 'type': 'mandatory'} + Package: libmateweather: {'basearchonly': False, 'type': 'mandatory'} + Package: libsecret: {'basearchonly': False, 'type': 'mandatory'} + Package: lightdm: {'basearchonly': False, 'type': 'mandatory'} + Package: lightdm-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: lightdm-gtk-greeter-settings: {'basearchonly': False, 'type': 'mandatory'} + Package: marco: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-applets: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-backgrounds: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-calc: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-control-center: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-desktop: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-dictionary: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-disk-usage-analyzer: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-media: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-menus: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-menus-preferences-category-menu: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-notification-daemon: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-panel: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-polkit: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-power-manager: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-screensaver: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-screenshot: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-search-tool: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-session-manager: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-settings-daemon: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-system-log: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-system-monitor: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-terminal: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-themes: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-user-guide: {'basearchonly': False, 'type': 'mandatory'} + Package: mozo: {'basearchonly': False, 'type': 'mandatory'} + Package: network-manager-applet: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-adsl: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-bluetooth: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-iodine-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-l2tp: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-libreswan-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-openconnect: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-openvpn-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-pptp-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-vpnc-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: p7zip: {'basearchonly': False, 'type': 'mandatory'} + Package: p7zip-plugins: {'basearchonly': False, 'type': 'mandatory'} + Package: parole: {'basearchonly': False, 'type': 'mandatory'} + Package: pluma: {'basearchonly': False, 'type': 'mandatory'} + Package: seahorse: {'basearchonly': False, 'type': 'mandatory'} + Package: setroubleshoot: {'basearchonly': False, 'type': 'mandatory'} + Package: simple-scan: {'basearchonly': False, 'type': 'mandatory'} + Package: system-config-date: {'basearchonly': False, 'type': 'mandatory'} + Package: system-config-language: {'basearchonly': False, 'type': 'mandatory'} + Package: system-config-printer: {'basearchonly': False, 'type': 'mandatory'} + Package: system-config-users: {'basearchonly': False, 'type': 'mandatory'} + Package: transmission-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: vim-enhanced: {'basearchonly': False, 'type': 'mandatory'} + Package: xdg-user-dirs-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: xfburn: {'basearchonly': False, 'type': 'mandatory'} + Package: yelp: {'basearchonly': False, 'type': 'mandatory'} + Package: yumex-dnf: {'basearchonly': False, 'type': 'mandatory'} Group: medical (Medical Applications) - Package: aeskulap: {'type': 'default', 'basearchonly': False} - Package: gnumed: {'type': 'default', 'basearchonly': False} - Package: gnumed-server: {'type': 'default', 'basearchonly': False} + Package: aeskulap: {'basearchonly': False, 'type': 'default'} + Package: gnumed: {'basearchonly': False, 'type': 'default'} + Package: gnumed-server: {'basearchonly': False, 'type': 'default'} Group: milkymist (Milkymist) - Package: autoconf: {'type': 'default', 'basearchonly': False} - Package: automake: {'type': 'default', 'basearchonly': False} - Package: avr-binutils: {'type': 'default', 'basearchonly': False} - Package: avr-gcc: {'type': 'default', 'basearchonly': False} - Package: avr-gcc-c++: {'type': 'default', 'basearchonly': False} - Package: avr-gdb: {'type': 'default', 'basearchonly': False} - Package: avr-libc: {'type': 'default', 'basearchonly': False} - Package: avr-libc-doc: {'type': 'default', 'basearchonly': False} - Package: clang: {'type': 'default', 'basearchonly': False} - Package: flterm: {'type': 'default', 'basearchonly': False} - Package: gcc: {'type': 'default', 'basearchonly': False} - Package: gd-devel: {'type': 'default', 'basearchonly': False} - Package: gplcver: {'type': 'default', 'basearchonly': False} - Package: gtkwave: {'type': 'default', 'basearchonly': False} - Package: iverilog: {'type': 'default', 'basearchonly': False} - Package: lemon: {'type': 'default', 'basearchonly': False} - Package: libftdi-devel: {'type': 'default', 'basearchonly': False} - Package: llvm: {'type': 'default', 'basearchonly': False} - Package: openocd: {'type': 'default', 'basearchonly': False} - Package: qemu: {'type': 'default', 'basearchonly': False} - Package: re2c: {'type': 'default', 'basearchonly': False} - Package: srecord: {'type': 'default', 'basearchonly': False} - Package: tftp: {'type': 'default', 'basearchonly': False} - Package: tftp-server: {'type': 'default', 'basearchonly': False} - Package: vim-common: {'type': 'default', 'basearchonly': False} + Package: autoconf: {'basearchonly': False, 'type': 'default'} + Package: automake: {'basearchonly': False, 'type': 'default'} + Package: avr-binutils: {'basearchonly': False, 'type': 'default'} + Package: avr-gcc: {'basearchonly': False, 'type': 'default'} + Package: avr-gcc-c++: {'basearchonly': False, 'type': 'default'} + Package: avr-gdb: {'basearchonly': False, 'type': 'default'} + Package: avr-libc: {'basearchonly': False, 'type': 'default'} + Package: avr-libc-doc: {'basearchonly': False, 'type': 'default'} + Package: clang: {'basearchonly': False, 'type': 'default'} + Package: flterm: {'basearchonly': False, 'type': 'default'} + Package: gcc: {'basearchonly': False, 'type': 'default'} + Package: gd-devel: {'basearchonly': False, 'type': 'default'} + Package: gplcver: {'basearchonly': False, 'type': 'default'} + Package: gtkwave: {'basearchonly': False, 'type': 'default'} + Package: iverilog: {'basearchonly': False, 'type': 'default'} + Package: lemon: {'basearchonly': False, 'type': 'default'} + Package: libftdi-devel: {'basearchonly': False, 'type': 'default'} + Package: llvm: {'basearchonly': False, 'type': 'default'} + Package: openocd: {'basearchonly': False, 'type': 'default'} + Package: qemu: {'basearchonly': False, 'type': 'default'} + Package: re2c: {'basearchonly': False, 'type': 'default'} + Package: srecord: {'basearchonly': False, 'type': 'default'} + Package: tftp: {'basearchonly': False, 'type': 'default'} + Package: tftp-server: {'basearchonly': False, 'type': 'default'} + Package: vim-common: {'basearchonly': False, 'type': 'default'} Group: mingw32 (MinGW cross-compiler) - Package: mingw32-binutils: {'type': 'mandatory', 'basearchonly': False} - Package: mingw32-crt: {'type': 'mandatory', 'basearchonly': False} - Package: mingw32-filesystem: {'type': 'mandatory', 'basearchonly': False} - Package: mingw32-gcc: {'type': 'mandatory', 'basearchonly': False} - Package: mingw32-headers: {'type': 'mandatory', 'basearchonly': False} - Package: mingw32-nsiswrapper: {'requires': u'mingw32-nsis', 'type': 'conditional', 'basearchonly': False} - Package: mingw32-crossreport: {'type': 'default', 'basearchonly': False} - Package: mingw32-nsis: {'type': 'default', 'basearchonly': False} - Package: wine: {'type': 'default', 'basearchonly': False} - Package: mingw32-atk: {'type': 'optional', 'basearchonly': False} - Package: mingw32-bzip2: {'type': 'optional', 'basearchonly': False} - Package: mingw32-cairo: {'type': 'optional', 'basearchonly': False} - Package: mingw32-dlfcn: {'type': 'optional', 'basearchonly': False} - Package: mingw32-freetype: {'type': 'optional', 'basearchonly': False} - Package: mingw32-gdbm: {'type': 'optional', 'basearchonly': False} - Package: mingw32-gettext: {'type': 'optional', 'basearchonly': False} - Package: mingw32-glib2: {'type': 'optional', 'basearchonly': False} - Package: mingw32-libgcrypt: {'type': 'optional', 'basearchonly': False} - Package: mingw32-libgpg-error: {'type': 'optional', 'basearchonly': False} - Package: mingw32-libjpeg-turbo: {'type': 'optional', 'basearchonly': False} - Package: mingw32-libpng: {'type': 'optional', 'basearchonly': False} - Package: mingw32-libxml2: {'type': 'optional', 'basearchonly': False} - Package: mingw32-openssl: {'type': 'optional', 'basearchonly': False} - Package: mingw32-pdcurses: {'type': 'optional', 'basearchonly': False} - Package: mingw32-pixman: {'type': 'optional', 'basearchonly': False} - Package: mingw32-proj: {'type': 'optional', 'basearchonly': False} - Package: mingw32-pthreads: {'type': 'optional', 'basearchonly': False} - Package: mingw32-readline: {'type': 'optional', 'basearchonly': False} - Package: mingw32-SDL: {'type': 'optional', 'basearchonly': False} - Package: mingw32-sqlite: {'type': 'optional', 'basearchonly': False} - Package: mingw32-termcap: {'type': 'optional', 'basearchonly': False} - Package: mingw32-win-iconv: {'type': 'optional', 'basearchonly': False} - Package: mingw32-zlib: {'type': 'optional', 'basearchonly': False} + Package: mingw32-binutils: {'basearchonly': False, 'type': 'mandatory'} + Package: mingw32-crt: {'basearchonly': False, 'type': 'mandatory'} + Package: mingw32-filesystem: {'basearchonly': False, 'type': 'mandatory'} + Package: mingw32-gcc: {'basearchonly': False, 'type': 'mandatory'} + Package: mingw32-headers: {'basearchonly': False, 'type': 'mandatory'} + Package: mingw32-nsiswrapper: {'basearchonly': False, 'requires': 'mingw32-nsis', 'type': 'conditional'} + Package: mingw32-crossreport: {'basearchonly': False, 'type': 'default'} + Package: mingw32-nsis: {'basearchonly': False, 'type': 'default'} + Package: wine: {'basearchonly': False, 'type': 'default'} + Package: mingw32-atk: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-bzip2: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-cairo: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-dlfcn: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-freetype: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-gdbm: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-gettext: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-glib2: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-libgcrypt: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-libgpg-error: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-libjpeg-turbo: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-libpng: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-libxml2: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-openssl: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-pdcurses: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-pixman: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-proj: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-pthreads: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-readline: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-SDL: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-sqlite: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-termcap: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-win-iconv: {'basearchonly': False, 'type': 'optional'} + Package: mingw32-zlib: {'basearchonly': False, 'type': 'optional'} Group: mongodb (MongoDB) - Package: libmongodb: {'type': 'mandatory', 'basearchonly': False} - Package: mongodb: {'type': 'mandatory', 'basearchonly': False} - Package: mongodb-devel: {'type': 'mandatory', 'basearchonly': False} - Package: mongodb-server: {'type': 'mandatory', 'basearchonly': False} + Package: libmongodb: {'basearchonly': False, 'type': 'mandatory'} + Package: mongodb: {'basearchonly': False, 'type': 'mandatory'} + Package: mongodb-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: mongodb-server: {'basearchonly': False, 'type': 'mandatory'} Group: multimedia (Multimedia) - Package: alsa-plugins-pulseaudio: {'type': 'mandatory', 'basearchonly': False} - Package: alsa-ucm: {'type': 'mandatory', 'basearchonly': False} - Package: alsa-utils: {'type': 'mandatory', 'basearchonly': False} - Package: gstreamer1-plugins-bad-free: {'type': 'mandatory', 'basearchonly': False} - Package: gstreamer1-plugins-good: {'type': 'mandatory', 'basearchonly': False} - Package: PackageKit-gstreamer-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: pulseaudio: {'type': 'mandatory', 'basearchonly': False} - Package: pulseaudio-module-x11: {'type': 'mandatory', 'basearchonly': False} - Package: pulseaudio-utils: {'type': 'mandatory', 'basearchonly': False} - Package: gstreamer-plugins-bad-free: {'requires': u'gstreamer', 'type': 'conditional', 'basearchonly': False} - Package: gstreamer-plugins-espeak: {'requires': u'gstreamer', 'type': 'conditional', 'basearchonly': False} - Package: gstreamer-plugins-good: {'requires': u'gstreamer', 'type': 'conditional', 'basearchonly': False} + Package: alsa-plugins-pulseaudio: {'basearchonly': False, 'type': 'mandatory'} + Package: alsa-ucm: {'basearchonly': False, 'type': 'mandatory'} + Package: alsa-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: gstreamer1-plugins-bad-free: {'basearchonly': False, 'type': 'mandatory'} + Package: gstreamer1-plugins-good: {'basearchonly': False, 'type': 'mandatory'} + Package: PackageKit-gstreamer-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: pulseaudio: {'basearchonly': False, 'type': 'mandatory'} + Package: pulseaudio-module-x11: {'basearchonly': False, 'type': 'mandatory'} + Package: pulseaudio-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: gstreamer-plugins-bad-free: {'basearchonly': False, 'requires': 'gstreamer', 'type': 'conditional'} + Package: gstreamer-plugins-espeak: {'basearchonly': False, 'requires': 'gstreamer', 'type': 'conditional'} + Package: gstreamer-plugins-good: {'basearchonly': False, 'requires': 'gstreamer', 'type': 'conditional'} Group: mysql (MariaDB (MySQL) Database) - Package: mariadb: {'type': 'mandatory', 'basearchonly': False} - Package: libdbi-dbd-mysql: {'type': 'default', 'basearchonly': False} - Package: mariadb-server: {'type': 'default', 'basearchonly': False} - Package: mysql-connector-odbc: {'type': 'default', 'basearchonly': False} - Package: perl-DBD-MySQL: {'type': 'default', 'basearchonly': False} - Package: python-mysql: {'type': 'default', 'basearchonly': False} - Package: unixODBC: {'type': 'default', 'basearchonly': False} - Package: mariadb-bench: {'type': 'optional', 'basearchonly': False} - Package: mariadb-devel: {'type': 'optional', 'basearchonly': False} - Package: mysqlreport: {'type': 'optional', 'basearchonly': False} - Package: mysqltuner: {'type': 'optional', 'basearchonly': False} - Package: php-mysqlnd: {'type': 'optional', 'basearchonly': False} - Package: qt-mysql: {'type': 'optional', 'basearchonly': False} - Package: qt3-MySQL: {'type': 'optional', 'basearchonly': False} + Package: mariadb: {'basearchonly': False, 'type': 'mandatory'} + Package: libdbi-dbd-mysql: {'basearchonly': False, 'type': 'default'} + Package: mariadb-server: {'basearchonly': False, 'type': 'default'} + Package: mysql-connector-odbc: {'basearchonly': False, 'type': 'default'} + Package: perl-DBD-MySQL: {'basearchonly': False, 'type': 'default'} + Package: python-mysql: {'basearchonly': False, 'type': 'default'} + Package: unixODBC: {'basearchonly': False, 'type': 'default'} + Package: mariadb-bench: {'basearchonly': False, 'type': 'optional'} + Package: mariadb-devel: {'basearchonly': False, 'type': 'optional'} + Package: mysqlreport: {'basearchonly': False, 'type': 'optional'} + Package: mysqltuner: {'basearchonly': False, 'type': 'optional'} + Package: php-mysqlnd: {'basearchonly': False, 'type': 'optional'} + Package: qt-mysql: {'basearchonly': False, 'type': 'optional'} + Package: qt3-MySQL: {'basearchonly': False, 'type': 'optional'} Group: nepali-support (Nepali Support) - Package: lohit-devanagari-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: madan-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: scim-tables-nepali: {'type': 'optional', 'basearchonly': False} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: madan-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: scim-tables-nepali: {'basearchonly': False, 'type': 'optional'} Group: network-server (Network Servers) - Package: 389-ds-base: {'type': 'optional', 'basearchonly': False} - Package: ahcpd: {'type': 'optional', 'basearchonly': False} - Package: amanda-server: {'type': 'optional', 'basearchonly': False} - Package: babeld: {'type': 'optional', 'basearchonly': False} - Package: cobbler: {'type': 'optional', 'basearchonly': False} - Package: dhcp: {'type': 'optional', 'basearchonly': False} - Package: dnsmasq: {'type': 'optional', 'basearchonly': False} - Package: ejabberd: {'type': 'optional', 'basearchonly': False} - Package: flumotion: {'type': 'optional', 'basearchonly': False} - Package: freenx-server: {'type': 'optional', 'basearchonly': False} - Package: freeradius: {'type': 'optional', 'basearchonly': False} - Package: fwknop: {'type': 'optional', 'basearchonly': False} - Package: icecast: {'type': 'optional', 'basearchonly': False} - Package: ipxripd: {'type': 'optional', 'basearchonly': False} - Package: jabberd: {'type': 'optional', 'basearchonly': False} - Package: kannel: {'type': 'optional', 'basearchonly': False} - Package: koan: {'type': 'optional', 'basearchonly': False} - Package: krb5-server: {'type': 'optional', 'basearchonly': False} - Package: libreswan: {'type': 'optional', 'basearchonly': False} - Package: netatalk: {'type': 'optional', 'basearchonly': False} - Package: nsd: {'type': 'optional', 'basearchonly': False} - Package: oidentd: {'type': 'optional', 'basearchonly': False} - Package: openldap-servers: {'type': 'optional', 'basearchonly': False} - Package: polipo: {'type': 'optional', 'basearchonly': False} - Package: privoxy: {'type': 'optional', 'basearchonly': False} - Package: puppet-server: {'type': 'optional', 'basearchonly': False} - Package: quagga: {'type': 'optional', 'basearchonly': False} - Package: radvd: {'type': 'optional', 'basearchonly': False} - Package: rinetd: {'type': 'optional', 'basearchonly': False} - Package: sobby: {'type': 'optional', 'basearchonly': False} - Package: tigervnc-server: {'type': 'optional', 'basearchonly': False} - Package: torque-server: {'type': 'optional', 'basearchonly': False} - Package: ucarp: {'type': 'optional', 'basearchonly': False} - Package: vnc-reflector: {'type': 'optional', 'basearchonly': False} - Package: vtun: {'type': 'optional', 'basearchonly': False} - Package: xl2tpd: {'type': 'optional', 'basearchonly': False} - Package: ypserv: {'type': 'optional', 'basearchonly': False} - Package: znc: {'type': 'optional', 'basearchonly': False} + Package: 389-ds-base: {'basearchonly': False, 'type': 'optional'} + Package: ahcpd: {'basearchonly': False, 'type': 'optional'} + Package: amanda-server: {'basearchonly': False, 'type': 'optional'} + Package: babeld: {'basearchonly': False, 'type': 'optional'} + Package: cobbler: {'basearchonly': False, 'type': 'optional'} + Package: dhcp: {'basearchonly': False, 'type': 'optional'} + Package: dnsmasq: {'basearchonly': False, 'type': 'optional'} + Package: ejabberd: {'basearchonly': False, 'type': 'optional'} + Package: flumotion: {'basearchonly': False, 'type': 'optional'} + Package: freenx-server: {'basearchonly': False, 'type': 'optional'} + Package: freeradius: {'basearchonly': False, 'type': 'optional'} + Package: fwknop: {'basearchonly': False, 'type': 'optional'} + Package: icecast: {'basearchonly': False, 'type': 'optional'} + Package: ipxripd: {'basearchonly': False, 'type': 'optional'} + Package: jabberd: {'basearchonly': False, 'type': 'optional'} + Package: kannel: {'basearchonly': False, 'type': 'optional'} + Package: koan: {'basearchonly': False, 'type': 'optional'} + Package: krb5-server: {'basearchonly': False, 'type': 'optional'} + Package: libreswan: {'basearchonly': False, 'type': 'optional'} + Package: netatalk: {'basearchonly': False, 'type': 'optional'} + Package: nsd: {'basearchonly': False, 'type': 'optional'} + Package: oidentd: {'basearchonly': False, 'type': 'optional'} + Package: openldap-servers: {'basearchonly': False, 'type': 'optional'} + Package: polipo: {'basearchonly': False, 'type': 'optional'} + Package: privoxy: {'basearchonly': False, 'type': 'optional'} + Package: puppet-server: {'basearchonly': False, 'type': 'optional'} + Package: quagga: {'basearchonly': False, 'type': 'optional'} + Package: radvd: {'basearchonly': False, 'type': 'optional'} + Package: rinetd: {'basearchonly': False, 'type': 'optional'} + Package: sobby: {'basearchonly': False, 'type': 'optional'} + Package: tigervnc-server: {'basearchonly': False, 'type': 'optional'} + Package: torque-server: {'basearchonly': False, 'type': 'optional'} + Package: ucarp: {'basearchonly': False, 'type': 'optional'} + Package: vnc-reflector: {'basearchonly': False, 'type': 'optional'} + Package: vtun: {'basearchonly': False, 'type': 'optional'} + Package: xl2tpd: {'basearchonly': False, 'type': 'optional'} + Package: ypserv: {'basearchonly': False, 'type': 'optional'} + Package: znc: {'basearchonly': False, 'type': 'optional'} Group: networkmanager-submodules (Common NetworkManager Submodules) - Package: NetworkManager-bluetooth: {'type': 'default', 'basearchonly': False} - Package: NetworkManager-wifi: {'type': 'default', 'basearchonly': False} - Package: NetworkManager-wwan: {'type': 'default', 'basearchonly': False} + Package: NetworkManager-bluetooth: {'basearchonly': False, 'type': 'default'} + Package: NetworkManager-wifi: {'basearchonly': False, 'type': 'default'} + Package: NetworkManager-wwan: {'basearchonly': False, 'type': 'default'} Group: news-server (News Server) - Package: inn: {'type': 'mandatory', 'basearchonly': False} - Package: cleanfeed: {'type': 'optional', 'basearchonly': False} - Package: leafnode: {'type': 'optional', 'basearchonly': False} - Package: newscache: {'type': 'optional', 'basearchonly': False} - Package: newsx: {'type': 'optional', 'basearchonly': False} - Package: suck: {'type': 'optional', 'basearchonly': False} + Package: inn: {'basearchonly': False, 'type': 'mandatory'} + Package: cleanfeed: {'basearchonly': False, 'type': 'optional'} + Package: leafnode: {'basearchonly': False, 'type': 'optional'} + Package: newscache: {'basearchonly': False, 'type': 'optional'} + Package: newsx: {'basearchonly': False, 'type': 'optional'} + Package: suck: {'basearchonly': False, 'type': 'optional'} Group: ocaml (OCaml) - Package: ocaml: {'type': 'mandatory', 'basearchonly': False} - Package: ocaml-findlib-devel: {'type': 'mandatory', 'basearchonly': False} - Package: ocaml-ocamldoc: {'type': 'mandatory', 'basearchonly': False} - Package: ocaml-runtime: {'type': 'mandatory', 'basearchonly': False} - Package: ocaml-x11: {'type': 'mandatory', 'basearchonly': False} - Package: emacs-tuareg: {'type': 'default', 'basearchonly': False} - Package: ocaml-camlp4-devel: {'type': 'default', 'basearchonly': False} - Package: ocaml-bitstring-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-calendar-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-camomile-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-csv-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-curl-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-curses-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-expat-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-extlib-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-lablgl-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-lablgtk-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-labltk-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-menhir-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-ocamlgraph-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-ocamlnet-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-pcre-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-pxp-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-ssl-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-tplib-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-xml-light-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-xmlrpc-light-devel: {'type': 'optional', 'basearchonly': False} - Package: ocaml-zarith-devel: {'type': 'optional', 'basearchonly': False} - Package: xemacs-tuareg: {'type': 'optional', 'basearchonly': False} + Package: ocaml: {'basearchonly': False, 'type': 'mandatory'} + Package: ocaml-findlib-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: ocaml-ocamldoc: {'basearchonly': False, 'type': 'mandatory'} + Package: ocaml-runtime: {'basearchonly': False, 'type': 'mandatory'} + Package: ocaml-x11: {'basearchonly': False, 'type': 'mandatory'} + Package: emacs-tuareg: {'basearchonly': False, 'type': 'default'} + Package: ocaml-camlp4-devel: {'basearchonly': False, 'type': 'default'} + Package: ocaml-bitstring-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-calendar-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-camomile-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-csv-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-curl-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-curses-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-expat-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-extlib-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-lablgl-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-lablgtk-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-labltk-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-menhir-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-ocamlgraph-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-ocamlnet-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-pcre-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-pxp-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-ssl-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-tplib-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-xml-light-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-xmlrpc-light-devel: {'basearchonly': False, 'type': 'optional'} + Package: ocaml-zarith-devel: {'basearchonly': False, 'type': 'optional'} + Package: xemacs-tuareg: {'basearchonly': False, 'type': 'optional'} Group: odia-support (Odia Support) - Package: lohit-odia-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: samyak-odia-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-odia-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: samyak-odia-fonts: {'basearchonly': False, 'type': 'default'} Group: office (Office/Productivity) - Package: abiword: {'type': 'optional', 'basearchonly': False} - Package: aiksaurus-thesaurus: {'type': 'optional', 'basearchonly': False} - Package: alexandria: {'type': 'optional', 'basearchonly': False} - Package: bibus: {'type': 'optional', 'basearchonly': False} - Package: calcurse: {'type': 'optional', 'basearchonly': False} - Package: calibre: {'type': 'optional', 'basearchonly': False} - Package: calligra: {'type': 'optional', 'basearchonly': False} - Package: calligra-braindump: {'type': 'optional', 'basearchonly': False} - Package: calligra-flow: {'type': 'optional', 'basearchonly': False} - Package: calligra-kexi: {'type': 'optional', 'basearchonly': False} - Package: calligra-plan: {'type': 'optional', 'basearchonly': False} - Package: calligra-sheets: {'type': 'optional', 'basearchonly': False} - Package: calligra-stage: {'type': 'optional', 'basearchonly': False} - Package: calligra-words: {'type': 'optional', 'basearchonly': False} - Package: cherrytree: {'type': 'optional', 'basearchonly': False} - Package: dayplanner: {'type': 'optional', 'basearchonly': False} - Package: dia: {'type': 'optional', 'basearchonly': False} - Package: evince: {'type': 'optional', 'basearchonly': False} - Package: glabels: {'type': 'optional', 'basearchonly': False} - Package: glom: {'type': 'optional', 'basearchonly': False} - Package: gnucash: {'type': 'optional', 'basearchonly': False} - Package: gnumeric: {'type': 'optional', 'basearchonly': False} - Package: gnumeric-plugins-extras: {'type': 'optional', 'basearchonly': False} - Package: gourmet: {'type': 'optional', 'basearchonly': False} - Package: gramps: {'type': 'optional', 'basearchonly': False} - Package: grisbi: {'type': 'optional', 'basearchonly': False} - Package: hnb: {'type': 'optional', 'basearchonly': False} - Package: htmldoc: {'type': 'optional', 'basearchonly': False} - Package: jpilot: {'type': 'optional', 'basearchonly': False} - Package: kchmviewer-qt: {'type': 'optional', 'basearchonly': False} - Package: kdepim: {'type': 'optional', 'basearchonly': False} - Package: keurocalc: {'type': 'optional', 'basearchonly': False} - Package: klatexformula: {'type': 'optional', 'basearchonly': False} - Package: klatexformula-ktexteditor-plugin: {'type': 'optional', 'basearchonly': False} - Package: kmymoney: {'type': 'optional', 'basearchonly': False} - Package: krecipes: {'type': 'optional', 'basearchonly': False} - Package: kreetingkard: {'type': 'optional', 'basearchonly': False} - Package: kreetingkard_templates: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-base: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-calc: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-draw: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-emailmerge: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-graphicfilter: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-impress: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-math: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-ogltrans: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-TexMaths: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-voikko: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-wiki-publisher: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-writer: {'type': 'optional', 'basearchonly': False} - Package: libreoffice-xsltfilter: {'type': 'optional', 'basearchonly': False} - Package: lyx: {'type': 'optional', 'basearchonly': False} - Package: MagicPoint: {'type': 'optional', 'basearchonly': False} - Package: okular: {'type': 'optional', 'basearchonly': False} - Package: pdfedit: {'type': 'optional', 'basearchonly': False} - Package: planner: {'type': 'optional', 'basearchonly': False} - Package: pybliographer: {'type': 'optional', 'basearchonly': False} - Package: rednotebook: {'type': 'optional', 'basearchonly': False} - Package: revelation: {'type': 'optional', 'basearchonly': False} - Package: Saaghar: {'type': 'optional', 'basearchonly': False} - Package: skrooge: {'type': 'optional', 'basearchonly': False} - Package: starcal: {'type': 'optional', 'basearchonly': False} - Package: taskcoach: {'type': 'optional', 'basearchonly': False} - Package: taskjuggler: {'type': 'optional', 'basearchonly': False} - Package: tellico: {'type': 'optional', 'basearchonly': False} - Package: tetex-IEEEtran: {'type': 'optional', 'basearchonly': False} - Package: texlive-xdvi: {'type': 'optional', 'basearchonly': False} - Package: texmaker: {'type': 'optional', 'basearchonly': False} - Package: vym: {'type': 'optional', 'basearchonly': False} - Package: wyrd: {'type': 'optional', 'basearchonly': False} - Package: xchm: {'type': 'optional', 'basearchonly': False} - Package: xfbib: {'type': 'optional', 'basearchonly': False} - Package: xournal: {'type': 'optional', 'basearchonly': False} - Package: Zim: {'type': 'optional', 'basearchonly': False} + Package: abiword: {'basearchonly': False, 'type': 'optional'} + Package: aiksaurus-thesaurus: {'basearchonly': False, 'type': 'optional'} + Package: alexandria: {'basearchonly': False, 'type': 'optional'} + Package: bibus: {'basearchonly': False, 'type': 'optional'} + Package: calcurse: {'basearchonly': False, 'type': 'optional'} + Package: calibre: {'basearchonly': False, 'type': 'optional'} + Package: calligra: {'basearchonly': False, 'type': 'optional'} + Package: calligra-braindump: {'basearchonly': False, 'type': 'optional'} + Package: calligra-flow: {'basearchonly': False, 'type': 'optional'} + Package: calligra-kexi: {'basearchonly': False, 'type': 'optional'} + Package: calligra-plan: {'basearchonly': False, 'type': 'optional'} + Package: calligra-sheets: {'basearchonly': False, 'type': 'optional'} + Package: calligra-stage: {'basearchonly': False, 'type': 'optional'} + Package: calligra-words: {'basearchonly': False, 'type': 'optional'} + Package: cherrytree: {'basearchonly': False, 'type': 'optional'} + Package: dayplanner: {'basearchonly': False, 'type': 'optional'} + Package: dia: {'basearchonly': False, 'type': 'optional'} + Package: evince: {'basearchonly': False, 'type': 'optional'} + Package: glabels: {'basearchonly': False, 'type': 'optional'} + Package: glom: {'basearchonly': False, 'type': 'optional'} + Package: gnucash: {'basearchonly': False, 'type': 'optional'} + Package: gnumeric: {'basearchonly': False, 'type': 'optional'} + Package: gnumeric-plugins-extras: {'basearchonly': False, 'type': 'optional'} + Package: gourmet: {'basearchonly': False, 'type': 'optional'} + Package: gramps: {'basearchonly': False, 'type': 'optional'} + Package: grisbi: {'basearchonly': False, 'type': 'optional'} + Package: hnb: {'basearchonly': False, 'type': 'optional'} + Package: htmldoc: {'basearchonly': False, 'type': 'optional'} + Package: jpilot: {'basearchonly': False, 'type': 'optional'} + Package: kchmviewer-qt: {'basearchonly': False, 'type': 'optional'} + Package: kdepim: {'basearchonly': False, 'type': 'optional'} + Package: keurocalc: {'basearchonly': False, 'type': 'optional'} + Package: klatexformula: {'basearchonly': False, 'type': 'optional'} + Package: klatexformula-ktexteditor-plugin: {'basearchonly': False, 'type': 'optional'} + Package: kmymoney: {'basearchonly': False, 'type': 'optional'} + Package: krecipes: {'basearchonly': False, 'type': 'optional'} + Package: kreetingkard: {'basearchonly': False, 'type': 'optional'} + Package: kreetingkard_templates: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-base: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-calc: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-draw: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-emailmerge: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-graphicfilter: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-impress: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-math: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-ogltrans: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-TexMaths: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-voikko: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-wiki-publisher: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-writer: {'basearchonly': False, 'type': 'optional'} + Package: libreoffice-xsltfilter: {'basearchonly': False, 'type': 'optional'} + Package: lyx: {'basearchonly': False, 'type': 'optional'} + Package: MagicPoint: {'basearchonly': False, 'type': 'optional'} + Package: okular: {'basearchonly': False, 'type': 'optional'} + Package: pdfedit: {'basearchonly': False, 'type': 'optional'} + Package: planner: {'basearchonly': False, 'type': 'optional'} + Package: pybliographer: {'basearchonly': False, 'type': 'optional'} + Package: rednotebook: {'basearchonly': False, 'type': 'optional'} + Package: revelation: {'basearchonly': False, 'type': 'optional'} + Package: Saaghar: {'basearchonly': False, 'type': 'optional'} + Package: skrooge: {'basearchonly': False, 'type': 'optional'} + Package: starcal: {'basearchonly': False, 'type': 'optional'} + Package: taskcoach: {'basearchonly': False, 'type': 'optional'} + Package: taskjuggler: {'basearchonly': False, 'type': 'optional'} + Package: tellico: {'basearchonly': False, 'type': 'optional'} + Package: tetex-IEEEtran: {'basearchonly': False, 'type': 'optional'} + Package: texlive-xdvi: {'basearchonly': False, 'type': 'optional'} + Package: texmaker: {'basearchonly': False, 'type': 'optional'} + Package: vym: {'basearchonly': False, 'type': 'optional'} + Package: wyrd: {'basearchonly': False, 'type': 'optional'} + Package: xchm: {'basearchonly': False, 'type': 'optional'} + Package: xfbib: {'basearchonly': False, 'type': 'optional'} + Package: xournal: {'basearchonly': False, 'type': 'optional'} + Package: Zim: {'basearchonly': False, 'type': 'optional'} Group: online-docs (Online Help and Documentation) - Package: system-config-date-docs: {'requires': u'system-config-date', 'type': 'conditional', 'basearchonly': False} - Package: system-config-nfs-docs: {'requires': u'system-config-nfs', 'type': 'conditional', 'basearchonly': False} - Package: system-config-samba-docs: {'requires': u'system-config-samba', 'type': 'conditional', 'basearchonly': False} - Package: system-config-services-docs: {'requires': u'system-config-services', 'type': 'conditional', 'basearchonly': False} - Package: system-config-users-docs: {'requires': u'system-config-users', 'type': 'conditional', 'basearchonly': False} + Package: system-config-date-docs: {'basearchonly': False, 'requires': 'system-config-date', 'type': 'conditional'} + Package: system-config-nfs-docs: {'basearchonly': False, 'requires': 'system-config-nfs', 'type': 'conditional'} + Package: system-config-samba-docs: {'basearchonly': False, 'requires': 'system-config-samba', 'type': 'conditional'} + Package: system-config-services-docs: {'basearchonly': False, 'requires': 'system-config-services', 'type': 'conditional'} + Package: system-config-users-docs: {'basearchonly': False, 'requires': 'system-config-users', 'type': 'conditional'} Group: perl (Perl Development) - Package: perl-core: {'type': 'mandatory', 'basearchonly': False} - Package: cpan-upload: {'type': 'default', 'basearchonly': False} - Package: git-cpan-patch: {'type': 'default', 'basearchonly': False} - Package: perltidy: {'type': 'default', 'basearchonly': False} - Package: cpanspec: {'type': 'optional', 'basearchonly': False} - Package: eclipse-epic: {'type': 'optional', 'basearchonly': False} - Package: parrot: {'type': 'optional', 'basearchonly': False} - Package: perl-Task-Catalyst: {'type': 'optional', 'basearchonly': False} - Package: vim-perl-support: {'type': 'optional', 'basearchonly': False} + Package: perl-core: {'basearchonly': False, 'type': 'mandatory'} + Package: cpan-upload: {'basearchonly': False, 'type': 'default'} + Package: git-cpan-patch: {'basearchonly': False, 'type': 'default'} + Package: perltidy: {'basearchonly': False, 'type': 'default'} + Package: cpanspec: {'basearchonly': False, 'type': 'optional'} + Package: eclipse-epic: {'basearchonly': False, 'type': 'optional'} + Package: parrot: {'basearchonly': False, 'type': 'optional'} + Package: perl-Task-Catalyst: {'basearchonly': False, 'type': 'optional'} + Package: vim-perl-support: {'basearchonly': False, 'type': 'optional'} Group: perl-web (Perl for Web) - Package: ImageMagick-perl: {'type': 'mandatory', 'basearchonly': False} - Package: mod_perl: {'type': 'mandatory', 'basearchonly': False} - Package: perl-App-cpanminus: {'type': 'mandatory', 'basearchonly': False} - Package: perl-core: {'type': 'mandatory', 'basearchonly': False} - Package: perl-CPAN: {'type': 'mandatory', 'basearchonly': False} - Package: perl-CPANPLUS: {'type': 'mandatory', 'basearchonly': False} - Package: perl-DBD-MySQL: {'type': 'mandatory', 'basearchonly': False} - Package: perl-DBD-SQLite: {'type': 'mandatory', 'basearchonly': False} - Package: perl-MongoDB: {'type': 'mandatory', 'basearchonly': False} + Package: ImageMagick-perl: {'basearchonly': False, 'type': 'mandatory'} + Package: mod_perl: {'basearchonly': False, 'type': 'mandatory'} + Package: perl-App-cpanminus: {'basearchonly': False, 'type': 'mandatory'} + Package: perl-core: {'basearchonly': False, 'type': 'mandatory'} + Package: perl-CPAN: {'basearchonly': False, 'type': 'mandatory'} + Package: perl-CPANPLUS: {'basearchonly': False, 'type': 'mandatory'} + Package: perl-DBD-MySQL: {'basearchonly': False, 'type': 'mandatory'} + Package: perl-DBD-SQLite: {'basearchonly': False, 'type': 'mandatory'} + Package: perl-MongoDB: {'basearchonly': False, 'type': 'mandatory'} Group: persian-support (Persian Support) - Package: sil-scheherazade-fonts: {'type': 'default', 'basearchonly': False} - Package: sil-lateef-fonts: {'type': 'optional', 'basearchonly': False} + Package: sil-scheherazade-fonts: {'basearchonly': False, 'type': 'default'} + Package: sil-lateef-fonts: {'basearchonly': False, 'type': 'optional'} Group: php (PHP) - Package: php: {'type': 'mandatory', 'basearchonly': False} - Package: php-bcmath: {'type': 'mandatory', 'basearchonly': False} - Package: php-devel: {'type': 'mandatory', 'basearchonly': False} - Package: php-gd: {'type': 'mandatory', 'basearchonly': False} - Package: php-imap: {'type': 'mandatory', 'basearchonly': False} - Package: php-mbstring: {'type': 'mandatory', 'basearchonly': False} - Package: php-mcrypt: {'type': 'mandatory', 'basearchonly': False} - Package: php-mysqlnd: {'type': 'mandatory', 'basearchonly': False} - Package: php-pdo: {'type': 'mandatory', 'basearchonly': False} - Package: php-pear: {'type': 'mandatory', 'basearchonly': False} - Package: php-pecl-apc: {'type': 'mandatory', 'basearchonly': False} - Package: php-pecl-mongo: {'type': 'mandatory', 'basearchonly': False} - Package: php-pgsql: {'type': 'mandatory', 'basearchonly': False} - Package: php-process: {'type': 'mandatory', 'basearchonly': False} - Package: php-soap: {'type': 'mandatory', 'basearchonly': False} - Package: php-xml: {'type': 'mandatory', 'basearchonly': False} + Package: php: {'basearchonly': False, 'type': 'mandatory'} + Package: php-bcmath: {'basearchonly': False, 'type': 'mandatory'} + Package: php-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: php-gd: {'basearchonly': False, 'type': 'mandatory'} + Package: php-imap: {'basearchonly': False, 'type': 'mandatory'} + Package: php-mbstring: {'basearchonly': False, 'type': 'mandatory'} + Package: php-mcrypt: {'basearchonly': False, 'type': 'mandatory'} + Package: php-mysqlnd: {'basearchonly': False, 'type': 'mandatory'} + Package: php-pdo: {'basearchonly': False, 'type': 'mandatory'} + Package: php-pear: {'basearchonly': False, 'type': 'mandatory'} + Package: php-pecl-apc: {'basearchonly': False, 'type': 'mandatory'} + Package: php-pecl-mongo: {'basearchonly': False, 'type': 'mandatory'} + Package: php-pgsql: {'basearchonly': False, 'type': 'mandatory'} + Package: php-process: {'basearchonly': False, 'type': 'mandatory'} + Package: php-soap: {'basearchonly': False, 'type': 'mandatory'} + Package: php-xml: {'basearchonly': False, 'type': 'mandatory'} Group: platform-vmware (VMware Platform Support) - Package: open-vm-tools: {'type': 'mandatory', 'basearchonly': False} + Package: open-vm-tools: {'basearchonly': False, 'type': 'mandatory'} Group: printing (Printing Support) - Package: cups: {'type': 'mandatory', 'basearchonly': False} - Package: cups-filters: {'type': 'mandatory', 'basearchonly': False} - Package: ghostscript: {'type': 'mandatory', 'basearchonly': False} - Package: bluez-cups: {'type': 'default', 'basearchonly': False} - Package: colord: {'type': 'default', 'basearchonly': False} - Package: cups-pk-helper: {'type': 'default', 'basearchonly': False} - Package: foomatic: {'type': 'default', 'basearchonly': False} - Package: foomatic-db-ppds: {'type': 'default', 'basearchonly': False} - Package: gutenprint: {'type': 'default', 'basearchonly': False} - Package: gutenprint-cups: {'type': 'default', 'basearchonly': False} - Package: hpijs: {'type': 'default', 'basearchonly': False} - Package: hplip: {'type': 'default', 'basearchonly': False} - Package: mpage: {'type': 'default', 'basearchonly': False} - Package: nss-mdns: {'type': 'default', 'basearchonly': False} - Package: paps: {'type': 'default', 'basearchonly': False} - Package: samba-client: {'type': 'default', 'basearchonly': False} - Package: system-config-printer-udev: {'type': 'default', 'basearchonly': False} - Package: a2ps: {'type': 'optional', 'basearchonly': False} - Package: cups-bjnp: {'type': 'optional', 'basearchonly': False} - Package: cups-pdf: {'type': 'optional', 'basearchonly': False} - Package: enscript: {'type': 'optional', 'basearchonly': False} - Package: min12xxw: {'type': 'optional', 'basearchonly': False} - Package: pnm2ppa: {'type': 'optional', 'basearchonly': False} - Package: ptouch-driver: {'type': 'optional', 'basearchonly': False} - Package: splix: {'type': 'optional', 'basearchonly': False} - Package: system-config-printer: {'type': 'optional', 'basearchonly': False} + Package: cups: {'basearchonly': False, 'type': 'mandatory'} + Package: cups-filters: {'basearchonly': False, 'type': 'mandatory'} + Package: ghostscript: {'basearchonly': False, 'type': 'mandatory'} + Package: bluez-cups: {'basearchonly': False, 'type': 'default'} + Package: colord: {'basearchonly': False, 'type': 'default'} + Package: cups-pk-helper: {'basearchonly': False, 'type': 'default'} + Package: foomatic: {'basearchonly': False, 'type': 'default'} + Package: foomatic-db-ppds: {'basearchonly': False, 'type': 'default'} + Package: gutenprint: {'basearchonly': False, 'type': 'default'} + Package: gutenprint-cups: {'basearchonly': False, 'type': 'default'} + Package: hpijs: {'basearchonly': False, 'type': 'default'} + Package: hplip: {'basearchonly': False, 'type': 'default'} + Package: mpage: {'basearchonly': False, 'type': 'default'} + Package: nss-mdns: {'basearchonly': False, 'type': 'default'} + Package: paps: {'basearchonly': False, 'type': 'default'} + Package: samba-client: {'basearchonly': False, 'type': 'default'} + Package: system-config-printer-udev: {'basearchonly': False, 'type': 'default'} + Package: a2ps: {'basearchonly': False, 'type': 'optional'} + Package: cups-bjnp: {'basearchonly': False, 'type': 'optional'} + Package: cups-pdf: {'basearchonly': False, 'type': 'optional'} + Package: enscript: {'basearchonly': False, 'type': 'optional'} + Package: min12xxw: {'basearchonly': False, 'type': 'optional'} + Package: pnm2ppa: {'basearchonly': False, 'type': 'optional'} + Package: ptouch-driver: {'basearchonly': False, 'type': 'optional'} + Package: splix: {'basearchonly': False, 'type': 'optional'} + Package: system-config-printer: {'basearchonly': False, 'type': 'optional'} Group: punjabi-support (Punjabi Support) - Package: lohit-gurmukhi-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: saab-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-gurmukhi-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: saab-fonts: {'basearchonly': False, 'type': 'default'} Group: python-web (Python) - Package: freetype-devel: {'type': 'mandatory', 'basearchonly': False} - Package: libcurl: {'type': 'mandatory', 'basearchonly': False} - Package: libcurl-devel: {'type': 'mandatory', 'basearchonly': False} - Package: libjpeg-turbo: {'type': 'mandatory', 'basearchonly': False} - Package: libjpeg-turbo-devel: {'type': 'mandatory', 'basearchonly': False} - Package: mod_wsgi: {'type': 'mandatory', 'basearchonly': False} - Package: numpy: {'type': 'mandatory', 'basearchonly': False} - Package: numpy-f2py: {'type': 'mandatory', 'basearchonly': False} - Package: pymongo: {'type': 'mandatory', 'basearchonly': False} - Package: pymongo-gridfs: {'type': 'mandatory', 'basearchonly': False} - Package: python: {'type': 'mandatory', 'basearchonly': False} - Package: python-magic: {'type': 'mandatory', 'basearchonly': False} - Package: python-mysql: {'type': 'mandatory', 'basearchonly': False} - Package: python-psycopg2: {'type': 'mandatory', 'basearchonly': False} - Package: python-virtualenv: {'type': 'mandatory', 'basearchonly': False} + Package: freetype-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: libcurl: {'basearchonly': False, 'type': 'mandatory'} + Package: libcurl-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: libjpeg-turbo: {'basearchonly': False, 'type': 'mandatory'} + Package: libjpeg-turbo-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: mod_wsgi: {'basearchonly': False, 'type': 'mandatory'} + Package: numpy: {'basearchonly': False, 'type': 'mandatory'} + Package: numpy-f2py: {'basearchonly': False, 'type': 'mandatory'} + Package: pymongo: {'basearchonly': False, 'type': 'mandatory'} + Package: pymongo-gridfs: {'basearchonly': False, 'type': 'mandatory'} + Package: python: {'basearchonly': False, 'type': 'mandatory'} + Package: python-magic: {'basearchonly': False, 'type': 'mandatory'} + Package: python-mysql: {'basearchonly': False, 'type': 'mandatory'} + Package: python-psycopg2: {'basearchonly': False, 'type': 'mandatory'} + Package: python-virtualenv: {'basearchonly': False, 'type': 'mandatory'} Group: robotics-suite (Robotics) - Package: arduino: {'type': 'default', 'basearchonly': False} - Package: catkin: {'type': 'default', 'basearchonly': False} - Package: eclipse-cdt: {'type': 'default', 'basearchonly': False} - Package: eclipse-egit: {'type': 'default', 'basearchonly': False} - Package: eclipse-subclipse: {'type': 'default', 'basearchonly': False} - Package: fawkes: {'type': 'default', 'basearchonly': False} - Package: fawkes-core: {'type': 'default', 'basearchonly': False} - Package: fawkes-doc: {'type': 'default', 'basearchonly': False} - Package: fawkes-firevision: {'type': 'default', 'basearchonly': False} - Package: fawkes-firevision-tools: {'type': 'default', 'basearchonly': False} - Package: fawkes-guis: {'type': 'default', 'basearchonly': False} - Package: fawkes-lua: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-bblogger: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-bbsync: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-flite: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-joystick: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-katana: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-laser: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-laserht: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-luaagent: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-pantilt: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-player: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-refboxcomm: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-skiller: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-ttmainloop: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-webview: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-worldmodel: {'type': 'default', 'basearchonly': False} - Package: fawkes-plugin-xmlrpc: {'type': 'default', 'basearchonly': False} - Package: gazebo: {'type': 'default', 'basearchonly': False} - Package: gazebo-doc: {'type': 'default', 'basearchonly': False} - Package: gearbox: {'type': 'default', 'basearchonly': False} - Package: libphidget: {'type': 'default', 'basearchonly': False} - Package: mrpt-apps: {'type': 'default', 'basearchonly': False} - Package: mrpt-doc: {'type': 'default', 'basearchonly': False} - Package: mrpt-libs: {'type': 'default', 'basearchonly': False} - Package: opencv: {'type': 'default', 'basearchonly': False} - Package: openni-primesense: {'type': 'default', 'basearchonly': False} - Package: pcl: {'type': 'default', 'basearchonly': False} - Package: player: {'type': 'default', 'basearchonly': False} - Package: player-doc: {'type': 'default', 'basearchonly': False} - Package: player-examples: {'type': 'default', 'basearchonly': False} - Package: player-python: {'type': 'default', 'basearchonly': False} - Package: player-ruby: {'type': 'default', 'basearchonly': False} - Package: python-bloom: {'type': 'default', 'basearchonly': False} - Package: python-catkin_lint: {'type': 'default', 'basearchonly': False} - Package: python-catkin_pkg: {'type': 'default', 'basearchonly': False} - Package: python-catkin_tools: {'type': 'default', 'basearchonly': False} - Package: python-rosdep: {'type': 'default', 'basearchonly': False} - Package: python-rosdistro: {'type': 'default', 'basearchonly': False} - Package: python-rosinstall: {'type': 'default', 'basearchonly': False} - Package: python-rosinstall_generator: {'type': 'default', 'basearchonly': False} - Package: python-rospkg: {'type': 'default', 'basearchonly': False} - Package: python-vcstools: {'type': 'default', 'basearchonly': False} - Package: python-wstool: {'type': 'default', 'basearchonly': False} - Package: rcsslogplayer: {'type': 'default', 'basearchonly': False} - Package: rcssmonitor: {'type': 'default', 'basearchonly': False} - Package: rcssserver: {'type': 'default', 'basearchonly': False} - Package: rcssserver-gui: {'type': 'default', 'basearchonly': False} - Package: rcssserver3d: {'type': 'default', 'basearchonly': False} - Package: rcssserver3d-doc: {'type': 'default', 'basearchonly': False} - Package: stage: {'type': 'default', 'basearchonly': False} - Package: stage-playerplugin: {'type': 'default', 'basearchonly': False} - Package: urg: {'type': 'default', 'basearchonly': False} - Package: fawkes-devel: {'type': 'optional', 'basearchonly': False} - Package: gazebo-devel: {'type': 'optional', 'basearchonly': False} - Package: gearbox-devel: {'type': 'optional', 'basearchonly': False} - Package: libphidget-devel: {'type': 'optional', 'basearchonly': False} - Package: mrpt-devel: {'type': 'optional', 'basearchonly': False} - Package: pcl-devel: {'type': 'optional', 'basearchonly': False} - Package: player-devel: {'type': 'optional', 'basearchonly': False} - Package: rcsslogplayer-devel: {'type': 'optional', 'basearchonly': False} - Package: rcssserver-devel: {'type': 'optional', 'basearchonly': False} - Package: rcssserver3d-devel: {'type': 'optional', 'basearchonly': False} - Package: stage-devel: {'type': 'optional', 'basearchonly': False} - Package: urg-devel: {'type': 'optional', 'basearchonly': False} + Package: arduino: {'basearchonly': False, 'type': 'default'} + Package: catkin: {'basearchonly': False, 'type': 'default'} + Package: eclipse-cdt: {'basearchonly': False, 'type': 'default'} + Package: eclipse-egit: {'basearchonly': False, 'type': 'default'} + Package: eclipse-subclipse: {'basearchonly': False, 'type': 'default'} + Package: fawkes: {'basearchonly': False, 'type': 'default'} + Package: fawkes-core: {'basearchonly': False, 'type': 'default'} + Package: fawkes-doc: {'basearchonly': False, 'type': 'default'} + Package: fawkes-firevision: {'basearchonly': False, 'type': 'default'} + Package: fawkes-firevision-tools: {'basearchonly': False, 'type': 'default'} + Package: fawkes-guis: {'basearchonly': False, 'type': 'default'} + Package: fawkes-lua: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-bblogger: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-bbsync: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-flite: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-joystick: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-katana: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-laser: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-laserht: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-luaagent: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-pantilt: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-player: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-refboxcomm: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-skiller: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-ttmainloop: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-webview: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-worldmodel: {'basearchonly': False, 'type': 'default'} + Package: fawkes-plugin-xmlrpc: {'basearchonly': False, 'type': 'default'} + Package: gazebo: {'basearchonly': False, 'type': 'default'} + Package: gazebo-doc: {'basearchonly': False, 'type': 'default'} + Package: gearbox: {'basearchonly': False, 'type': 'default'} + Package: libphidget: {'basearchonly': False, 'type': 'default'} + Package: mrpt-apps: {'basearchonly': False, 'type': 'default'} + Package: mrpt-doc: {'basearchonly': False, 'type': 'default'} + Package: mrpt-libs: {'basearchonly': False, 'type': 'default'} + Package: opencv: {'basearchonly': False, 'type': 'default'} + Package: openni-primesense: {'basearchonly': False, 'type': 'default'} + Package: pcl: {'basearchonly': False, 'type': 'default'} + Package: player: {'basearchonly': False, 'type': 'default'} + Package: player-doc: {'basearchonly': False, 'type': 'default'} + Package: player-examples: {'basearchonly': False, 'type': 'default'} + Package: player-python: {'basearchonly': False, 'type': 'default'} + Package: player-ruby: {'basearchonly': False, 'type': 'default'} + Package: python-bloom: {'basearchonly': False, 'type': 'default'} + Package: python-catkin_lint: {'basearchonly': False, 'type': 'default'} + Package: python-catkin_pkg: {'basearchonly': False, 'type': 'default'} + Package: python-catkin_tools: {'basearchonly': False, 'type': 'default'} + Package: python-rosdep: {'basearchonly': False, 'type': 'default'} + Package: python-rosdistro: {'basearchonly': False, 'type': 'default'} + Package: python-rosinstall: {'basearchonly': False, 'type': 'default'} + Package: python-rosinstall_generator: {'basearchonly': False, 'type': 'default'} + Package: python-rospkg: {'basearchonly': False, 'type': 'default'} + Package: python-vcstools: {'basearchonly': False, 'type': 'default'} + Package: python-wstool: {'basearchonly': False, 'type': 'default'} + Package: rcsslogplayer: {'basearchonly': False, 'type': 'default'} + Package: rcssmonitor: {'basearchonly': False, 'type': 'default'} + Package: rcssserver: {'basearchonly': False, 'type': 'default'} + Package: rcssserver-gui: {'basearchonly': False, 'type': 'default'} + Package: rcssserver3d: {'basearchonly': False, 'type': 'default'} + Package: rcssserver3d-doc: {'basearchonly': False, 'type': 'default'} + Package: stage: {'basearchonly': False, 'type': 'default'} + Package: stage-playerplugin: {'basearchonly': False, 'type': 'default'} + Package: urg: {'basearchonly': False, 'type': 'default'} + Package: fawkes-devel: {'basearchonly': False, 'type': 'optional'} + Package: gazebo-devel: {'basearchonly': False, 'type': 'optional'} + Package: gearbox-devel: {'basearchonly': False, 'type': 'optional'} + Package: libphidget-devel: {'basearchonly': False, 'type': 'optional'} + Package: mrpt-devel: {'basearchonly': False, 'type': 'optional'} + Package: pcl-devel: {'basearchonly': False, 'type': 'optional'} + Package: player-devel: {'basearchonly': False, 'type': 'optional'} + Package: rcsslogplayer-devel: {'basearchonly': False, 'type': 'optional'} + Package: rcssserver-devel: {'basearchonly': False, 'type': 'optional'} + Package: rcssserver3d-devel: {'basearchonly': False, 'type': 'optional'} + Package: stage-devel: {'basearchonly': False, 'type': 'optional'} + Package: urg-devel: {'basearchonly': False, 'type': 'optional'} Group: rpm-development-tools (RPM Development Tools) - Package: redhat-rpm-config: {'type': 'mandatory', 'basearchonly': False} - Package: rpm-build: {'type': 'mandatory', 'basearchonly': False} - Package: koji: {'type': 'default', 'basearchonly': False} - Package: mock: {'type': 'default', 'basearchonly': False} - Package: rpmdevtools: {'type': 'default', 'basearchonly': False} - Package: plague-client: {'type': 'optional', 'basearchonly': False} - Package: pungi: {'type': 'optional', 'basearchonly': False} - Package: rpmlint: {'type': 'optional', 'basearchonly': False} + Package: redhat-rpm-config: {'basearchonly': False, 'type': 'mandatory'} + Package: rpm-build: {'basearchonly': False, 'type': 'mandatory'} + Package: koji: {'basearchonly': False, 'type': 'default'} + Package: mock: {'basearchonly': False, 'type': 'default'} + Package: rpmdevtools: {'basearchonly': False, 'type': 'default'} + Package: plague-client: {'basearchonly': False, 'type': 'optional'} + Package: pungi: {'basearchonly': False, 'type': 'optional'} + Package: rpmlint: {'basearchonly': False, 'type': 'optional'} Group: ruby (Ruby) - Package: ruby: {'type': 'mandatory', 'basearchonly': False} - Package: ruby-devel: {'type': 'default', 'basearchonly': False} - Package: rubygem-abrt: {'type': 'default', 'basearchonly': False} + Package: ruby: {'basearchonly': False, 'type': 'mandatory'} + Package: ruby-devel: {'basearchonly': False, 'type': 'default'} + Package: rubygem-abrt: {'basearchonly': False, 'type': 'default'} Group: rubyonrails (Ruby on Rails) - Package: nodejs: {'type': 'mandatory', 'basearchonly': False} - Package: ruby-devel: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-abrt: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-bcrypt: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-bigdecimal: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-bundler: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-byebug: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-coffee-rails: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-jbuilder: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-jquery-rails: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-json: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-listen: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-minitest: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-rails: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-rake: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-sass-rails: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-sdoc: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-spring: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-spring-watcher-listen: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-sqlite3: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-turbolinks: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-uglifier: {'type': 'mandatory', 'basearchonly': False} - Package: rubygem-web-console: {'type': 'mandatory', 'basearchonly': False} - Package: sqlite-devel: {'type': 'mandatory', 'basearchonly': False} + Package: nodejs: {'basearchonly': False, 'type': 'mandatory'} + Package: ruby-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-abrt: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-bcrypt: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-bigdecimal: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-bundler: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-byebug: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-coffee-rails: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-jbuilder: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-jquery-rails: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-json: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-listen: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-minitest: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-rails: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-rake: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-sass-rails: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-sdoc: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-spring: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-spring-watcher-listen: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-sqlite3: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-turbolinks: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-uglifier: {'basearchonly': False, 'type': 'mandatory'} + Package: rubygem-web-console: {'basearchonly': False, 'type': 'mandatory'} + Package: sqlite-devel: {'basearchonly': False, 'type': 'mandatory'} Group: russian-support (Russian Support) - Package: paratype-pt-sans-fonts: {'type': 'default', 'basearchonly': False} - Package: apanov-edrip-fonts: {'type': 'optional', 'basearchonly': False} - Package: apanov-heuristica-fonts: {'type': 'optional', 'basearchonly': False} - Package: fonts-KOI8-R: {'type': 'optional', 'basearchonly': False} - Package: fonts-KOI8-R-100dpi: {'type': 'optional', 'basearchonly': False} - Package: fonts-KOI8-R-75dpi: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-cyrillic: {'type': 'optional', 'basearchonly': False} - Package: paratype-pt-mono-fonts: {'type': 'optional', 'basearchonly': False} - Package: paratype-pt-sans-caption-fonts: {'type': 'optional', 'basearchonly': False} - Package: paratype-pt-serif-caption-fonts: {'type': 'optional', 'basearchonly': False} - Package: paratype-pt-serif-fonts: {'type': 'optional', 'basearchonly': False} - Package: scim-tables-russian: {'type': 'optional', 'basearchonly': False} - Package: stardict-dic-ru: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-fonts-cyrillic: {'type': 'optional', 'basearchonly': False} + Package: paratype-pt-sans-fonts: {'basearchonly': False, 'type': 'default'} + Package: apanov-edrip-fonts: {'basearchonly': False, 'type': 'optional'} + Package: apanov-heuristica-fonts: {'basearchonly': False, 'type': 'optional'} + Package: fonts-KOI8-R: {'basearchonly': False, 'type': 'optional'} + Package: fonts-KOI8-R-100dpi: {'basearchonly': False, 'type': 'optional'} + Package: fonts-KOI8-R-75dpi: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-cyrillic: {'basearchonly': False, 'type': 'optional'} + Package: paratype-pt-mono-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paratype-pt-sans-caption-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paratype-pt-serif-caption-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paratype-pt-serif-fonts: {'basearchonly': False, 'type': 'optional'} + Package: scim-tables-russian: {'basearchonly': False, 'type': 'optional'} + Package: stardict-dic-ru: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-fonts-cyrillic: {'basearchonly': False, 'type': 'optional'} Group: sanskrit-support (Sanskrit Support) - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} Group: santali-support (Santali Support) - Package: lohit-devanagari-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: samyak-devanagari-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: samyak-devanagari-fonts: {'basearchonly': False, 'type': 'default'} Group: security-lab (Security Lab) - Package: afftools: {'type': 'default', 'basearchonly': False} - Package: aide: {'type': 'default', 'basearchonly': False} - Package: aircrack-ng: {'type': 'default', 'basearchonly': False} - Package: airsnort: {'type': 'default', 'basearchonly': False} - Package: argus: {'type': 'default', 'basearchonly': False} - Package: argus-clients: {'type': 'default', 'basearchonly': False} - Package: arp-scan: {'type': 'default', 'basearchonly': False} - Package: ArpON: {'type': 'default', 'basearchonly': False} - Package: bannergrab: {'type': 'default', 'basearchonly': False} - Package: binwalk: {'type': 'default', 'basearchonly': False} - Package: bkhive: {'type': 'default', 'basearchonly': False} - Package: bonesi: {'type': 'default', 'basearchonly': False} - Package: bro: {'type': 'default', 'basearchonly': False} - Package: chkrootkit: {'type': 'default', 'basearchonly': False} - Package: cmospwd: {'type': 'default', 'basearchonly': False} - Package: cowpatty: {'type': 'default', 'basearchonly': False} - Package: dc3dd: {'type': 'default', 'basearchonly': False} - Package: ddrescue: {'type': 'default', 'basearchonly': False} - Package: dhcping: {'type': 'default', 'basearchonly': False} - Package: dnsenum: {'type': 'default', 'basearchonly': False} - Package: dnsmap: {'type': 'default', 'basearchonly': False} - Package: dnstop: {'type': 'default', 'basearchonly': False} - Package: dnstracer: {'type': 'default', 'basearchonly': False} - Package: driftnet: {'type': 'default', 'basearchonly': False} - Package: dsniff: {'type': 'default', 'basearchonly': False} - Package: echoping: {'type': 'default', 'basearchonly': False} - Package: etherape: {'type': 'default', 'basearchonly': False} - Package: ettercap: {'type': 'default', 'basearchonly': False} - Package: examiner: {'type': 'default', 'basearchonly': False} - Package: firewalk: {'type': 'default', 'basearchonly': False} - Package: flawfinder: {'type': 'default', 'basearchonly': False} - Package: foremost: {'type': 'default', 'basearchonly': False} - Package: fping: {'type': 'default', 'basearchonly': False} - Package: goaccess: {'type': 'default', 'basearchonly': False} - Package: gparted: {'type': 'default', 'basearchonly': False} - Package: halberd: {'type': 'default', 'basearchonly': False} - Package: hexedit: {'type': 'default', 'basearchonly': False} - Package: hfsutils: {'type': 'default', 'basearchonly': False} - Package: horst: {'type': 'default', 'basearchonly': False} - Package: hping3: {'type': 'default', 'basearchonly': False} - Package: ht: {'type': 'default', 'basearchonly': False} - Package: httpie: {'type': 'default', 'basearchonly': False} - Package: httping: {'type': 'default', 'basearchonly': False} - Package: httpry: {'type': 'default', 'basearchonly': False} - Package: httrack: {'type': 'default', 'basearchonly': False} - Package: hunt: {'type': 'default', 'basearchonly': False} - Package: hydra: {'type': 'default', 'basearchonly': False} - Package: iftop: {'type': 'default', 'basearchonly': False} - Package: inception: {'type': 'default', 'basearchonly': False} - Package: iperf: {'type': 'default', 'basearchonly': False} - Package: iptraf-ng: {'type': 'default', 'basearchonly': False} - Package: irssi: {'type': 'default', 'basearchonly': False} - Package: john: {'type': 'default', 'basearchonly': False} - Package: kismet: {'type': 'default', 'basearchonly': False} - Package: kismon: {'type': 'default', 'basearchonly': False} - Package: labrea: {'type': 'default', 'basearchonly': False} - Package: lbd: {'type': 'default', 'basearchonly': False} - Package: lnav: {'type': 'default', 'basearchonly': False} - Package: lynis: {'type': 'default', 'basearchonly': False} - Package: macchanger: {'type': 'default', 'basearchonly': False} - Package: masscan: {'type': 'default', 'basearchonly': False} - Package: mc: {'type': 'default', 'basearchonly': False} - Package: mcabber: {'type': 'default', 'basearchonly': False} - Package: medusa: {'type': 'default', 'basearchonly': False} - Package: mtr: {'type': 'default', 'basearchonly': False} - Package: mutt: {'type': 'default', 'basearchonly': False} - Package: nano: {'type': 'default', 'basearchonly': False} - Package: nbtscan: {'type': 'default', 'basearchonly': False} - Package: ncrack: {'type': 'default', 'basearchonly': False} - Package: nebula: {'type': 'default', 'basearchonly': False} - Package: net-snmp: {'type': 'default', 'basearchonly': False} - Package: net-snmp-utils: {'type': 'default', 'basearchonly': False} - Package: nethogs: {'type': 'default', 'basearchonly': False} - Package: netsed: {'type': 'default', 'basearchonly': False} - Package: netsniff-ng: {'type': 'default', 'basearchonly': False} - Package: nfswatch: {'type': 'default', 'basearchonly': False} - Package: ngrep: {'type': 'default', 'basearchonly': False} - Package: nikto: {'type': 'default', 'basearchonly': False} - Package: nload: {'type': 'default', 'basearchonly': False} - Package: nmap: {'type': 'default', 'basearchonly': False} - Package: nmap-frontend: {'type': 'default', 'basearchonly': False} - Package: nmap-ncat: {'type': 'default', 'basearchonly': False} - Package: nmbscan: {'type': 'default', 'basearchonly': False} - Package: ntfs-3g: {'type': 'default', 'basearchonly': False} - Package: ntfsprogs: {'type': 'default', 'basearchonly': False} - Package: ntop: {'type': 'default', 'basearchonly': False} - Package: ntp: {'type': 'default', 'basearchonly': False} - Package: nwipe: {'type': 'default', 'basearchonly': False} - Package: onesixtyone: {'type': 'default', 'basearchonly': False} - Package: openssh: {'type': 'default', 'basearchonly': False} - Package: openvas-cli: {'type': 'default', 'basearchonly': False} - Package: openvas-scanner: {'type': 'default', 'basearchonly': False} - Package: ophcrack: {'type': 'default', 'basearchonly': False} - Package: p0f: {'type': 'default', 'basearchonly': False} - Package: packETH: {'type': 'default', 'basearchonly': False} - Package: pads: {'type': 'default', 'basearchonly': False} - Package: paris-traceroute: {'type': 'default', 'basearchonly': False} - Package: pcapdiff: {'type': 'default', 'basearchonly': False} - Package: pdfcrack: {'type': 'default', 'basearchonly': False} - Package: powertop: {'type': 'default', 'basearchonly': False} - Package: proxychains: {'type': 'default', 'basearchonly': False} - Package: pscan: {'type': 'default', 'basearchonly': False} - Package: pwgen: {'type': 'default', 'basearchonly': False} - Package: pyrit: {'type': 'default', 'basearchonly': False} - Package: raddump: {'type': 'default', 'basearchonly': False} - Package: ratproxy: {'type': 'default', 'basearchonly': False} - Package: rats: {'type': 'default', 'basearchonly': False} - Package: rkhunter: {'type': 'default', 'basearchonly': False} - Package: safecopy: {'type': 'default', 'basearchonly': False} - Package: samdump2: {'type': 'default', 'basearchonly': False} - Package: scalpel: {'type': 'default', 'basearchonly': False} - Package: scamper: {'type': 'default', 'basearchonly': False} - Package: scanmem: {'type': 'default', 'basearchonly': False} - Package: scapy: {'type': 'default', 'basearchonly': False} - Package: screen: {'type': 'default', 'basearchonly': False} - Package: scrub: {'type': 'default', 'basearchonly': False} - Package: siege: {'type': 'default', 'basearchonly': False} - Package: sing: {'type': 'default', 'basearchonly': False} - Package: sipp: {'type': 'default', 'basearchonly': False} - Package: sipsak: {'type': 'default', 'basearchonly': False} - Package: skipfish: {'type': 'default', 'basearchonly': False} - Package: sleuthkit: {'type': 'default', 'basearchonly': False} - Package: slowhttptest: {'type': 'default', 'basearchonly': False} - Package: snmpcheck: {'type': 'default', 'basearchonly': False} - Package: socat: {'type': 'default', 'basearchonly': False} - Package: splint: {'type': 'default', 'basearchonly': False} - Package: sqlninja: {'type': 'default', 'basearchonly': False} - Package: srm: {'type': 'default', 'basearchonly': False} - Package: ssldump: {'type': 'default', 'basearchonly': False} - Package: sslscan: {'type': 'default', 'basearchonly': False} - Package: sslsplit: {'type': 'default', 'basearchonly': False} - Package: sslstrip: {'type': 'default', 'basearchonly': False} - Package: subnetcalc: {'type': 'default', 'basearchonly': False} - Package: sucrack: {'type': 'default', 'basearchonly': False} - Package: swaks: {'type': 'default', 'basearchonly': False} - Package: tcpcopy: {'type': 'default', 'basearchonly': False} - Package: tcpdump: {'type': 'default', 'basearchonly': False} - Package: tcpflow: {'type': 'default', 'basearchonly': False} - Package: tcpick: {'type': 'default', 'basearchonly': False} - Package: tcpjunk: {'type': 'default', 'basearchonly': False} - Package: tcpreen: {'type': 'default', 'basearchonly': False} - Package: tcpreplay: {'type': 'default', 'basearchonly': False} - Package: tcptrack: {'type': 'default', 'basearchonly': False} - Package: tcpxtract: {'type': 'default', 'basearchonly': False} - Package: telnet: {'type': 'default', 'basearchonly': False} - Package: testdisk: {'type': 'default', 'basearchonly': False} - Package: trafshow: {'type': 'default', 'basearchonly': False} - Package: tripwire: {'type': 'default', 'basearchonly': False} - Package: unhide: {'type': 'default', 'basearchonly': False} - Package: unicornscan: {'type': 'default', 'basearchonly': False} - Package: uperf: {'type': 'default', 'basearchonly': False} - Package: vim-enhanced: {'type': 'default', 'basearchonly': False} - Package: vnstat: {'type': 'default', 'basearchonly': False} - Package: wavemon: {'type': 'default', 'basearchonly': False} - Package: wbox: {'type': 'default', 'basearchonly': False} - Package: weplab: {'type': 'default', 'basearchonly': False} - Package: wget: {'type': 'default', 'basearchonly': False} - Package: whois: {'type': 'default', 'basearchonly': False} - Package: wipe: {'type': 'default', 'basearchonly': False} - Package: wireshark: {'type': 'default', 'basearchonly': False} - Package: xmount: {'type': 'default', 'basearchonly': False} - Package: yersinia: {'type': 'default', 'basearchonly': False} - Package: zmap: {'type': 'default', 'basearchonly': False} + Package: afftools: {'basearchonly': False, 'type': 'default'} + Package: aide: {'basearchonly': False, 'type': 'default'} + Package: aircrack-ng: {'basearchonly': False, 'type': 'default'} + Package: airsnort: {'basearchonly': False, 'type': 'default'} + Package: argus: {'basearchonly': False, 'type': 'default'} + Package: argus-clients: {'basearchonly': False, 'type': 'default'} + Package: arp-scan: {'basearchonly': False, 'type': 'default'} + Package: ArpON: {'basearchonly': False, 'type': 'default'} + Package: bannergrab: {'basearchonly': False, 'type': 'default'} + Package: binwalk: {'basearchonly': False, 'type': 'default'} + Package: bkhive: {'basearchonly': False, 'type': 'default'} + Package: bonesi: {'basearchonly': False, 'type': 'default'} + Package: bro: {'basearchonly': False, 'type': 'default'} + Package: chkrootkit: {'basearchonly': False, 'type': 'default'} + Package: cmospwd: {'basearchonly': False, 'type': 'default'} + Package: cowpatty: {'basearchonly': False, 'type': 'default'} + Package: dc3dd: {'basearchonly': False, 'type': 'default'} + Package: ddrescue: {'basearchonly': False, 'type': 'default'} + Package: dhcping: {'basearchonly': False, 'type': 'default'} + Package: dnsenum: {'basearchonly': False, 'type': 'default'} + Package: dnsmap: {'basearchonly': False, 'type': 'default'} + Package: dnstop: {'basearchonly': False, 'type': 'default'} + Package: dnstracer: {'basearchonly': False, 'type': 'default'} + Package: driftnet: {'basearchonly': False, 'type': 'default'} + Package: dsniff: {'basearchonly': False, 'type': 'default'} + Package: echoping: {'basearchonly': False, 'type': 'default'} + Package: etherape: {'basearchonly': False, 'type': 'default'} + Package: ettercap: {'basearchonly': False, 'type': 'default'} + Package: examiner: {'basearchonly': False, 'type': 'default'} + Package: firewalk: {'basearchonly': False, 'type': 'default'} + Package: flawfinder: {'basearchonly': False, 'type': 'default'} + Package: foremost: {'basearchonly': False, 'type': 'default'} + Package: fping: {'basearchonly': False, 'type': 'default'} + Package: goaccess: {'basearchonly': False, 'type': 'default'} + Package: gparted: {'basearchonly': False, 'type': 'default'} + Package: halberd: {'basearchonly': False, 'type': 'default'} + Package: hexedit: {'basearchonly': False, 'type': 'default'} + Package: hfsutils: {'basearchonly': False, 'type': 'default'} + Package: horst: {'basearchonly': False, 'type': 'default'} + Package: hping3: {'basearchonly': False, 'type': 'default'} + Package: ht: {'basearchonly': False, 'type': 'default'} + Package: httpie: {'basearchonly': False, 'type': 'default'} + Package: httping: {'basearchonly': False, 'type': 'default'} + Package: httpry: {'basearchonly': False, 'type': 'default'} + Package: httrack: {'basearchonly': False, 'type': 'default'} + Package: hunt: {'basearchonly': False, 'type': 'default'} + Package: hydra: {'basearchonly': False, 'type': 'default'} + Package: iftop: {'basearchonly': False, 'type': 'default'} + Package: inception: {'basearchonly': False, 'type': 'default'} + Package: iperf: {'basearchonly': False, 'type': 'default'} + Package: iptraf-ng: {'basearchonly': False, 'type': 'default'} + Package: irssi: {'basearchonly': False, 'type': 'default'} + Package: john: {'basearchonly': False, 'type': 'default'} + Package: kismet: {'basearchonly': False, 'type': 'default'} + Package: kismon: {'basearchonly': False, 'type': 'default'} + Package: labrea: {'basearchonly': False, 'type': 'default'} + Package: lbd: {'basearchonly': False, 'type': 'default'} + Package: lnav: {'basearchonly': False, 'type': 'default'} + Package: lynis: {'basearchonly': False, 'type': 'default'} + Package: macchanger: {'basearchonly': False, 'type': 'default'} + Package: masscan: {'basearchonly': False, 'type': 'default'} + Package: mc: {'basearchonly': False, 'type': 'default'} + Package: mcabber: {'basearchonly': False, 'type': 'default'} + Package: medusa: {'basearchonly': False, 'type': 'default'} + Package: mtr: {'basearchonly': False, 'type': 'default'} + Package: mutt: {'basearchonly': False, 'type': 'default'} + Package: nano: {'basearchonly': False, 'type': 'default'} + Package: nbtscan: {'basearchonly': False, 'type': 'default'} + Package: ncrack: {'basearchonly': False, 'type': 'default'} + Package: nebula: {'basearchonly': False, 'type': 'default'} + Package: net-snmp: {'basearchonly': False, 'type': 'default'} + Package: net-snmp-utils: {'basearchonly': False, 'type': 'default'} + Package: nethogs: {'basearchonly': False, 'type': 'default'} + Package: netsed: {'basearchonly': False, 'type': 'default'} + Package: netsniff-ng: {'basearchonly': False, 'type': 'default'} + Package: nfswatch: {'basearchonly': False, 'type': 'default'} + Package: ngrep: {'basearchonly': False, 'type': 'default'} + Package: nikto: {'basearchonly': False, 'type': 'default'} + Package: nload: {'basearchonly': False, 'type': 'default'} + Package: nmap: {'basearchonly': False, 'type': 'default'} + Package: nmap-frontend: {'basearchonly': False, 'type': 'default'} + Package: nmap-ncat: {'basearchonly': False, 'type': 'default'} + Package: nmbscan: {'basearchonly': False, 'type': 'default'} + Package: ntfs-3g: {'basearchonly': False, 'type': 'default'} + Package: ntfsprogs: {'basearchonly': False, 'type': 'default'} + Package: ntop: {'basearchonly': False, 'type': 'default'} + Package: ntp: {'basearchonly': False, 'type': 'default'} + Package: nwipe: {'basearchonly': False, 'type': 'default'} + Package: onesixtyone: {'basearchonly': False, 'type': 'default'} + Package: openssh: {'basearchonly': False, 'type': 'default'} + Package: openvas-cli: {'basearchonly': False, 'type': 'default'} + Package: openvas-scanner: {'basearchonly': False, 'type': 'default'} + Package: ophcrack: {'basearchonly': False, 'type': 'default'} + Package: p0f: {'basearchonly': False, 'type': 'default'} + Package: packETH: {'basearchonly': False, 'type': 'default'} + Package: pads: {'basearchonly': False, 'type': 'default'} + Package: paris-traceroute: {'basearchonly': False, 'type': 'default'} + Package: pcapdiff: {'basearchonly': False, 'type': 'default'} + Package: pdfcrack: {'basearchonly': False, 'type': 'default'} + Package: powertop: {'basearchonly': False, 'type': 'default'} + Package: proxychains: {'basearchonly': False, 'type': 'default'} + Package: pscan: {'basearchonly': False, 'type': 'default'} + Package: pwgen: {'basearchonly': False, 'type': 'default'} + Package: pyrit: {'basearchonly': False, 'type': 'default'} + Package: raddump: {'basearchonly': False, 'type': 'default'} + Package: ratproxy: {'basearchonly': False, 'type': 'default'} + Package: rats: {'basearchonly': False, 'type': 'default'} + Package: rkhunter: {'basearchonly': False, 'type': 'default'} + Package: safecopy: {'basearchonly': False, 'type': 'default'} + Package: samdump2: {'basearchonly': False, 'type': 'default'} + Package: scalpel: {'basearchonly': False, 'type': 'default'} + Package: scamper: {'basearchonly': False, 'type': 'default'} + Package: scanmem: {'basearchonly': False, 'type': 'default'} + Package: scapy: {'basearchonly': False, 'type': 'default'} + Package: screen: {'basearchonly': False, 'type': 'default'} + Package: scrub: {'basearchonly': False, 'type': 'default'} + Package: siege: {'basearchonly': False, 'type': 'default'} + Package: sing: {'basearchonly': False, 'type': 'default'} + Package: sipp: {'basearchonly': False, 'type': 'default'} + Package: sipsak: {'basearchonly': False, 'type': 'default'} + Package: skipfish: {'basearchonly': False, 'type': 'default'} + Package: sleuthkit: {'basearchonly': False, 'type': 'default'} + Package: slowhttptest: {'basearchonly': False, 'type': 'default'} + Package: snmpcheck: {'basearchonly': False, 'type': 'default'} + Package: socat: {'basearchonly': False, 'type': 'default'} + Package: splint: {'basearchonly': False, 'type': 'default'} + Package: sqlninja: {'basearchonly': False, 'type': 'default'} + Package: srm: {'basearchonly': False, 'type': 'default'} + Package: ssldump: {'basearchonly': False, 'type': 'default'} + Package: sslscan: {'basearchonly': False, 'type': 'default'} + Package: sslsplit: {'basearchonly': False, 'type': 'default'} + Package: sslstrip: {'basearchonly': False, 'type': 'default'} + Package: subnetcalc: {'basearchonly': False, 'type': 'default'} + Package: sucrack: {'basearchonly': False, 'type': 'default'} + Package: swaks: {'basearchonly': False, 'type': 'default'} + Package: tcpcopy: {'basearchonly': False, 'type': 'default'} + Package: tcpdump: {'basearchonly': False, 'type': 'default'} + Package: tcpflow: {'basearchonly': False, 'type': 'default'} + Package: tcpick: {'basearchonly': False, 'type': 'default'} + Package: tcpjunk: {'basearchonly': False, 'type': 'default'} + Package: tcpreen: {'basearchonly': False, 'type': 'default'} + Package: tcpreplay: {'basearchonly': False, 'type': 'default'} + Package: tcptrack: {'basearchonly': False, 'type': 'default'} + Package: tcpxtract: {'basearchonly': False, 'type': 'default'} + Package: telnet: {'basearchonly': False, 'type': 'default'} + Package: testdisk: {'basearchonly': False, 'type': 'default'} + Package: trafshow: {'basearchonly': False, 'type': 'default'} + Package: tripwire: {'basearchonly': False, 'type': 'default'} + Package: unhide: {'basearchonly': False, 'type': 'default'} + Package: unicornscan: {'basearchonly': False, 'type': 'default'} + Package: uperf: {'basearchonly': False, 'type': 'default'} + Package: vim-enhanced: {'basearchonly': False, 'type': 'default'} + Package: vnstat: {'basearchonly': False, 'type': 'default'} + Package: wavemon: {'basearchonly': False, 'type': 'default'} + Package: wbox: {'basearchonly': False, 'type': 'default'} + Package: weplab: {'basearchonly': False, 'type': 'default'} + Package: wget: {'basearchonly': False, 'type': 'default'} + Package: whois: {'basearchonly': False, 'type': 'default'} + Package: wipe: {'basearchonly': False, 'type': 'default'} + Package: wireshark: {'basearchonly': False, 'type': 'default'} + Package: xmount: {'basearchonly': False, 'type': 'default'} + Package: yersinia: {'basearchonly': False, 'type': 'default'} + Package: zmap: {'basearchonly': False, 'type': 'default'} Group: server-cfg (Server Configuration Tools) - Package: cups-pk-helper: {'type': 'default', 'basearchonly': False} - Package: system-config-httpd: {'type': 'default', 'basearchonly': False} - Package: system-config-nfs: {'type': 'default', 'basearchonly': False} - Package: system-config-samba: {'type': 'default', 'basearchonly': False} - Package: system-config-services: {'type': 'default', 'basearchonly': False} - Package: system-config-bind: {'type': 'optional', 'basearchonly': False} - Package: system-config-printer: {'type': 'optional', 'basearchonly': False} - Package: system-switch-mail-gnome: {'type': 'optional', 'basearchonly': False} + Package: cups-pk-helper: {'basearchonly': False, 'type': 'default'} + Package: system-config-httpd: {'basearchonly': False, 'type': 'default'} + Package: system-config-nfs: {'basearchonly': False, 'type': 'default'} + Package: system-config-samba: {'basearchonly': False, 'type': 'default'} + Package: system-config-services: {'basearchonly': False, 'type': 'default'} + Package: system-config-bind: {'basearchonly': False, 'type': 'optional'} + Package: system-config-printer: {'basearchonly': False, 'type': 'optional'} + Package: system-switch-mail-gnome: {'basearchonly': False, 'type': 'optional'} Group: server-hardware-support (Hardware Support for Server Systems) - Package: lm_sensors: {'type': 'default', 'basearchonly': False} - Package: openhpi: {'type': 'default', 'basearchonly': False} - Package: smp_utils: {'type': 'default', 'basearchonly': False} - Package: firmware-addon-dell: {'type': 'optional', 'basearchonly': False} - Package: hddtemp: {'type': 'optional', 'basearchonly': False} - Package: hdparm: {'type': 'optional', 'basearchonly': False} - Package: lsscsi: {'type': 'optional', 'basearchonly': False} + Package: lm_sensors: {'basearchonly': False, 'type': 'default'} + Package: openhpi: {'basearchonly': False, 'type': 'default'} + Package: smp_utils: {'basearchonly': False, 'type': 'default'} + Package: firmware-addon-dell: {'basearchonly': False, 'type': 'optional'} + Package: hddtemp: {'basearchonly': False, 'type': 'optional'} + Package: hdparm: {'basearchonly': False, 'type': 'optional'} + Package: lsscsi: {'basearchonly': False, 'type': 'optional'} Group: server-product (Fedora Server product core) - Package: chrony: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-release-server: {'type': 'mandatory', 'basearchonly': False} - Package: PackageKit: {'type': 'mandatory', 'basearchonly': False} - Package: polkit: {'type': 'mandatory', 'basearchonly': False} - Package: realmd: {'type': 'mandatory', 'basearchonly': False} - Package: timedatex: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-team: {'type': 'default', 'basearchonly': False} + Package: chrony: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-release-server: {'basearchonly': False, 'type': 'mandatory'} + Package: PackageKit: {'basearchonly': False, 'type': 'mandatory'} + Package: polkit: {'basearchonly': False, 'type': 'mandatory'} + Package: realmd: {'basearchonly': False, 'type': 'mandatory'} + Package: timedatex: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-team: {'basearchonly': False, 'type': 'default'} Group: simplified-chinese-support (Simplified Chinese Support) - Package: ibus-libpinyin: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: adobe-source-han-sans-cn-fonts: {'type': 'default', 'basearchonly': False} - Package: fcitx: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-erbi: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-wubi-haifeng: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-wubi-jidian: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-yong: {'type': 'optional', 'basearchonly': False} - Package: lv: {'type': 'optional', 'basearchonly': False} - Package: m17n-db-extras: {'type': 'optional', 'basearchonly': False} - Package: scim-fcitx: {'type': 'optional', 'basearchonly': False} - Package: scim-pinyin: {'type': 'optional', 'basearchonly': False} - Package: scim-tables-chinese: {'type': 'optional', 'basearchonly': False} - Package: scim-tables-chinese-extra: {'type': 'optional', 'basearchonly': False} - Package: stardict-dic-zh_CN: {'type': 'optional', 'basearchonly': False} - Package: wqy-bitmap-fonts: {'type': 'optional', 'basearchonly': False} - Package: wqy-microhei-fonts: {'type': 'optional', 'basearchonly': False} - Package: wqy-unibit-fonts: {'type': 'optional', 'basearchonly': False} - Package: wqy-zenhei-fonts: {'type': 'optional', 'basearchonly': False} + Package: ibus-libpinyin: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: adobe-source-han-sans-cn-fonts: {'basearchonly': False, 'type': 'default'} + Package: fcitx: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-erbi: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-wubi-haifeng: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-wubi-jidian: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-yong: {'basearchonly': False, 'type': 'optional'} + Package: lv: {'basearchonly': False, 'type': 'optional'} + Package: m17n-db-extras: {'basearchonly': False, 'type': 'optional'} + Package: scim-fcitx: {'basearchonly': False, 'type': 'optional'} + Package: scim-pinyin: {'basearchonly': False, 'type': 'optional'} + Package: scim-tables-chinese: {'basearchonly': False, 'type': 'optional'} + Package: scim-tables-chinese-extra: {'basearchonly': False, 'type': 'optional'} + Package: stardict-dic-zh_CN: {'basearchonly': False, 'type': 'optional'} + Package: wqy-bitmap-fonts: {'basearchonly': False, 'type': 'optional'} + Package: wqy-microhei-fonts: {'basearchonly': False, 'type': 'optional'} + Package: wqy-unibit-fonts: {'basearchonly': False, 'type': 'optional'} + Package: wqy-zenhei-fonts: {'basearchonly': False, 'type': 'optional'} Group: sindhi-support (Sindhi Support) - Package: lohit-devanagari-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: paktype-naskh-basic-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-devanagari-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-devanagari-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} + Package: lohit-devanagari-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: paktype-naskh-basic-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-devanagari-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-devanagari-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} Group: sinhala-support (Sinhala Support) - Package: lklug-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: ibus-sayura: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: scim-sayura: {'type': 'optional', 'basearchonly': False} + Package: lklug-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: ibus-sayura: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: scim-sayura: {'basearchonly': False, 'type': 'optional'} Group: smb-server (Windows File Server) - Package: samba: {'type': 'mandatory', 'basearchonly': False} - Package: samba-client: {'type': 'mandatory', 'basearchonly': False} - Package: cifs-utils: {'type': 'default', 'basearchonly': False} + Package: samba: {'basearchonly': False, 'type': 'mandatory'} + Package: samba-client: {'basearchonly': False, 'type': 'mandatory'} + Package: cifs-utils: {'basearchonly': False, 'type': 'default'} Group: sound-and-video (Sound and Video) - Package: abcde: {'type': 'optional', 'basearchonly': False} - Package: adplay: {'type': 'optional', 'basearchonly': False} - Package: alsamixergui: {'type': 'optional', 'basearchonly': False} - Package: amarok: {'type': 'optional', 'basearchonly': False} - Package: argyllcms: {'type': 'optional', 'basearchonly': False} - Package: asunder: {'type': 'optional', 'basearchonly': False} - Package: audacious: {'type': 'optional', 'basearchonly': False} - Package: audacity: {'type': 'optional', 'basearchonly': False} - Package: banshee: {'type': 'optional', 'basearchonly': False} - Package: brasero: {'type': 'optional', 'basearchonly': False} - Package: camE: {'type': 'optional', 'basearchonly': False} - Package: cdcollect: {'type': 'optional', 'basearchonly': False} - Package: cdlabelgen: {'type': 'optional', 'basearchonly': False} - Package: cdparanoia: {'type': 'optional', 'basearchonly': False} - Package: cdrskin: {'type': 'optional', 'basearchonly': False} - Package: cmusphinx3: {'type': 'optional', 'basearchonly': False} - Package: csound-csoundac: {'type': 'optional', 'basearchonly': False} - Package: decibel-audio-player: {'type': 'optional', 'basearchonly': False} - Package: denemo: {'type': 'optional', 'basearchonly': False} - Package: dragon: {'type': 'optional', 'basearchonly': False} - Package: dvdauthor: {'type': 'optional', 'basearchonly': False} - Package: dvdisaster: {'type': 'optional', 'basearchonly': False} - Package: dvgrab: {'type': 'optional', 'basearchonly': False} - Package: easytag: {'type': 'optional', 'basearchonly': False} - Package: exaile: {'type': 'optional', 'basearchonly': False} - Package: festvox-bdl-arctic-hts: {'type': 'optional', 'basearchonly': False} - Package: festvox-clb-arctic-hts: {'type': 'optional', 'basearchonly': False} - Package: festvox-rms-arctic-hts: {'type': 'optional', 'basearchonly': False} - Package: gcstar: {'type': 'optional', 'basearchonly': False} - Package: genisoimage: {'type': 'optional', 'basearchonly': False} - Package: gnomad2: {'type': 'optional', 'basearchonly': False} - Package: gnome-sound-recorder: {'type': 'optional', 'basearchonly': False} - Package: gnomebaker: {'type': 'optional', 'basearchonly': False} - Package: grip: {'type': 'optional', 'basearchonly': False} - Package: gtk-v4l: {'type': 'optional', 'basearchonly': False} - Package: gtkpod: {'type': 'optional', 'basearchonly': False} - Package: icedax: {'type': 'optional', 'basearchonly': False} - Package: id3v2: {'type': 'optional', 'basearchonly': False} - Package: irstlm: {'type': 'optional', 'basearchonly': False} - Package: isomaster: {'type': 'optional', 'basearchonly': False} - Package: jack-audio-connection-kit: {'type': 'optional', 'basearchonly': False} - Package: juk: {'type': 'optional', 'basearchonly': False} - Package: k3b: {'type': 'optional', 'basearchonly': False} - Package: kid3: {'type': 'optional', 'basearchonly': False} - Package: kmix: {'type': 'optional', 'basearchonly': False} - Package: kover: {'type': 'optional', 'basearchonly': False} - Package: kscd: {'type': 'optional', 'basearchonly': False} - Package: lingot: {'type': 'optional', 'basearchonly': False} - Package: lxmusic: {'type': 'optional', 'basearchonly': False} - Package: mikmod: {'type': 'optional', 'basearchonly': False} - Package: milkytracker: {'type': 'optional', 'basearchonly': False} - Package: mkvtoolnix-gui: {'type': 'optional', 'basearchonly': False} - Package: multimedia-menus: {'type': 'optional', 'basearchonly': False} - Package: mybashburn: {'type': 'optional', 'basearchonly': False} - Package: nyquist: {'type': 'optional', 'basearchonly': False} - Package: openfst-tools: {'type': 'optional', 'basearchonly': False} - Package: opengrm-ngram-tools: {'type': 'optional', 'basearchonly': False} - Package: paman: {'type': 'optional', 'basearchonly': False} - Package: paprefs: {'type': 'optional', 'basearchonly': False} - Package: parole: {'type': 'optional', 'basearchonly': False} - Package: pavucontrol: {'type': 'optional', 'basearchonly': False} - Package: pavumeter: {'type': 'optional', 'basearchonly': False} - Package: picard: {'type': 'optional', 'basearchonly': False} - Package: pitivi: {'type': 'optional', 'basearchonly': False} - Package: pnmixer: {'type': 'optional', 'basearchonly': False} - Package: pocketsphinx: {'type': 'optional', 'basearchonly': False} - Package: pocketsphinx-plugin: {'type': 'optional', 'basearchonly': False} - Package: pulseaudio-module-lirc: {'type': 'optional', 'basearchonly': False} - Package: pulseaudio-module-zeroconf: {'type': 'optional', 'basearchonly': False} - Package: pyvnc2swf: {'type': 'optional', 'basearchonly': False} - Package: qmmp: {'type': 'optional', 'basearchonly': False} - Package: qmmp-plugin-pack: {'type': 'optional', 'basearchonly': False} - Package: quodlibet: {'type': 'optional', 'basearchonly': False} - Package: rakarrack: {'type': 'optional', 'basearchonly': False} - Package: regionset: {'type': 'optional', 'basearchonly': False} - Package: rhythmbox: {'type': 'optional', 'basearchonly': False} - Package: rosegarden4: {'type': 'optional', 'basearchonly': False} - Package: sound-juicer: {'type': 'optional', 'basearchonly': False} - Package: soundconverter: {'type': 'optional', 'basearchonly': False} - Package: soundtracker: {'type': 'optional', 'basearchonly': False} - Package: sox: {'type': 'optional', 'basearchonly': False} - Package: sphinxtrain: {'type': 'optional', 'basearchonly': False} - Package: sweep: {'type': 'optional', 'basearchonly': False} - Package: tagtool: {'type': 'optional', 'basearchonly': False} - Package: tclabc: {'type': 'optional', 'basearchonly': False} - Package: tomahawk: {'type': 'optional', 'basearchonly': False} - Package: totem: {'type': 'optional', 'basearchonly': False} - Package: totem-lirc: {'type': 'optional', 'basearchonly': False} - Package: totem-nautilus: {'type': 'optional', 'basearchonly': False} - Package: tvtime: {'type': 'optional', 'basearchonly': False} - Package: ucview: {'type': 'optional', 'basearchonly': False} - Package: v4l2ucp: {'type': 'optional', 'basearchonly': False} - Package: vdr: {'type': 'optional', 'basearchonly': False} - Package: vdr-epgsearch: {'type': 'optional', 'basearchonly': False} - Package: vdr-femon: {'type': 'optional', 'basearchonly': False} - Package: vdr-osdteletext: {'type': 'optional', 'basearchonly': False} - Package: vdr-remote: {'type': 'optional', 'basearchonly': False} - Package: vdr-skinsoppalusikka: {'type': 'optional', 'basearchonly': False} - Package: vdr-streamdev-client: {'type': 'optional', 'basearchonly': False} - Package: vdr-streamdev-server: {'type': 'optional', 'basearchonly': False} - Package: vdr-sudoku: {'type': 'optional', 'basearchonly': False} - Package: vdr-ttxtsubs: {'type': 'optional', 'basearchonly': False} - Package: vdr-tvonscreen: {'type': 'optional', 'basearchonly': False} - Package: volumeicon: {'type': 'optional', 'basearchonly': False} - Package: vorbis-tools: {'type': 'optional', 'basearchonly': False} - Package: whaawmp: {'type': 'optional', 'basearchonly': False} - Package: wodim: {'type': 'optional', 'basearchonly': False} - Package: xcdroast: {'type': 'optional', 'basearchonly': False} - Package: xfburn: {'type': 'optional', 'basearchonly': False} - Package: xmms: {'type': 'optional', 'basearchonly': False} - Package: xmms-adplug: {'type': 'optional', 'basearchonly': False} - Package: xmms-flac: {'type': 'optional', 'basearchonly': False} - Package: xmp: {'type': 'optional', 'basearchonly': False} + Package: abcde: {'basearchonly': False, 'type': 'optional'} + Package: adplay: {'basearchonly': False, 'type': 'optional'} + Package: alsamixergui: {'basearchonly': False, 'type': 'optional'} + Package: amarok: {'basearchonly': False, 'type': 'optional'} + Package: argyllcms: {'basearchonly': False, 'type': 'optional'} + Package: asunder: {'basearchonly': False, 'type': 'optional'} + Package: audacious: {'basearchonly': False, 'type': 'optional'} + Package: audacity: {'basearchonly': False, 'type': 'optional'} + Package: banshee: {'basearchonly': False, 'type': 'optional'} + Package: brasero: {'basearchonly': False, 'type': 'optional'} + Package: camE: {'basearchonly': False, 'type': 'optional'} + Package: cdcollect: {'basearchonly': False, 'type': 'optional'} + Package: cdlabelgen: {'basearchonly': False, 'type': 'optional'} + Package: cdparanoia: {'basearchonly': False, 'type': 'optional'} + Package: cdrskin: {'basearchonly': False, 'type': 'optional'} + Package: cmusphinx3: {'basearchonly': False, 'type': 'optional'} + Package: csound-csoundac: {'basearchonly': False, 'type': 'optional'} + Package: decibel-audio-player: {'basearchonly': False, 'type': 'optional'} + Package: denemo: {'basearchonly': False, 'type': 'optional'} + Package: dragon: {'basearchonly': False, 'type': 'optional'} + Package: dvdauthor: {'basearchonly': False, 'type': 'optional'} + Package: dvdisaster: {'basearchonly': False, 'type': 'optional'} + Package: dvgrab: {'basearchonly': False, 'type': 'optional'} + Package: easytag: {'basearchonly': False, 'type': 'optional'} + Package: exaile: {'basearchonly': False, 'type': 'optional'} + Package: festvox-bdl-arctic-hts: {'basearchonly': False, 'type': 'optional'} + Package: festvox-clb-arctic-hts: {'basearchonly': False, 'type': 'optional'} + Package: festvox-rms-arctic-hts: {'basearchonly': False, 'type': 'optional'} + Package: gcstar: {'basearchonly': False, 'type': 'optional'} + Package: genisoimage: {'basearchonly': False, 'type': 'optional'} + Package: gnomad2: {'basearchonly': False, 'type': 'optional'} + Package: gnome-sound-recorder: {'basearchonly': False, 'type': 'optional'} + Package: gnomebaker: {'basearchonly': False, 'type': 'optional'} + Package: grip: {'basearchonly': False, 'type': 'optional'} + Package: gtk-v4l: {'basearchonly': False, 'type': 'optional'} + Package: gtkpod: {'basearchonly': False, 'type': 'optional'} + Package: icedax: {'basearchonly': False, 'type': 'optional'} + Package: id3v2: {'basearchonly': False, 'type': 'optional'} + Package: irstlm: {'basearchonly': False, 'type': 'optional'} + Package: isomaster: {'basearchonly': False, 'type': 'optional'} + Package: jack-audio-connection-kit: {'basearchonly': False, 'type': 'optional'} + Package: juk: {'basearchonly': False, 'type': 'optional'} + Package: k3b: {'basearchonly': False, 'type': 'optional'} + Package: kid3: {'basearchonly': False, 'type': 'optional'} + Package: kmix: {'basearchonly': False, 'type': 'optional'} + Package: kover: {'basearchonly': False, 'type': 'optional'} + Package: kscd: {'basearchonly': False, 'type': 'optional'} + Package: lingot: {'basearchonly': False, 'type': 'optional'} + Package: lxmusic: {'basearchonly': False, 'type': 'optional'} + Package: mikmod: {'basearchonly': False, 'type': 'optional'} + Package: milkytracker: {'basearchonly': False, 'type': 'optional'} + Package: mkvtoolnix-gui: {'basearchonly': False, 'type': 'optional'} + Package: multimedia-menus: {'basearchonly': False, 'type': 'optional'} + Package: mybashburn: {'basearchonly': False, 'type': 'optional'} + Package: nyquist: {'basearchonly': False, 'type': 'optional'} + Package: openfst-tools: {'basearchonly': False, 'type': 'optional'} + Package: opengrm-ngram-tools: {'basearchonly': False, 'type': 'optional'} + Package: paman: {'basearchonly': False, 'type': 'optional'} + Package: paprefs: {'basearchonly': False, 'type': 'optional'} + Package: parole: {'basearchonly': False, 'type': 'optional'} + Package: pavucontrol: {'basearchonly': False, 'type': 'optional'} + Package: pavumeter: {'basearchonly': False, 'type': 'optional'} + Package: picard: {'basearchonly': False, 'type': 'optional'} + Package: pitivi: {'basearchonly': False, 'type': 'optional'} + Package: pnmixer: {'basearchonly': False, 'type': 'optional'} + Package: pocketsphinx: {'basearchonly': False, 'type': 'optional'} + Package: pocketsphinx-plugin: {'basearchonly': False, 'type': 'optional'} + Package: pulseaudio-module-lirc: {'basearchonly': False, 'type': 'optional'} + Package: pulseaudio-module-zeroconf: {'basearchonly': False, 'type': 'optional'} + Package: pyvnc2swf: {'basearchonly': False, 'type': 'optional'} + Package: qmmp: {'basearchonly': False, 'type': 'optional'} + Package: qmmp-plugin-pack: {'basearchonly': False, 'type': 'optional'} + Package: quodlibet: {'basearchonly': False, 'type': 'optional'} + Package: rakarrack: {'basearchonly': False, 'type': 'optional'} + Package: regionset: {'basearchonly': False, 'type': 'optional'} + Package: rhythmbox: {'basearchonly': False, 'type': 'optional'} + Package: rosegarden4: {'basearchonly': False, 'type': 'optional'} + Package: sound-juicer: {'basearchonly': False, 'type': 'optional'} + Package: soundconverter: {'basearchonly': False, 'type': 'optional'} + Package: soundtracker: {'basearchonly': False, 'type': 'optional'} + Package: sox: {'basearchonly': False, 'type': 'optional'} + Package: sphinxtrain: {'basearchonly': False, 'type': 'optional'} + Package: sweep: {'basearchonly': False, 'type': 'optional'} + Package: tagtool: {'basearchonly': False, 'type': 'optional'} + Package: tclabc: {'basearchonly': False, 'type': 'optional'} + Package: tomahawk: {'basearchonly': False, 'type': 'optional'} + Package: totem: {'basearchonly': False, 'type': 'optional'} + Package: totem-lirc: {'basearchonly': False, 'type': 'optional'} + Package: totem-nautilus: {'basearchonly': False, 'type': 'optional'} + Package: tvtime: {'basearchonly': False, 'type': 'optional'} + Package: ucview: {'basearchonly': False, 'type': 'optional'} + Package: v4l2ucp: {'basearchonly': False, 'type': 'optional'} + Package: vdr: {'basearchonly': False, 'type': 'optional'} + Package: vdr-epgsearch: {'basearchonly': False, 'type': 'optional'} + Package: vdr-femon: {'basearchonly': False, 'type': 'optional'} + Package: vdr-osdteletext: {'basearchonly': False, 'type': 'optional'} + Package: vdr-remote: {'basearchonly': False, 'type': 'optional'} + Package: vdr-skinsoppalusikka: {'basearchonly': False, 'type': 'optional'} + Package: vdr-streamdev-client: {'basearchonly': False, 'type': 'optional'} + Package: vdr-streamdev-server: {'basearchonly': False, 'type': 'optional'} + Package: vdr-sudoku: {'basearchonly': False, 'type': 'optional'} + Package: vdr-ttxtsubs: {'basearchonly': False, 'type': 'optional'} + Package: vdr-tvonscreen: {'basearchonly': False, 'type': 'optional'} + Package: volumeicon: {'basearchonly': False, 'type': 'optional'} + Package: vorbis-tools: {'basearchonly': False, 'type': 'optional'} + Package: whaawmp: {'basearchonly': False, 'type': 'optional'} + Package: wodim: {'basearchonly': False, 'type': 'optional'} + Package: xcdroast: {'basearchonly': False, 'type': 'optional'} + Package: xfburn: {'basearchonly': False, 'type': 'optional'} + Package: xmms: {'basearchonly': False, 'type': 'optional'} + Package: xmms-adplug: {'basearchonly': False, 'type': 'optional'} + Package: xmms-flac: {'basearchonly': False, 'type': 'optional'} + Package: xmp: {'basearchonly': False, 'type': 'optional'} Group: sql-server (PostgreSQL Database) - Package: postgresql: {'type': 'mandatory', 'basearchonly': False} - Package: libdbi-dbd-pgsql: {'type': 'default', 'basearchonly': False} - Package: perl-DBD-Pg: {'type': 'default', 'basearchonly': False} - Package: postgresql-server: {'type': 'default', 'basearchonly': False} - Package: rhdb-utils: {'type': 'default', 'basearchonly': False} - Package: unixODBC: {'type': 'default', 'basearchonly': False} - Package: postgresql-contrib: {'type': 'optional', 'basearchonly': False} - Package: postgresql-docs: {'type': 'optional', 'basearchonly': False} - Package: postgresql-jdbc: {'type': 'optional', 'basearchonly': False} - Package: postgresql-odbc: {'type': 'optional', 'basearchonly': False} - Package: postgresql-test: {'type': 'optional', 'basearchonly': False} - Package: PyGreSQL: {'type': 'optional', 'basearchonly': False} - Package: qt-odbc: {'type': 'optional', 'basearchonly': False} - Package: qt-postgresql: {'type': 'optional', 'basearchonly': False} - Package: qt3-ODBC: {'type': 'optional', 'basearchonly': False} - Package: qt3-PostgreSQL: {'type': 'optional', 'basearchonly': False} - Package: tcl-pgtcl: {'type': 'optional', 'basearchonly': False} + Package: postgresql: {'basearchonly': False, 'type': 'mandatory'} + Package: libdbi-dbd-pgsql: {'basearchonly': False, 'type': 'default'} + Package: perl-DBD-Pg: {'basearchonly': False, 'type': 'default'} + Package: postgresql-server: {'basearchonly': False, 'type': 'default'} + Package: rhdb-utils: {'basearchonly': False, 'type': 'default'} + Package: unixODBC: {'basearchonly': False, 'type': 'default'} + Package: postgresql-contrib: {'basearchonly': False, 'type': 'optional'} + Package: postgresql-docs: {'basearchonly': False, 'type': 'optional'} + Package: postgresql-jdbc: {'basearchonly': False, 'type': 'optional'} + Package: postgresql-odbc: {'basearchonly': False, 'type': 'optional'} + Package: postgresql-test: {'basearchonly': False, 'type': 'optional'} + Package: PyGreSQL: {'basearchonly': False, 'type': 'optional'} + Package: qt-odbc: {'basearchonly': False, 'type': 'optional'} + Package: qt-postgresql: {'basearchonly': False, 'type': 'optional'} + Package: qt3-ODBC: {'basearchonly': False, 'type': 'optional'} + Package: qt3-PostgreSQL: {'basearchonly': False, 'type': 'optional'} + Package: tcl-pgtcl: {'basearchonly': False, 'type': 'optional'} Group: standard (Standard) - Package: abrt-cli: {'type': 'mandatory', 'basearchonly': False} - Package: acl: {'type': 'mandatory', 'basearchonly': False} - Package: at: {'type': 'mandatory', 'basearchonly': False} - Package: attr: {'type': 'mandatory', 'basearchonly': False} - Package: bash-completion: {'type': 'mandatory', 'basearchonly': False} - Package: bc: {'type': 'mandatory', 'basearchonly': False} - Package: bind-utils: {'type': 'mandatory', 'basearchonly': False} - Package: bridge-utils: {'type': 'mandatory', 'basearchonly': False} - Package: btrfs-progs: {'type': 'mandatory', 'basearchonly': False} - Package: bzip2: {'type': 'mandatory', 'basearchonly': False} - Package: cifs-utils: {'type': 'mandatory', 'basearchonly': False} - Package: coolkey: {'type': 'mandatory', 'basearchonly': False} - Package: cpio: {'type': 'mandatory', 'basearchonly': False} - Package: crontabs: {'type': 'mandatory', 'basearchonly': False} - Package: cryptsetup: {'type': 'mandatory', 'basearchonly': False} - Package: cyrus-sasl-plain: {'type': 'mandatory', 'basearchonly': False} - Package: dbus: {'type': 'mandatory', 'basearchonly': False} - Package: deltarpm: {'type': 'mandatory', 'basearchonly': False} - Package: dnf-langpacks: {'type': 'mandatory', 'basearchonly': False} - Package: dos2unix: {'type': 'mandatory', 'basearchonly': False} - Package: dosfstools: {'type': 'mandatory', 'basearchonly': False} - Package: ed: {'type': 'mandatory', 'basearchonly': False} - Package: ethtool: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-release-notes: {'type': 'mandatory', 'basearchonly': False} - Package: file: {'type': 'mandatory', 'basearchonly': False} - Package: fpaste: {'type': 'mandatory', 'basearchonly': False} - Package: fprintd-pam: {'type': 'mandatory', 'basearchonly': False} - Package: gnupg2: {'type': 'mandatory', 'basearchonly': False} - Package: hunspell: {'type': 'mandatory', 'basearchonly': False} - Package: iptstate: {'type': 'mandatory', 'basearchonly': False} - Package: irqbalance: {'type': 'mandatory', 'basearchonly': False} - Package: jwhois: {'type': 'mandatory', 'basearchonly': False} - Package: logrotate: {'type': 'mandatory', 'basearchonly': False} - Package: lsof: {'type': 'mandatory', 'basearchonly': False} - Package: mailcap: {'type': 'mandatory', 'basearchonly': False} - Package: man-pages: {'type': 'mandatory', 'basearchonly': False} - Package: mcelog: {'type': 'mandatory', 'basearchonly': False} - Package: mdadm: {'type': 'mandatory', 'basearchonly': False} - Package: microcode_ctl: {'type': 'mandatory', 'basearchonly': False} - Package: mlocate: {'type': 'mandatory', 'basearchonly': False} - Package: mtr: {'type': 'mandatory', 'basearchonly': False} - Package: nano: {'type': 'mandatory', 'basearchonly': False} - Package: net-tools: {'type': 'mandatory', 'basearchonly': False} - Package: nfs-utils: {'type': 'mandatory', 'basearchonly': False} - Package: nmap-ncat: {'type': 'mandatory', 'basearchonly': False} - Package: ntfs-3g: {'type': 'mandatory', 'basearchonly': False} - Package: ntfsprogs: {'type': 'mandatory', 'basearchonly': False} - Package: pam_krb5: {'type': 'mandatory', 'basearchonly': False} - Package: pam_pkcs11: {'type': 'mandatory', 'basearchonly': False} - Package: passwdqc: {'type': 'mandatory', 'basearchonly': False} - Package: pciutils: {'type': 'mandatory', 'basearchonly': False} - Package: pinfo: {'type': 'mandatory', 'basearchonly': False} - Package: plymouth: {'type': 'mandatory', 'basearchonly': False} - Package: psacct: {'type': 'mandatory', 'basearchonly': False} - Package: quota: {'type': 'mandatory', 'basearchonly': False} - Package: realmd: {'type': 'mandatory', 'basearchonly': False} - Package: rng-tools: {'type': 'mandatory', 'basearchonly': False} - Package: rsync: {'type': 'mandatory', 'basearchonly': False} - Package: rsyslog: {'type': 'mandatory', 'basearchonly': False} - Package: setuptool: {'type': 'mandatory', 'basearchonly': False} - Package: smartmontools: {'type': 'mandatory', 'basearchonly': False} - Package: sos: {'type': 'mandatory', 'basearchonly': False} - Package: sssd: {'type': 'mandatory', 'basearchonly': False} - Package: sudo: {'type': 'mandatory', 'basearchonly': False} - Package: symlinks: {'type': 'mandatory', 'basearchonly': False} - Package: systemd-udev: {'type': 'mandatory', 'basearchonly': False} - Package: tar: {'type': 'mandatory', 'basearchonly': False} - Package: tcpdump: {'type': 'mandatory', 'basearchonly': False} - Package: tcp_wrappers: {'type': 'mandatory', 'basearchonly': False} - Package: telnet: {'type': 'mandatory', 'basearchonly': False} - Package: time: {'type': 'mandatory', 'basearchonly': False} - Package: traceroute: {'type': 'mandatory', 'basearchonly': False} - Package: tree: {'type': 'mandatory', 'basearchonly': False} - Package: unzip: {'type': 'mandatory', 'basearchonly': False} - Package: usbutils: {'type': 'mandatory', 'basearchonly': False} - Package: vconfig: {'type': 'mandatory', 'basearchonly': False} - Package: wget: {'type': 'mandatory', 'basearchonly': False} - Package: which: {'type': 'mandatory', 'basearchonly': False} - Package: wireless-tools: {'type': 'mandatory', 'basearchonly': False} - Package: words: {'type': 'mandatory', 'basearchonly': False} - Package: zip: {'type': 'mandatory', 'basearchonly': False} - Package: chrony: {'requires': u'control-center', 'type': 'conditional', 'basearchonly': False} + Package: abrt-cli: {'basearchonly': False, 'type': 'mandatory'} + Package: acl: {'basearchonly': False, 'type': 'mandatory'} + Package: at: {'basearchonly': False, 'type': 'mandatory'} + Package: attr: {'basearchonly': False, 'type': 'mandatory'} + Package: bash-completion: {'basearchonly': False, 'type': 'mandatory'} + Package: bc: {'basearchonly': False, 'type': 'mandatory'} + Package: bind-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: bridge-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: btrfs-progs: {'basearchonly': False, 'type': 'mandatory'} + Package: bzip2: {'basearchonly': False, 'type': 'mandatory'} + Package: cifs-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: coolkey: {'basearchonly': False, 'type': 'mandatory'} + Package: cpio: {'basearchonly': False, 'type': 'mandatory'} + Package: crontabs: {'basearchonly': False, 'type': 'mandatory'} + Package: cryptsetup: {'basearchonly': False, 'type': 'mandatory'} + Package: cyrus-sasl-plain: {'basearchonly': False, 'type': 'mandatory'} + Package: dbus: {'basearchonly': False, 'type': 'mandatory'} + Package: deltarpm: {'basearchonly': False, 'type': 'mandatory'} + Package: dnf-langpacks: {'basearchonly': False, 'type': 'mandatory'} + Package: dos2unix: {'basearchonly': False, 'type': 'mandatory'} + Package: dosfstools: {'basearchonly': False, 'type': 'mandatory'} + Package: ed: {'basearchonly': False, 'type': 'mandatory'} + Package: ethtool: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-release-notes: {'basearchonly': False, 'type': 'mandatory'} + Package: file: {'basearchonly': False, 'type': 'mandatory'} + Package: fpaste: {'basearchonly': False, 'type': 'mandatory'} + Package: fprintd-pam: {'basearchonly': False, 'type': 'mandatory'} + Package: gnupg2: {'basearchonly': False, 'type': 'mandatory'} + Package: hunspell: {'basearchonly': False, 'type': 'mandatory'} + Package: iptstate: {'basearchonly': False, 'type': 'mandatory'} + Package: irqbalance: {'basearchonly': False, 'type': 'mandatory'} + Package: jwhois: {'basearchonly': False, 'type': 'mandatory'} + Package: logrotate: {'basearchonly': False, 'type': 'mandatory'} + Package: lsof: {'basearchonly': False, 'type': 'mandatory'} + Package: mailcap: {'basearchonly': False, 'type': 'mandatory'} + Package: man-pages: {'basearchonly': False, 'type': 'mandatory'} + Package: mcelog: {'basearchonly': False, 'type': 'mandatory'} + Package: mdadm: {'basearchonly': False, 'type': 'mandatory'} + Package: microcode_ctl: {'basearchonly': False, 'type': 'mandatory'} + Package: mlocate: {'basearchonly': False, 'type': 'mandatory'} + Package: mtr: {'basearchonly': False, 'type': 'mandatory'} + Package: nano: {'basearchonly': False, 'type': 'mandatory'} + Package: net-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: nfs-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: nmap-ncat: {'basearchonly': False, 'type': 'mandatory'} + Package: ntfs-3g: {'basearchonly': False, 'type': 'mandatory'} + Package: ntfsprogs: {'basearchonly': False, 'type': 'mandatory'} + Package: pam_krb5: {'basearchonly': False, 'type': 'mandatory'} + Package: pam_pkcs11: {'basearchonly': False, 'type': 'mandatory'} + Package: passwdqc: {'basearchonly': False, 'type': 'mandatory'} + Package: pciutils: {'basearchonly': False, 'type': 'mandatory'} + Package: pinfo: {'basearchonly': False, 'type': 'mandatory'} + Package: plymouth: {'basearchonly': False, 'type': 'mandatory'} + Package: psacct: {'basearchonly': False, 'type': 'mandatory'} + Package: quota: {'basearchonly': False, 'type': 'mandatory'} + Package: realmd: {'basearchonly': False, 'type': 'mandatory'} + Package: rng-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: rsync: {'basearchonly': False, 'type': 'mandatory'} + Package: rsyslog: {'basearchonly': False, 'type': 'mandatory'} + Package: setuptool: {'basearchonly': False, 'type': 'mandatory'} + Package: smartmontools: {'basearchonly': False, 'type': 'mandatory'} + Package: sos: {'basearchonly': False, 'type': 'mandatory'} + Package: sssd: {'basearchonly': False, 'type': 'mandatory'} + Package: sudo: {'basearchonly': False, 'type': 'mandatory'} + Package: symlinks: {'basearchonly': False, 'type': 'mandatory'} + Package: systemd-udev: {'basearchonly': False, 'type': 'mandatory'} + Package: tar: {'basearchonly': False, 'type': 'mandatory'} + Package: tcpdump: {'basearchonly': False, 'type': 'mandatory'} + Package: tcp_wrappers: {'basearchonly': False, 'type': 'mandatory'} + Package: telnet: {'basearchonly': False, 'type': 'mandatory'} + Package: time: {'basearchonly': False, 'type': 'mandatory'} + Package: traceroute: {'basearchonly': False, 'type': 'mandatory'} + Package: tree: {'basearchonly': False, 'type': 'mandatory'} + Package: unzip: {'basearchonly': False, 'type': 'mandatory'} + Package: usbutils: {'basearchonly': False, 'type': 'mandatory'} + Package: vconfig: {'basearchonly': False, 'type': 'mandatory'} + Package: wget: {'basearchonly': False, 'type': 'mandatory'} + Package: which: {'basearchonly': False, 'type': 'mandatory'} + Package: wireless-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: words: {'basearchonly': False, 'type': 'mandatory'} + Package: zip: {'basearchonly': False, 'type': 'mandatory'} + Package: chrony: {'basearchonly': False, 'requires': 'control-center', 'type': 'conditional'} Group: sugar-apps (Additional Sugar Activities) - Package: sugar-analyze: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-calendario: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-connect: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-distance: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-emulator: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-flipsticks: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-implode: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-playgo: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-pukllanapac: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-view-slides: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-xomail: {'type': 'mandatory', 'basearchonly': False} + Package: sugar-analyze: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-calendario: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-connect: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-distance: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-emulator: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-flipsticks: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-implode: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-playgo: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-pukllanapac: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-view-slides: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-xomail: {'basearchonly': False, 'type': 'mandatory'} Group: sugar-desktop (Sugar Desktop Environment) - Package: csound-python: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-power-manager: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs: {'type': 'mandatory', 'basearchonly': False} - Package: lightdm: {'type': 'mandatory', 'basearchonly': False} - Package: lightdm-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: metacity: {'type': 'mandatory', 'basearchonly': False} - Package: pygame: {'type': 'mandatory', 'basearchonly': False} - Package: sugar: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-abacus: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-browse: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-calculator: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-chat: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-clock: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-countries: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-cp-all: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-finance: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-fototoon: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-getiabooks: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-help: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-imageviewer: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-infoslicer: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-jukebox: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-labyrinth: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-log: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-maze: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-memorize: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-moon: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-paint: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-physics: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-pippy: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-portfolio: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-read: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-record: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-ruler: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-speak: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-stopwatch: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-story: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-terminal: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-toolkit: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-toolkit-gtk3: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-turtleart: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-typing-turtle: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-visualmatch: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-words: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-write: {'type': 'mandatory', 'basearchonly': False} - Package: sugar-xoirc: {'type': 'mandatory', 'basearchonly': False} + Package: csound-python: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-power-manager: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs: {'basearchonly': False, 'type': 'mandatory'} + Package: lightdm: {'basearchonly': False, 'type': 'mandatory'} + Package: lightdm-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: metacity: {'basearchonly': False, 'type': 'mandatory'} + Package: pygame: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-abacus: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-browse: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-calculator: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-chat: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-clock: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-countries: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-cp-all: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-finance: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-fototoon: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-getiabooks: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-help: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-imageviewer: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-infoslicer: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-jukebox: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-labyrinth: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-log: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-maze: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-memorize: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-moon: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-paint: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-physics: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-pippy: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-portfolio: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-read: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-record: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-ruler: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-speak: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-stopwatch: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-story: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-terminal: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-toolkit: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-toolkit-gtk3: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-turtleart: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-typing-turtle: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-visualmatch: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-words: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-write: {'basearchonly': False, 'type': 'mandatory'} + Package: sugar-xoirc: {'basearchonly': False, 'type': 'mandatory'} Group: system-tools (System Tools) - Package: BackupPC: {'type': 'default', 'basearchonly': False} - Package: bonnie++: {'type': 'default', 'basearchonly': False} - Package: chrony: {'type': 'default', 'basearchonly': False} - Package: cifs-utils: {'type': 'default', 'basearchonly': False} - Package: jigdo: {'type': 'default', 'basearchonly': False} - Package: libreswan: {'type': 'default', 'basearchonly': False} - Package: NetworkManager-l2tp: {'type': 'default', 'basearchonly': False} - Package: NetworkManager-libreswan: {'type': 'default', 'basearchonly': False} - Package: NetworkManager-openconnect: {'type': 'default', 'basearchonly': False} - Package: NetworkManager-openvpn: {'type': 'default', 'basearchonly': False} - Package: NetworkManager-vpnc: {'type': 'default', 'basearchonly': False} - Package: nmap: {'type': 'default', 'basearchonly': False} - Package: ntfs-3g: {'type': 'default', 'basearchonly': False} - Package: openconnect: {'type': 'default', 'basearchonly': False} - Package: openldap-clients: {'type': 'default', 'basearchonly': False} - Package: openvpn: {'type': 'default', 'basearchonly': False} - Package: samba-client: {'type': 'default', 'basearchonly': False} - Package: screen: {'type': 'default', 'basearchonly': False} - Package: setserial: {'type': 'default', 'basearchonly': False} - Package: tigervnc: {'type': 'default', 'basearchonly': False} - Package: vpnc: {'type': 'default', 'basearchonly': False} - Package: xdelta: {'type': 'default', 'basearchonly': False} - Package: zisofs-tools: {'type': 'default', 'basearchonly': False} - Package: zsh: {'type': 'default', 'basearchonly': False} - Package: aide: {'type': 'optional', 'basearchonly': False} - Package: aircrack-ng: {'type': 'optional', 'basearchonly': False} - Package: airsnort: {'type': 'optional', 'basearchonly': False} - Package: am-utils: {'type': 'optional', 'basearchonly': False} - Package: amanda-client: {'type': 'optional', 'basearchonly': False} - Package: apcupsd: {'type': 'optional', 'basearchonly': False} - Package: apcupsd-gui: {'type': 'optional', 'basearchonly': False} - Package: apg: {'type': 'optional', 'basearchonly': False} - Package: apt: {'type': 'optional', 'basearchonly': False} - Package: arc: {'type': 'optional', 'basearchonly': False} - Package: arj: {'type': 'optional', 'basearchonly': False} - Package: arptables: {'type': 'optional', 'basearchonly': False} - Package: arpwatch: {'type': 'optional', 'basearchonly': False} - Package: autofs: {'type': 'optional', 'basearchonly': False} - Package: avahi-tools: {'type': 'optional', 'basearchonly': False} - Package: bochs: {'type': 'optional', 'basearchonly': False} - Package: cabextract: {'type': 'optional', 'basearchonly': False} - Package: catfish: {'type': 'optional', 'basearchonly': False} - Package: cfengine: {'type': 'optional', 'basearchonly': False} - Package: chrpath: {'type': 'optional', 'basearchonly': False} - Package: conman: {'type': 'optional', 'basearchonly': False} - Package: connect-proxy: {'type': 'optional', 'basearchonly': False} - Package: convmv: {'type': 'optional', 'basearchonly': False} - Package: crack: {'type': 'optional', 'basearchonly': False} - Package: crash: {'type': 'optional', 'basearchonly': False} - Package: createrepo: {'type': 'optional', 'basearchonly': False} - Package: dar: {'type': 'optional', 'basearchonly': False} - Package: ddclient: {'type': 'optional', 'basearchonly': False} - Package: denyhosts: {'type': 'optional', 'basearchonly': False} - Package: dkms: {'type': 'optional', 'basearchonly': False} - Package: dstat: {'type': 'optional', 'basearchonly': False} - Package: dtach: {'type': 'optional', 'basearchonly': False} - Package: ebtables: {'type': 'optional', 'basearchonly': False} - Package: ed2k_hash: {'type': 'optional', 'basearchonly': False} - Package: eiciel: {'type': 'optional', 'basearchonly': False} - Package: emelfm2: {'type': 'optional', 'basearchonly': False} - Package: enca: {'type': 'optional', 'basearchonly': False} - Package: environment-modules: {'type': 'optional', 'basearchonly': False} - Package: epylog: {'type': 'optional', 'basearchonly': False} - Package: etherbat: {'type': 'optional', 'basearchonly': False} - Package: ettercap: {'type': 'optional', 'basearchonly': False} - Package: fatsort: {'type': 'optional', 'basearchonly': False} - Package: fdupes: {'type': 'optional', 'basearchonly': False} - Package: fedora-package-config-apt: {'type': 'optional', 'basearchonly': False} - Package: festival: {'type': 'optional', 'basearchonly': False} - Package: foremost: {'type': 'optional', 'basearchonly': False} - Package: freerdp: {'type': 'optional', 'basearchonly': False} - Package: freeze: {'type': 'optional', 'basearchonly': False} - Package: fuse: {'type': 'optional', 'basearchonly': False} - Package: fwknop: {'type': 'optional', 'basearchonly': False} - Package: fwrestart: {'type': 'optional', 'basearchonly': False} - Package: ganglia: {'type': 'optional', 'basearchonly': False} - Package: geoclue: {'type': 'optional', 'basearchonly': False} - Package: ghasher: {'type': 'optional', 'basearchonly': False} - Package: ghex: {'type': 'optional', 'basearchonly': False} - Package: gigolo: {'type': 'optional', 'basearchonly': False} - Package: gkrellm: {'type': 'optional', 'basearchonly': False} - Package: gnokii: {'type': 'optional', 'basearchonly': False} - Package: gnutls-utils: {'type': 'optional', 'basearchonly': False} - Package: greadelf: {'type': 'optional', 'basearchonly': False} - Package: grepmail: {'type': 'optional', 'basearchonly': False} - Package: grsync: {'type': 'optional', 'basearchonly': False} - Package: gssdp: {'type': 'optional', 'basearchonly': False} - Package: gtkhash: {'type': 'optional', 'basearchonly': False} - Package: gtkterm: {'type': 'optional', 'basearchonly': False} - Package: gupnp: {'type': 'optional', 'basearchonly': False} - Package: gxemul: {'type': 'optional', 'basearchonly': False} - Package: hercules: {'type': 'optional', 'basearchonly': False} - Package: hfsplus-tools: {'type': 'optional', 'basearchonly': False} - Package: htop: {'type': 'optional', 'basearchonly': False} - Package: hyperestraier: {'type': 'optional', 'basearchonly': False} - Package: ibmonitor: {'type': 'optional', 'basearchonly': False} - Package: iftop: {'type': 'optional', 'basearchonly': False} - Package: inadyn-mt: {'type': 'optional', 'basearchonly': False} - Package: incron: {'type': 'optional', 'basearchonly': False} - Package: iotop: {'type': 'optional', 'basearchonly': False} - Package: ipsec-tools: {'type': 'optional', 'basearchonly': False} - Package: ircp-tray: {'type': 'optional', 'basearchonly': False} - Package: javasysmon: {'type': 'optional', 'basearchonly': False} - Package: jfbterm: {'type': 'optional', 'basearchonly': False} - Package: john: {'type': 'optional', 'basearchonly': False} - Package: kdirstat: {'type': 'optional', 'basearchonly': False} - Package: keychain: {'type': 'optional', 'basearchonly': False} - Package: ksmarttray: {'type': 'optional', 'basearchonly': False} - Package: limph: {'type': 'optional', 'basearchonly': False} - Package: lirc: {'type': 'optional', 'basearchonly': False} - Package: liveusb-creator: {'type': 'optional', 'basearchonly': False} - Package: lzop: {'type': 'optional', 'basearchonly': False} - Package: macchanger: {'type': 'optional', 'basearchonly': False} - Package: mc: {'type': 'optional', 'basearchonly': False} - Package: mmv: {'type': 'optional', 'basearchonly': False} - Package: mrtg: {'type': 'optional', 'basearchonly': False} - Package: mtx: {'type': 'optional', 'basearchonly': False} - Package: munin: {'type': 'optional', 'basearchonly': False} - Package: nagios: {'type': 'optional', 'basearchonly': False} - Package: net-snmp-utils: {'type': 'optional', 'basearchonly': False} - Package: nethogs: {'type': 'optional', 'basearchonly': False} - Package: netstat-nat: {'type': 'optional', 'basearchonly': False} - Package: nfswatch: {'type': 'optional', 'basearchonly': False} - Package: nmap-frontend: {'type': 'optional', 'basearchonly': False} - Package: noip: {'type': 'optional', 'basearchonly': False} - Package: nomarch: {'type': 'optional', 'basearchonly': False} - Package: nrg2iso: {'type': 'optional', 'basearchonly': False} - Package: ntp: {'type': 'optional', 'basearchonly': False} - Package: ntp-perl: {'type': 'optional', 'basearchonly': False} - Package: ntpdate: {'type': 'optional', 'basearchonly': False} - Package: nut: {'type': 'optional', 'basearchonly': False} - Package: obexftp: {'type': 'optional', 'basearchonly': False} - Package: oddjob: {'type': 'optional', 'basearchonly': False} - Package: oddjob-mkhomedir: {'type': 'optional', 'basearchonly': False} - Package: p0f: {'type': 'optional', 'basearchonly': False} - Package: p7zip: {'type': 'optional', 'basearchonly': False} - Package: p7zip-plugins: {'type': 'optional', 'basearchonly': False} - Package: PackageKit-command-not-found: {'type': 'optional', 'basearchonly': False} - Package: par2cmdline: {'type': 'optional', 'basearchonly': False} - Package: pbzip2: {'type': 'optional', 'basearchonly': False} - Package: portecle: {'type': 'optional', 'basearchonly': False} - Package: powerman: {'type': 'optional', 'basearchonly': False} - Package: powertop: {'type': 'optional', 'basearchonly': False} - Package: procinfo: {'type': 'optional', 'basearchonly': False} - Package: puppet: {'type': 'optional', 'basearchonly': False} - Package: pwgen: {'type': 'optional', 'basearchonly': False} - Package: qdbm: {'type': 'optional', 'basearchonly': False} - Package: qstat: {'type': 'optional', 'basearchonly': False} - Package: radeontool: {'type': 'optional', 'basearchonly': False} - Package: rdesktop: {'type': 'optional', 'basearchonly': False} - Package: rdiff-backup: {'type': 'optional', 'basearchonly': False} - Package: rear: {'type': 'optional', 'basearchonly': False} - Package: remmina: {'type': 'optional', 'basearchonly': False} - Package: remmina-plugins-nx: {'type': 'optional', 'basearchonly': False} - Package: remmina-plugins-rdp: {'type': 'optional', 'basearchonly': False} - Package: remmina-plugins-telepathy: {'type': 'optional', 'basearchonly': False} - Package: remmina-plugins-xdmcp: {'type': 'optional', 'basearchonly': False} - Package: reptyr: {'type': 'optional', 'basearchonly': False} - Package: rmanage: {'type': 'optional', 'basearchonly': False} - Package: rootsh: {'type': 'optional', 'basearchonly': False} - Package: rsnapshot: {'type': 'optional', 'basearchonly': False} - Package: scrub: {'type': 'optional', 'basearchonly': False} - Package: sec: {'type': 'optional', 'basearchonly': False} - Package: shorewall: {'type': 'optional', 'basearchonly': False} - Package: socat: {'type': 'optional', 'basearchonly': False} - Package: speech-dispatcher: {'type': 'optional', 'basearchonly': False} - Package: speech-dispatcher-espeak: {'type': 'optional', 'basearchonly': False} - Package: speech-dispatcher-festival: {'type': 'optional', 'basearchonly': False} - Package: speech-dispatcher-flite: {'type': 'optional', 'basearchonly': False} - Package: stripesnoop: {'type': 'optional', 'basearchonly': False} - Package: swaks: {'type': 'optional', 'basearchonly': False} - Package: swatch: {'type': 'optional', 'basearchonly': False} - Package: synaptic: {'type': 'optional', 'basearchonly': False} - Package: syslog-ng: {'type': 'optional', 'basearchonly': False} - Package: sysstat: {'type': 'optional', 'basearchonly': False} - Package: testdisk: {'type': 'optional', 'basearchonly': False} - Package: tn5250: {'type': 'optional', 'basearchonly': False} - Package: torque-client: {'type': 'optional', 'basearchonly': False} - Package: torque-gui: {'type': 'optional', 'basearchonly': False} - Package: ttywatch: {'type': 'optional', 'basearchonly': False} - Package: tunctl: {'type': 'optional', 'basearchonly': False} - Package: unison213: {'type': 'optional', 'basearchonly': False} - Package: unison227: {'type': 'optional', 'basearchonly': False} - Package: upx: {'type': 'optional', 'basearchonly': False} - Package: uucp: {'type': 'optional', 'basearchonly': False} - Package: vnstat: {'type': 'optional', 'basearchonly': False} - Package: wine: {'type': 'optional', 'basearchonly': False} - Package: wireshark-gnome: {'type': 'optional', 'basearchonly': False} - Package: wlassistant: {'type': 'optional', 'basearchonly': False} - Package: w_scan: {'type': 'optional', 'basearchonly': False} - Package: x3270-x11: {'type': 'optional', 'basearchonly': False} - Package: xmobar: {'type': 'optional', 'basearchonly': False} - Package: xsel: {'type': 'optional', 'basearchonly': False} - Package: xsupplicant: {'type': 'optional', 'basearchonly': False} - Package: zidrav: {'type': 'optional', 'basearchonly': False} + Package: BackupPC: {'basearchonly': False, 'type': 'default'} + Package: bonnie++: {'basearchonly': False, 'type': 'default'} + Package: chrony: {'basearchonly': False, 'type': 'default'} + Package: cifs-utils: {'basearchonly': False, 'type': 'default'} + Package: jigdo: {'basearchonly': False, 'type': 'default'} + Package: libreswan: {'basearchonly': False, 'type': 'default'} + Package: NetworkManager-l2tp: {'basearchonly': False, 'type': 'default'} + Package: NetworkManager-libreswan: {'basearchonly': False, 'type': 'default'} + Package: NetworkManager-openconnect: {'basearchonly': False, 'type': 'default'} + Package: NetworkManager-openvpn: {'basearchonly': False, 'type': 'default'} + Package: NetworkManager-vpnc: {'basearchonly': False, 'type': 'default'} + Package: nmap: {'basearchonly': False, 'type': 'default'} + Package: ntfs-3g: {'basearchonly': False, 'type': 'default'} + Package: openconnect: {'basearchonly': False, 'type': 'default'} + Package: openldap-clients: {'basearchonly': False, 'type': 'default'} + Package: openvpn: {'basearchonly': False, 'type': 'default'} + Package: samba-client: {'basearchonly': False, 'type': 'default'} + Package: screen: {'basearchonly': False, 'type': 'default'} + Package: setserial: {'basearchonly': False, 'type': 'default'} + Package: tigervnc: {'basearchonly': False, 'type': 'default'} + Package: vpnc: {'basearchonly': False, 'type': 'default'} + Package: xdelta: {'basearchonly': False, 'type': 'default'} + Package: zisofs-tools: {'basearchonly': False, 'type': 'default'} + Package: zsh: {'basearchonly': False, 'type': 'default'} + Package: aide: {'basearchonly': False, 'type': 'optional'} + Package: aircrack-ng: {'basearchonly': False, 'type': 'optional'} + Package: airsnort: {'basearchonly': False, 'type': 'optional'} + Package: am-utils: {'basearchonly': False, 'type': 'optional'} + Package: amanda-client: {'basearchonly': False, 'type': 'optional'} + Package: apcupsd: {'basearchonly': False, 'type': 'optional'} + Package: apcupsd-gui: {'basearchonly': False, 'type': 'optional'} + Package: apg: {'basearchonly': False, 'type': 'optional'} + Package: apt: {'basearchonly': False, 'type': 'optional'} + Package: arc: {'basearchonly': False, 'type': 'optional'} + Package: arj: {'basearchonly': False, 'type': 'optional'} + Package: arptables: {'basearchonly': False, 'type': 'optional'} + Package: arpwatch: {'basearchonly': False, 'type': 'optional'} + Package: autofs: {'basearchonly': False, 'type': 'optional'} + Package: avahi-tools: {'basearchonly': False, 'type': 'optional'} + Package: bochs: {'basearchonly': False, 'type': 'optional'} + Package: cabextract: {'basearchonly': False, 'type': 'optional'} + Package: catfish: {'basearchonly': False, 'type': 'optional'} + Package: cfengine: {'basearchonly': False, 'type': 'optional'} + Package: chrpath: {'basearchonly': False, 'type': 'optional'} + Package: conman: {'basearchonly': False, 'type': 'optional'} + Package: connect-proxy: {'basearchonly': False, 'type': 'optional'} + Package: convmv: {'basearchonly': False, 'type': 'optional'} + Package: crack: {'basearchonly': False, 'type': 'optional'} + Package: crash: {'basearchonly': False, 'type': 'optional'} + Package: createrepo: {'basearchonly': False, 'type': 'optional'} + Package: dar: {'basearchonly': False, 'type': 'optional'} + Package: ddclient: {'basearchonly': False, 'type': 'optional'} + Package: denyhosts: {'basearchonly': False, 'type': 'optional'} + Package: dkms: {'basearchonly': False, 'type': 'optional'} + Package: dstat: {'basearchonly': False, 'type': 'optional'} + Package: dtach: {'basearchonly': False, 'type': 'optional'} + Package: ebtables: {'basearchonly': False, 'type': 'optional'} + Package: ed2k_hash: {'basearchonly': False, 'type': 'optional'} + Package: eiciel: {'basearchonly': False, 'type': 'optional'} + Package: emelfm2: {'basearchonly': False, 'type': 'optional'} + Package: enca: {'basearchonly': False, 'type': 'optional'} + Package: environment-modules: {'basearchonly': False, 'type': 'optional'} + Package: epylog: {'basearchonly': False, 'type': 'optional'} + Package: etherbat: {'basearchonly': False, 'type': 'optional'} + Package: ettercap: {'basearchonly': False, 'type': 'optional'} + Package: fatsort: {'basearchonly': False, 'type': 'optional'} + Package: fdupes: {'basearchonly': False, 'type': 'optional'} + Package: fedora-package-config-apt: {'basearchonly': False, 'type': 'optional'} + Package: festival: {'basearchonly': False, 'type': 'optional'} + Package: foremost: {'basearchonly': False, 'type': 'optional'} + Package: freerdp: {'basearchonly': False, 'type': 'optional'} + Package: freeze: {'basearchonly': False, 'type': 'optional'} + Package: fuse: {'basearchonly': False, 'type': 'optional'} + Package: fwknop: {'basearchonly': False, 'type': 'optional'} + Package: fwrestart: {'basearchonly': False, 'type': 'optional'} + Package: ganglia: {'basearchonly': False, 'type': 'optional'} + Package: geoclue: {'basearchonly': False, 'type': 'optional'} + Package: ghasher: {'basearchonly': False, 'type': 'optional'} + Package: ghex: {'basearchonly': False, 'type': 'optional'} + Package: gigolo: {'basearchonly': False, 'type': 'optional'} + Package: gkrellm: {'basearchonly': False, 'type': 'optional'} + Package: gnokii: {'basearchonly': False, 'type': 'optional'} + Package: gnutls-utils: {'basearchonly': False, 'type': 'optional'} + Package: greadelf: {'basearchonly': False, 'type': 'optional'} + Package: grepmail: {'basearchonly': False, 'type': 'optional'} + Package: grsync: {'basearchonly': False, 'type': 'optional'} + Package: gssdp: {'basearchonly': False, 'type': 'optional'} + Package: gtkhash: {'basearchonly': False, 'type': 'optional'} + Package: gtkterm: {'basearchonly': False, 'type': 'optional'} + Package: gupnp: {'basearchonly': False, 'type': 'optional'} + Package: gxemul: {'basearchonly': False, 'type': 'optional'} + Package: hercules: {'basearchonly': False, 'type': 'optional'} + Package: hfsplus-tools: {'basearchonly': False, 'type': 'optional'} + Package: htop: {'basearchonly': False, 'type': 'optional'} + Package: hyperestraier: {'basearchonly': False, 'type': 'optional'} + Package: ibmonitor: {'basearchonly': False, 'type': 'optional'} + Package: iftop: {'basearchonly': False, 'type': 'optional'} + Package: inadyn-mt: {'basearchonly': False, 'type': 'optional'} + Package: incron: {'basearchonly': False, 'type': 'optional'} + Package: iotop: {'basearchonly': False, 'type': 'optional'} + Package: ipsec-tools: {'basearchonly': False, 'type': 'optional'} + Package: ircp-tray: {'basearchonly': False, 'type': 'optional'} + Package: javasysmon: {'basearchonly': False, 'type': 'optional'} + Package: jfbterm: {'basearchonly': False, 'type': 'optional'} + Package: john: {'basearchonly': False, 'type': 'optional'} + Package: kdirstat: {'basearchonly': False, 'type': 'optional'} + Package: keychain: {'basearchonly': False, 'type': 'optional'} + Package: ksmarttray: {'basearchonly': False, 'type': 'optional'} + Package: limph: {'basearchonly': False, 'type': 'optional'} + Package: lirc: {'basearchonly': False, 'type': 'optional'} + Package: liveusb-creator: {'basearchonly': False, 'type': 'optional'} + Package: lzop: {'basearchonly': False, 'type': 'optional'} + Package: macchanger: {'basearchonly': False, 'type': 'optional'} + Package: mc: {'basearchonly': False, 'type': 'optional'} + Package: mmv: {'basearchonly': False, 'type': 'optional'} + Package: mrtg: {'basearchonly': False, 'type': 'optional'} + Package: mtx: {'basearchonly': False, 'type': 'optional'} + Package: munin: {'basearchonly': False, 'type': 'optional'} + Package: nagios: {'basearchonly': False, 'type': 'optional'} + Package: net-snmp-utils: {'basearchonly': False, 'type': 'optional'} + Package: nethogs: {'basearchonly': False, 'type': 'optional'} + Package: netstat-nat: {'basearchonly': False, 'type': 'optional'} + Package: nfswatch: {'basearchonly': False, 'type': 'optional'} + Package: nmap-frontend: {'basearchonly': False, 'type': 'optional'} + Package: noip: {'basearchonly': False, 'type': 'optional'} + Package: nomarch: {'basearchonly': False, 'type': 'optional'} + Package: nrg2iso: {'basearchonly': False, 'type': 'optional'} + Package: ntp: {'basearchonly': False, 'type': 'optional'} + Package: ntp-perl: {'basearchonly': False, 'type': 'optional'} + Package: ntpdate: {'basearchonly': False, 'type': 'optional'} + Package: nut: {'basearchonly': False, 'type': 'optional'} + Package: obexftp: {'basearchonly': False, 'type': 'optional'} + Package: oddjob: {'basearchonly': False, 'type': 'optional'} + Package: oddjob-mkhomedir: {'basearchonly': False, 'type': 'optional'} + Package: p0f: {'basearchonly': False, 'type': 'optional'} + Package: p7zip: {'basearchonly': False, 'type': 'optional'} + Package: p7zip-plugins: {'basearchonly': False, 'type': 'optional'} + Package: PackageKit-command-not-found: {'basearchonly': False, 'type': 'optional'} + Package: par2cmdline: {'basearchonly': False, 'type': 'optional'} + Package: pbzip2: {'basearchonly': False, 'type': 'optional'} + Package: portecle: {'basearchonly': False, 'type': 'optional'} + Package: powerman: {'basearchonly': False, 'type': 'optional'} + Package: powertop: {'basearchonly': False, 'type': 'optional'} + Package: procinfo: {'basearchonly': False, 'type': 'optional'} + Package: puppet: {'basearchonly': False, 'type': 'optional'} + Package: pwgen: {'basearchonly': False, 'type': 'optional'} + Package: qdbm: {'basearchonly': False, 'type': 'optional'} + Package: qstat: {'basearchonly': False, 'type': 'optional'} + Package: radeontool: {'basearchonly': False, 'type': 'optional'} + Package: rdesktop: {'basearchonly': False, 'type': 'optional'} + Package: rdiff-backup: {'basearchonly': False, 'type': 'optional'} + Package: rear: {'basearchonly': False, 'type': 'optional'} + Package: remmina: {'basearchonly': False, 'type': 'optional'} + Package: remmina-plugins-nx: {'basearchonly': False, 'type': 'optional'} + Package: remmina-plugins-rdp: {'basearchonly': False, 'type': 'optional'} + Package: remmina-plugins-telepathy: {'basearchonly': False, 'type': 'optional'} + Package: remmina-plugins-xdmcp: {'basearchonly': False, 'type': 'optional'} + Package: reptyr: {'basearchonly': False, 'type': 'optional'} + Package: rmanage: {'basearchonly': False, 'type': 'optional'} + Package: rootsh: {'basearchonly': False, 'type': 'optional'} + Package: rsnapshot: {'basearchonly': False, 'type': 'optional'} + Package: scrub: {'basearchonly': False, 'type': 'optional'} + Package: sec: {'basearchonly': False, 'type': 'optional'} + Package: shorewall: {'basearchonly': False, 'type': 'optional'} + Package: socat: {'basearchonly': False, 'type': 'optional'} + Package: speech-dispatcher: {'basearchonly': False, 'type': 'optional'} + Package: speech-dispatcher-espeak: {'basearchonly': False, 'type': 'optional'} + Package: speech-dispatcher-festival: {'basearchonly': False, 'type': 'optional'} + Package: speech-dispatcher-flite: {'basearchonly': False, 'type': 'optional'} + Package: stripesnoop: {'basearchonly': False, 'type': 'optional'} + Package: swaks: {'basearchonly': False, 'type': 'optional'} + Package: swatch: {'basearchonly': False, 'type': 'optional'} + Package: synaptic: {'basearchonly': False, 'type': 'optional'} + Package: syslog-ng: {'basearchonly': False, 'type': 'optional'} + Package: sysstat: {'basearchonly': False, 'type': 'optional'} + Package: testdisk: {'basearchonly': False, 'type': 'optional'} + Package: tn5250: {'basearchonly': False, 'type': 'optional'} + Package: torque-client: {'basearchonly': False, 'type': 'optional'} + Package: torque-gui: {'basearchonly': False, 'type': 'optional'} + Package: ttywatch: {'basearchonly': False, 'type': 'optional'} + Package: tunctl: {'basearchonly': False, 'type': 'optional'} + Package: unison213: {'basearchonly': False, 'type': 'optional'} + Package: unison227: {'basearchonly': False, 'type': 'optional'} + Package: upx: {'basearchonly': False, 'type': 'optional'} + Package: uucp: {'basearchonly': False, 'type': 'optional'} + Package: vnstat: {'basearchonly': False, 'type': 'optional'} + Package: wine: {'basearchonly': False, 'type': 'optional'} + Package: wireshark-gnome: {'basearchonly': False, 'type': 'optional'} + Package: wlassistant: {'basearchonly': False, 'type': 'optional'} + Package: w_scan: {'basearchonly': False, 'type': 'optional'} + Package: x3270-x11: {'basearchonly': False, 'type': 'optional'} + Package: xmobar: {'basearchonly': False, 'type': 'optional'} + Package: xsel: {'basearchonly': False, 'type': 'optional'} + Package: xsupplicant: {'basearchonly': False, 'type': 'optional'} + Package: zidrav: {'basearchonly': False, 'type': 'optional'} Group: tamil-support (Tamil Support) - Package: lohit-tamil-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-tamil-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-tamil-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: samyak-tamil-fonts: {'type': 'default', 'basearchonly': False} - Package: serafettin-cartoon-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-tamil-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-tamil-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-tamil-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: samyak-tamil-fonts: {'basearchonly': False, 'type': 'default'} + Package: serafettin-cartoon-fonts: {'basearchonly': False, 'type': 'default'} Group: telugu-support (Telugu Support) - Package: lohit-telugu-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: m17n-db: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-telugu-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-telugu-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: iok: {'type': 'default', 'basearchonly': False} - Package: pothana2000-fonts: {'type': 'default', 'basearchonly': False} - Package: vemana2000-fonts: {'type': 'default', 'basearchonly': False} + Package: lohit-telugu-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: m17n-db: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-telugu-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-telugu-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: iok: {'basearchonly': False, 'type': 'default'} + Package: pothana2000-fonts: {'basearchonly': False, 'type': 'default'} + Package: vemana2000-fonts: {'basearchonly': False, 'type': 'default'} Group: text-internet (Text-based Internet) - Package: abook: {'type': 'optional', 'basearchonly': False} - Package: alpine: {'type': 'optional', 'basearchonly': False} - Package: archivemail: {'type': 'optional', 'basearchonly': False} - Package: argus: {'type': 'optional', 'basearchonly': False} - Package: aria2: {'type': 'optional', 'basearchonly': False} - Package: axel: {'type': 'optional', 'basearchonly': False} - Package: cadaver: {'type': 'optional', 'basearchonly': False} - Package: centerim: {'type': 'optional', 'basearchonly': False} - Package: cone: {'type': 'optional', 'basearchonly': False} - Package: ctorrent: {'type': 'optional', 'basearchonly': False} - Package: deletemail: {'type': 'optional', 'basearchonly': False} - Package: elinks: {'type': 'optional', 'basearchonly': False} - Package: emacs-mew: {'type': 'optional', 'basearchonly': False} - Package: epic: {'type': 'optional', 'basearchonly': False} - Package: fetchmail: {'type': 'optional', 'basearchonly': False} - Package: fpaste: {'type': 'optional', 'basearchonly': False} - Package: getmail: {'type': 'optional', 'basearchonly': False} - Package: iperf: {'type': 'optional', 'basearchonly': False} - Package: irssi: {'type': 'optional', 'basearchonly': False} - Package: isync: {'type': 'optional', 'basearchonly': False} - Package: lftp: {'type': 'optional', 'basearchonly': False} - Package: libtranslate: {'type': 'optional', 'basearchonly': False} - Package: lynx: {'type': 'optional', 'basearchonly': False} - Package: maildirproc: {'type': 'optional', 'basearchonly': False} - Package: mutt: {'type': 'optional', 'basearchonly': False} - Package: ncftp: {'type': 'optional', 'basearchonly': False} - Package: nmh: {'type': 'optional', 'basearchonly': False} - Package: offlineimap: {'type': 'optional', 'basearchonly': False} - Package: rss2email: {'type': 'optional', 'basearchonly': False} - Package: rtorrent: {'type': 'optional', 'basearchonly': False} - Package: sitecopy: {'type': 'optional', 'basearchonly': False} - Package: slrn: {'type': 'optional', 'basearchonly': False} - Package: snownews: {'type': 'optional', 'basearchonly': False} - Package: tftp: {'type': 'optional', 'basearchonly': False} - Package: tin: {'type': 'optional', 'basearchonly': False} - Package: trickle: {'type': 'optional', 'basearchonly': False} - Package: w3m: {'type': 'optional', 'basearchonly': False} - Package: websec: {'type': 'optional', 'basearchonly': False} - Package: whatmask: {'type': 'optional', 'basearchonly': False} - Package: xprobe2: {'type': 'optional', 'basearchonly': False} - Package: yafc: {'type': 'optional', 'basearchonly': False} - Package: youtube-dl: {'type': 'optional', 'basearchonly': False} + Package: abook: {'basearchonly': False, 'type': 'optional'} + Package: alpine: {'basearchonly': False, 'type': 'optional'} + Package: archivemail: {'basearchonly': False, 'type': 'optional'} + Package: argus: {'basearchonly': False, 'type': 'optional'} + Package: aria2: {'basearchonly': False, 'type': 'optional'} + Package: axel: {'basearchonly': False, 'type': 'optional'} + Package: cadaver: {'basearchonly': False, 'type': 'optional'} + Package: centerim: {'basearchonly': False, 'type': 'optional'} + Package: cone: {'basearchonly': False, 'type': 'optional'} + Package: ctorrent: {'basearchonly': False, 'type': 'optional'} + Package: deletemail: {'basearchonly': False, 'type': 'optional'} + Package: elinks: {'basearchonly': False, 'type': 'optional'} + Package: emacs-mew: {'basearchonly': False, 'type': 'optional'} + Package: epic: {'basearchonly': False, 'type': 'optional'} + Package: fetchmail: {'basearchonly': False, 'type': 'optional'} + Package: fpaste: {'basearchonly': False, 'type': 'optional'} + Package: getmail: {'basearchonly': False, 'type': 'optional'} + Package: iperf: {'basearchonly': False, 'type': 'optional'} + Package: irssi: {'basearchonly': False, 'type': 'optional'} + Package: isync: {'basearchonly': False, 'type': 'optional'} + Package: lftp: {'basearchonly': False, 'type': 'optional'} + Package: libtranslate: {'basearchonly': False, 'type': 'optional'} + Package: lynx: {'basearchonly': False, 'type': 'optional'} + Package: maildirproc: {'basearchonly': False, 'type': 'optional'} + Package: mutt: {'basearchonly': False, 'type': 'optional'} + Package: ncftp: {'basearchonly': False, 'type': 'optional'} + Package: nmh: {'basearchonly': False, 'type': 'optional'} + Package: offlineimap: {'basearchonly': False, 'type': 'optional'} + Package: rss2email: {'basearchonly': False, 'type': 'optional'} + Package: rtorrent: {'basearchonly': False, 'type': 'optional'} + Package: sitecopy: {'basearchonly': False, 'type': 'optional'} + Package: slrn: {'basearchonly': False, 'type': 'optional'} + Package: snownews: {'basearchonly': False, 'type': 'optional'} + Package: tftp: {'basearchonly': False, 'type': 'optional'} + Package: tin: {'basearchonly': False, 'type': 'optional'} + Package: trickle: {'basearchonly': False, 'type': 'optional'} + Package: w3m: {'basearchonly': False, 'type': 'optional'} + Package: websec: {'basearchonly': False, 'type': 'optional'} + Package: whatmask: {'basearchonly': False, 'type': 'optional'} + Package: xprobe2: {'basearchonly': False, 'type': 'optional'} + Package: yafc: {'basearchonly': False, 'type': 'optional'} + Package: youtube-dl: {'basearchonly': False, 'type': 'optional'} Group: thai-support (Thai Support) - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: google-noto-sans-thai-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-sans-thai-ui-fonts: {'type': 'default', 'basearchonly': False} - Package: google-noto-serif-thai-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-garuda-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-kinnari-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-loma-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-norasi-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-purisa-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-sawasdee-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-tlwgmono-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-tlwgtypewriter-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-tlwgtypist-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-tlwgtypo-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-umpush-fonts: {'type': 'default', 'basearchonly': False} - Package: thai-scalable-waree-fonts: {'type': 'default', 'basearchonly': False} - Package: scim-tables-thai: {'type': 'optional', 'basearchonly': False} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: google-noto-sans-thai-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-sans-thai-ui-fonts: {'basearchonly': False, 'type': 'default'} + Package: google-noto-serif-thai-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-garuda-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-kinnari-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-loma-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-norasi-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-purisa-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-sawasdee-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-tlwgmono-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-tlwgtypewriter-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-tlwgtypist-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-tlwgtypo-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-umpush-fonts: {'basearchonly': False, 'type': 'default'} + Package: thai-scalable-waree-fonts: {'basearchonly': False, 'type': 'default'} + Package: scim-tables-thai: {'basearchonly': False, 'type': 'optional'} Group: tibetan-support (Tibetan Support) - Package: tibetan-machine-uni-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: jomolhari-fonts: {'type': 'default', 'basearchonly': False} + Package: tibetan-machine-uni-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: jomolhari-fonts: {'basearchonly': False, 'type': 'default'} Group: tomcat (Tomcat) - Package: tomcat: {'type': 'mandatory', 'basearchonly': False} - Package: tomcat-admin-webapps: {'type': 'mandatory', 'basearchonly': False} - Package: tomcat-native: {'type': 'mandatory', 'basearchonly': False} - Package: tomcat-webapps: {'type': 'mandatory', 'basearchonly': False} + Package: tomcat: {'basearchonly': False, 'type': 'mandatory'} + Package: tomcat-admin-webapps: {'basearchonly': False, 'type': 'mandatory'} + Package: tomcat-native: {'basearchonly': False, 'type': 'mandatory'} + Package: tomcat-webapps: {'basearchonly': False, 'type': 'mandatory'} Group: traditional-chinese-support (Traditional Chinese Support) - Package: ibus-libzhuyin: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: adobe-source-han-sans-tw-fonts: {'type': 'default', 'basearchonly': False} - Package: cjkuni-ukai-fonts: {'type': 'optional', 'basearchonly': False} - Package: cjkuni-uming-fonts: {'type': 'optional', 'basearchonly': False} - Package: gcin: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-array: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-cangjie: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-cantonese: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-easy: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-quick: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-scj: {'type': 'optional', 'basearchonly': False} - Package: ibus-table-chinese-stroke5: {'type': 'optional', 'basearchonly': False} - Package: lv: {'type': 'optional', 'basearchonly': False} - Package: m17n-db-extras: {'type': 'optional', 'basearchonly': False} - Package: scim-array: {'type': 'optional', 'basearchonly': False} - Package: scim-tables-chinese: {'type': 'optional', 'basearchonly': False} - Package: scim-tables-chinese-extra: {'type': 'optional', 'basearchonly': False} - Package: stardict-dic-zh_TW: {'type': 'optional', 'basearchonly': False} - Package: taipeifonts: {'type': 'optional', 'basearchonly': False} + Package: ibus-libzhuyin: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: adobe-source-han-sans-tw-fonts: {'basearchonly': False, 'type': 'default'} + Package: cjkuni-ukai-fonts: {'basearchonly': False, 'type': 'optional'} + Package: cjkuni-uming-fonts: {'basearchonly': False, 'type': 'optional'} + Package: gcin: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-array: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-cangjie: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-cantonese: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-easy: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-quick: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-scj: {'basearchonly': False, 'type': 'optional'} + Package: ibus-table-chinese-stroke5: {'basearchonly': False, 'type': 'optional'} + Package: lv: {'basearchonly': False, 'type': 'optional'} + Package: m17n-db-extras: {'basearchonly': False, 'type': 'optional'} + Package: scim-array: {'basearchonly': False, 'type': 'optional'} + Package: scim-tables-chinese: {'basearchonly': False, 'type': 'optional'} + Package: scim-tables-chinese-extra: {'basearchonly': False, 'type': 'optional'} + Package: stardict-dic-zh_TW: {'basearchonly': False, 'type': 'optional'} + Package: taipeifonts: {'basearchonly': False, 'type': 'optional'} Group: urdu-support (Urdu Support) - Package: paktype-naskh-basic-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: paktype-tehreer-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} - Package: dejavu-sans-fonts: {'type': 'default', 'basearchonly': False} - Package: dejavu-sans-mono-fonts: {'type': 'default', 'basearchonly': False} - Package: nafees-nastaleeq-fonts: {'type': 'default', 'basearchonly': False} - Package: nafees-web-naskh-fonts: {'type': 'default', 'basearchonly': False} - Package: kacst-art-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-book-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-decorative-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-digital-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-farsi-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-letter-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-office-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-one-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-pen-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-poster-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-qurn-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-screen-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-title-fonts: {'type': 'optional', 'basearchonly': False} - Package: kacst-titlel-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-pakistani-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-pakistani-web-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-riqa-fonts: {'type': 'optional', 'basearchonly': False} - Package: nafees-tehreer-naskh-fonts: {'type': 'optional', 'basearchonly': False} - Package: paktype-ajrak-fonts: {'type': 'optional', 'basearchonly': False} - Package: paktype-naqsh-fonts: {'type': 'optional', 'basearchonly': False} + Package: paktype-naskh-basic-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: paktype-tehreer-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} + Package: dejavu-sans-fonts: {'basearchonly': False, 'type': 'default'} + Package: dejavu-sans-mono-fonts: {'basearchonly': False, 'type': 'default'} + Package: nafees-nastaleeq-fonts: {'basearchonly': False, 'type': 'default'} + Package: nafees-web-naskh-fonts: {'basearchonly': False, 'type': 'default'} + Package: kacst-art-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-book-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-decorative-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-digital-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-farsi-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-letter-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-office-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-one-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-pen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-poster-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-qurn-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-screen-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-title-fonts: {'basearchonly': False, 'type': 'optional'} + Package: kacst-titlel-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-pakistani-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-pakistani-web-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-riqa-fonts: {'basearchonly': False, 'type': 'optional'} + Package: nafees-tehreer-naskh-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paktype-ajrak-fonts: {'basearchonly': False, 'type': 'optional'} + Package: paktype-naqsh-fonts: {'basearchonly': False, 'type': 'optional'} Group: vagrant (Vagrant with libvirt support) - Package: vagrant: {'type': 'mandatory', 'basearchonly': False} - Package: vagrant-libvirt: {'type': 'default', 'basearchonly': False} - Package: vagrant-cachier: {'type': 'optional', 'basearchonly': False} - Package: vagrant-registration: {'type': 'optional', 'basearchonly': False} + Package: vagrant: {'basearchonly': False, 'type': 'mandatory'} + Package: vagrant-libvirt: {'basearchonly': False, 'type': 'default'} + Package: vagrant-cachier: {'basearchonly': False, 'type': 'optional'} + Package: vagrant-registration: {'basearchonly': False, 'type': 'optional'} Group: vietnamese-support (Vietnamese Support) - Package: ibus-bogo: {'requires': u'xorg-x11-server-Xorg', 'type': 'conditional', 'basearchonly': False} + Package: ibus-bogo: {'basearchonly': False, 'requires': 'xorg-x11-server-Xorg', 'type': 'conditional'} Group: virtualization (Virtualization) - Package: virt-install: {'type': 'mandatory', 'basearchonly': False} - Package: libvirt-daemon-config-network: {'type': 'default', 'basearchonly': False} - Package: libvirt-daemon-kvm: {'type': 'default', 'basearchonly': False} - Package: qemu-kvm: {'type': 'default', 'basearchonly': False} - Package: virt-manager: {'type': 'default', 'basearchonly': False} - Package: virt-viewer: {'type': 'default', 'basearchonly': False} - Package: guestfs-browser: {'type': 'optional', 'basearchonly': False} - Package: libguestfs-tools: {'type': 'optional', 'basearchonly': False} - Package: python-libguestfs: {'type': 'optional', 'basearchonly': False} - Package: virt-top: {'type': 'optional', 'basearchonly': False} + Package: virt-install: {'basearchonly': False, 'type': 'mandatory'} + Package: libvirt-daemon-config-network: {'basearchonly': False, 'type': 'default'} + Package: libvirt-daemon-kvm: {'basearchonly': False, 'type': 'default'} + Package: qemu-kvm: {'basearchonly': False, 'type': 'default'} + Package: virt-manager: {'basearchonly': False, 'type': 'default'} + Package: virt-viewer: {'basearchonly': False, 'type': 'default'} + Package: guestfs-browser: {'basearchonly': False, 'type': 'optional'} + Package: libguestfs-tools: {'basearchonly': False, 'type': 'optional'} + Package: python-libguestfs: {'basearchonly': False, 'type': 'optional'} + Package: virt-top: {'basearchonly': False, 'type': 'optional'} Group: virtualization-headless (Headless Virtualization) - Package: virt-install: {'type': 'mandatory', 'basearchonly': False} - Package: libvirt-daemon-config-network: {'type': 'default', 'basearchonly': False} - Package: libvirt-daemon-kvm: {'type': 'default', 'basearchonly': False} - Package: qemu-kvm: {'type': 'default', 'basearchonly': False} - Package: systemd-container: {'type': 'default', 'basearchonly': False} - Package: guestfs-browser: {'type': 'optional', 'basearchonly': False} - Package: libguestfs-tools: {'type': 'optional', 'basearchonly': False} - Package: python-libguestfs: {'type': 'optional', 'basearchonly': False} - Package: virt-top: {'type': 'optional', 'basearchonly': False} + Package: virt-install: {'basearchonly': False, 'type': 'mandatory'} + Package: libvirt-daemon-config-network: {'basearchonly': False, 'type': 'default'} + Package: libvirt-daemon-kvm: {'basearchonly': False, 'type': 'default'} + Package: qemu-kvm: {'basearchonly': False, 'type': 'default'} + Package: systemd-container: {'basearchonly': False, 'type': 'default'} + Package: guestfs-browser: {'basearchonly': False, 'type': 'optional'} + Package: libguestfs-tools: {'basearchonly': False, 'type': 'optional'} + Package: python-libguestfs: {'basearchonly': False, 'type': 'optional'} + Package: virt-top: {'basearchonly': False, 'type': 'optional'} Group: web-server (Basic Web Server) - Package: httpd: {'type': 'mandatory', 'basearchonly': False} - Package: crypto-utils: {'type': 'default', 'basearchonly': False} - Package: httpd-manual: {'type': 'default', 'basearchonly': False} - Package: mod_perl: {'type': 'default', 'basearchonly': False} - Package: mod_ssl: {'type': 'default', 'basearchonly': False} - Package: php: {'type': 'default', 'basearchonly': False} - Package: php-ldap: {'type': 'default', 'basearchonly': False} - Package: php-mysqlnd: {'type': 'default', 'basearchonly': False} - Package: squid: {'type': 'default', 'basearchonly': False} - Package: webalizer: {'type': 'default', 'basearchonly': False} - Package: apachetop: {'type': 'optional', 'basearchonly': False} - Package: awstats: {'type': 'optional', 'basearchonly': False} - Package: boa: {'type': 'optional', 'basearchonly': False} - Package: cherokee: {'type': 'optional', 'basearchonly': False} - Package: dap-server: {'type': 'optional', 'basearchonly': False} - Package: drupal7: {'type': 'optional', 'basearchonly': False} - Package: lighttpd: {'type': 'optional', 'basearchonly': False} - Package: lighttpd-fastcgi: {'type': 'optional', 'basearchonly': False} - Package: mediawiki: {'type': 'optional', 'basearchonly': False} - Package: mod_auth_kerb: {'type': 'optional', 'basearchonly': False} - Package: mod_fcgid: {'type': 'optional', 'basearchonly': False} - Package: mod_geoip: {'type': 'optional', 'basearchonly': False} - Package: mod_security: {'type': 'optional', 'basearchonly': False} - Package: mod_xsendfile: {'type': 'optional', 'basearchonly': False} - Package: moin: {'type': 'optional', 'basearchonly': False} - Package: ocspd: {'type': 'optional', 'basearchonly': False} - Package: perl-HTML-Mason: {'type': 'optional', 'basearchonly': False} - Package: perl-Kwiki: {'type': 'optional', 'basearchonly': False} - Package: php-odbc: {'type': 'optional', 'basearchonly': False} - Package: php-pecl-apc: {'type': 'optional', 'basearchonly': False} - Package: php-pgsql: {'type': 'optional', 'basearchonly': False} - Package: phpldapadmin: {'type': 'optional', 'basearchonly': False} - Package: phpMyAdmin: {'type': 'optional', 'basearchonly': False} - Package: Pound: {'type': 'optional', 'basearchonly': False} - Package: thttpd: {'type': 'optional', 'basearchonly': False} - Package: tiquit: {'type': 'optional', 'basearchonly': False} - Package: wordpress: {'type': 'optional', 'basearchonly': False} + Package: httpd: {'basearchonly': False, 'type': 'mandatory'} + Package: crypto-utils: {'basearchonly': False, 'type': 'default'} + Package: httpd-manual: {'basearchonly': False, 'type': 'default'} + Package: mod_perl: {'basearchonly': False, 'type': 'default'} + Package: mod_ssl: {'basearchonly': False, 'type': 'default'} + Package: php: {'basearchonly': False, 'type': 'default'} + Package: php-ldap: {'basearchonly': False, 'type': 'default'} + Package: php-mysqlnd: {'basearchonly': False, 'type': 'default'} + Package: squid: {'basearchonly': False, 'type': 'default'} + Package: webalizer: {'basearchonly': False, 'type': 'default'} + Package: apachetop: {'basearchonly': False, 'type': 'optional'} + Package: awstats: {'basearchonly': False, 'type': 'optional'} + Package: boa: {'basearchonly': False, 'type': 'optional'} + Package: cherokee: {'basearchonly': False, 'type': 'optional'} + Package: dap-server: {'basearchonly': False, 'type': 'optional'} + Package: drupal7: {'basearchonly': False, 'type': 'optional'} + Package: lighttpd: {'basearchonly': False, 'type': 'optional'} + Package: lighttpd-fastcgi: {'basearchonly': False, 'type': 'optional'} + Package: mediawiki: {'basearchonly': False, 'type': 'optional'} + Package: mod_auth_kerb: {'basearchonly': False, 'type': 'optional'} + Package: mod_fcgid: {'basearchonly': False, 'type': 'optional'} + Package: mod_geoip: {'basearchonly': False, 'type': 'optional'} + Package: mod_security: {'basearchonly': False, 'type': 'optional'} + Package: mod_xsendfile: {'basearchonly': False, 'type': 'optional'} + Package: moin: {'basearchonly': False, 'type': 'optional'} + Package: ocspd: {'basearchonly': False, 'type': 'optional'} + Package: perl-HTML-Mason: {'basearchonly': False, 'type': 'optional'} + Package: perl-Kwiki: {'basearchonly': False, 'type': 'optional'} + Package: php-odbc: {'basearchonly': False, 'type': 'optional'} + Package: php-pecl-apc: {'basearchonly': False, 'type': 'optional'} + Package: php-pgsql: {'basearchonly': False, 'type': 'optional'} + Package: phpldapadmin: {'basearchonly': False, 'type': 'optional'} + Package: phpMyAdmin: {'basearchonly': False, 'type': 'optional'} + Package: Pound: {'basearchonly': False, 'type': 'optional'} + Package: thttpd: {'basearchonly': False, 'type': 'optional'} + Package: tiquit: {'basearchonly': False, 'type': 'optional'} + Package: wordpress: {'basearchonly': False, 'type': 'optional'} Group: window-managers (Window Managers) - Package: bbkeys: {'type': 'optional', 'basearchonly': False} - Package: blackbox: {'type': 'optional', 'basearchonly': False} - Package: bluetile: {'type': 'optional', 'basearchonly': False} - Package: dwm: {'type': 'optional', 'basearchonly': False} - Package: dwm-user: {'type': 'optional', 'basearchonly': False} - Package: fluxbox: {'type': 'optional', 'basearchonly': False} - Package: fvwm: {'type': 'optional', 'basearchonly': False} - Package: hackedbox: {'type': 'optional', 'basearchonly': False} - Package: i3: {'type': 'optional', 'basearchonly': False} - Package: i3-doc: {'type': 'optional', 'basearchonly': False} - Package: i3lock: {'type': 'optional', 'basearchonly': False} - Package: i3status: {'type': 'optional', 'basearchonly': False} - Package: icewm: {'type': 'optional', 'basearchonly': False} - Package: matchbox-window-manager: {'type': 'optional', 'basearchonly': False} - Package: obconf: {'type': 'optional', 'basearchonly': False} - Package: obmenu: {'type': 'optional', 'basearchonly': False} - Package: openbox: {'type': 'optional', 'basearchonly': False} - Package: ratpoison: {'type': 'optional', 'basearchonly': False} - Package: WindowMaker: {'type': 'optional', 'basearchonly': False} - Package: wmx: {'type': 'optional', 'basearchonly': False} - Package: xcompmgr: {'type': 'optional', 'basearchonly': False} - Package: xmonad: {'type': 'optional', 'basearchonly': False} - Package: xmonad-mate: {'type': 'optional', 'basearchonly': False} + Package: bbkeys: {'basearchonly': False, 'type': 'optional'} + Package: blackbox: {'basearchonly': False, 'type': 'optional'} + Package: bluetile: {'basearchonly': False, 'type': 'optional'} + Package: dwm: {'basearchonly': False, 'type': 'optional'} + Package: dwm-user: {'basearchonly': False, 'type': 'optional'} + Package: fluxbox: {'basearchonly': False, 'type': 'optional'} + Package: fvwm: {'basearchonly': False, 'type': 'optional'} + Package: hackedbox: {'basearchonly': False, 'type': 'optional'} + Package: i3: {'basearchonly': False, 'type': 'optional'} + Package: i3-doc: {'basearchonly': False, 'type': 'optional'} + Package: i3lock: {'basearchonly': False, 'type': 'optional'} + Package: i3status: {'basearchonly': False, 'type': 'optional'} + Package: icewm: {'basearchonly': False, 'type': 'optional'} + Package: matchbox-window-manager: {'basearchonly': False, 'type': 'optional'} + Package: obconf: {'basearchonly': False, 'type': 'optional'} + Package: obmenu: {'basearchonly': False, 'type': 'optional'} + Package: openbox: {'basearchonly': False, 'type': 'optional'} + Package: ratpoison: {'basearchonly': False, 'type': 'optional'} + Package: WindowMaker: {'basearchonly': False, 'type': 'optional'} + Package: wmx: {'basearchonly': False, 'type': 'optional'} + Package: xcompmgr: {'basearchonly': False, 'type': 'optional'} + Package: xmonad: {'basearchonly': False, 'type': 'optional'} + Package: xmonad-mate: {'basearchonly': False, 'type': 'optional'} Group: workstation-product (Fedora Workstation product core) - Package: abrt-cli: {'type': 'mandatory', 'basearchonly': False} - Package: abrt-desktop: {'type': 'mandatory', 'basearchonly': False} - Package: abrt-java-connector: {'type': 'mandatory', 'basearchonly': False} - Package: acl: {'type': 'mandatory', 'basearchonly': False} - Package: adwaita-qt4: {'type': 'mandatory', 'basearchonly': False} - Package: adwaita-qt5: {'type': 'mandatory', 'basearchonly': False} - Package: at: {'type': 'mandatory', 'basearchonly': False} - Package: attr: {'type': 'mandatory', 'basearchonly': False} - Package: bash-completion: {'type': 'mandatory', 'basearchonly': False} - Package: bc: {'type': 'mandatory', 'basearchonly': False} - Package: bind-utils: {'type': 'mandatory', 'basearchonly': False} - Package: bridge-utils: {'type': 'mandatory', 'basearchonly': False} - Package: btrfs-progs: {'type': 'mandatory', 'basearchonly': False} - Package: bzip2: {'type': 'mandatory', 'basearchonly': False} - Package: chrony: {'type': 'mandatory', 'basearchonly': False} - Package: cifs-utils: {'type': 'mandatory', 'basearchonly': False} - Package: cpio: {'type': 'mandatory', 'basearchonly': False} - Package: crontabs: {'type': 'mandatory', 'basearchonly': False} - Package: cryptsetup: {'type': 'mandatory', 'basearchonly': False} - Package: cyrus-sasl-plain: {'type': 'mandatory', 'basearchonly': False} - Package: deltarpm: {'type': 'mandatory', 'basearchonly': False} - Package: dnf: {'type': 'mandatory', 'basearchonly': False} - Package: dnf-langpacks: {'type': 'mandatory', 'basearchonly': False} - Package: dnf-plugins-core: {'type': 'mandatory', 'basearchonly': False} - Package: dos2unix: {'type': 'mandatory', 'basearchonly': False} - Package: dosfstools: {'type': 'mandatory', 'basearchonly': False} - Package: ethtool: {'type': 'mandatory', 'basearchonly': False} - Package: evolution: {'type': 'mandatory', 'basearchonly': False} - Package: evolution-ews: {'type': 'mandatory', 'basearchonly': False} - Package: evolution-help: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-productimg-workstation: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-release-workstation: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-user-agent-chrome: {'type': 'mandatory', 'basearchonly': False} - Package: file: {'type': 'mandatory', 'basearchonly': False} - Package: fpaste: {'type': 'mandatory', 'basearchonly': False} - Package: fros-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: git: {'type': 'mandatory', 'basearchonly': False} - Package: glibc-all-langpacks: {'type': 'mandatory', 'basearchonly': False} - Package: gnome-shell-extension-background-logo: {'type': 'mandatory', 'basearchonly': False} - Package: gnupg2: {'type': 'mandatory', 'basearchonly': False} - Package: google-android-emoji-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: hunspell: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-gtk2: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-gtk3: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-hangul: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-kkc: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-libpinyin: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-libzhuyin: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-m17n: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-qt: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-rawcode: {'type': 'mandatory', 'basearchonly': False} - Package: ibus-typing-booster: {'type': 'mandatory', 'basearchonly': False} - Package: iptstate: {'type': 'mandatory', 'basearchonly': False} - Package: jwhois: {'type': 'mandatory', 'basearchonly': False} - Package: logrotate: {'type': 'mandatory', 'basearchonly': False} - Package: lrzsz: {'type': 'mandatory', 'basearchonly': False} - Package: lsof: {'type': 'mandatory', 'basearchonly': False} - Package: mailcap: {'type': 'mandatory', 'basearchonly': False} - Package: man-pages: {'type': 'mandatory', 'basearchonly': False} - Package: mcelog: {'type': 'mandatory', 'basearchonly': False} - Package: mdadm: {'type': 'mandatory', 'basearchonly': False} - Package: microcode_ctl: {'type': 'mandatory', 'basearchonly': False} - Package: mlocate: {'type': 'mandatory', 'basearchonly': False} - Package: mtr: {'type': 'mandatory', 'basearchonly': False} - Package: net-tools: {'type': 'mandatory', 'basearchonly': False} - Package: nfs-utils: {'type': 'mandatory', 'basearchonly': False} - Package: nmap-ncat: {'type': 'mandatory', 'basearchonly': False} - Package: nss-mdns: {'type': 'mandatory', 'basearchonly': False} - Package: ntfs-3g: {'type': 'mandatory', 'basearchonly': False} - Package: ntfsprogs: {'type': 'mandatory', 'basearchonly': False} - Package: pam_krb5: {'type': 'mandatory', 'basearchonly': False} - Package: pam_pkcs11: {'type': 'mandatory', 'basearchonly': False} - Package: passwdqc: {'type': 'mandatory', 'basearchonly': False} - Package: pciutils: {'type': 'mandatory', 'basearchonly': False} - Package: pinentry-gnome3: {'type': 'mandatory', 'basearchonly': False} - Package: pinfo: {'type': 'mandatory', 'basearchonly': False} - Package: plymouth: {'type': 'mandatory', 'basearchonly': False} - Package: polkit: {'type': 'mandatory', 'basearchonly': False} - Package: ppp: {'type': 'mandatory', 'basearchonly': False} - Package: psacct: {'type': 'mandatory', 'basearchonly': False} - Package: qgnomeplatform: {'type': 'mandatory', 'basearchonly': False} - Package: qt: {'type': 'mandatory', 'basearchonly': False} - Package: qt-settings: {'type': 'mandatory', 'basearchonly': False} - Package: qt-x11: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtbase: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtbase-gui: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtdeclarative: {'type': 'mandatory', 'basearchonly': False} - Package: qt5-qtxmlpatterns: {'type': 'mandatory', 'basearchonly': False} - Package: quota: {'type': 'mandatory', 'basearchonly': False} - Package: rdist: {'type': 'mandatory', 'basearchonly': False} - Package: realmd: {'type': 'mandatory', 'basearchonly': False} - Package: rhythmbox: {'type': 'mandatory', 'basearchonly': False} - Package: rng-tools: {'type': 'mandatory', 'basearchonly': False} - Package: rp-pppoe: {'type': 'mandatory', 'basearchonly': False} - Package: rsync: {'type': 'mandatory', 'basearchonly': False} - Package: scl-utils: {'type': 'mandatory', 'basearchonly': False} - Package: seahorse: {'type': 'mandatory', 'basearchonly': False} - Package: setroubleshoot: {'type': 'mandatory', 'basearchonly': False} - Package: setuptool: {'type': 'mandatory', 'basearchonly': False} - Package: shotwell: {'type': 'mandatory', 'basearchonly': False} - Package: sos: {'type': 'mandatory', 'basearchonly': False} - Package: sssd: {'type': 'mandatory', 'basearchonly': False} - Package: sudo: {'type': 'mandatory', 'basearchonly': False} - Package: symlinks: {'type': 'mandatory', 'basearchonly': False} - Package: systemd-udev: {'type': 'mandatory', 'basearchonly': False} - Package: tar: {'type': 'mandatory', 'basearchonly': False} - Package: tcpdump: {'type': 'mandatory', 'basearchonly': False} - Package: tcp_wrappers: {'type': 'mandatory', 'basearchonly': False} - Package: telnet: {'type': 'mandatory', 'basearchonly': False} - Package: time: {'type': 'mandatory', 'basearchonly': False} - Package: traceroute: {'type': 'mandatory', 'basearchonly': False} - Package: tree: {'type': 'mandatory', 'basearchonly': False} - Package: unoconv: {'type': 'mandatory', 'basearchonly': False} - Package: unzip: {'type': 'mandatory', 'basearchonly': False} - Package: usbutils: {'type': 'mandatory', 'basearchonly': False} - Package: vconfig: {'type': 'mandatory', 'basearchonly': False} - Package: wget: {'type': 'mandatory', 'basearchonly': False} - Package: which: {'type': 'mandatory', 'basearchonly': False} - Package: wireless-tools: {'type': 'mandatory', 'basearchonly': False} - Package: words: {'type': 'mandatory', 'basearchonly': False} - Package: wvdial: {'type': 'mandatory', 'basearchonly': False} - Package: xorg-x11-drv-libinput: {'type': 'mandatory', 'basearchonly': False} - Package: zip: {'type': 'mandatory', 'basearchonly': False} + Package: abrt-cli: {'basearchonly': False, 'type': 'mandatory'} + Package: abrt-desktop: {'basearchonly': False, 'type': 'mandatory'} + Package: abrt-java-connector: {'basearchonly': False, 'type': 'mandatory'} + Package: acl: {'basearchonly': False, 'type': 'mandatory'} + Package: adwaita-qt4: {'basearchonly': False, 'type': 'mandatory'} + Package: adwaita-qt5: {'basearchonly': False, 'type': 'mandatory'} + Package: at: {'basearchonly': False, 'type': 'mandatory'} + Package: attr: {'basearchonly': False, 'type': 'mandatory'} + Package: bash-completion: {'basearchonly': False, 'type': 'mandatory'} + Package: bc: {'basearchonly': False, 'type': 'mandatory'} + Package: bind-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: bridge-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: btrfs-progs: {'basearchonly': False, 'type': 'mandatory'} + Package: bzip2: {'basearchonly': False, 'type': 'mandatory'} + Package: chrony: {'basearchonly': False, 'type': 'mandatory'} + Package: cifs-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: cpio: {'basearchonly': False, 'type': 'mandatory'} + Package: crontabs: {'basearchonly': False, 'type': 'mandatory'} + Package: cryptsetup: {'basearchonly': False, 'type': 'mandatory'} + Package: cyrus-sasl-plain: {'basearchonly': False, 'type': 'mandatory'} + Package: deltarpm: {'basearchonly': False, 'type': 'mandatory'} + Package: dnf: {'basearchonly': False, 'type': 'mandatory'} + Package: dnf-langpacks: {'basearchonly': False, 'type': 'mandatory'} + Package: dnf-plugins-core: {'basearchonly': False, 'type': 'mandatory'} + Package: dos2unix: {'basearchonly': False, 'type': 'mandatory'} + Package: dosfstools: {'basearchonly': False, 'type': 'mandatory'} + Package: ethtool: {'basearchonly': False, 'type': 'mandatory'} + Package: evolution: {'basearchonly': False, 'type': 'mandatory'} + Package: evolution-ews: {'basearchonly': False, 'type': 'mandatory'} + Package: evolution-help: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-productimg-workstation: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-release-workstation: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-user-agent-chrome: {'basearchonly': False, 'type': 'mandatory'} + Package: file: {'basearchonly': False, 'type': 'mandatory'} + Package: fpaste: {'basearchonly': False, 'type': 'mandatory'} + Package: fros-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: git: {'basearchonly': False, 'type': 'mandatory'} + Package: glibc-all-langpacks: {'basearchonly': False, 'type': 'mandatory'} + Package: gnome-shell-extension-background-logo: {'basearchonly': False, 'type': 'mandatory'} + Package: gnupg2: {'basearchonly': False, 'type': 'mandatory'} + Package: google-android-emoji-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: hunspell: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-gtk2: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-gtk3: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-hangul: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-kkc: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-libpinyin: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-libzhuyin: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-m17n: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-qt: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-rawcode: {'basearchonly': False, 'type': 'mandatory'} + Package: ibus-typing-booster: {'basearchonly': False, 'type': 'mandatory'} + Package: iptstate: {'basearchonly': False, 'type': 'mandatory'} + Package: jwhois: {'basearchonly': False, 'type': 'mandatory'} + Package: logrotate: {'basearchonly': False, 'type': 'mandatory'} + Package: lrzsz: {'basearchonly': False, 'type': 'mandatory'} + Package: lsof: {'basearchonly': False, 'type': 'mandatory'} + Package: mailcap: {'basearchonly': False, 'type': 'mandatory'} + Package: man-pages: {'basearchonly': False, 'type': 'mandatory'} + Package: mcelog: {'basearchonly': False, 'type': 'mandatory'} + Package: mdadm: {'basearchonly': False, 'type': 'mandatory'} + Package: microcode_ctl: {'basearchonly': False, 'type': 'mandatory'} + Package: mlocate: {'basearchonly': False, 'type': 'mandatory'} + Package: mtr: {'basearchonly': False, 'type': 'mandatory'} + Package: net-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: nfs-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: nmap-ncat: {'basearchonly': False, 'type': 'mandatory'} + Package: nss-mdns: {'basearchonly': False, 'type': 'mandatory'} + Package: ntfs-3g: {'basearchonly': False, 'type': 'mandatory'} + Package: ntfsprogs: {'basearchonly': False, 'type': 'mandatory'} + Package: pam_krb5: {'basearchonly': False, 'type': 'mandatory'} + Package: pam_pkcs11: {'basearchonly': False, 'type': 'mandatory'} + Package: passwdqc: {'basearchonly': False, 'type': 'mandatory'} + Package: pciutils: {'basearchonly': False, 'type': 'mandatory'} + Package: pinentry-gnome3: {'basearchonly': False, 'type': 'mandatory'} + Package: pinfo: {'basearchonly': False, 'type': 'mandatory'} + Package: plymouth: {'basearchonly': False, 'type': 'mandatory'} + Package: polkit: {'basearchonly': False, 'type': 'mandatory'} + Package: ppp: {'basearchonly': False, 'type': 'mandatory'} + Package: psacct: {'basearchonly': False, 'type': 'mandatory'} + Package: qgnomeplatform: {'basearchonly': False, 'type': 'mandatory'} + Package: qt: {'basearchonly': False, 'type': 'mandatory'} + Package: qt-settings: {'basearchonly': False, 'type': 'mandatory'} + Package: qt-x11: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtbase: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtbase-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtdeclarative: {'basearchonly': False, 'type': 'mandatory'} + Package: qt5-qtxmlpatterns: {'basearchonly': False, 'type': 'mandatory'} + Package: quota: {'basearchonly': False, 'type': 'mandatory'} + Package: rdist: {'basearchonly': False, 'type': 'mandatory'} + Package: realmd: {'basearchonly': False, 'type': 'mandatory'} + Package: rhythmbox: {'basearchonly': False, 'type': 'mandatory'} + Package: rng-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: rp-pppoe: {'basearchonly': False, 'type': 'mandatory'} + Package: rsync: {'basearchonly': False, 'type': 'mandatory'} + Package: scl-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: seahorse: {'basearchonly': False, 'type': 'mandatory'} + Package: setroubleshoot: {'basearchonly': False, 'type': 'mandatory'} + Package: setuptool: {'basearchonly': False, 'type': 'mandatory'} + Package: shotwell: {'basearchonly': False, 'type': 'mandatory'} + Package: sos: {'basearchonly': False, 'type': 'mandatory'} + Package: sssd: {'basearchonly': False, 'type': 'mandatory'} + Package: sudo: {'basearchonly': False, 'type': 'mandatory'} + Package: symlinks: {'basearchonly': False, 'type': 'mandatory'} + Package: systemd-udev: {'basearchonly': False, 'type': 'mandatory'} + Package: tar: {'basearchonly': False, 'type': 'mandatory'} + Package: tcpdump: {'basearchonly': False, 'type': 'mandatory'} + Package: tcp_wrappers: {'basearchonly': False, 'type': 'mandatory'} + Package: telnet: {'basearchonly': False, 'type': 'mandatory'} + Package: time: {'basearchonly': False, 'type': 'mandatory'} + Package: traceroute: {'basearchonly': False, 'type': 'mandatory'} + Package: tree: {'basearchonly': False, 'type': 'mandatory'} + Package: unoconv: {'basearchonly': False, 'type': 'mandatory'} + Package: unzip: {'basearchonly': False, 'type': 'mandatory'} + Package: usbutils: {'basearchonly': False, 'type': 'mandatory'} + Package: vconfig: {'basearchonly': False, 'type': 'mandatory'} + Package: wget: {'basearchonly': False, 'type': 'mandatory'} + Package: which: {'basearchonly': False, 'type': 'mandatory'} + Package: wireless-tools: {'basearchonly': False, 'type': 'mandatory'} + Package: words: {'basearchonly': False, 'type': 'mandatory'} + Package: wvdial: {'basearchonly': False, 'type': 'mandatory'} + Package: xorg-x11-drv-libinput: {'basearchonly': False, 'type': 'mandatory'} + Package: zip: {'basearchonly': False, 'type': 'mandatory'} Group: x-software-development (X Software Development) - Package: libICE-devel: {'type': 'mandatory', 'basearchonly': False} - Package: libX11-devel: {'type': 'mandatory', 'basearchonly': False} - Package: libXaw-devel: {'type': 'mandatory', 'basearchonly': False} - Package: libXfixes-devel: {'type': 'mandatory', 'basearchonly': False} - Package: libXt-devel: {'type': 'mandatory', 'basearchonly': False} - Package: freetype-devel: {'type': 'default', 'basearchonly': False} - Package: gd-devel: {'type': 'default', 'basearchonly': False} - Package: giflib-devel: {'type': 'default', 'basearchonly': False} - Package: libdmx-devel: {'type': 'default', 'basearchonly': False} - Package: libdrm-devel: {'type': 'default', 'basearchonly': False} - Package: libjpeg-turbo-devel: {'type': 'default', 'basearchonly': False} - Package: libmng-devel: {'type': 'default', 'basearchonly': False} - Package: libpng-devel: {'type': 'default', 'basearchonly': False} - Package: libSM-devel: {'type': 'default', 'basearchonly': False} - Package: libtiff-devel: {'type': 'default', 'basearchonly': False} - Package: libXau-devel: {'type': 'default', 'basearchonly': False} - Package: libXcomposite-devel: {'type': 'default', 'basearchonly': False} - Package: libXcursor-devel: {'type': 'default', 'basearchonly': False} - Package: libXdamage-devel: {'type': 'default', 'basearchonly': False} - Package: libXdmcp-devel: {'type': 'default', 'basearchonly': False} - Package: libXevie-devel: {'type': 'default', 'basearchonly': False} - Package: libXext-devel: {'type': 'default', 'basearchonly': False} - Package: libXfont-devel: {'type': 'default', 'basearchonly': False} - Package: libXft-devel: {'type': 'default', 'basearchonly': False} - Package: libxkbfile-devel: {'type': 'default', 'basearchonly': False} - Package: libXmu-devel: {'type': 'default', 'basearchonly': False} - Package: libXrandr-devel: {'type': 'default', 'basearchonly': False} - Package: libXrender-devel: {'type': 'default', 'basearchonly': False} - Package: libXres-devel: {'type': 'default', 'basearchonly': False} - Package: libXScrnSaver-devel: {'type': 'default', 'basearchonly': False} - Package: libXtst-devel: {'type': 'default', 'basearchonly': False} - Package: libXvMC-devel: {'type': 'default', 'basearchonly': False} - Package: libXxf86dga-devel: {'type': 'default', 'basearchonly': False} - Package: libXxf86misc-devel: {'type': 'default', 'basearchonly': False} - Package: libXxf86vm-devel: {'type': 'default', 'basearchonly': False} - Package: mesa-libGL-devel: {'type': 'default', 'basearchonly': False} - Package: netpbm-devel: {'type': 'default', 'basearchonly': False} - Package: pixman-devel: {'type': 'default', 'basearchonly': False} - Package: SDL-devel: {'type': 'default', 'basearchonly': False} - Package: Xaw3d-devel: {'type': 'default', 'basearchonly': False} - Package: xorg-x11-docs: {'type': 'default', 'basearchonly': False} - Package: xorg-x11-xtrans-devel: {'type': 'default', 'basearchonly': False} - Package: xrestop: {'type': 'default', 'basearchonly': False} - Package: icon-naming-utils: {'type': 'optional', 'basearchonly': False} - Package: icon-slicer: {'type': 'optional', 'basearchonly': False} - Package: libXp-devel: {'type': 'optional', 'basearchonly': False} - Package: mesa-libGLU-devel: {'type': 'optional', 'basearchonly': False} - Package: neXtaw-devel: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-server-devel: {'type': 'optional', 'basearchonly': False} - Package: xorg-x11-xbitmaps: {'type': 'optional', 'basearchonly': False} + Package: libICE-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: libX11-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: libXaw-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: libXfixes-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: libXt-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: freetype-devel: {'basearchonly': False, 'type': 'default'} + Package: gd-devel: {'basearchonly': False, 'type': 'default'} + Package: giflib-devel: {'basearchonly': False, 'type': 'default'} + Package: libdmx-devel: {'basearchonly': False, 'type': 'default'} + Package: libdrm-devel: {'basearchonly': False, 'type': 'default'} + Package: libjpeg-turbo-devel: {'basearchonly': False, 'type': 'default'} + Package: libmng-devel: {'basearchonly': False, 'type': 'default'} + Package: libpng-devel: {'basearchonly': False, 'type': 'default'} + Package: libSM-devel: {'basearchonly': False, 'type': 'default'} + Package: libtiff-devel: {'basearchonly': False, 'type': 'default'} + Package: libXau-devel: {'basearchonly': False, 'type': 'default'} + Package: libXcomposite-devel: {'basearchonly': False, 'type': 'default'} + Package: libXcursor-devel: {'basearchonly': False, 'type': 'default'} + Package: libXdamage-devel: {'basearchonly': False, 'type': 'default'} + Package: libXdmcp-devel: {'basearchonly': False, 'type': 'default'} + Package: libXevie-devel: {'basearchonly': False, 'type': 'default'} + Package: libXext-devel: {'basearchonly': False, 'type': 'default'} + Package: libXfont-devel: {'basearchonly': False, 'type': 'default'} + Package: libXft-devel: {'basearchonly': False, 'type': 'default'} + Package: libxkbfile-devel: {'basearchonly': False, 'type': 'default'} + Package: libXmu-devel: {'basearchonly': False, 'type': 'default'} + Package: libXrandr-devel: {'basearchonly': False, 'type': 'default'} + Package: libXrender-devel: {'basearchonly': False, 'type': 'default'} + Package: libXres-devel: {'basearchonly': False, 'type': 'default'} + Package: libXScrnSaver-devel: {'basearchonly': False, 'type': 'default'} + Package: libXtst-devel: {'basearchonly': False, 'type': 'default'} + Package: libXvMC-devel: {'basearchonly': False, 'type': 'default'} + Package: libXxf86dga-devel: {'basearchonly': False, 'type': 'default'} + Package: libXxf86misc-devel: {'basearchonly': False, 'type': 'default'} + Package: libXxf86vm-devel: {'basearchonly': False, 'type': 'default'} + Package: mesa-libGL-devel: {'basearchonly': False, 'type': 'default'} + Package: netpbm-devel: {'basearchonly': False, 'type': 'default'} + Package: pixman-devel: {'basearchonly': False, 'type': 'default'} + Package: SDL-devel: {'basearchonly': False, 'type': 'default'} + Package: Xaw3d-devel: {'basearchonly': False, 'type': 'default'} + Package: xorg-x11-docs: {'basearchonly': False, 'type': 'default'} + Package: xorg-x11-xtrans-devel: {'basearchonly': False, 'type': 'default'} + Package: xrestop: {'basearchonly': False, 'type': 'default'} + Package: icon-naming-utils: {'basearchonly': False, 'type': 'optional'} + Package: icon-slicer: {'basearchonly': False, 'type': 'optional'} + Package: libXp-devel: {'basearchonly': False, 'type': 'optional'} + Package: mesa-libGLU-devel: {'basearchonly': False, 'type': 'optional'} + Package: neXtaw-devel: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-server-devel: {'basearchonly': False, 'type': 'optional'} + Package: xorg-x11-xbitmaps: {'basearchonly': False, 'type': 'optional'} Group: xfce-apps (Applications for the Xfce Desktop) - Package: catfish: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-archive: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-att-remover: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-attachwarner: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-fetchinfo: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-mailmbox: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-newmail: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-notification: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-pgp: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-rssyl: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-smime: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-spam-report: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-tnef: {'type': 'mandatory', 'basearchonly': False} - Package: claws-mail-plugins-vcalendar: {'type': 'mandatory', 'basearchonly': False} - Package: evince: {'type': 'mandatory', 'basearchonly': False} - Package: firefox: {'type': 'mandatory', 'basearchonly': False} - Package: florence: {'type': 'mandatory', 'basearchonly': False} - Package: galculator: {'type': 'mandatory', 'basearchonly': False} - Package: geany: {'type': 'mandatory', 'basearchonly': False} - Package: gparted: {'type': 'mandatory', 'basearchonly': False} - Package: leafpad: {'type': 'mandatory', 'basearchonly': False} - Package: orage: {'type': 'mandatory', 'basearchonly': False} - Package: pidgin: {'type': 'mandatory', 'basearchonly': False} - Package: ristretto: {'type': 'mandatory', 'basearchonly': False} - Package: seahorse: {'type': 'mandatory', 'basearchonly': False} - Package: transmission: {'type': 'mandatory', 'basearchonly': False} - Package: xarchiver: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-clipman-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-dict-plugin: {'type': 'mandatory', 'basearchonly': False} + Package: catfish: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-archive: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-att-remover: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-attachwarner: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-fetchinfo: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-mailmbox: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-newmail: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-notification: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-pgp: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-rssyl: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-smime: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-spam-report: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-tnef: {'basearchonly': False, 'type': 'mandatory'} + Package: claws-mail-plugins-vcalendar: {'basearchonly': False, 'type': 'mandatory'} + Package: evince: {'basearchonly': False, 'type': 'mandatory'} + Package: firefox: {'basearchonly': False, 'type': 'mandatory'} + Package: florence: {'basearchonly': False, 'type': 'mandatory'} + Package: galculator: {'basearchonly': False, 'type': 'mandatory'} + Package: geany: {'basearchonly': False, 'type': 'mandatory'} + Package: gparted: {'basearchonly': False, 'type': 'mandatory'} + Package: leafpad: {'basearchonly': False, 'type': 'mandatory'} + Package: orage: {'basearchonly': False, 'type': 'mandatory'} + Package: pidgin: {'basearchonly': False, 'type': 'mandatory'} + Package: ristretto: {'basearchonly': False, 'type': 'mandatory'} + Package: seahorse: {'basearchonly': False, 'type': 'mandatory'} + Package: transmission: {'basearchonly': False, 'type': 'mandatory'} + Package: xarchiver: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-clipman-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-dict-plugin: {'basearchonly': False, 'type': 'mandatory'} Group: xfce-desktop (Xfce) - Package: abrt-desktop: {'type': 'mandatory', 'basearchonly': False} - Package: adwaita-gtk2-theme: {'type': 'mandatory', 'basearchonly': False} - Package: adwaita-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: albatross-gtk2-theme: {'type': 'mandatory', 'basearchonly': False} - Package: albatross-gtk3-theme: {'type': 'mandatory', 'basearchonly': False} - Package: albatross-xfwm4-theme: {'type': 'mandatory', 'basearchonly': False} - Package: alsa-utils: {'type': 'mandatory', 'basearchonly': False} - Package: bluebird-gtk2-theme: {'type': 'mandatory', 'basearchonly': False} - Package: bluebird-gtk3-theme: {'type': 'mandatory', 'basearchonly': False} - Package: bluebird-xfwm4-theme: {'type': 'mandatory', 'basearchonly': False} - Package: blueman: {'type': 'mandatory', 'basearchonly': False} - Package: desktop-backgrounds-compat: {'type': 'mandatory', 'basearchonly': False} - Package: fedora-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: firewall-config: {'type': 'mandatory', 'basearchonly': False} - Package: fros-recordmydesktop: {'type': 'mandatory', 'basearchonly': False} - Package: greybird-gtk2-theme: {'type': 'mandatory', 'basearchonly': False} - Package: greybird-gtk3-theme: {'type': 'mandatory', 'basearchonly': False} - Package: greybird-xfce4-notifyd-theme: {'type': 'mandatory', 'basearchonly': False} - Package: greybird-xfwm4-theme: {'type': 'mandatory', 'basearchonly': False} - Package: gtk-xfce-engine: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs: {'type': 'mandatory', 'basearchonly': False} - Package: gvfs-archive: {'type': 'mandatory', 'basearchonly': False} - Package: initial-setup-gui: {'type': 'mandatory', 'basearchonly': False} - Package: lightdm-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: network-manager-applet: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-l2tp: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-openconnect: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-openvpn: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-pptp: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-vpnc: {'type': 'mandatory', 'basearchonly': False} - Package: NetworkManager-vpnc-gnome: {'type': 'mandatory', 'basearchonly': False} - Package: nm-connection-editor: {'type': 'mandatory', 'basearchonly': False} - Package: openssh-askpass: {'type': 'mandatory', 'basearchonly': False} - Package: rodent-icon-theme: {'type': 'mandatory', 'basearchonly': False} - Package: Thunar: {'type': 'mandatory', 'basearchonly': False} - Package: thunar-archive-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: thunar-media-tags-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: thunar-volman: {'type': 'mandatory', 'basearchonly': False} - Package: tumbler: {'type': 'mandatory', 'basearchonly': False} - Package: xdg-user-dirs-gtk: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-about: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-appfinder: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-datetime-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-panel: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-places-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-power-manager: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-pulseaudio-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-screenshooter-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-session: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-session-engines: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-settings: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-terminal: {'type': 'mandatory', 'basearchonly': False} - Package: xfconf: {'type': 'mandatory', 'basearchonly': False} - Package: xfdesktop: {'type': 'mandatory', 'basearchonly': False} - Package: xfwm4: {'type': 'mandatory', 'basearchonly': False} - Package: xfwm4-theme-nodoka: {'type': 'mandatory', 'basearchonly': False} - Package: xfwm4-themes: {'type': 'mandatory', 'basearchonly': False} - Package: xscreensaver-base: {'type': 'mandatory', 'basearchonly': False} - Package: yumex: {'type': 'mandatory', 'basearchonly': False} + Package: abrt-desktop: {'basearchonly': False, 'type': 'mandatory'} + Package: adwaita-gtk2-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: adwaita-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: albatross-gtk2-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: albatross-gtk3-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: albatross-xfwm4-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: alsa-utils: {'basearchonly': False, 'type': 'mandatory'} + Package: bluebird-gtk2-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: bluebird-gtk3-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: bluebird-xfwm4-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: blueman: {'basearchonly': False, 'type': 'mandatory'} + Package: desktop-backgrounds-compat: {'basearchonly': False, 'type': 'mandatory'} + Package: fedora-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: firewall-config: {'basearchonly': False, 'type': 'mandatory'} + Package: fros-recordmydesktop: {'basearchonly': False, 'type': 'mandatory'} + Package: greybird-gtk2-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: greybird-gtk3-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: greybird-xfce4-notifyd-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: greybird-xfwm4-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: gtk-xfce-engine: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs: {'basearchonly': False, 'type': 'mandatory'} + Package: gvfs-archive: {'basearchonly': False, 'type': 'mandatory'} + Package: initial-setup-gui: {'basearchonly': False, 'type': 'mandatory'} + Package: lightdm-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: network-manager-applet: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-l2tp: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-openconnect: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-openvpn: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-pptp: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-vpnc: {'basearchonly': False, 'type': 'mandatory'} + Package: NetworkManager-vpnc-gnome: {'basearchonly': False, 'type': 'mandatory'} + Package: nm-connection-editor: {'basearchonly': False, 'type': 'mandatory'} + Package: openssh-askpass: {'basearchonly': False, 'type': 'mandatory'} + Package: rodent-icon-theme: {'basearchonly': False, 'type': 'mandatory'} + Package: Thunar: {'basearchonly': False, 'type': 'mandatory'} + Package: thunar-archive-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: thunar-media-tags-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: thunar-volman: {'basearchonly': False, 'type': 'mandatory'} + Package: tumbler: {'basearchonly': False, 'type': 'mandatory'} + Package: xdg-user-dirs-gtk: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-about: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-appfinder: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-datetime-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-panel: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-places-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-power-manager: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-pulseaudio-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-screenshooter-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-session: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-session-engines: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-settings: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-terminal: {'basearchonly': False, 'type': 'mandatory'} + Package: xfconf: {'basearchonly': False, 'type': 'mandatory'} + Package: xfdesktop: {'basearchonly': False, 'type': 'mandatory'} + Package: xfwm4: {'basearchonly': False, 'type': 'mandatory'} + Package: xfwm4-theme-nodoka: {'basearchonly': False, 'type': 'mandatory'} + Package: xfwm4-themes: {'basearchonly': False, 'type': 'mandatory'} + Package: xscreensaver-base: {'basearchonly': False, 'type': 'mandatory'} + Package: yumex: {'basearchonly': False, 'type': 'mandatory'} Group: xfce-extra-plugins (Extra plugins for the Xfce panel) - Package: xfce4-battery-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-cpugraph-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-diskperf-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-eyes-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-fsguard-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-genmon-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-mailwatch-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-mount-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-netload-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-sensors-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-systemload-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-taskmanager: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-time-out-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-verve-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-weather-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-whiskermenu-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfce4-xkb-plugin: {'type': 'mandatory', 'basearchonly': False} - Package: xfdashboard: {'type': 'mandatory', 'basearchonly': False} - Package: xfdashboard-themes: {'type': 'mandatory', 'basearchonly': False} - Package: xfpanel-switch: {'type': 'mandatory', 'basearchonly': False} + Package: xfce4-battery-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-cpugraph-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-diskperf-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-eyes-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-fsguard-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-genmon-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-mailwatch-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-mount-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-netload-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-sensors-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-systemload-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-taskmanager: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-time-out-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-verve-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-weather-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-whiskermenu-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfce4-xkb-plugin: {'basearchonly': False, 'type': 'mandatory'} + Package: xfdashboard: {'basearchonly': False, 'type': 'mandatory'} + Package: xfdashboard-themes: {'basearchonly': False, 'type': 'mandatory'} + Package: xfpanel-switch: {'basearchonly': False, 'type': 'mandatory'} Group: xfce-media (Multimedia support for Xfce) - Package: asunder: {'type': 'mandatory', 'basearchonly': False} - Package: parole: {'type': 'mandatory', 'basearchonly': False} - Package: pavucontrol: {'type': 'mandatory', 'basearchonly': False} - Package: pragha: {'type': 'mandatory', 'basearchonly': False} - Package: xfburn: {'type': 'mandatory', 'basearchonly': False} + Package: asunder: {'basearchonly': False, 'type': 'mandatory'} + Package: parole: {'basearchonly': False, 'type': 'mandatory'} + Package: pavucontrol: {'basearchonly': False, 'type': 'mandatory'} + Package: pragha: {'basearchonly': False, 'type': 'mandatory'} + Package: xfburn: {'basearchonly': False, 'type': 'mandatory'} Group: xfce-office (Xfce Office) - Package: abiword: {'type': 'mandatory', 'basearchonly': False} - Package: gnumeric: {'type': 'mandatory', 'basearchonly': False} + Package: abiword: {'basearchonly': False, 'type': 'mandatory'} + Package: gnumeric: {'basearchonly': False, 'type': 'mandatory'} Group: xfce-software-development (Xfce Software Development) - Package: libxfce4ui-devel: {'type': 'mandatory', 'basearchonly': False} - Package: libxfce4util-devel: {'type': 'mandatory', 'basearchonly': False} - Package: exo-devel: {'type': 'default', 'basearchonly': False} - Package: garcon-devel: {'type': 'default', 'basearchonly': False} - Package: Thunar-devel: {'type': 'default', 'basearchonly': False} - Package: tumbler-devel: {'type': 'default', 'basearchonly': False} - Package: xfce4-dev-tools: {'type': 'default', 'basearchonly': False} - Package: xfce4-panel-devel: {'type': 'default', 'basearchonly': False} - Package: xfconf-devel: {'type': 'default', 'basearchonly': False} - Package: xfce4-session-devel: {'type': 'optional', 'basearchonly': False} + Package: libxfce4ui-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: libxfce4util-devel: {'basearchonly': False, 'type': 'mandatory'} + Package: exo-devel: {'basearchonly': False, 'type': 'default'} + Package: garcon-devel: {'basearchonly': False, 'type': 'default'} + Package: Thunar-devel: {'basearchonly': False, 'type': 'default'} + Package: tumbler-devel: {'basearchonly': False, 'type': 'default'} + Package: xfce4-dev-tools: {'basearchonly': False, 'type': 'default'} + Package: xfce4-panel-devel: {'basearchonly': False, 'type': 'default'} + Package: xfconf-devel: {'basearchonly': False, 'type': 'default'} + Package: xfce4-session-devel: {'basearchonly': False, 'type': 'optional'} Group: xmonad (XMonad) - Package: xmobar: {'type': 'mandatory', 'basearchonly': False} - Package: xmonad: {'type': 'mandatory', 'basearchonly': False} + Package: xmobar: {'basearchonly': False, 'type': 'mandatory'} + Package: xmonad: {'basearchonly': False, 'type': 'mandatory'} Group: xmonad-mate (XMonad for MATE) - Package: mate-control-center: {'type': 'mandatory', 'basearchonly': False} - Package: mate-panel: {'type': 'mandatory', 'basearchonly': False} - Package: mate-screensaver: {'type': 'mandatory', 'basearchonly': False} - Package: xmonad-mate: {'type': 'mandatory', 'basearchonly': False} + Package: mate-control-center: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-panel: {'basearchonly': False, 'type': 'mandatory'} + Package: mate-screensaver: {'basearchonly': False, 'type': 'mandatory'} + Package: xmonad-mate: {'basearchonly': False, 'type': 'mandatory'} Group: yiddish-support (Yiddish Support) - Package: dejavu-sans-fonts: {'type': 'mandatory', 'basearchonly': False} - Package: culmus-aharoni-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-caladings-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-david-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-drugulin-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-ellinia-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-frank-ruehl-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-hadasim-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-keteryg-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-miriam-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-miriam-mono-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-nachlieli-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-simple-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-stamashkenaz-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-stamsefarad-clm-fonts: {'type': 'default', 'basearchonly': False} - Package: culmus-yehuda-clm-fonts: {'type': 'default', 'basearchonly': False} + Package: dejavu-sans-fonts: {'basearchonly': False, 'type': 'mandatory'} + Package: culmus-aharoni-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-caladings-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-david-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-drugulin-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-ellinia-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-frank-ruehl-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-hadasim-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-keteryg-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-miriam-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-miriam-mono-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-nachlieli-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-simple-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-stamashkenaz-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-stamsefarad-clm-fonts: {'basearchonly': False, 'type': 'default'} + Package: culmus-yehuda-clm-fonts: {'basearchonly': False, 'type': 'default'} diff --git a/tests/test_cli/data/comps-sample.libcomps.out b/tests/test_cli/data/comps-sample.libcomps.out index 7052924..6dd3126 100644 --- a/tests/test_cli/data/comps-sample.libcomps.out +++ b/tests/test_cli/data/comps-sample.libcomps.out @@ -1,39 +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} + Package: alsa-lib-devel: {'basearchonly': False, 'type': 'default'} + Package: audit-libs-devel: {'basearchonly': False, 'type': 'default'} + Package: binutils-devel: {'basearchonly': False, 'type': 'default'} + Package: boost-devel: {'basearchonly': False, 'type': 'default'} + Package: bzip2-devel: {'basearchonly': False, 'type': 'default'} + Package: cyrus-sasl-devel: {'basearchonly': False, 'type': 'default'} Group: backup-client (Backup Client) - Package: amanda-client: {'type': 'mandatory', 'basearchonly': False} - Package: bacula-client: {'type': 'optional', 'basearchonly': False} + Package: amanda-client: {'basearchonly': False, 'type': 'mandatory'} + Package: bacula-client: {'basearchonly': False, 'type': 'optional'} 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} + Package: amanda-server: {'basearchonly': False, 'type': 'mandatory'} + Package: mt-st: {'basearchonly': False, 'type': 'optional'} + Package: mtx: {'basearchonly': False, 'type': 'optional'} Group: ansible-node (Ansible node) - Package: python2-dnf: {'type': 'mandatory', 'basearchonly': False} - Package: libselinux-python: {'requires': u'selinux-policy', 'type': 'conditional', 'basearchonly': False} + Package: python2-dnf: {'basearchonly': False, 'type': 'mandatory'} + Package: libselinux-python: {'basearchonly': False, 'requires': 'selinux-policy', 'type': 'conditional'} 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} + Package: ldc: {'basearchonly': True, 'type': 'mandatory'} + Package: ldc-druntime: {'basearchonly': True, 'type': 'mandatory'} + Package: ldc-druntime-devel: {'basearchonly': True, 'type': 'mandatory'} + Package: ldc-phobos-devel: {'basearchonly': True, 'type': 'mandatory'} + Package: make: {'basearchonly': False, 'type': 'mandatory'} + Package: pkgconfig: {'basearchonly': False, 'type': 'mandatory'} + Package: ctags: {'basearchonly': False, 'type': 'default'} + Package: indent: {'basearchonly': False, 'type': 'default'} + Package: astyle: {'basearchonly': False, 'type': 'optional'} + Package: cmake: {'basearchonly': False, 'type': 'optional'} + Package: derelict-devel: {'basearchonly': False, 'type': 'optional'} + Package: geany: {'basearchonly': False, 'type': 'optional'} + Package: gl3n-devel: {'basearchonly': False, 'type': 'optional'} + Package: insight: {'basearchonly': False, 'type': 'optional'} + Package: nemiver: {'basearchonly': False, 'type': 'optional'} + Package: uncrustify: {'basearchonly': False, 'type': 'optional'} 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} + Package: unknown: {'basearchonly': False, 'type': 'unknown'} + Package: unknown2: {'basearchonly': False, 'type': 'unknown'} diff --git a/tests/test_cli/loadcli.py b/tests/test_cli/loadcli.py index 703aeaa..37b4e48 100644 --- a/tests/test_cli/loadcli.py +++ b/tests/test_cli/loadcli.py @@ -6,11 +6,14 @@ import sys # koji module, or the koji cli module. Jump through hoops accordingly. # https://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) +''' + +import imp +cli = imp.load_source('koji_cli', CLI_FILENAME) diff --git a/tests/test_cli/test_list_commands.py b/tests/test_cli/test_list_commands.py index 56c0b23..b73ade0 100644 --- a/tests/test_cli/test_list_commands.py +++ b/tests/test_cli/test_list_commands.py @@ -28,7 +28,10 @@ class TestListCommands(unittest.TestCase): def test_list_commands(self, stdout): cli.list_commands() actual = stdout.getvalue() - actual = actual.replace('nosetests', 'koji') + if six.PY2: + actual = actual.replace('nosetests', 'koji') + else: + actual = actual.replace('python3 -m nose', 'koji') filename = os.path.dirname(__file__) + '/data/list-commands.txt' with open(filename, 'rb') as f: expected = f.read().decode('ascii') @@ -41,7 +44,10 @@ class TestListCommands(unittest.TestCase): self.parser.parse_args.return_value = [options, arguments] cli.handle_help(self.options, self.session, self.args) actual = stdout.getvalue() - actual = actual.replace('nosetests', 'koji') + if six.PY2: + actual = actual.replace('nosetests', 'koji') + else: + actual = actual.replace('python3 -m nose', 'koji') filename = os.path.dirname(__file__) + '/data/list-commands-admin.txt' with open(filename, 'rb') as f: expected = f.read().decode('ascii') diff --git a/tests/test_cli/test_unique_path.py b/tests/test_cli/test_unique_path.py index 82aeea7..ed413b5 100644 --- a/tests/test_cli/test_unique_path.py +++ b/tests/test_cli/test_unique_path.py @@ -16,7 +16,7 @@ class TestUniquePath(unittest.TestCase): cli._unique_path('prefix')) self.assertRegexpMatches( cli._unique_path('prefix'), - '^prefix/\d{10}\.\d{1,6}\.[a-zA-Z]{8}$') + '^prefix/\d{10}\.\d{1,7}\.[a-zA-Z]{8}$') if __name__ == '__main__': unittest.main() diff --git a/tests/test_hub/test_insert_processor.py b/tests/test_hub/test_insert_processor.py index fde1cc3..ae45fb9 100644 --- a/tests/test_hub/test_insert_processor.py +++ b/tests/test_hub/test_insert_processor.py @@ -69,9 +69,11 @@ class TestInsertProcessor(unittest.TestCase): proc.dup_check() args = cursor.execute.call_args actual = ' '.join(args[0][0].split()) - expected = 'SELECT active, foo FROM sometable WHERE ' + \ + expected1 = 'SELECT foo, active FROM sometable WHERE ' + \ + '(foo = %(foo)s) AND (active = %(active)s)' + expected2 = 'SELECT active, foo FROM sometable WHERE ' + \ '(active = %(active)s) AND (foo = %(foo)s)' - self.assertEquals(actual, expected) + self.assertIn(actual, (expected1, expected2)) proc.set(onething='another') proc.rawset(something='something else') From 6948551318d8b2784b670d547ace578c3a564ea4 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:23 +0000 Subject: [PATCH 33/61] read json data in text-mode instead of binary --- diff --git a/hub/kojihub.py b/hub/kojihub.py index 0283ee5..578ecb2 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -5141,7 +5141,7 @@ class CG_Importer(object): path = os.path.join(workdir, directory, metadata) if not os.path.exists(path): raise koji.GenericError("No such file: %s" % metadata) - fo = open(path, 'rb') + fo = open(path, 'rt') metadata = fo.read() fo.close() self.raw_metadata = metadata From d2ab86584aac1a6e4f322c543588b985b3d83356 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 34/61] explicit unicode in cli --- diff --git a/cli/koji b/cli/koji index ccb1022..d00c580 100755 --- a/cli/koji +++ b/cli/koji @@ -116,6 +116,12 @@ def _(args): """Stub function for translation""" return args +def _printable_unicode(s): + if six.PY2: + return s.encode('utf-8') + else: + return s + ARGMAP = {'None': None, 'True': True, 'False': False} @@ -4055,15 +4061,15 @@ def _printInheritance(tags, sibdepths=None, reverse=False): if depth < currtag['currdepth']: outspacing = depth - outdepth sys.stdout.write(' ' * (outspacing * 3 - 1)) - sys.stdout.write(u'\u2502'.encode('UTF-8')) + sys.stdout.write(_printable_unicode(u'\u2502')) outdepth = depth sys.stdout.write(' ' * ((currtag['currdepth'] - outdepth) * 3 - 1)) if siblings: - sys.stdout.write(u'\u251c'.encode('UTF-8')) + sys.stdout.write(_printable_unicode(u'\u251c')) else: - sys.stdout.write(u'\u2514'.encode('UTF-8')) - sys.stdout.write(u'\u2500'.encode('UTF-8')) + sys.stdout.write(_printable_unicode(u'\u2514')) + sys.stdout.write(_printable_unicode(u'\u2500')) if reverse: sys.stdout.write('%(name)s (%(tag_id)i)\n' % currtag) else: @@ -7349,7 +7355,7 @@ def handle_moshimoshi(options, session, args): if not u: print("Not authenticated") u = {'name' : 'anonymous user'} - print("%s, %s!" % (random.choice(greetings).encode('utf-8'), u["name"])) + print("%s, %s!" % (_printable_unicode(random.choice(greetings)), u["name"])) print("") print("You are using the hub at %s" % session.baseurl) authtype = u.get('authtype', getattr(session, 'authtype', None)) From d625c0aa4d28bd01f6b2daac839d3167cee13b6c Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 35/61] remove changes not relevant to cli --- diff --git a/builder/kojid b/builder/kojid index 2da22fb..235cbeb 100755 --- a/builder/kojid +++ b/builder/kojid @@ -21,9 +21,6 @@ # Mike McLean # Mike Bonnet -from __future__ import absolute_import -from six.moves import zip -import six try: import krbV except ImportError: # pragma: no cover @@ -58,11 +55,11 @@ import sys import time import traceback import xml.dom.minidom -import six.moves.xmlrpc_client +import xmlrpclib import zipfile import copy import Cheetah.Template -from six.moves.configparser import ConfigParser +from ConfigParser import ConfigParser from fnmatch import fnmatch from gzip import GzipFile from optparse import OptionParser, SUPPRESS_HELP @@ -256,7 +253,7 @@ class BuildRoot(object): output = koji.genMockConfig(self.name, self.br_arch, managed=True, **opts) #write config - fo = open(configfile,'w') + fo = file(configfile,'w') fo.write(output) fo.close() @@ -269,7 +266,7 @@ class BuildRoot(object): id_suffix = 'repo' name_prefix = 'Repository for Koji' for dep in self.deps: - if isinstance(dep, six.integer_types): + if isinstance(dep, (int, long)): # dep is a task ID, the url points to the task output directory repo_type = 'task' dep_url = pi.task(dep) @@ -356,7 +353,7 @@ class BuildRoot(object): """ settings = settings % locals() - fo = open(self.rootdir() + destfile, 'w') + fo = file(self.rootdir() + destfile, 'w') fo.write(settings) fo.close() @@ -410,7 +407,7 @@ class BuildRoot(object): self.logger.info('Rereading %s, inode: %s -> %s, size: %s -> %s' % (fpath, inode, stat_info.st_ino, size, stat_info.st_size)) fd.close() - fd = open(fpath, 'r') + fd = file(fpath, 'r') logs[fname] = (fd, stat_info.st_ino, stat_info.st_size, fpath) except: self.logger.error("Error reading mock log: %s", fpath) @@ -431,7 +428,7 @@ class BuildRoot(object): if workdir: outfile = os.path.join(workdir, mocklog) flags = os.O_CREAT | os.O_WRONLY | os.O_APPEND - fd = os.open(outfile, flags, 0o666) + fd = os.open(outfile, flags, 0666) os.dup2(fd, 1) os.dup2(fd, 2) if os.getuid() == 0 and hasattr(self.options,"mockuser"): @@ -659,7 +656,7 @@ class BuildRoot(object): repodir = pathinfo.repo(self.repo_info['id'], self.repo_info['tag_name']) repomdpath = os.path.join(repodir, self.br_arch, 'repodata', 'repomd.xml') - opts = dict([(k, getattr(self.options, k)) for k in ('topurl','topdir')]) + opts = dict([(k, getattr(self.options, k)) for k in 'topurl','topdir']) opts['tempdir'] = self.options.workdir fo = koji.openRemoteFile(repomdpath, **opts) try: @@ -914,7 +911,7 @@ class BuildTask(BaseTaskHandler): #srpm arg should be a path relative to /work self.logger.debug("Reading SRPM") relpath = "work/%s" % srpm - opts = dict([(k, getattr(self.options, k)) for k in ('topurl','topdir')]) + opts = dict([(k, getattr(self.options, k)) for k in 'topurl','topdir']) opts['tempdir'] = self.workdir fo = koji.openRemoteFile(relpath, **opts) h = koji.get_rpm_header(fo) @@ -967,7 +964,7 @@ class BuildTask(BaseTaskHandler): archdict[a] = 1 if not archdict: raise koji.BuildError("No matching arches were found") - return list(archdict.keys()) + return archdict.keys() def choose_taskarch(self, arch, srpm, build_tag): @@ -1029,7 +1026,7 @@ class BuildTask(BaseTaskHandler): # wait for subtasks to finish failany = not getattr(self.options, 'build_arch_can_fail', False) - results = self.wait(list(subtasks.values()), all=True, failany=failany) + results = self.wait(subtasks.values(), all=True, failany=failany) # finalize import # merge data into needed args for completeBuild call @@ -1037,7 +1034,7 @@ class BuildTask(BaseTaskHandler): brmap = {} logs = {} built_srpm = None - for (arch, task_id) in six.iteritems(subtasks): + for (arch, task_id) in subtasks.iteritems(): result = results[task_id] self.logger.debug("DEBUG: %r : %r " % (arch,result,)) brootid = result['brootid'] @@ -1348,7 +1345,7 @@ class BuildMavenTask(BaseBuildTask): st = os.lstat(filepath) mtime = time.localtime(st.st_mtime) info = zipfile.ZipInfo(filepath[roottrim:]) - info.external_attr |= 0o120000 << 16 # symlink file type + info.external_attr |= 0120000 << 16L # symlink file type info.compress_type = zipfile.ZIP_STORED info.date_time = mtime[:6] zfo.writestr(info, content) @@ -1516,7 +1513,7 @@ class BuildMavenTask(BaseBuildTask): for filepath in logs: self.uploadFile(os.path.join(outputdir, filepath), relPath=os.path.dirname(filepath)) - for relpath, files in six.iteritems(output_files): + for relpath, files in output_files.iteritems(): for filename in files: self.uploadFile(os.path.join(outputdir, relpath, filename), relPath=relpath) @@ -1746,7 +1743,7 @@ class WrapperRPMTask(BaseBuildTask): contents = contents.encode('utf-8') specfile = spec_template[:-5] - specfd = open(specfile, 'w') + specfd = file(specfile, 'w') specfd.write(contents) specfd.close() @@ -1957,7 +1954,7 @@ class ChainMavenTask(MultiPlatformTask): pkg_to_wrap = params['buildrequires'][0] to_wrap = self.done[pkg_to_wrap] - if isinstance(to_wrap, six.integer_types): + if isinstance(to_wrap, (int, long)): task_to_wrap = self.session.getTaskInfo(to_wrap, request=True) build_to_wrap = None else: @@ -1976,8 +1973,8 @@ class ChainMavenTask(MultiPlatformTask): running[task_id] = package del todo[package] try: - results = self.wait(list(running.keys())) - except (six.moves.xmlrpc_client.Fault, koji.GenericError) as e: + results = self.wait(running.keys()) + except (xmlrpclib.Fault, koji.GenericError), e: # One task has failed, wait for the rest to complete before the # chainmaven task fails. self.wait(all=True) should thrown an exception. self.wait(all=True) @@ -2029,8 +2026,8 @@ class ChainMavenTask(MultiPlatformTask): have the same keys and those keys have the same values. If a value is list, it will be considered equal to a list with the same values in a different order.""" - akeys = list(a.keys()) - bkeys = list(b.keys()) + akeys = a.keys() + bkeys = b.keys() if sorted(akeys) != sorted(bkeys): return False for key in akeys: @@ -2114,7 +2111,7 @@ class TagBuildTask(BaseTaskHandler): #XXX - add more post tests self.session.host.tagBuild(self.id,tag_id,build_id,force=force,fromtag=fromtag) self.session.host.tagNotification(True, tag_id, fromtag, build_id, user_id, ignore_success) - except Exception as e: + except Exception, e: exctype, value = sys.exc_info()[:2] self.session.host.tagNotification(False, tag_id, fromtag, build_id, user_id, ignore_success, "%s: %s" % (exctype, value)) raise e @@ -2191,7 +2188,7 @@ class BuildBaseImageTask(BuildImageTask): canfail.append(subtasks[arch]) self.logger.debug("Got image subtasks: %r" % (subtasks)) self.logger.debug("Waiting on image subtasks (%s can fail)..." % canfail) - results = self.wait(list(subtasks.values()), all=True, failany=True, canfail=canfail) + results = self.wait(subtasks.values(), all=True, failany=True, canfail=canfail) # if everything failed, fail even if all subtasks are in canfail self.logger.debug('subtask results: %r', results) @@ -2500,7 +2497,7 @@ class BuildLiveMediaTask(BuildImageTask): self.logger.debug("Got image subtasks: %r", subtasks) self.logger.debug("Waiting on livemedia subtasks...") - results = self.wait(list(subtasks.values()), all=True, failany=True, canfail=canfail) + results = self.wait(subtasks.values(), all=True, failany=True, canfail=canfail) # if everything failed, fail even if all subtasks are in canfail self.logger.debug('subtask results: %r', results) @@ -2536,7 +2533,7 @@ class BuildLiveMediaTask(BuildImageTask): wrapper_tasks[arch] = self.subtask('wrapperRPM', arglist, label='wrapper %s' % arch, arch='noarch') - results2 = self.wait(list(wrapper_tasks.values()), all=True, failany=True) + results2 = self.wait(wrapper_tasks.values(), all=True, failany=True) self.logger.debug('wrapper results: %r', results2) # add wrapper rpm results into main results @@ -2677,10 +2674,10 @@ class ImageTask(BaseTaskHandler): self.ks = ksparser.KickstartParser(version) try: self.ks.readKickstart(kspath) - except IOError as e: + except IOError, e: raise koji.LiveCDError("Failed to read kickstart file " "'%s' : %s" % (kspath, e)) - except kserrors.KickstartError as e: + except kserrors.KickstartError, e: raise koji.LiveCDError("Failed to parse kickstart file " "'%s' : %s" % (kspath, e)) @@ -2707,7 +2704,7 @@ class ImageTask(BaseTaskHandler): self.ks.handler.repo.repoList = [] # delete whatever the ks file told us if opts.get('repo'): user_repos = opts['repo'] - if isinstance(user_repos, six.string_types): + if isinstance(user_repos, basestring): user_repos = user_repos.split(',') index = 0 for user_repo in user_repos: @@ -2781,7 +2778,7 @@ class ImageTask(BaseTaskHandler): 'TC': 'T', } - for k, v in six.iteritems(substitutions): + for k, v in substitutions.iteritems(): if k in name: name = name.replace(k, v) if k in version: @@ -3261,7 +3258,7 @@ class OzImageTask(BaseTaskHandler): self.getUploadDir(), logfile) kspath = os.path.join(scmsrcdir, os.path.basename(ksfile)) else: - tops = dict([(k, getattr(self.options, k)) for k in ('topurl','topdir')]) + tops = dict([(k, getattr(self.options, k)) for k in 'topurl','topdir']) tops['tempdir'] = self.workdir ks_src = koji.openRemoteFile(ksfile, **tops) kspath = os.path.join(self.workdir, os.path.basename(ksfile)) @@ -3292,10 +3289,10 @@ class OzImageTask(BaseTaskHandler): self.logger.debug('attempting to read kickstart: %s' % kspath) try: ks.readKickstart(kspath) - except IOError as e: + except IOError, e: raise koji.BuildError("Failed to read kickstart file " "'%s' : %s" % (kspath, e)) - except kserrors.KickstartError as e: + except kserrors.KickstartError, e: raise koji.BuildError("Failed to parse kickstart file " "'%s' : %s" % (kspath, e)) return ks @@ -3538,7 +3535,7 @@ class BaseImageTask(OzImageTask): if len(formats) == 0: # we only want a raw disk image (no format option given) f_dict['raw'] = True - elif 'raw' not in list(f_dict.keys()): + elif 'raw' not in f_dict.keys(): f_dict['raw'] = False self.logger.debug('Image delivery plan: %s' % f_dict) return f_dict @@ -4068,7 +4065,7 @@ class BuildIndirectionImageTask(OzImageTask): self.getUploadDir(), logfile) final_path = os.path.join(scmsrcdir, os.path.basename(filepath)) else: - tops = dict([(k, getattr(self.options, k)) for k in ('topurl','topdir')]) + tops = dict([(k, getattr(self.options, k)) for k in 'topurl','topdir']) tops['tempdir'] = self.workdir remote_fileobj = koji.openRemoteFile(filepath, **tops) final_path = os.path.join(self.workdir, os.path.basename(filepath)) @@ -4229,7 +4226,7 @@ class BuildIndirectionImageTask(OzImageTask): base_factory_image = _nvr_to_image(opts['base_image_build'], opts['arch']) else: base_factory_image = _task_to_image(int(opts['base_image_task'])) - except Exception as e: + except Exception, e: self.logger.exception(e) raise @@ -4291,7 +4288,7 @@ class BuildIndirectionImageTask(OzImageTask): image_id=base_factory_image.identifier, parameters=params) target.target_thread.join() - except Exception as e: + except Exception, e: self.logger.debug("Exception encountered during target build") self.logger.exception(e) finally: @@ -4761,8 +4758,8 @@ Build Info: %(weburl)s/buildinfo?buildID=%(build_id)i\r def uniq(self, items): """Remove duplicates from the list of items, and sort the list.""" - m = dict(list(zip(items, [1] * len(items)))) - l = list(m.keys()) + m = dict(zip(items, [1] * len(items))) + l = m.keys() l.sort() return l @@ -4807,8 +4804,8 @@ class NewRepoTask(BaseTaskHandler): # gather subtask results data = {} if subtasks: - results = self.wait(list(subtasks.values()), all=True, failany=True) - for (arch, task_id) in six.iteritems(subtasks): + results = self.wait(subtasks.values(), all=True, failany=True) + for (arch, task_id) in subtasks.iteritems(): data[arch] = results[task_id] self.logger.debug("DEBUG: %r : %r " % (arch,data[arch],)) @@ -4849,7 +4846,7 @@ class CreaterepoTask(BaseTaskHandler): if external_repos: self.merge_repos(external_repos, arch, groupdata) elif pkglist is None: - fo = open(os.path.join(self.datadir, "EMPTY_REPO"), 'w') + fo = file(os.path.join(self.datadir, "EMPTY_REPO"), 'w') fo.write("This repo is empty because its tag has no content for this arch\n") fo.close() @@ -4967,7 +4964,7 @@ class NewDistRepoTask(BaseTaskHandler): method='createdistrepo', arglist=arglist, label=arch, parent=self.id, arch='noarch') if len(subtasks) > 0 and task_opts['multilib']: - results = self.wait(list(subtasks.values()), all=True, failany=True) + results = self.wait(subtasks.values(), all=True, failany=True) for arch in arch32s: # move the 32-bit task output to the final resting place # so the 64-bit arches can use it for multilib @@ -4983,8 +4980,8 @@ class NewDistRepoTask(BaseTaskHandler): parent=self.id, arch='noarch') # wait for 64-bit subtasks to finish data = {} - results = self.wait(list(subtasks.values()), all=True, failany=True) - for (arch, task_id) in six.iteritems(subtasks): + results = self.wait(subtasks.values(), all=True, failany=True) + for (arch, task_id) in subtasks.iteritems(): data[arch] = results[task_id] self.logger.debug("DEBUG: %r : %r " % (arch, data[arch])) if task_opts['multilib'] and arch in arch32s: @@ -5064,7 +5061,7 @@ class createDistRepoTask(CreaterepoTask): self.pkglist = None self.create_local_repo(self.rinfo, arch, self.pkglist, groupdata, None, oldpkgs=oldpkgs) if self.pkglist is None: - fo = open(os.path.join(self.datadir, "EMPTY_REPO"), 'w') + fo = file(os.path.join(self.datadir, "EMPTY_REPO"), 'w') fo.write("This repo is empty because its tag has no content for this arch\n") fo.close() files = ['pkglist', 'kojipkgs'] @@ -5078,7 +5075,7 @@ class createDistRepoTask(CreaterepoTask): files.append(f) self.session.uploadWrapper('%s/%s' % (ddir, f), self.uploadpath, f) - return [self.uploadpath, files, list(self.sigmap.items())] + return [self.uploadpath, files, self.sigmap.items()] def do_multilib(self, arch, ml_arch, conf): self.repo_id = self.rinfo['id'] @@ -5258,7 +5255,7 @@ enabled=1 # select our rpms selected = {} for rpm_id in rpm_idx: - avail_keys = list(rpm_idx[rpm_id].keys()) + avail_keys = rpm_idx[rpm_id].keys() best_key = self.pick_key(keys, avail_keys) if best_key is None: # we lack a matching key for this rpm @@ -5271,7 +5268,7 @@ enabled=1 #generate pkglist files pkgfile = os.path.join(self.repodir, 'pkglist') - pkglist = open(pkgfile, 'w') + pkglist = file(pkgfile, 'w') fs_missing = [] sig_missing = [] kojipkgs = {} @@ -5331,7 +5328,7 @@ enabled=1 fmt = '%(name)s-%(version)s-%(release)s.%(arch)s' filenames = [[fmt % selected[r], r] for r in sig_missing] for fname, rpm_id in sorted(filenames): - avail = list(rpm_idx.get(rpm_id, {}).keys()) + avail = rpm_idx.get(rpm_id, {}).keys() outfile.write('%s: %r\n' % (fname, avail)) outfile.close() self.session.uploadWrapper(missing_log, self.uploadpath) @@ -5344,7 +5341,7 @@ enabled=1 def write_kojipkgs(self): filename = os.path.join(self.repodir, 'kojipkgs') - datafile = open(filename, 'w') + datafile = file(filename, 'w') try: json.dump(self.kojipkgs, datafile, indent=4) finally: @@ -5383,7 +5380,7 @@ class WaitrepoTask(BaseTaskHandler): if not targets: raise koji.GenericError("No build target for tag: %s" % taginfo['name']) - if isinstance(newer_than, six.string_types) and newer_than.lower() == "now": + if isinstance(newer_than, basestring) and newer_than.lower() == "now": newer_than = start if not isinstance(newer_than, (type(None), int, long, float)): raise koji.GenericError("Invalid value for newer_than: %s" % newer_than) @@ -5546,7 +5543,7 @@ def get_options(): defaults[name] = config.getboolean('kojid', name) elif name in ['plugin', 'plugins']: defaults['plugin'] = value.split() - elif name in list(defaults.keys()): + elif name in defaults.keys(): defaults[name] = value elif name.upper().startswith('RLIMIT_'): defaults[name.upper()] = value @@ -5634,9 +5631,9 @@ if __name__ == "__main__": # authenticate using SSL client certificates session.ssl_login(options.cert, None, options.serverca) - except koji.AuthError as e: + except koji.AuthError, e: quit("Error: Unable to log in: %s" % e) - except six.moves.xmlrpc_client.ProtocolError: + except xmlrpclib.ProtocolError: quit("Error: Unable to connect to server %s" % (options.server)) elif options.user: try: @@ -5644,7 +5641,7 @@ if __name__ == "__main__": session.login() except koji.AuthError: quit("Error: Unable to log in. Bad credentials?") - except six.moves.xmlrpc_client.ProtocolError: + except xmlrpclib.ProtocolError: quit("Error: Unable to connect to server %s" % (options.server)) elif 'krbV' in sys.modules: krb_principal = options.krb_principal @@ -5654,9 +5651,9 @@ if __name__ == "__main__": session.krb_login(principal=krb_principal, keytab=options.keytab, ccache=options.ccache) - except krbV.Krb5Error as e: + except krbV.Krb5Error, e: quit("Kerberos authentication failed: '%s' (%s)" % (e.args[1], e.args[0])) - except socket.error as e: + except socket.error, e: quit("Could not connect to Kerberos authentication service: '%s'" % e.args[1]) else: quit("No username/password supplied and Kerberos missing or not configured") @@ -5670,7 +5667,7 @@ if __name__ == "__main__": #make sure it works try: ret = session.echo("OK") - except six.moves.xmlrpc_client.ProtocolError: + except xmlrpclib.ProtocolError: quit("Error: Unable to connect to server %s" % (options.server)) if ret != ["OK"]: quit("Error: incorrect server response: %r" % (ret)) diff --git a/builder/mergerepos b/builder/mergerepos index a27c1ee..cb081bb 100755 --- a/builder/mergerepos +++ b/builder/mergerepos @@ -21,7 +21,6 @@ # Largely borrowed from the mergerepo script included in createrepo and # written by Seth Vidal -from __future__ import absolute_import import createrepo import os.path import rpmUtils.miscutils @@ -239,7 +238,7 @@ class RepoMerge(object): include_srpms[srpm_name] = (pkg.sourcerpm, pkg.repoid) pkgorigins = os.path.join(self.yumbase.conf.cachedir, 'pkgorigins') - origins = open(pkgorigins, 'w') + origins = file(pkgorigins, 'w') seen_rpms = {} for repo in repos: @@ -284,7 +283,7 @@ def main(args): opts = parse_args(args) if opts.blocked: - blocked_fo = open(opts.blocked) + blocked_fo = file(opts.blocked) blocked_list = blocked_fo.readlines() blocked_fo.close() blocked = dict([(b.strip(), 1) for b in blocked_list]) diff --git a/cli/koji b/cli/koji index d00c580..349d595 100755 --- a/cli/koji +++ b/cli/koji @@ -1863,7 +1863,7 @@ def _import_comps(session, filename, tag, options): if pkg.type == libcomps.PACKAGE_TYPE_CONDITIONAL: pkgopts['requires'] = pkg.requires for k in pkgopts.keys(): - if isinstance(pkgopts[k], unicode): + if six.PY2 and isinstance(pkgopts[k], unicode): pkgopts[k] = str(pkgopts[k]) s_opts = ', '.join(["'%s': %r" % (k, pkgopts[k]) for k in sorted(list(pkgopts.keys()))]) print(" Package: %s: {%s}" % (pkg.name, s_opts)) @@ -1896,7 +1896,7 @@ def _import_comps_alt(session, filename, tag, options): if ptype == 'conditional': pkgopts['requires'] = pdata[pkg] for k in pkgopts.keys(): - if isinstance(pkgopts[k], unicode): + if six.PY2 and isinstance(pkgopts[k], unicode): pkgopts[k] = str(pkgopts[k]) s_opts = ', '.join(["'%s': %r" % (k, pkgopts[k]) for k in sorted(list(pkgopts.keys()))]) print(" Package: %s: {%s}" % (pkg, s_opts)) diff --git a/hub/kojihub.py b/hub/kojihub.py index 578ecb2..947f60d 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -22,7 +22,6 @@ # Mike Bonnet # Cristian Balint -from __future__ import absolute_import import base64 import calendar import cgi @@ -54,12 +53,9 @@ import tarfile import tempfile import time import types -import six.moves.xmlrpc_client +import xmlrpclib import zipfile from koji.context import context -from six.moves import range -from six.moves import zip -import six try: import json @@ -401,7 +397,7 @@ class Task(object): if xml_request.find(' @@ -2441,7 +2437,7 @@ def _write_maven_repo_metadata(destdir, artifacts): """ % datetime.datetime.now().strftime('%Y%m%d%H%M%S') - mdfile = open(os.path.join(destdir, 'maven-metadata.xml'), 'w') + mdfile = file(os.path.join(destdir, 'maven-metadata.xml'), 'w') mdfile.write(contents) mdfile.close() _generate_maven_metadata(destdir) @@ -2549,7 +2545,7 @@ def repo_references(repo_id): 'host_id': 'host_id', 'create_event': 'create_event', 'state': 'state'} - fields, aliases = list(zip(*list(fields.items()))) + fields, aliases = zip(*fields.items()) values = {'repo_id': repo_id} clauses = ['repo_id=%(repo_id)s', 'retire_event IS NULL'] query = QueryProcessor(columns=fields, aliases=aliases, tables=['standard_buildroot'], @@ -2796,7 +2792,7 @@ def lookup_name(table, info, strict=False, create=False): q = """SELECT id,name FROM %s WHERE id=%%(info)d""" % table elif isinstance(info, str): q = """SELECT id,name FROM %s WHERE name=%%(info)s""" % table - elif isinstance(info, six.text_type): + elif isinstance(info, unicode): info = koji.fixEncoding(info) q = """SELECT id,name FROM %s WHERE name=%%(info)s""" % table else: @@ -2914,7 +2910,7 @@ def _create_tag(name, parent=None, arches=None, perm=None, locked=False, maven_s # add extra data if extra is not None: - for key, value in six.iteritems(extra): + for key, value in extra.iteritems(): data = { 'tag_id': tag_id, 'key': key, @@ -2971,15 +2967,15 @@ def get_tag(tagInfo, strict=False, event=None): 'tag_config.maven_include_all': 'maven_include_all' } clauses = [eventCondition(event, table='tag_config')] - if isinstance(tagInfo, six.integer_types): + if isinstance(tagInfo, (int, long)): clauses.append("tag.id = %(tagInfo)i") - elif isinstance(tagInfo, six.string_types): + elif isinstance(tagInfo, basestring): clauses.append("tag.name = %(tagInfo)s") else: raise koji.GenericError('invalid type for tagInfo: %s' % type(tagInfo)) data = {'tagInfo': tagInfo} - fields, aliases = list(zip(*list(fields.items()))) + fields, aliases = zip(*fields.items()) query = QueryProcessor(columns=fields, aliases=aliases, tables=tables, joins=joins, clauses=clauses, values=data) result = query.executeOne() @@ -3199,7 +3195,7 @@ def get_external_repos(info=None, url=None, event=None, queryOpts=None): if info is not None: if isinstance(info, str): clauses.append('name = %(info)s') - elif isinstance(info, six.integer_types): + elif isinstance(info, (int, long)): clauses.append('id = %(info)i') else: raise koji.GenericError('invalid type for lookup: %s' % type(info)) @@ -3521,7 +3517,7 @@ def get_build(buildInfo, strict=False): ('users.id', 'owner_id'), ('users.name', 'owner_name'), ('build.source', 'source'), ('build.extra', 'extra')) - fields, aliases = list(zip(*fields)) + fields, aliases = zip(*fields) joins = ['events ON build.create_event = events.id', 'package on build.pkg_id = package.id', 'volume on build.volume_id = volume.id', @@ -3638,7 +3634,7 @@ def get_rpm(rpminfo, strict=False, multi=False): ) # we can look up by id or NVRA data = None - if isinstance(rpminfo, six.integer_types): + if isinstance(rpminfo, (int, long)): data = {'id': rpminfo} elif isinstance(rpminfo, str): data = koji.parse_NVRA(rpminfo) @@ -3756,7 +3752,7 @@ def list_rpms(buildID=None, buildrootID=None, imageID=None, componentBuildrootID else: raise koji.GenericError('invalid type for "arches" parameter: %s' % type(arches)) - fields, aliases = list(zip(*fields)) + fields, aliases = zip(*fields) query = QueryProcessor(columns=fields, aliases=aliases, tables=['rpminfo'], joins=joins, clauses=clauses, values=locals(), transform=_fix_rpm_row, opts=queryOpts) @@ -4081,7 +4077,7 @@ def list_archives(buildID=None, buildrootID=None, componentBuildrootID=None, hos clauses.append('archiveinfo.btype_id = %(btype_id)s') values['btype_id'] = btype['id'] - columns, aliases = list(zip(*fields)) + columns, aliases = zip(*fields) ret = QueryProcessor(tables=tables, columns=columns, aliases=aliases, joins=joins, transform=_fix_archive_row, clauses=clauses, values=values, opts=queryOpts).execute() @@ -4400,7 +4396,7 @@ def _multiRow(query, values, fields): as a list of maps. Each map in the list will have a key for each element in the "fields" list. If there are no results, an empty list will be returned.""" - return [dict(list(zip(fields, row))) for row in _fetchMulti(query, values)] + return [dict(zip(fields, row)) for row in _fetchMulti(query, values)] def _singleRow(query, values, fields, strict=False): """Return a single row from "query". Named parameters can be @@ -4412,7 +4408,7 @@ def _singleRow(query, values, fields, strict=False): returned.""" row = _fetchSingle(query, values, strict) if row: - return dict(list(zip(fields, row))) + return dict(zip(fields, row)) else: #strict enforced by _fetchSingle return None @@ -4964,7 +4960,7 @@ def import_build(srpm, rpms, brmap=None, task_id=None, build_id=None, logs=None) import_rpm_file(fn, binfo, rpminfo) add_rpm_sig(rpminfo['id'], koji.rip_rpm_sighdr(fn)) if logs: - for key, files in six.iteritems(logs): + for key, files in logs.iteritems(): if not key: key = None for relpath in files: @@ -5133,7 +5129,7 @@ class CG_Importer(object): if metadata is None: #default to looking for uploaded file metadata = 'metadata.json' - if not isinstance(metadata, (str, six.text_type)): + if not isinstance(metadata, (str, unicode)): raise koji.GenericError("Invalid metadata value: %r" % metadata) if metadata.endswith('.json'): # handle uploaded metadata @@ -5141,7 +5137,7 @@ class CG_Importer(object): path = os.path.join(workdir, directory, metadata) if not os.path.exists(path): raise koji.GenericError("No such file: %s" % metadata) - fo = open(path, 'rt') + fo = open(path, 'rb') metadata = fo.read() fo.close() self.raw_metadata = metadata @@ -5191,7 +5187,7 @@ class CG_Importer(object): datetime.datetime.fromtimestamp(float(metadata['build']['end_time'])).isoformat(' ') owner = metadata['build'].get('owner', None) if owner: - if not isinstance(owner, six.string_types): + if not isinstance(owner, basestring): raise koji.GenericError("Invalid owner format (expected username): %s" % owner) buildinfo['owner'] = get_user(owner, strict=True)['id'] self.buildinfo = buildinfo @@ -5532,14 +5528,14 @@ def add_external_rpm(rpminfo, external_repo, strict=True): #sanity check rpminfo dtypes = ( - ('name', six.string_types), - ('version', six.string_types), - ('release', six.string_types), + ('name', basestring), + ('version', basestring), + ('release', basestring), ('epoch', (int, type(None))), - ('arch', six.string_types), + ('arch', basestring), ('payloadhash', str), ('size', int), - ('buildtime', six.integer_types)) + ('buildtime', (int, long))) for field, allowed in dtypes: if field not in rpminfo: raise koji.GenericError("%s field missing: %r" % (field, rpminfo)) @@ -5973,7 +5969,7 @@ def check_old_image_files(old): (img_path, img_size, old['filesize'])) # old images always used sha256 hashes sha256sum = hashlib.sha256() - image_fo = open(img_path, 'r') + image_fo = file(img_path, 'r') while True: data = image_fo.read(1048576) sha256sum.update(data) @@ -6125,7 +6121,7 @@ def import_archive_internal(filepath, buildinfo, type, typeInfo, buildroot_id=No filename = koji.fixEncoding(os.path.basename(filepath)) archiveinfo['filename'] = filename archiveinfo['size'] = os.path.getsize(filepath) - archivefp = open(filepath) + archivefp = file(filepath) m = md5_constructor() while True: contents = archivefp.read(8192) @@ -6265,14 +6261,14 @@ def _generate_maven_metadata(mavendir): sumfile = mavenfile + ext if sumfile not in mavenfiles: sum = sum_constr() - fobj = open('%s/%s' % (mavendir, mavenfile)) + fobj = file('%s/%s' % (mavendir, mavenfile)) while True: content = fobj.read(8192) if not content: break sum.update(content) fobj.close() - sumobj = open('%s/%s' % (mavendir, sumfile), 'w') + sumobj = file('%s/%s' % (mavendir, sumfile), 'w') sumobj.write(sum.hexdigest()) sumobj.close() @@ -6328,7 +6324,7 @@ def add_rpm_sig(an_rpm, sighdr): # - write to fs sigpath = "%s/%s" % (builddir, koji.pathinfo.sighdr(rinfo, sigkey)) koji.ensuredir(os.path.dirname(sigpath)) - fo = open(sigpath, 'wb') + fo = file(sigpath, 'wb') fo.write(sighdr) fo.close() koji.plugin.run_callbacks('postRPMSign', sigkey=sigkey, sighash=sighash, build=binfo, rpm=rinfo) @@ -6344,7 +6340,7 @@ def _scan_sighdr(sighdr, fn): sig_start, sigsize = koji.find_rpm_sighdr(fn) hdr_start = sig_start + sigsize hdrsize = koji.rpm_hdr_size(fn, hdr_start) - inp = open(fn, 'rb') + inp = file(fn, 'rb') outp = tempfile.TemporaryFile(mode='w+b') #before signature outp.write(inp.read(sig_start)) @@ -6381,7 +6377,7 @@ def check_rpm_sig(an_rpm, sigkey, sighdr): koji.splice_rpm_sighdr(sighdr, rpm_path, temp) ts = rpm.TransactionSet() ts.setVSFlags(0) #full verify - fo = open(temp, 'rb') + fo = file(temp, 'rb') hdr = ts.hdrFromFdno(fo.fileno()) fo.close() except: @@ -6444,7 +6440,7 @@ def write_signed_rpm(an_rpm, sigkey, force=False): else: os.unlink(signedpath) sigpath = "%s/%s" % (builddir, koji.pathinfo.sighdr(rinfo, sigkey)) - fo = open(sigpath, 'rb') + fo = file(sigpath, 'rb') sighdr = fo.read() fo.close() koji.ensuredir(os.path.dirname(signedpath)) @@ -6677,7 +6673,7 @@ def query_history(tables=None, **kwargs): fields['creator.id = %(editor)i'] = '_created_by' fields['revoker.id = %(editor)i'] = '_revoked_by' elif arg == 'after': - if not isinstance(value, six.string_types): + if not isinstance(value, basestring): value = datetime.datetime.fromtimestamp(value).isoformat(' ') data['after'] = value clauses.append('ev1.time > %(after)s OR ev2.time > %(after)s') @@ -6692,7 +6688,7 @@ def query_history(tables=None, **kwargs): fields[c_test] = '_created_after_event' fields[r_test] = '_revoked_after_event' elif arg == 'before': - if not isinstance(value, six.string_types): + if not isinstance(value, basestring): value = datetime.datetime.fromtimestamp(value).isoformat(' ') data['before'] = value clauses.append('ev1.time < %(before)s OR ev2.time < %(before)s') @@ -6708,7 +6704,7 @@ def query_history(tables=None, **kwargs): fields[r_test] = '_revoked_before_event' if skip: continue - fields, aliases = list(zip(*list(fields.items()))) + fields, aliases = zip(*fields.items()) query = QueryProcessor(columns=fields, aliases=aliases, tables=[table], joins=joins, clauses=clauses, values=data) ret[table] = query.iterate() @@ -6847,7 +6843,7 @@ def build_references(build_id, limit=None): idx.setdefault(row['id'], row) if limit is not None and len(idx) > limit: break - ret['rpms'] = list(idx.values()) + ret['rpms'] = idx.values() ret['component_of'] = [] # find images/archives that contain the build rpms @@ -6878,7 +6874,7 @@ def build_references(build_id, limit=None): idx.setdefault(row['id'], row) if limit is not None and len(idx) > limit: break - ret['archives'] = list(idx.values()) + ret['archives'] = idx.values() # find images/archives that contain the build archives fields = ['archive_id'] @@ -7202,7 +7198,7 @@ def get_notification_recipients(build, tag_id, state): #FIXME - if tag_id is None, we don't have a good way to get the package owner. # using all package owners from all tags would be way overkill. - emails_uniq = list(dict([(x, 1) for x in emails]).keys()) + emails_uniq = dict([(x, 1) for x in emails]).keys() return emails_uniq def tag_notification(is_successful, tag_id, from_id, build_id, user_id, ignore_success=False, failure_msg=''): @@ -7225,7 +7221,7 @@ def tag_notification(is_successful, tag_id, from_id, build_id, user_id, ignore_s from_tag = get_tag(from_id) for email in get_notification_recipients(build, from_tag['id'], state): recipients[email] = 1 - recipients_uniq = list(recipients.keys()) + recipients_uniq = recipients.keys() if len(recipients_uniq) > 0 and not (is_successful and ignore_success): task_id = make_task('tagNotification', [recipients_uniq, is_successful, tag_id, from_id, build_id, user_id, ignore_success, failure_msg]) return task_id @@ -7439,8 +7435,8 @@ class InsertProcessor(object): if not self.data and not self.rawdata: return "-- incomplete update: no assigns" parts = ['INSERT INTO %s ' % self.table] - columns = list(self.data.keys()) - columns.extend(list(self.rawdata.keys())) + columns = self.data.keys() + columns.extend(self.rawdata.keys()) parts.append("(%s) " % ', '.join(columns)) values = [] for key in columns: @@ -7483,7 +7479,7 @@ class InsertProcessor(object): del data['create_event'] del data['creator_id'] clauses = ["%s = %%(%s)s" % (k, k) for k in data] - query = QueryProcessor(columns=list(data.keys()), tables=[self.table], + query = QueryProcessor(columns=data.keys(), tables=[self.table], clauses=clauses, values=data) if query.execute(): return True @@ -7602,7 +7598,7 @@ class QueryProcessor(object): if columns and aliases: if len(columns) != len(aliases): raise Exception('column and alias lists must be the same length') - self.colsByAlias = dict(list(zip(aliases, columns))) + self.colsByAlias = dict(zip(aliases, columns)) else: self.colsByAlias = {} self.tables = tables @@ -7862,7 +7858,7 @@ def policy_get_pkg(data): if not pkginfo: #for some operations (e.g. adding a new package), the package #entry may not exist yet - if isinstance(data['package'], six.string_types): + if isinstance(data['package'], basestring): return {'id' : None, 'name' : data['package']} else: raise koji.GenericError("Invalid package: %s" % data['package']) @@ -8144,7 +8140,7 @@ class UserInGroupTest(koji.policy.BaseSimpleTest): return False groups = koji.auth.get_user_groups(user['id']) args = self.str.split()[1:] - for group_id, group in six.iteritems(groups): + for group_id, group in groups.iteritems(): for pattern in args: if fnmatch.fnmatch(group, pattern): return True @@ -8782,7 +8778,7 @@ class RootExports(object): # we will accept offset and size as strings to work around xmlrpc limits offset = koji.decode_int(offset) size = koji.decode_int(size) - if isinstance(md5sum, six.string_types): + if isinstance(md5sum, basestring): # this case is for backwards compatibility verify = "md5" digest = md5sum @@ -8800,7 +8796,7 @@ class RootExports(object): fn = get_upload_path(path, name, create=True, volume=volume) try: st = os.lstat(fn) - except OSError as e: + except OSError, e: if e.errno == errno.ENOENT: pass else: @@ -8814,7 +8810,7 @@ class RootExports(object): # but we allow .log files to be uploaded multiple times to support # realtime log-file viewing raise koji.GenericError("file already exists: %s" % fn) - fd = os.open(fn, os.O_RDWR | os.O_CREAT, 0o666) + fd = os.open(fn, os.O_RDWR | os.O_CREAT, 0666) # log_error("fd=%r" %fd) try: if offset == 0 or (offset == -1 and size == len(contents)): @@ -8869,7 +8865,7 @@ class RootExports(object): data = {} try: fd = os.open(fn, os.O_RDONLY) - except OSError as e: + except OSError, e: if e.errno == errno.ENOENT: return None else: @@ -8877,7 +8873,7 @@ class RootExports(object): try: try: fcntl.lockf(fd, fcntl.LOCK_SH|fcntl.LOCK_NB) - except IOError as e: + except IOError, e: raise koji.LockError(e) st = os.fstat(fd) if not stat.S_ISREG(st.st_mode): @@ -8916,7 +8912,7 @@ class RootExports(object): if not os.path.isfile(filePath): raise koji.GenericError('no file "%s" output by task %i' % (fileName, taskID)) # Let the caller handler any IO or permission errors - f = open(filePath, 'r') + f = file(filePath, 'r') if isinstance(offset, str): offset = int(offset) if offset != None and offset > 0: @@ -9342,9 +9338,9 @@ class RootExports(object): if before: if isinstance(before, datetime.datetime): before = calendar.timegm(before.utctimetuple()) - elif isinstance(before, (str, six.text_type)): + elif isinstance(before, (str, unicode)): before = koji.util.parseTime(before) - elif isinstance(before, six.integer_types): + elif isinstance(before, (int, long)): pass else: raise koji.GenericError('invalid type for before: %s' % type(before)) @@ -9352,9 +9348,9 @@ class RootExports(object): if after: if isinstance(after, datetime.datetime): after = calendar.timegm(after.utctimetuple()) - elif isinstance(after, (str, six.text_type)): + elif isinstance(after, (str, unicode)): after = koji.util.parseTime(after) - elif isinstance(after, six.integer_types): + elif isinstance(after, (int, long)): pass else: raise koji.GenericError('invalid type for after: %s' % type(after)) @@ -9443,7 +9439,7 @@ class RootExports(object): def listTagged(self, tag, event=None, inherit=False, prefix=None, latest=False, package=None, owner=None, type=None): """List builds tagged with tag""" - if not isinstance(tag, six.integer_types): + if not isinstance(tag, (int, long)): #lookup tag id tag = get_tag_id(tag, strict=True) results = readTaggedBuilds(tag, event, inherit=inherit, latest=latest, package=package, owner=owner, type=type) @@ -9454,14 +9450,14 @@ class RootExports(object): def listTaggedRPMS(self, tag, event=None, inherit=False, latest=False, package=None, arch=None, rpmsigs=False, owner=None, type=None): """List rpms and builds within tag""" - if not isinstance(tag, six.integer_types): + if not isinstance(tag, (int, long)): #lookup tag id tag = get_tag_id(tag, strict=True) return readTaggedRPMS(tag, event=event, inherit=inherit, latest=latest, package=package, arch=arch, rpmsigs=rpmsigs, owner=owner, type=type) def listTaggedArchives(self, tag, event=None, inherit=False, latest=False, package=None, type=None): """List archives and builds within a tag""" - if not isinstance(tag, six.integer_types): + if not isinstance(tag, (int, long)): tag = get_tag_id(tag, strict=True) return readTaggedArchives(tag, event=event, inherit=inherit, latest=latest, package=package, type=type) @@ -9618,14 +9614,14 @@ class RootExports(object): def getLatestBuilds(self, tag, event=None, package=None, type=None): """List latest builds for tag (inheritance enabled)""" - if not isinstance(tag, six.integer_types): + if not isinstance(tag, (int, long)): #lookup tag id tag = get_tag_id(tag, strict=True) return readTaggedBuilds(tag, event, inherit=True, latest=True, package=package, type=type) def getLatestRPMS(self, tag, package=None, arch=None, event=None, rpmsigs=False, type=None): """List latest RPMS for tag (inheritance enabled)""" - if not isinstance(tag, six.integer_types): + if not isinstance(tag, (int, long)): #lookup tag id tag = get_tag_id(tag, strict=True) return readTaggedRPMS(tag, package=package, arch=arch, event=event, inherit=True, latest=True, rpmsigs=rpmsigs, type=type) @@ -9685,13 +9681,13 @@ class RootExports(object): def getInheritanceData(self, tag, event=None): """Return inheritance data for tag""" - if not isinstance(tag, six.integer_types): + if not isinstance(tag, (int, long)): #lookup tag id tag = get_tag_id(tag, strict=True) return readInheritanceData(tag, event) def setInheritanceData(self, tag, data, clear=False): - if not isinstance(tag, six.integer_types): + if not isinstance(tag, (int, long)): #lookup tag id tag = get_tag_id(tag, strict=True) context.session.assertPerm('admin') @@ -9702,7 +9698,7 @@ class RootExports(object): stops = {} if jumps is None: jumps = {} - if not isinstance(tag, six.integer_types): + if not isinstance(tag, (int, long)): #lookup tag id tag = get_tag_id(tag, strict=True) for mapping in [stops, jumps]: @@ -9729,7 +9725,7 @@ class RootExports(object): - buildroot_id If no build has the given ID, or the build generated no RPMs, an empty list is returned.""" - if not isinstance(build, six.integer_types): + if not isinstance(build, (int, long)): #lookup build id build = self.findBuildID(build, strict=True) return self.listRPMs(buildID=build) @@ -9953,9 +9949,9 @@ class RootExports(object): userID = get_user(userID, strict=True)['id'] if pkgID is not None: pkgID = get_package_id(pkgID, strict=True) - result_list = list(readPackageList(tagID=tagID, userID=userID, pkgID=pkgID, + result_list = readPackageList(tagID=tagID, userID=userID, pkgID=pkgID, inherit=inherited, with_dups=with_dups, - event=event).values()) + event=event).values() if with_dups: # when with_dups=True, readPackageList returns a list of list of dicts # convert it to a list of dicts for consistency @@ -10120,7 +10116,7 @@ class RootExports(object): return taginfo def getRepo(self, tag, state=None, event=None, dist=False): - if isinstance(tag, six.integer_types): + if isinstance(tag, (int, long)): id = tag else: id = get_tag_id(tag, strict=True) @@ -10386,8 +10382,8 @@ class RootExports(object): if val.find(' -from __future__ import absolute_import -from __future__ import division -from six.moves.configparser import RawConfigParser +from ConfigParser import RawConfigParser import datetime import inspect import logging @@ -31,8 +29,8 @@ import traceback import types import pprint import resource -import six.moves.xmlrpc_client -from six.moves.xmlrpc_client import getparser, dumps, Fault +import xmlrpclib +from xmlrpclib import getparser, dumps, Fault from koji.server import WSGIWrapper import koji @@ -42,13 +40,12 @@ import koji.plugin import koji.policy import koji.util from koji.context import context -from six.moves import range # Workaround to allow xmlrpclib deal with iterators -class Marshaller(six.moves.xmlrpc_client.Marshaller): +class Marshaller(xmlrpclib.Marshaller): - dispatch = six.moves.xmlrpc_client.Marshaller.dispatch.copy() + dispatch = xmlrpclib.Marshaller.dispatch.copy() def dump_generator(self, value, write): dump = self.__dump @@ -64,7 +61,7 @@ class Marshaller(six.moves.xmlrpc_client.Marshaller): self.dump_string(value, write) dispatch[datetime.datetime] = dump_datetime -six.moves.xmlrpc_client.Marshaller = Marshaller +xmlrpclib.Marshaller = Marshaller class HandlerRegistry(object): @@ -112,7 +109,7 @@ class HandlerRegistry(object): Handlers are functions marked with one of the decorators defined in koji.plugin """ - for v in six.itervalues(vars(plugin)): + for v in vars(plugin).itervalues(): if isinstance(v, type): #skip classes continue @@ -132,7 +129,7 @@ class HandlerRegistry(object): if ret: return ret ret = tuple(inspect.getargspec(func)) - if inspect.ismethod(func) and func.__self__: + if inspect.ismethod(func) and func.im_self: # bound method, remove first arg args, varargs, varkw, defaults = ret if args: @@ -159,17 +156,17 @@ class HandlerRegistry(object): def _getFuncArgs(self, func): args = [] - for x in range(0, func.__code__.co_argcount): - if x == 0 and func.__code__.co_varnames[x] == "self": + for x in range(0, func.func_code.co_argcount): + if x == 0 and func.func_code.co_varnames[x] == "self": continue - if func.__defaults__ and func.__code__.co_argcount - x <= len(func.__defaults__): - args.append((func.__code__.co_varnames[x], func.__defaults__[x - func.__code__.co_argcount + len(func.__defaults__)])) + if func.func_defaults and func.func_code.co_argcount - x <= len(func.func_defaults): + args.append((func.func_code.co_varnames[x], func.func_defaults[x - func.func_code.co_argcount + len(func.func_defaults)])) else: - args.append(func.__code__.co_varnames[x]) + args.append(func.func_code.co_varnames[x]) return args def system_listMethods(self): - return list(self.funcs.keys()) + return self.funcs.keys() def system_methodSignature(self, method): #it is not possible to autogenerate this data @@ -245,7 +242,7 @@ class ModXMLRPCRequestHandler(object): # wrap response in a singleton tuple response = (response,) response = dumps(response, methodresponse=1, allow_none=1) - except Fault as fault: + except Fault, fault: self.traceback = True response = dumps(fault) except: @@ -339,7 +336,7 @@ class ModXMLRPCRequestHandler(object): for call in calls: try: result = self._dispatch(call['methodName'], call['params']) - except Fault as fault: + except Fault, fault: results.append({'faultCode': fault.faultCode, 'faultString': fault.faultString}) except: # transform unknown exceptions into XML-RPC Faults @@ -515,7 +512,7 @@ def load_config(environ): opts['policy'] = dict(config.items('policy')) else: opts['policy'] = {} - for pname, text in six.iteritems(_default_policies): + for pname, text in _default_policies.iteritems(): opts['policy'].setdefault(pname, text) # use configured KojiDir if opts.get('KojiDir') is not None: @@ -577,14 +574,14 @@ def get_policy(opts, plugins): for plugin_name in opts.get('Plugins', '').split(): alltests.append(koji.policy.findSimpleTests(vars(plugins.get(plugin_name)))) policy = {} - for pname, text in six.iteritems(opts['policy']): + for pname, text in opts['policy'].iteritems(): #filter/merge tests merged = {} for tests in alltests: # tests can be limited to certain policies by setting a class variable - for name, test in six.iteritems(tests): + for name, test in tests.iteritems(): if hasattr(test, 'policy'): - if isinstance(test.policy, six.string_types): + if isinstance(test.policy, basestring): if pname != test.policy: continue elif pname not in test.policy: @@ -690,7 +687,7 @@ def handler(req): def get_memory_usage(): pagesize = resource.getpagesize() - statm = [pagesize*int(y)//1024 for y in "".join(open("/proc/self/statm").readlines()).strip().split()] + statm = [pagesize*int(y)/1024 for y in "".join(open("/proc/self/statm").readlines()).strip().split()] size, res, shr, text, lib, data, dirty = statm return res - shr diff --git a/hub/rpmdiff b/hub/rpmdiff index b11c300..7ef9562 100755 --- a/hub/rpmdiff +++ b/hub/rpmdiff @@ -20,14 +20,11 @@ # This library and program is heavily based on rpmdiff from the rpmlint package # It was modified to be used as standalone library for the Koji project. -from __future__ import absolute_import import rpm import os import itertools import sys, getopt -from six.moves import zip -import six class Rpmdiff: @@ -114,8 +111,8 @@ class Rpmdiff: old_files_dict = self.__fileIteratorToDict(old.fiFromHeader()) new_files_dict = self.__fileIteratorToDict(new.fiFromHeader()) - files = list(set(itertools.chain(six.iterkeys(old_files_dict), - six.iterkeys(new_files_dict)))) + files = list(set(itertools.chain(old_files_dict.iterkeys(), + new_files_dict.iterkeys()))) files.sort() for f in files: @@ -178,8 +175,8 @@ class Rpmdiff: if not isinstance(oldflags, list): oldflags = [ oldflags ] if not isinstance(newflags, list): newflags = [ newflags ] - o = list(zip(old[name], oldflags, old[name[:-1]+'VERSION'])) - n = list(zip(new[name], newflags, new[name[:-1]+'VERSION'])) + o = zip(old[name], oldflags, old[name[:-1]+'VERSION']) + n = zip(new[name], newflags, new[name[:-1]+'VERSION']) if name == 'PROVIDES': # filter our self provide oldNV = (old['name'], rpm.RPMSENSE_EQUAL, @@ -228,7 +225,7 @@ def main(): ignore_tags = [] try: opts, args = getopt.getopt(sys.argv[1:], "hi:", ["help", "ignore="]) - except getopt.GetoptError as e: + except getopt.GetoptError, e: print("Error: %s" % e) _usage() diff --git a/koji/context.py b/koji/context.py index 707c626..56a79f7 100755 --- a/koji/context.py +++ b/koji/context.py @@ -24,10 +24,7 @@ # - request data # - auth data -from __future__ import absolute_import -import six.moves._thread -from six.moves import range -import six +import thread class _data(object): pass @@ -38,7 +35,7 @@ class ThreadLocal(object): # should probably be getattribute, but easier to debug this way def __getattr__(self, key): - id = six.moves._thread.get_ident() + id = thread.get_ident() tdict = object.__getattribute__(self, '_tdict') if id not in tdict: raise AttributeError(key) @@ -46,7 +43,7 @@ class ThreadLocal(object): return object.__getattribute__(data, key) def __setattr__(self, key, value): - id = six.moves._thread.get_ident() + id = thread.get_ident() tdict = object.__getattribute__(self, '_tdict') if id not in tdict: tdict[id] = _data() @@ -54,7 +51,7 @@ class ThreadLocal(object): return object.__setattr__(data, key, value) def __delattr__(self, key): - id = six.moves._thread.get_ident() + id = thread.get_ident() tdict = object.__getattribute__(self, '_tdict') if id not in tdict: raise AttributeError(key) @@ -65,14 +62,14 @@ class ThreadLocal(object): return ret def __str__(self): - id = six.moves._thread.get_ident() + id = thread.get_ident() tdict = object.__getattribute__(self, '_tdict') return "(current thread: %s) {" % id + \ - ", ".join(["%s : %s" %(k, v.__dict__) for (k, v) in six.iteritems(tdict)]) + \ + ", ".join(["%s : %s" %(k, v.__dict__) for (k, v) in tdict.iteritems()]) + \ "}" def _threadclear(self): - id = six.moves._thread.get_ident() + id = thread.get_ident() tdict = object.__getattribute__(self, '_tdict') if id not in tdict: return @@ -100,8 +97,8 @@ if __name__ == '__main__': context._threadclear() print(context) - for x in range(1, 10): - six.moves._thread.start_new_thread(test, ()) + for x in xrange(1, 10): + thread.start_new_thread(test, ()) time.sleep(4) print('') diff --git a/koji/daemon.py b/koji/daemon.py index 45a14c5..637566f 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -20,8 +20,6 @@ # Mike McLean # Mike Bonnet -from __future__ import absolute_import -from __future__ import division import koji import koji.tasks from koji.tasks import safe_rmtree @@ -29,16 +27,14 @@ from koji.util import md5_constructor, adler32_constructor, parseStatus import os import signal import logging +import urlparse from fnmatch import fnmatch import base64 import time import sys import traceback import errno -import six.moves.xmlrpc_client -from six.moves import range -import six.moves.urllib -import six +import xmlrpclib def incremental_upload(session, fname, fd, path, retries=5, logger=None): @@ -115,7 +111,7 @@ def log_output(session, path, args, outfile, uploadpath, cwd=None, logerror=0, a flags = os.O_CREAT | os.O_WRONLY if append: flags |= os.O_APPEND - fd = os.open(outfile, flags, 0o666) + fd = os.open(outfile, flags, 0666) os.dup2(fd, 1) if logerror: os.dup2(fd, 2) @@ -146,7 +142,7 @@ def log_output(session, path, args, outfile, uploadpath, cwd=None, logerror=0, a if not outfd: try: - outfd = open(outfile, 'r') + outfd = file(outfile, 'r') except IOError: # will happen if the forked process has not created the logfile yet continue @@ -247,7 +243,7 @@ class SCM(object): # replace the scheme with http:// so that the urlparse works in all cases dummyurl = self.url.replace(scheme, 'http://', 1) - dummyscheme, netloc, path, params, query, fragment = six.moves.urllib.parse.urlparse(dummyurl) + dummyscheme, netloc, path, params, query, fragment = urlparse.urlparse(dummyurl) user = None userhost = netloc.split('@') @@ -529,7 +525,7 @@ class TaskManager(object): """Attempt to shut down cleanly""" for task_id in self.pids.keys(): self.cleanupTask(task_id) - self.session.host.freeTasks(list(self.tasks.keys())) + self.session.host.freeTasks(self.tasks.keys()) self.session.host.updateHost(task_load=0.0, ready=False) def updateBuildroots(self, nolocal=False): @@ -560,14 +556,14 @@ class TaskManager(object): #task not running - expire the buildroot #TODO - consider recycling hooks here (with strong sanity checks) self.logger.info("Expiring buildroot: %(id)i/%(tag_name)s/%(arch)s" % br) - self.logger.debug("Buildroot task: %r, Current tasks: %r" % (task_id, list(self.tasks.keys()))) + self.logger.debug("Buildroot task: %r, Current tasks: %r" % (task_id, self.tasks.keys())) self.session.host.setBuildRootState(id, st_expired) continue if nolocal: return local_br = self._scanLocalBuildroots() # get info on local_only buildroots (most likely expired) - local_only = [id for id in six.iterkeys(local_br) if id not in db_br] + local_only = [id for id in local_br.iterkeys() if id not in db_br] if local_only: missed_br = self.session.listBuildroots(buildrootID=tuple(local_only)) #get all the task info in one call @@ -611,7 +607,7 @@ class TaskManager(object): rootdir = "%s/root" % topdir try: st = os.lstat(rootdir) - except OSError as e: + except OSError, e: if e.errno == errno.ENOENT: rootdir = None else: @@ -632,13 +628,13 @@ class TaskManager(object): #also remove the config try: os.unlink(data['cfg']) - except OSError as e: + except OSError, e: self.logger.warn("%s: can't remove config: %s" % (desc, e)) elif age > 120: if rootdir: try: flist = os.listdir(rootdir) - except OSError as e: + except OSError, e: self.logger.warn("%s: can't list rootdir: %s" % (desc, e)) continue if flist: @@ -665,10 +661,10 @@ class TaskManager(object): fn = "%s/%s" % (configdir, f) if not os.path.isfile(fn): continue - fo = open(fn, 'r') + fo = file(fn, 'r') id = None name = None - for n in range(10): + for n in xrange(10): # data should be in first few lines line = fo.readline() if line.startswith('# Koji buildroot id:'): @@ -799,7 +795,7 @@ class TaskManager(object): # Note: we may still take an assigned task below #sort available capacities for each of our bins avail = {} - for bin in six.iterkeys(bins): + for bin in bins.iterkeys(): avail[bin] = [host['capacity'] - host['task_load'] for host in bin_hosts[bin]] avail[bin].sort() avail[bin].reverse() @@ -831,7 +827,7 @@ class TaskManager(object): #accept this task) bin_avail = avail.get(bin, [0]) self.logger.debug("available capacities for bin: %r" % bin_avail) - median = bin_avail[(len(bin_avail)-1)//2] + median = bin_avail[(len(bin_avail)-1)/2] self.logger.debug("ours: %.2f, median: %.2f" % (our_avail, median)) if not self.checkRelAvail(bin_avail, our_avail): #decline for now and give the upper half a chance @@ -849,7 +845,7 @@ class TaskManager(object): Check our available capacity against the capacity of other hosts in this bin. Return True if we should take a task, False otherwise. """ - median = bin_avail[(len(bin_avail)-1)//2] + median = bin_avail[(len(bin_avail)-1)/2] self.logger.debug("ours: %.2f, median: %.2f" % (avail, median)) if avail >= median: return True @@ -866,7 +862,7 @@ class TaskManager(object): prefix = "Task %i (pid %i)" % (task_id, pid) try: (childpid, status) = os.waitpid(pid, os.WNOHANG) - except OSError as e: + except OSError, e: #check errno if e.errno != errno.ECHILD: #should not happen @@ -907,7 +903,7 @@ class TaskManager(object): try: os.kill(pid, sig) - except OSError as e: + except OSError, e: # process probably went away, we'll find out on the next iteration self.logger.info('Error sending signal %i to %s (pid %i, taskID %i): %s' % (sig, execname, pid, task_id, e)) @@ -931,14 +927,14 @@ class TaskManager(object): proc_path = '/proc/%i/stat' % pid if not os.path.isfile(proc_path): return None - proc_file = open(proc_path) + proc_file = file(proc_path) procstats = [not field.isdigit() and field or int(field) for field in proc_file.read().split()] proc_file.close() cmd_path = '/proc/%i/cmdline' % pid if not os.path.isfile(cmd_path): return None - cmd_file = open(cmd_path) + cmd_file = file(cmd_path) procstats[1] = cmd_file.read().replace('\0', ' ').strip() cmd_file.close() if not procstats[1]: @@ -1042,7 +1038,7 @@ class TaskManager(object): raise IOError("No such directory: %s" % br_path) fs_stat = os.statvfs(br_path) available = fs_stat.f_bavail * fs_stat.f_bsize - availableMB = available // 1024**2 + availableMB = available / 1024 / 1024 self.logger.debug("disk space available in '%s': %i MB", br_path, availableMB) if availableMB < self.options.minspace: self.status = "Insufficient disk space: %i MB, %i MB required" % (availableMB, self.options.minspace) @@ -1192,12 +1188,12 @@ class TaskManager(object): try: response = (handler.run(),) # note that we wrap response in a singleton tuple - response = six.moves.xmlrpc_client.dumps(response, methodresponse=1, allow_none=1) + response = xmlrpclib.dumps(response, methodresponse=1, allow_none=1) self.logger.info("RESPONSE: %r" % response) self.session.host.closeTask(handler.id, response) return - except six.moves.xmlrpc_client.Fault as fault: - response = six.moves.xmlrpc_client.dumps(fault) + except xmlrpclib.Fault, fault: + response = xmlrpclib.dumps(fault) tb = ''.join(traceback.format_exception(*sys.exc_info())).replace(r"\n", "\n") self.logger.warn("FAULT:\n%s" % tb) except (SystemExit, koji.tasks.ServerExit, KeyboardInterrupt): @@ -1216,7 +1212,7 @@ class TaskManager(object): if issubclass(e_class, koji.GenericError): #just pass it through tb = str(e) - response = six.moves.xmlrpc_client.dumps(six.moves.xmlrpc_client.Fault(faultCode, tb)) + response = xmlrpclib.dumps(xmlrpclib.Fault(faultCode, tb)) # if we get here, then we're handling an exception, so fail the task self.session.host.failTask(handler.id, response) diff --git a/koji/db.py b/koji/db.py index c4e9ab3..9e92191 100644 --- a/koji/db.py +++ b/koji/db.py @@ -21,7 +21,6 @@ # Mike McLean -from __future__ import absolute_import import logging import sys import psycopg2 @@ -34,7 +33,7 @@ import psycopg2 # del psycopg2.extensions.string_types[1266] import time import traceback -from . import context +import context import re POSITIONAL_RE = re.compile(r'%[a-z]') diff --git a/koji/plugin.py b/koji/plugin.py index 2ac1db0..e4fe19d 100644 --- a/koji/plugin.py +++ b/koji/plugin.py @@ -19,13 +19,11 @@ # Mike McLean # Mike Bonnet -from __future__ import absolute_import import imp import koji import logging import sys import traceback -import six # the available callback hooks and a list # of functions to be called for each event @@ -87,7 +85,7 @@ class PluginTracker(object): return self.plugins.get(name) def pathlist(self, path): - if isinstance(path, six.string_types): + if isinstance(path, basestring): return [path] else: return path diff --git a/koji/policy.py b/koji/policy.py index 808ad8a..ec2e119 100644 --- a/koji/policy.py +++ b/koji/policy.py @@ -17,10 +17,8 @@ # Authors: # Mike McLean -from __future__ import absolute_import import fnmatch import koji -import six class BaseSimpleTest(object): @@ -291,7 +289,7 @@ class SimpleRuleSet(object): index[name] = 1 index = {} _recurse(self.ruleset, index) - return list(index.keys()) + return index.keys() def _apply(self, rules, data, top=False): for tests, negate, action in rules: @@ -354,7 +352,7 @@ def findSimpleTests(namespace): namespace = (namespace,) ret = {} for ns in namespace: - for key, value in six.iteritems(ns): + for key, value in ns.iteritems(): if value is BaseSimpleTest: # skip this abstract base class if we encounter it # this module contains generic tests, so it is valid to include it diff --git a/koji/server.py b/koji/server.py index 47ebacf..6a6ae6a 100644 --- a/koji/server.py +++ b/koji/server.py @@ -19,7 +19,6 @@ # Authors: # Mike McLean -from __future__ import absolute_import import sys import traceback from koji.util import LazyDict diff --git a/koji/tasks.py b/koji/tasks.py index 05606cb..9591c23 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -20,19 +20,17 @@ # Mike McLean # Mike Bonnet -from __future__ import absolute_import import koji import koji.util import os import logging -import six.moves.xmlrpc_client +import xmlrpclib import signal +import urllib2 import shutil import random import time import pprint -from six.moves import range -import six.moves.urllib def scan_mounts(topdir): """Search path for mountpoints""" @@ -234,15 +232,13 @@ class BaseTaskHandler(object): if all: if failany: failed = False - task_error = None for task in finished: if task in canfail: # no point in checking continue try: self.session.getTaskResult(task) - except (koji.GenericError, six.moves.xmlrpc_client.Fault) as te: - task_error = te + except (koji.GenericError, xmlrpclib.Fault), task_error: self.logger.info("task %s failed or was canceled" % task) failed = True break @@ -313,10 +309,10 @@ class BaseTaskHandler(object): return fn self.logger.debug("Downloading %s", relpath) url = "%s/%s" % (self.options.topurl, relpath) - fsrc = six.moves.urllib.request.urlopen(url) + fsrc = urllib2.urlopen(url) if not os.path.exists(os.path.dirname(fn)): os.makedirs(os.path.dirname(fn)) - fdst = open(fn, 'w') + fdst = file(fn, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() fdst.close() @@ -365,7 +361,7 @@ class BaseTaskHandler(object): else: # no overlap raise koji.BuildError("host %s (%s) does not support any arches of tag %s (%s)" % \ - (host['name'], ', '.join(sorted(host_arches)), tag['name'], ', '.join(sorted(tag_arches)))) + (host['name'], ', '.join(host_arches), tag['name'], ', '.join(tag_arches))) def getRepo(self, tag): """ @@ -406,7 +402,7 @@ class SleepTask(BaseTaskHandler): class ForkTask(BaseTaskHandler): Methods = ['fork'] def handler(self, n=5, m=37): - for i in range(n): + for i in xrange(n): os.spawnvp(os.P_NOWAIT, 'sleep', ['sleep', str(m)]) class WaitTestTask(BaseTaskHandler): @@ -421,7 +417,7 @@ class WaitTestTask(BaseTaskHandler): _taskWeight = 0.1 def handler(self, count, seconds=10): tasks = [] - for i in range(count): + for i in xrange(count): task_id = self.subtask(method='sleep', arglist=[seconds], label=str(i), parent=self.id) tasks.append(task_id) bad_task = self.subtask('sleep', ['BAD_ARG'], label='bad') diff --git a/plugins/builder/runroot.py b/plugins/builder/runroot.py index 7856ce8..fe23bd0 100644 --- a/plugins/builder/runroot.py +++ b/plugins/builder/runroot.py @@ -1,9 +1,8 @@ # kojid plugin -from __future__ import absolute_import import commands import koji -import six.moves.configparser +import ConfigParser import os import platform compat_mode = False @@ -57,7 +56,7 @@ class RunRootTask(tasks.BaseTaskHandler): return res def _read_config(self): - cp = six.moves.configparser.SafeConfigParser() + cp = ConfigParser.SafeConfigParser() cp.read(CONFIG_FILE) self.config = { 'default_mounts': [], @@ -85,7 +84,7 @@ class RunRootTask(tasks.BaseTaskHandler): 'fstype': cp.get(section_name, 'fstype'), 'options': cp.get(section_name, 'options'), }) - except six.moves.configparser.NoOptionError: + except ConfigParser.NoOptionError: raise koji.GenericError("bad config: missing options in %s section" % section_name) count += 1 diff --git a/plugins/builder/save_failed_tree.py b/plugins/builder/save_failed_tree.py index 7c579a7..4c202c9 100644 --- a/plugins/builder/save_failed_tree.py +++ b/plugins/builder/save_failed_tree.py @@ -1,9 +1,8 @@ -from __future__ import absolute_import import fnmatch import os import sys import tarfile -import six.moves.configparser +import ConfigParser import koji import koji.tasks as tasks @@ -28,7 +27,7 @@ def omit_paths3(tarinfo): def read_config(): global config - cp = six.moves.configparser.SafeConfigParser() + cp = ConfigParser.SafeConfigParser() cp.read(CONFIG_FILE) config = { 'path_filters': [], diff --git a/plugins/hub/echo.py b/plugins/hub/echo.py index 739dfeb..6727d41 100644 --- a/plugins/hub/echo.py +++ b/plugins/hub/echo.py @@ -5,11 +5,10 @@ # Authors: # Mike Bonnet -from __future__ import absolute_import from koji.plugin import callbacks, callback, ignore_error import logging -@callback(*list(callbacks.keys())) +@callback(*callbacks.keys()) @ignore_error def echo(cbtype, *args, **kws): logging.getLogger('koji.plugin.echo').info('Called the %s callback, args: %s; kws: %s', diff --git a/plugins/hub/messagebus.py b/plugins/hub/messagebus.py index 4841624..10c8b00 100644 --- a/plugins/hub/messagebus.py +++ b/plugins/hub/messagebus.py @@ -4,10 +4,9 @@ # Authors: # Mike Bonnet -from __future__ import absolute_import from koji import PluginError from koji.plugin import callbacks, callback, ignore_error -import six.moves.configparser +import ConfigParser import logging import qpid.messaging import qpid.messaging.transports @@ -79,7 +78,7 @@ def get_sender(): session = None target = None - config = six.moves.configparser.SafeConfigParser() + config = ConfigParser.SafeConfigParser() config.read(CONFIG_FILE) if not config.has_option('broker', 'timeout'): config.set('broker', 'timeout', '60') diff --git a/plugins/hub/protonmsg.py b/plugins/hub/protonmsg.py index 91e7e66..cf3a82c 100644 --- a/plugins/hub/protonmsg.py +++ b/plugins/hub/protonmsg.py @@ -5,11 +5,10 @@ # Authors: # Mike Bonnet -from __future__ import absolute_import import koji from koji.plugin import callback, ignore_error from koji.context import context -import six.moves.configparser +import ConfigParser import logging import json import random @@ -247,7 +246,7 @@ def send_queued_msgs(cbtype, *args, **kws): log = logging.getLogger('koji.plugin.protonmsg') global CONFIG if not CONFIG: - conf = six.moves.configparser.SafeConfigParser() + conf = ConfigParser.SafeConfigParser() with open(CONFIG_FILE) as conffile: conf.readfp(conffile) CONFIG = conf diff --git a/plugins/hub/rpm2maven.py b/plugins/hub/rpm2maven.py index e918013..b1310ea 100644 --- a/plugins/hub/rpm2maven.py +++ b/plugins/hub/rpm2maven.py @@ -5,11 +5,10 @@ # Authors: # Mike Bonnet -from __future__ import absolute_import import koji from koji.context import context from koji.plugin import callback -import six.moves.configparser +import ConfigParser import fnmatch import os import shutil @@ -31,7 +30,7 @@ def maven_import(cbtype, *args, **kws): filepath = kws['filepath'] if not config: - config = six.moves.configparser.SafeConfigParser() + config = ConfigParser.SafeConfigParser() config.read(CONFIG_FILE) name_patterns = config.get('patterns', 'rpm_names').split() for pattern in name_patterns: @@ -52,7 +51,7 @@ def maven_import(cbtype, *args, **kws): shutil.rmtree(tmpdir) def expand_rpm(filepath, tmpdir): - devnull = open('/dev/null', 'r+') + devnull = file('/dev/null', 'r+') rpm2cpio = subprocess.Popen(['/usr/bin/rpm2cpio', filepath], stdout=subprocess.PIPE, stdin=devnull, stderr=devnull, diff --git a/plugins/hub/runroot_hub.py b/plugins/hub/runroot_hub.py index 708aede..e6ee0b3 100644 --- a/plugins/hub/runroot_hub.py +++ b/plugins/hub/runroot_hub.py @@ -3,7 +3,6 @@ # plugin has a config file. This hub plugin has no config file. -from __future__ import absolute_import from koji.context import context from koji.plugin import export import koji diff --git a/plugins/hub/save_failed_tree.py b/plugins/hub/save_failed_tree.py index 70a796f..3a98128 100644 --- a/plugins/hub/save_failed_tree.py +++ b/plugins/hub/save_failed_tree.py @@ -1,6 +1,5 @@ -from __future__ import absolute_import import sys -import six.moves.configparser +import ConfigParser import koji from koji.context import context from koji.plugin import export @@ -29,7 +28,7 @@ def saveFailedTree(buildrootID, full=False, **opts): # read configuration only once if config is None: - config = six.moves.configparser.SafeConfigParser() + config = ConfigParser.SafeConfigParser() config.read(CONFIG_FILE) allowed_methods = config.get('permissions', 'allowed_methods').split() if len(allowed_methods) == 1 and allowed_methods[0] == '*': diff --git a/util/koji-gc b/util/koji-gc index 7289f7a..bea2cd3 100755 --- a/util/koji-gc +++ b/util/koji-gc @@ -6,9 +6,6 @@ # Authors: # Mike McLean -from __future__ import absolute_import -from six.moves import zip -import six try: import krbV except ImportError: # pragma: no cover @@ -16,7 +13,7 @@ except ImportError: # pragma: no cover import koji from koji.util import LazyDict, LazyValue import koji.policy -import six.moves.configparser +import ConfigParser from email.MIMEText import MIMEText import fnmatch import optparse @@ -26,7 +23,7 @@ import smtplib import socket # for socket.error import sys import time -import six.moves.xmlrpc_client # for ProtocolError and Fault +import xmlrpclib # for ProtocolError and Fault OptionParser = optparse.OptionParser @@ -115,7 +112,7 @@ def get_options(): defaults = parser.get_default_values() - config = six.moves.configparser.ConfigParser() + config = ConfigParser.ConfigParser() cf = getattr(options, 'config_file', None) if cf: if not os.access(cf, os.F_OK): @@ -199,7 +196,7 @@ def get_options(): if len(parts) < 2: continue options.key_aliases[parts[0].upper()] = parts[1] - except ValueError as e: + except ValueError, e: print(e) parser.error(_("Invalid key alias data in config: %s") % config.get('main','key_aliases')) @@ -340,7 +337,7 @@ def warn(msg): def ensure_connection(session): try: ret = session.getAPIVersion() - except six.moves.xmlrpc_client.ProtocolError: + except xmlrpclib.ProtocolError: error(_("Error: Unable to connect to server")) if ret != koji.API_VERSION: warn(_("WARNING: The server is at API version %d and the client is at %d" % (ret, koji.API_VERSION))) @@ -374,9 +371,9 @@ def activate_session(session): session.krb_login(principal=options.principal, keytab=options.keytab, proxyuser=options.runas) else: session.krb_login(proxyuser=options.runas) - except krbV.Krb5Error as e: + except krbV.Krb5Error, e: error(_("Kerberos authentication failed: %s (%s)") % (e.args[1], e.args[0])) - except socket.error as e: + except socket.error, e: warn(_("Could not connect to Kerberos authentication service: '%s'") % e.args[1]) if not options.noauth and not session.logged_in: error(_("Error: unable to log in, no authentication methods available")) @@ -455,7 +452,7 @@ def handle_trash(): continue try: refs = session.buildReferences(binfo['id'], limit=10) - except six.moves.xmlrpc_client.Fault: + except xmlrpclib.Fault: print("[%i/%i] Error checking references for %s. Skipping" % (i, N, nvr)) continue #XXX - this is more data than we need @@ -536,7 +533,7 @@ def handle_trash(): by_owner = {} for binfo in to_trash: by_owner.setdefault(binfo['owner_name'], []).append(binfo) - owners = list(by_owner.keys()) + owners = by_owner.keys() owners.sort() for owner_name in owners: builds = [(b['nvr'], b) for b in by_owner[owner_name]] @@ -558,7 +555,7 @@ def handle_trash(): #best we can do currently owner = binfo['owner_id'] else: - owner = max([(n, k) for k, n in six.iteritems(count)])[1] + owner = max([(n, k) for k, n in count.iteritems()])[1] session.packageListAdd(trashcan_tag, binfo['name'], owner) session.tagBuildBypass(trashcan_tag, binfo['id'], force=True) @@ -657,7 +654,7 @@ def handle_delete(just_salvage=False): session.untagBuildBypass(trashcan_tag, binfo['id']) try: session.deleteBuild(binfo['id']) - except (six.moves.xmlrpc_client.Fault, koji.GenericError) as e: + except (xmlrpclib.Fault, koji.GenericError), e: print("Warning: deletion failed: %s" % e) #server issue pass @@ -736,7 +733,7 @@ def read_policies(fn=None): The expected format as follows test [params] [&& test [params] ...] :: (keep|untag|skip) """ - fo = open(fn, 'r') + fo = file(fn, 'r') tests = koji.policy.findSimpleTests(globals()) ret = koji.policy.SimpleRuleSet(fo, tests) fo.close() @@ -771,7 +768,7 @@ def get_build_sigs(build, cache=False): for sig in sigs: if sig['sigkey']: keys.setdefault(sig['sigkey'], 1) - ret = build_sig_cache[build] = list(keys.keys()) + ret = build_sig_cache[build] = keys.keys() return ret def handle_prune(): @@ -831,7 +828,7 @@ def handle_prune(): pkghist.setdefault(h['name'] + '-' + h['version'], []).append(h) else: pkghist.setdefault(h['name'], []).append(h) - pkgs = list(pkghist.keys()) + pkgs = pkghist.keys() pkgs.sort() for pkg in pkgs: if not check_package(pkg): @@ -876,7 +873,7 @@ def handle_prune(): try: session.untagBuildBypass(taginfo['id'], entry['build_id'], force=bypass) untagged.setdefault(nvr, {})[tagname] = 1 - except (six.moves.xmlrpc_client.Fault, koji.GenericError) as e: + except (xmlrpclib.Fault, koji.GenericError), e: print("Warning: untag operation failed: %s" % e) pass # if action == 'keep' do nothing @@ -910,7 +907,7 @@ def handle_prune(): print("Deleting untagged build: %s" % nvr) try: session.deleteBuild(build_id, strict=False) - except (six.moves.xmlrpc_client.Fault, koji.GenericError) as e: + except (xmlrpclib.Fault, koji.GenericError), e: print("Warning: deletion failed: %s" % e) #server issue pass diff --git a/util/koji-shadow b/util/koji-shadow index c170665..233d33d 100755 --- a/util/koji-shadow +++ b/util/koji-shadow @@ -22,16 +22,12 @@ # Dennis Gilmore # Karsten Hopp -from __future__ import absolute_import -from six.moves import range -from six.moves import zip -import six try: import krbV except ImportError: # pragma: no cover pass import koji -import six.moves.configparser +import ConfigParser import fnmatch import optparse import os @@ -42,8 +38,9 @@ import socket # for socket.error and socket.setdefaulttimeout import string import sys import time -import six.moves.xmlrpc_client # for ProtocolError and Fault -import six.moves.urllib +import urllib2 +import urlgrabber.grabber as grabber +import xmlrpclib # for ProtocolError and Fault import rpm # koji.fp.o keeps stalling, probably network errors... @@ -163,7 +160,7 @@ def get_options(): (options, args) = parser.parse_args() defaults = parser.get_default_values() - config = six.moves.configparser.ConfigParser() + config = ConfigParser.ConfigParser() cf = getattr(options, 'config_file', None) if cf: if not os.access(cf, os.F_OK): @@ -299,7 +296,7 @@ def warn(msg): def ensure_connection(session): try: ret = session.getAPIVersion() - except six.moves.xmlrpc_client.ProtocolError: + except xmlrpclib.ProtocolError: error(_("Error: Unable to connect to server")) if ret != koji.API_VERSION: warn(_("WARNING: The server is at API version %d and the client is at " @@ -329,9 +326,9 @@ def activate_session(session): session.krb_login(principal=options.principal, keytab=options.keytab, proxyuser=options.runas) else: session.krb_login(proxyuser=options.runas) - except krbV.Krb5Error as e: + except krbV.Krb5Error, e: error(_("Kerberos authentication failed: '%s' (%s)") % (e.args[1], e.args[0])) - except socket.error as e: + except socket.error, e: warn(_("Could not connect to Kerberos authentication service: '%s'") % e.args[1]) if not options.noauth and not session.logged_in: error(_("Error: unable to log in")) @@ -448,10 +445,10 @@ class TrackedBuild(object): url = "%s/%s" % (pathinfo.build(self.info), pathinfo.rpm(self.srpm)) log("Downloading %s" % url) #XXX - this is not really the right place for this - fsrc = six.moves.urllib.request.urlopen(url) + fsrc = urllib2.urlopen(url) fn = "%s/%s.src.rpm" % (options.workpath, self.nvr) koji.ensuredir(os.path.dirname(fn)) - fdst = open(fn, 'w') + fdst = file(fn, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() fdst.close() @@ -498,7 +495,7 @@ class TrackedBuild(object): log("Warning: some rpms for %s lacked buildroots:" % self.nvr) for rinfo in bad: log(" %(name)s-%(version)s-%(release)s.%(arch)s" % rinfo) - return list(brs.keys()) + return brs.keys() def getDeps(self): buildroots = self.getBuildroots() @@ -547,7 +544,7 @@ class TrackedBuild(object): # changes happened during the build startup and some subtasks got the old # repo and others the new one. base = [] - for name, brlist in six.iteritems(bases): + for name, brlist in bases.iteritems(): #We want to determine for each name if that package was present #in /all/ the buildroots or just some. #Because brlist is constructed only from elements of buildroots, we @@ -557,12 +554,12 @@ class TrackedBuild(object): #each buildroot had this as a base package base.append(name) if len(tags) > 1: - log("Warning: found multiple buildroot tags for %s: %s" % (self.nvr, list(tags.keys()))) - counts = [(n, tag) for tag, n in six.iteritems(tags)] + log("Warning: found multiple buildroot tags for %s: %s" % (self.nvr, tags.keys())) + counts = [(n, tag) for tag, n in tags.iteritems()] sort(counts) tag = counts[-1][1] else: - tag = list(tags.keys())[0] + tag = tags.keys()[0] # due bugs in used tools mainline koji instance could store empty buildroot infos for builds if len(builds) == 0: self.setState("noroot") @@ -662,10 +659,8 @@ class BuildTracker(object): return grey return default - def rpmvercmp(self, evr1, evr2): + def rpmvercmp(self, (e1, v1, r1), (e2, v2, r2)): """find out which build is newer""" - (e1, v1, r1) = evr1 - (e2, v2, r2) = evr2 rc = rpm.labelCompare((e1, v1, r1), (e2, v2, r2)) if rc == 1: #first evr wins @@ -866,7 +861,7 @@ class BuildTracker(object): taginfo = remote.getTag(tag) builds = remote.listTagged(taginfo['id'], latest=True) for build in builds: - for retry in range(10): + for retry in xrange(10): try: self.scanBuild(build['id'], tag=tag) if options.first_one: @@ -885,13 +880,13 @@ class BuildTracker(object): if options.link_imports: #bit of a hack, but faster than uploading dst = "%s/%s/%s" % (koji.pathinfo.work(), serverdir, fn) - old_umask = os.umask(0o02) + old_umask = os.umask(002) try: koji.ensuredir(os.path.dirname(dst)) os.chown(os.path.dirname(dst), 48, 48) #XXX - hack log ("Downloading %s to %s" % (url, dst)) - fsrc = six.moves.urllib.request.urlopen(url) - fdst = open(fn, 'w') + fsrc = urllib2.urlopen(url) + fdst = file(fn, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() fdst.close() @@ -903,8 +898,8 @@ class BuildTracker(object): koji.ensuredir(options.workpath) dst = "%s/%s" % (options.workpath, fn) log ("Downloading %s to %s..." % (url, dst)) - fsrc = six.moves.urllib.request.urlopen(url) - fdst = open(dst, 'w') + fsrc = urllib2.urlopen(url) + fdst = file(dst, 'w') shutil.copyfileobj(fsrc, fdst) fsrc.close() fdst.close() @@ -1008,7 +1003,7 @@ class BuildTracker(object): for pkg in session.listPackages(pkgID=name): owners.setdefault(pkg['owner_id'], []).append(pkg) if owners: - order = [(len(v), k) for k, v in six.iteritems(owners)] + order = [(len(v), k) for k, v in owners.iteritems()] order.sort() owner = order[-1][1] else: @@ -1124,7 +1119,7 @@ class BuildTracker(object): log("-- %s --" % time.asctime()) self.report_brief() for state in ('broken', 'noroot', 'blocked'): - builds = list(self.state_idx[state].values()) + builds = self.state_idx[state].values() not_replaced = [b for b in builds if not b.substitute] n_replaced = len(builds) - len(not_replaced) log("%s: %i (+%i replaced)" % (state, len(not_replaced), n_replaced)) @@ -1154,7 +1149,7 @@ class BuildTracker(object): nvr = dep.substitute problem_counts.setdefault(nvr, 0) problem_counts[nvr] += 1 - order = [(c, nvr) for (nvr, c) in six.iteritems(problem_counts)] + order = [(c, nvr) for (nvr, c) in problem_counts.iteritems()] if order: order.sort() order.reverse() @@ -1165,7 +1160,7 @@ class BuildTracker(object): def report_brief(self): N = len(self.builds) - states = list(self.state_idx.keys()) + states = self.state_idx.keys() states.sort() parts = ["%s: %i" % (s, len(self.state_idx[s])) for s in states] parts.append("total: %i" % N) @@ -1237,7 +1232,7 @@ class BuildTracker(object): ret = False if options.max_jobs and len(self.state_idx['pending']) >= options.max_jobs: return ret - missing = [(b.order, b.id, b) for b in six.itervalues(self.state_idx['missing'])] + missing = [(b.order, b.id, b) for b in self.state_idx['missing'].itervalues()] missing.sort() for order, build_id, build in missing: if not self.checkBuildDeps(build): @@ -1305,7 +1300,7 @@ def main(args): if options.logfile: filename = options.logfile try: - logfile = os.open(filename,os.O_CREAT|os.O_RDWR|os.O_APPEND, 0o777) + logfile = os.open(filename,os.O_CREAT|os.O_RDWR|os.O_APPEND, 0777) except: logfile = None if logfile is not None: diff --git a/util/kojira b/util/kojira index e15c149..4a21332 100755 --- a/util/kojira +++ b/util/kojira @@ -20,8 +20,6 @@ # Authors: # Mike McLean -from __future__ import absolute_import -import six try: import krbV except ImportError: # pragma: no cover @@ -31,7 +29,7 @@ import os import koji from koji.util import rmtree, parseStatus from optparse import OptionParser -from six.moves.configparser import ConfigParser +from ConfigParser import ConfigParser import errno import fnmatch import logging @@ -87,7 +85,7 @@ class ManagedRepo(object): tags = {self.tag_id : 1} for x in order: tags[x['parent_id']] = 1 - self.taglist = list(tags.keys()) + self.taglist = tags.keys() def expire(self): """Mark the repo expired""" @@ -148,7 +146,7 @@ class ManagedRepo(object): #also check dir age. We do this because a repo can be created from an older event #and should not be removed based solely on that event's timestamp. mtime = os.stat(path).st_mtime - except OSError as e: + except OSError, e: if e.errno == 2: # No such file or directory, so the repo either never existed, # or has already been deleted, so allow it to be marked deleted. @@ -200,9 +198,9 @@ class RepoManager(object): def printState(self): self.logger.debug('Tracking %i repos, %i child processes', len(self.repos), len(self.delete_pids)) - for tag_id, task_id in six.iteritems(self.tasks): + for tag_id, task_id in self.tasks.iteritems(): self.logger.debug("Tracking task %s for tag %s", task_id, tag_id) - for pid, desc in six.iteritems(self.delete_pids): + for pid, desc in self.delete_pids.iteritems(): self.logger.debug("Delete job %s: %r", pid, desc) def rmtree(self, path): @@ -228,7 +226,7 @@ class RepoManager(object): prefix = "pid %i (%s)" % (pid, self.delete_pids.get(pid)) try: (childpid, status) = os.waitpid(pid, os.WNOHANG) - except OSError as e: + except OSError, e: if e.errno != errno.ECHILD: #should not happen raise @@ -263,7 +261,7 @@ class RepoManager(object): for pid in self.delete_pids: try: os.kill(pid, sig) - except OSError as e: + except OSError, e: if e.errno != errno.ESRCH: logger.error("Unable to kill process %s", pid) @@ -298,7 +296,7 @@ class RepoManager(object): if session is None: session = self.session to_check = [] - repo_ids = list(self.repos.keys()) + repo_ids = self.repos.keys() for repo_id in repo_ids: repo = self.repos.get(repo_id) if repo is None: @@ -533,8 +531,8 @@ class RepoManager(object): tag_repos = {} for repo in self.repos.values(): tag_repos.setdefault(repo.tag_id, []).append(repo) - self.logger.debug("Needed tags: %r" % list(tags.keys())) - self.logger.debug("Current tags: %r" % list(tag_repos.keys())) + self.logger.debug("Needed tags: %r" % tags.keys()) + self.logger.debug("Current tags: %r" % tag_repos.keys()) #we need to determine: # - which tags need a new repo @@ -542,7 +540,7 @@ class RepoManager(object): #self.checkCurrentRepos now runs continually in a separate thread regen = [] expire_times = {} - for tag_id in six.iterkeys(tags): + for tag_id in tags.iterkeys(): covered = False for repo in tag_repos.get(tag_id,[]): if repo.current: diff --git a/vm/kojikamid.py b/vm/kojikamid.py index fe70dd6..0499c74 100755 --- a/vm/kojikamid.py +++ b/vm/kojikamid.py @@ -26,15 +26,14 @@ # kojiwind --install # in a cygwin shell. -from __future__ import absolute_import from optparse import OptionParser -from six.moves.configparser import ConfigParser +from ConfigParser import ConfigParser import os import subprocess import sys import tempfile import time -import six.moves.xmlrpc_client +import xmlrpclib import base64 import hashlib import logging @@ -43,7 +42,6 @@ import threading import re import glob import zipfile -import six MANAGER_PORT = 7000 @@ -303,7 +301,7 @@ class WindowsBuild(object): """Download the file from buildreq, at filepath, into the basedir""" destpath = os.path.join(basedir, fileinfo['localpath']) ensuredir(os.path.dirname(destpath)) - destfile = open(destpath, 'w') + destfile = file(destpath, 'w') offset = 0 checksum = hashlib.md5() while True: @@ -562,7 +560,7 @@ def upload_file(server, prefix, path): """upload a single file to the vmd""" logger = logging.getLogger('koji.vm') destpath = os.path.join(prefix, path) - fobj = open(destpath, 'r') + fobj = file(destpath, 'r') offset = 0 sum = hashlib.md5() while True: @@ -588,13 +586,13 @@ def get_mgmt_server(): macaddr, gateway = find_net_info() logger.debug('found MAC address %s, connecting to %s:%s', macaddr, gateway, MANAGER_PORT) - server = six.moves.xmlrpc_client.ServerProxy('http://%s:%s/' % + server = xmlrpclib.ServerProxy('http://%s:%s/' % (gateway, MANAGER_PORT), allow_none=True) # we would set a timeout on the socket here, but that is apparently not # supported by python/cygwin/Windows task_port = server.getPort(macaddr) logger.debug('found task-specific port %s', task_port) - return six.moves.xmlrpc_client.ServerProxy('http://%s:%s/' % (gateway, task_port), allow_none=True) + return xmlrpclib.ServerProxy('http://%s:%s/' % (gateway, task_port), allow_none=True) def get_options(): """handle usage and parse options""" @@ -616,7 +614,7 @@ def setup_logging(opts): if opts.debug: level = logging.DEBUG logger.setLevel(level) - logfd = open(logfile, 'w') + logfd = file(logfile, 'w') handler = logging.StreamHandler(logfd) handler.setLevel(level) handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(name)s: %(message)s')) @@ -641,11 +639,11 @@ def stream_logs(server, handler, builds): logpath = os.path.join(build.source_dir, relpath) if logpath not in logs: logs[logpath] = (relpath, None) - for log, (relpath, fd) in six.iteritems(logs): + for log, (relpath, fd) in logs.iteritems(): if not fd: if os.path.isfile(log): try: - fd = open(log, 'r') + fd = file(log, 'r') logs[log] = (relpath, fd) except: log_local('Error opening %s' % log) diff --git a/www/kojiweb/archiveinfo.chtml b/www/kojiweb/archiveinfo.chtml index 1b763ca..ee2d3f4 100644 --- a/www/kojiweb/archiveinfo.chtml +++ b/www/kojiweb/archiveinfo.chtml @@ -1,7 +1,7 @@ #import koji #from kojiweb import util #from pprint import pformat -#import six.moves.urllib +#import urllib #attr _PASSTHROUGH = ['archiveID', 'fileOrder', 'fileStart', 'buildrootOrder', 'buildrootStart'] @@ -97,7 +97,7 @@ #for $file in $files - $file.name$file.size + $file.name$file.size #end for diff --git a/www/kojiweb/fileinfo.chtml b/www/kojiweb/fileinfo.chtml index b402527..6359d60 100644 --- a/www/kojiweb/fileinfo.chtml +++ b/www/kojiweb/fileinfo.chtml @@ -1,12 +1,12 @@ #from kojiweb import util -#import six.moves.urllib +#import urllib #import datetime #include "includes/header.chtml" #if $rpm -

Information for file $file.name

+

Information for file $file.name

#elif $archive -

Information for file $file.name

+

Information for file $file.name

#end if diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py index 85784bd..49ea24b 100644 --- a/www/kojiweb/index.py +++ b/www/kojiweb/index.py @@ -20,13 +20,12 @@ # Mike Bonnet # Mike McLean -from __future__ import absolute_import import os import os.path import re import sys import mimetypes -import six.moves.http_cookies +import Cookie import datetime import logging import time @@ -37,9 +36,6 @@ from kojiweb.util import _initValues from kojiweb.util import _genHTML from kojiweb.util import _getValidTokens from koji.util import sha1_constructor -from six.moves import range -from six.moves import zip -import six # Convenience definition of a commonly-used sort function _sortbyname = kojiweb.util.sortByKeyFunc('name') @@ -57,7 +53,7 @@ def _setUserCookie(environ, user): shasum = sha1_constructor(value) shasum.update(options['Secret'].value) value = "%s:%s" % (shasum.hexdigest(), value) - cookies = six.moves.http_cookies.SimpleCookie() + cookies = Cookie.SimpleCookie() cookies['user'] = value c = cookies['user'] #morsel instance c['secure'] = True @@ -70,7 +66,7 @@ def _setUserCookie(environ, user): environ['koji.headers'].append(['Cache-Control', 'no-cache="set-cookie"']) def _clearUserCookie(environ): - cookies = six.moves.http_cookies.SimpleCookie() + cookies = Cookie.SimpleCookie() cookies['user'] = '' c = cookies['user'] #morsel instance c['path'] = os.path.dirname(environ['SCRIPT_NAME']) @@ -80,7 +76,7 @@ def _clearUserCookie(environ): def _getUserCookie(environ): options = environ['koji.options'] - cookies = six.moves.http_cookies.SimpleCookie(environ.get('HTTP_COOKIE', '')) + cookies = Cookie.SimpleCookie(environ.get('HTTP_COOKIE', '')) if 'user' not in cookies: return None value = cookies['user'].value @@ -683,7 +679,7 @@ def taskinfo(environ, taskID): values['pathinfo'] = pathinfo paths = [] # (volume, relpath) tuples - for relname, volumes in six.iteritems(server.listTaskOutput(task['id'], all_volumes=True)): + for relname, volumes in server.listTaskOutput(task['id'], all_volumes=True).iteritems(): paths += [(volume, relname) for volume in volumes] values['output'] = sorted(paths, cmp = _sortByExtAndName) if environ['koji.currentUser']: @@ -702,8 +698,8 @@ def taskstatus(environ, taskID): return '' files = server.listTaskOutput(taskID, stat=True, all_volumes=True) output = '%i:%s\n' % (task['id'], koji.TASK_STATES[task['state']]) - for filename, volumes_data in six.iteritems(files): - for volume, file_stats in six.iteritems(volumes_data): + for filename, volumes_data in files.iteritems(): + for volume, file_stats in volumes_data.iteritems(): output += '%s:%s:%s\n' % (volume, filename, file_stats['st_size']) return output @@ -813,7 +809,7 @@ def tags(environ, start=None, order=None, childID=None): return _genHTML(environ, 'tags.chtml') -_PREFIX_CHARS = [chr(char) for char in list(range(48, 58)) + list(range(97, 123))] +_PREFIX_CHARS = [chr(char) for char in range(48, 58) + range(97, 123)] def packages(environ, tagID=None, userID=None, order='package_name', start=None, prefix=None, inherited='1'): values = _initValues(environ, 'Packages', 'packages') @@ -2116,7 +2112,7 @@ def buildsbytarget(environ, days='7', start=None, order='-builds'): if builds > maxBuilds: maxBuilds = builds - kojiweb.util.paginateList(values, list(targets.values()), start, 'targets', 'target', order) + kojiweb.util.paginateList(values, targets.values(), start, 'targets', 'target', order) values['order'] = order diff --git a/www/kojiweb/rpminfo.chtml b/www/kojiweb/rpminfo.chtml index 9b357d4..38b7a00 100644 --- a/www/kojiweb/rpminfo.chtml +++ b/www/kojiweb/rpminfo.chtml @@ -2,7 +2,7 @@ #from kojiweb import util #from pprint import pformat #import time -#import six.moves.urllib +#import urllib #attr _PASSTHROUGH = ['rpmID', 'fileOrder', 'fileStart', 'buildrootOrder', 'buildrootStart'] @@ -237,7 +237,7 @@ #for $file in $files - + #end for
$util.escapeHTML($file.name)$file.size$util.escapeHTML($file.name)$file.size
diff --git a/www/kojiweb/searchresults.chtml b/www/kojiweb/searchresults.chtml index 882d673..e0c4ece 100644 --- a/www/kojiweb/searchresults.chtml +++ b/www/kojiweb/searchresults.chtml @@ -1,5 +1,5 @@ #from kojiweb import util -#import six.moves.urllib +#import urllib #include "includes/header.chtml" @@ -38,7 +38,7 @@ $result.id #set $quoted = $result.copy() - #silent $quoted['name'] = $six.moves.urllib.parse.quote($quoted['name']) + #silent $quoted['name'] = $urllib.quote($quoted['name']) $result.name #end for diff --git a/www/kojiweb/taskinfo.chtml b/www/kojiweb/taskinfo.chtml index 1f02cf7..a4e050f 100644 --- a/www/kojiweb/taskinfo.chtml +++ b/www/kojiweb/taskinfo.chtml @@ -1,6 +1,6 @@ #import koji #from kojiweb import util -#import six.moves.urllib +#import urllib #import cgi #def printValue($key, $value, $sep=', ') @@ -424,9 +424,9 @@ $value Output #for $volume, $filename in $output - $filename + $filename #if $filename.endswith('.log') - (tail) + (tail) #end if
#end for diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py index 5140625..e2d427b 100644 --- a/www/kojiweb/wsgi_publisher.py +++ b/www/kojiweb/wsgi_publisher.py @@ -19,7 +19,6 @@ # Authors: # Mike McLean -from __future__ import absolute_import import cgi import inspect import koji @@ -30,10 +29,9 @@ import pprint import sys import traceback -from six.moves.configparser import RawConfigParser +from ConfigParser import RawConfigParser from koji.server import WSGIWrapper, ServerError, ServerRedirect from koji.util import dslice -import six class URLNotFound(ServerError): @@ -423,14 +421,14 @@ class Dispatcher(object): else: # last one wins headers[key] = (name, value) - if isinstance(result, six.string_types): + if isinstance(result, basestring): headers.setdefault('content-length', ('Content-Length', str(len(result)))) headers.setdefault('content-type', ('Content-Type', 'text/html')) - headers = list(headers.values()) + extra + headers = headers.values() + extra self.logger.debug("Headers:") self.logger.debug(koji.util.LazyString(pprint.pformat, [headers])) start_response(status, headers) - if isinstance(result, six.string_types): + if isinstance(result, basestring): result = [result] return result diff --git a/www/lib/kojiweb/util.py b/www/lib/kojiweb/util.py index 23d168f..6cdcecc 100644 --- a/www/lib/kojiweb/util.py +++ b/www/lib/kojiweb/util.py @@ -20,8 +20,6 @@ # Mike Bonnet # Mike McLean -from __future__ import absolute_import -from __future__ import division import Cheetah.Template import datetime import koji @@ -31,11 +29,9 @@ import stat #a bunch of exception classes that explainError needs from socket import error as socket_error from socket import sslerror as socket_sslerror -from six.moves.xmlrpc_client import ProtocolError +from xmlrpclib import ProtocolError from xml.parsers.expat import ExpatError import cgi -from six.moves import range -import six class NoSuchException(Exception): pass @@ -98,7 +94,7 @@ class DecodeUTF8(Cheetah.Filters.Filter): def filter(self, *args, **kw): """Convert all strs to unicode objects""" result = super(DecodeUTF8, self).filter(*args, **kw) - if isinstance(result, six.text_type): + if isinstance(result, unicode): pass else: result = result.decode('utf-8', 'replace') @@ -153,7 +149,7 @@ def _genHTML(environ, fileName): def _truncTime(): now = datetime.datetime.now() # truncate to the nearest 15 minutes - return now.replace(minute=(now.minute // 15 * 15), second=0, microsecond=0) + return now.replace(minute=(now.minute / 15 * 15), second=0, microsecond=0) def _genToken(environ, tstamp=None): if 'koji.currentLogin' in environ and environ['koji.currentLogin']: @@ -358,9 +354,9 @@ def _populateValues(values, dataName, prefix, data, totalRows, start, count, pag values[(prefix and prefix + 'Count' or 'count')] = count values[(prefix and prefix + 'Range' or 'range')] = pageSize values[(prefix and prefix + 'Order' or 'order')] = order - currentPage = start // pageSize + currentPage = start / pageSize values[(prefix and prefix + 'CurrentPage' or 'currentPage')] = currentPage - totalPages = totalRows // pageSize + totalPages = totalRows / pageSize if totalRows % pageSize > 0: totalPages += 1 pages = [page for page in range(0, totalPages) if (abs(page - currentPage) < 100 or ((page + 1) % 100 == 0))] From c0fccab2b7e8e1abe3d13bc934c6ae3844a999de Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 36/61] correct sort() usage --- diff --git a/cli/koji b/cli/koji index 349d595..d3fc313 100755 --- a/cli/koji +++ b/cli/koji @@ -4168,7 +4168,7 @@ def anon_handle_list_tags(options, session, args): assert False # pragma: no cover tags = session.listTags(buildinfo.get('id',None), pkginfo.get('id',None)) - tags.sort(lambda a,b: cmp(a['name'],b['name'])) + tags.sort(key=lambda x: x['name']) #if options.verbose: # fmt = "%(name)s [%(id)i] %(perm)s %(locked)s %(arches)s" if options.show_id: diff --git a/koji/__init__.py b/koji/__init__.py index fda9e4a..6eb8093 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -411,7 +411,7 @@ def listFaults(): info['name'] = n info['desc'] = getattr(v, '__doc__', None) ret.append(info) - ret.sort(lambda a, b: cmp(a['faultCode'], b['faultCode'])) + ret.sort(key=lambda x: x['faultCode']) return ret #functions for encoding/decoding optional arguments @@ -1219,7 +1219,7 @@ BuildArch: noarch continue data.append("#Group: %s\n" % group_name) pkglist = list(group['packagelist']) - pkglist.sort(lambda a, b: cmp(a['package'], b['package'])) + pkglist.sort(key=lambda x: x['package']) for pkg in pkglist: pkg_name = pkg['package'] if pkg_name in seen_pkg: @@ -1261,7 +1261,7 @@ def generate_comps(groups, expand_groups=False): """] groups = list(groups) group_idx = dict([(g['name'], g) for g in groups]) - groups.sort(lambda a, b: cmp(a['name'], b['name'])) + groups.sort(key=lambda x: x['name']) for g in groups: group_id = g['name'] name = g['display_name'] @@ -1288,7 +1288,7 @@ def generate_comps(groups, expand_groups=False): """ """) grouplist = list(g['grouplist']) - grouplist.sort(lambda a, b: cmp(a['name'], b['name'])) + grouplist.sort(key=lambda x: x['name']) for x in grouplist: #['req_id','type','is_metapkg','name'] name = x['name'] @@ -1324,7 +1324,7 @@ def generate_comps(groups, expand_groups=False): """) if g['packagelist']: packagelist = list(g['packagelist']) - packagelist.sort(lambda a, b: cmp(a['package'], b['package'])) + packagelist.sort(key=lambda x: x['package']) for p in packagelist: data.append( """ %s @@ -1351,7 +1351,7 @@ def generate_comps(groups, expand_groups=False): """ """ % group_name) pkglist = list(group['packagelist']) - pkglist.sort(lambda a, b: cmp(a['package'], b['package'])) + pkglist.sort(key=lambda x: x['package']) for pkg in pkglist: pkg_name = pkg['package'] if pkg_name in seen_pkg: From 2a233d519f9297640353e119bf569a0ade61218a Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 37/61] update requires for python-six --- diff --git a/koji.spec b/koji.spec index 22a7cb6..a391910 100644 --- a/koji.spec +++ b/koji.spec @@ -32,6 +32,7 @@ Requires: python-requests Requires: python-requests-kerberos Requires: python-pycurl Requires: python-dateutil +Requires: python-six BuildRequires: python %if %{use_systemd} BuildRequires: systemd From 709cf93b755b01546500652e3d163761041ac8c1 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 38/61] fix adler32 iterations --- diff --git a/koji/util.py b/koji/util.py index af1a0b0..2cde6c6 100644 --- a/koji/util.py +++ b/koji/util.py @@ -467,14 +467,14 @@ class adler32_constructor(object): #mimicing the hashlib constructors def __init__(self, arg=''): - if six.PY3: + if six.PY3 and isinstance(arg, str): arg = bytes(arg, 'utf-8') self._value = adler32(arg) & 0xffffffff #the bitwise and works around a bug in some versions of python #see: https://bugs.python.org/issue1202 def update(self, arg): - if six.PY3: + if six.PY3 and isinstance(arg, str): arg = bytes(arg, 'utf-8') self._value = adler32(arg, self._value) & 0xffffffff From ed6800d613d99997ea7d5dc0b660c0a99920f623 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 39/61] bytes in rpm headers --- diff --git a/koji/__init__.py b/koji/__init__.py index 6eb8093..f4dde34 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -915,8 +915,12 @@ def get_header_field(hdr, name, src_arch=False): result = [] elif isinstance(result, six.integer_types): result = [result] - if isinstance(result, bytes): - result = result.decode('utf-8') + if six.PY3 and isinstance(result, bytes): + try: + result = result.decode('utf-8') + except UnicodeDecodeError: + # typically signatures + pass return result From e9a536ae07de2c4e78fc0c0c0db3a6b4dc1cf3a9 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 40/61] str/bytes in rpm headers --- diff --git a/koji/__init__.py b/koji/__init__.py index f4dde34..8c31469 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -550,7 +550,7 @@ def rpm_hdr_size(f, ofs=None): f = filename or file object ofs = offset of the header """ - if isinstance(f, (str, six.text_type)): + if isinstance(f, six.string_types): fo = open(f, 'rb') else: fo = f @@ -567,7 +567,7 @@ def rpm_hdr_size(f, ofs=None): # now read two 4-byte integers which tell us # - # of index entries # - bytes of data in header - data = [ord(x) for x in fo.read(8)] + data = [__ord(x) for x in fo.read(8)] il = multibyte(data[0:4]) dl = multibyte(data[4:8]) @@ -580,7 +580,7 @@ def rpm_hdr_size(f, ofs=None): # add eight bytes for section header hdrsize = hdrsize + 8 - if not isinstance(f, (str, six.text_type)): + if not isinstance(f, six.string_types): fo.close() return hdrsize @@ -597,13 +597,13 @@ class RawHeader(object): def version(self): #fourth byte is the version - return ord(self.header[3]) + return __ord(self.header[3]) def _index(self): # read two 4-byte integers which tell us # - # of index entries (each 16 bytes long) # - bytes of data in header - data = [ord(x) for x in self.header[8:12]] + data = [__ord(x) for x in self.header[8:12]] il = multibyte(data[:4]) dl = multibyte(data[4:8]) @@ -613,7 +613,7 @@ class RawHeader(object): entry = [] for j in range(4): ofs = 16 + i*16 + j*4 - data = [ord(x) for x in self.header[ofs:ofs+4]] + data = [__ord(x) for x in self.header[ofs:ofs+4]] entry.append(multibyte(data)) #print("Tag: %d, Type: %d, Offset: %x, Count: %d" % tuple(entry)) index[entry[0]] = entry @@ -664,7 +664,7 @@ class RawHeader(object): #integer n = 1 << (dtype - 2) for i in range(count): - data = [ord(x) for x in self.header[pos:pos+n]] + data = [__ord(x) for x in self.header[pos:pos+n]] print("%r" % data) num = multibyte(data) print("Int(%d): %d" % (n, num)) @@ -717,7 +717,7 @@ class RawHeader(object): if dtype >= 2 and dtype <= 5: n = 1 << (dtype - 2) # n-byte integer - data = [ord(x) for x in self.header[pos:pos+n]] + data = [__ord(x) for x in self.header[pos:pos+n]] return multibyte(data) elif dtype == 6: # string (null terminated) @@ -758,9 +758,16 @@ def rip_rpm_hdr(src): fo.close() return hdr +def __ord(s): + # in python2 it is char/str, while in py3 it is already int/bytes + if isinstance(s, int): + return s + else: + return ord(s) + def __parse_packet_header(pgp_packet): """Parse pgp_packet header, return tag type and the rest of pgp_packet""" - byte0 = ord(pgp_packet[0]) + byte0 = __ord(pgp_packet[0]) if (byte0 & 0x80) == 0: raise ValueError('Not an OpenPGP packet') if (byte0 & 0x40) == 0: @@ -774,12 +781,12 @@ def __parse_packet_header(pgp_packet): length = struct.unpack(fmt, pgp_packet[1:offset])[0] else: tag = byte0 & 0x3F - byte1 = ord(pgp_packet[1]) + byte1 = __ord(pgp_packet[1]) if byte1 < 192: length = byte1 offset = 2 elif byte1 < 224: - length = ((byte1 - 192) << 8) + ord(pgp_packet[2]) + 192 + length = ((byte1 - 192) << 8) + __ord(pgp_packet[2]) + 192 offset = 3 elif byte1 == 255: length = struct.unpack('>I', pgp_packet[2:6])[0] @@ -796,17 +803,17 @@ def __subpacket_key_ids(subs): """Parse v4 signature subpackets and return a list of issuer key IDs""" res = [] while len(subs) > 0: - byte0 = ord(subs[0]) + byte0 = __ord(subs[0]) if byte0 < 192: length = byte0 off = 1 elif byte0 < 255: - length = ((byte0 - 192) << 8) + ord(subs[1]) + 192 + length = ((byte0 - 192) << 8) + __ord(subs[1]) + 192 off = 2 else: length = struct.unpack('>I', subs[1:5])[0] off = 5 - if ord(subs[off]) == 16: + if __ord(subs[off]) == 16: res.append(subs[off+1 : off+length]) subs = subs[off+length:] return res @@ -816,9 +823,9 @@ def get_sigpacket_key_id(sigpacket): (tag, sigpacket) = __parse_packet_header(sigpacket) if tag != 2: raise ValueError('Not a signature packet') - if ord(sigpacket[0]) == 0x03: + if __ord(sigpacket[0]) == 0x03: key_id = sigpacket[11:15] - elif ord(sigpacket[0]) == 0x04: + elif __ord(sigpacket[0]) == 0x04: sub_len = struct.unpack('>H', sigpacket[4:6])[0] off = 6 + sub_len key_ids = __subpacket_key_ids(sigpacket[6:off]) @@ -831,7 +838,7 @@ def get_sigpacket_key_id(sigpacket): key_id = key_ids[0][-4:] else: raise NotImplementedError( - 'Unknown PGP signature packet version %s' % ord(sigpacket[0])) + 'Unknown PGP signature packet version %s' % __ord(sigpacket[0])) return hex_string(key_id) def get_sighdr_key(sighdr): @@ -870,7 +877,7 @@ def get_rpm_header(f, ts=None): if ts is None: ts = rpm.TransactionSet() ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES|rpm._RPMVSF_NODIGESTS) - if isinstance(f, (str, six.text_type)): + if isinstance(f, six.string_types): fo = open(f, "r") else: fo = f @@ -1183,7 +1190,7 @@ def mavenLabel(maveninfo): def hex_string(s): """Converts a string to a string of hex digits""" - return ''.join(['%02x' % ord(x) for x in s]) + return ''.join(['%02x' % __ord(x) for x in s]) def make_groups_spec(grplist, name='buildsys-build', buildgroup=None): From 7d5358a336073e1b27c2c64f3811ebfa0327f30b Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 41/61] fix python2 test --- diff --git a/koji/tasks.py b/koji/tasks.py index 9591c23..36c50cf 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -26,11 +26,11 @@ import os import logging import xmlrpclib import signal -import urllib2 import shutil import random import time import pprint +import six.moves.urllib.request def scan_mounts(topdir): """Search path for mountpoints""" @@ -309,7 +309,7 @@ class BaseTaskHandler(object): return fn self.logger.debug("Downloading %s", relpath) url = "%s/%s" % (self.options.topurl, relpath) - fsrc = urllib2.urlopen(url) + fsrc = six.moves.urllib.request.urlopen(url) if not os.path.exists(os.path.dirname(fn)): os.makedirs(os.path.dirname(fn)) fdst = file(fn, 'w') From a47eb50a3492da1dfd9224f9be85e0e7ba0075c1 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 42/61] __ord -> _ord --- diff --git a/koji/__init__.py b/koji/__init__.py index 8c31469..e47a4b6 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -567,7 +567,7 @@ def rpm_hdr_size(f, ofs=None): # now read two 4-byte integers which tell us # - # of index entries # - bytes of data in header - data = [__ord(x) for x in fo.read(8)] + data = [_ord(x) for x in fo.read(8)] il = multibyte(data[0:4]) dl = multibyte(data[4:8]) @@ -597,13 +597,13 @@ class RawHeader(object): def version(self): #fourth byte is the version - return __ord(self.header[3]) + return _ord(self.header[3]) def _index(self): # read two 4-byte integers which tell us # - # of index entries (each 16 bytes long) # - bytes of data in header - data = [__ord(x) for x in self.header[8:12]] + data = [_ord(x) for x in self.header[8:12]] il = multibyte(data[:4]) dl = multibyte(data[4:8]) @@ -613,7 +613,7 @@ class RawHeader(object): entry = [] for j in range(4): ofs = 16 + i*16 + j*4 - data = [__ord(x) for x in self.header[ofs:ofs+4]] + data = [_ord(x) for x in self.header[ofs:ofs+4]] entry.append(multibyte(data)) #print("Tag: %d, Type: %d, Offset: %x, Count: %d" % tuple(entry)) index[entry[0]] = entry @@ -664,7 +664,7 @@ class RawHeader(object): #integer n = 1 << (dtype - 2) for i in range(count): - data = [__ord(x) for x in self.header[pos:pos+n]] + data = [_ord(x) for x in self.header[pos:pos+n]] print("%r" % data) num = multibyte(data) print("Int(%d): %d" % (n, num)) @@ -717,7 +717,7 @@ class RawHeader(object): if dtype >= 2 and dtype <= 5: n = 1 << (dtype - 2) # n-byte integer - data = [__ord(x) for x in self.header[pos:pos+n]] + data = [_ord(x) for x in self.header[pos:pos+n]] return multibyte(data) elif dtype == 6: # string (null terminated) @@ -758,7 +758,7 @@ def rip_rpm_hdr(src): fo.close() return hdr -def __ord(s): +def _ord(s): # in python2 it is char/str, while in py3 it is already int/bytes if isinstance(s, int): return s @@ -767,7 +767,7 @@ def __ord(s): def __parse_packet_header(pgp_packet): """Parse pgp_packet header, return tag type and the rest of pgp_packet""" - byte0 = __ord(pgp_packet[0]) + byte0 = _ord(pgp_packet[0]) if (byte0 & 0x80) == 0: raise ValueError('Not an OpenPGP packet') if (byte0 & 0x40) == 0: @@ -781,12 +781,12 @@ def __parse_packet_header(pgp_packet): length = struct.unpack(fmt, pgp_packet[1:offset])[0] else: tag = byte0 & 0x3F - byte1 = __ord(pgp_packet[1]) + byte1 = _ord(pgp_packet[1]) if byte1 < 192: length = byte1 offset = 2 elif byte1 < 224: - length = ((byte1 - 192) << 8) + __ord(pgp_packet[2]) + 192 + length = ((byte1 - 192) << 8) + _ord(pgp_packet[2]) + 192 offset = 3 elif byte1 == 255: length = struct.unpack('>I', pgp_packet[2:6])[0] @@ -803,17 +803,17 @@ def __subpacket_key_ids(subs): """Parse v4 signature subpackets and return a list of issuer key IDs""" res = [] while len(subs) > 0: - byte0 = __ord(subs[0]) + byte0 = _ord(subs[0]) if byte0 < 192: length = byte0 off = 1 elif byte0 < 255: - length = ((byte0 - 192) << 8) + __ord(subs[1]) + 192 + length = ((byte0 - 192) << 8) + _ord(subs[1]) + 192 off = 2 else: length = struct.unpack('>I', subs[1:5])[0] off = 5 - if __ord(subs[off]) == 16: + if _ord(subs[off]) == 16: res.append(subs[off+1 : off+length]) subs = subs[off+length:] return res @@ -823,9 +823,9 @@ def get_sigpacket_key_id(sigpacket): (tag, sigpacket) = __parse_packet_header(sigpacket) if tag != 2: raise ValueError('Not a signature packet') - if __ord(sigpacket[0]) == 0x03: + if _ord(sigpacket[0]) == 0x03: key_id = sigpacket[11:15] - elif __ord(sigpacket[0]) == 0x04: + elif _ord(sigpacket[0]) == 0x04: sub_len = struct.unpack('>H', sigpacket[4:6])[0] off = 6 + sub_len key_ids = __subpacket_key_ids(sigpacket[6:off]) @@ -838,7 +838,7 @@ def get_sigpacket_key_id(sigpacket): key_id = key_ids[0][-4:] else: raise NotImplementedError( - 'Unknown PGP signature packet version %s' % __ord(sigpacket[0])) + 'Unknown PGP signature packet version %s' % _ord(sigpacket[0])) return hex_string(key_id) def get_sighdr_key(sighdr): @@ -1190,7 +1190,7 @@ def mavenLabel(maveninfo): def hex_string(s): """Converts a string to a string of hex digits""" - return ''.join(['%02x' % __ord(x) for x in s]) + return ''.join(['%02x' % _ord(x) for x in s]) def make_groups_spec(grplist, name='buildsys-build', buildgroup=None): From ff6fc4aa771efa54e0f5e35b693ac19be6d4e661 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 43/61] header magic is bytes --- diff --git a/koji/__init__.py b/koji/__init__.py index e47a4b6..956d4cf 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -88,7 +88,7 @@ def _(args): ## Constants ## -RPM_HEADER_MAGIC = '\x8e\xad\xe8' +RPM_HEADER_MAGIC = six.b('\x8e\xad\xe8') RPM_TAG_HEADERSIGNATURES = 62 RPM_TAG_FILEDIGESTALGO = 5011 RPM_SIGTAG_PGP = 1002 From 08d7abd2aba32d500219d1e918c94bbbbd80dc47 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 44/61] use bytes for finding \0 in file data --- diff --git a/koji/__init__.py b/koji/__init__.py index 956d4cf..799adfd 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -672,7 +672,7 @@ class RawHeader(object): next = pos elif dtype == 6: # string (null terminated) - end = self.header.find('\0', pos) + end = self.header.find(six.b('\0'), pos) print("String(%d): %r" % (end-pos, self.header[pos:end])) next = end + 1 elif dtype == 7: @@ -681,14 +681,14 @@ class RawHeader(object): elif dtype == 8: # string array for i in range(count): - end = self.header.find('\0', pos) + end = self.header.find(six.b('\0'), pos) print("String(%d): %r" % (end-pos, self.header[pos:end])) pos = end + 1 next = pos elif dtype == 9: # unicode string array for i in range(count): - end = self.header.find('\0', pos) + end = self.header.find(six.b('\0'), pos) print("i18n(%d): %r" % (end-pos, self.header[pos:end])) pos = end + 1 next = pos From efa92224ad6ab32aaa6d3061531d569530ac4086 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 45/61] fix mocking of open() in utils test case --- diff --git a/tests/test_utils.py b/tests/test_utils.py index 09df6ef..1ff221c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -40,6 +40,14 @@ class EnumTestCase(unittest.TestCase): self.assertEquals(test[1:], ('two', 'three')) +def mock_open(): + """Return the right patch decorator for open""" + if six.PY2: + return mock.patch('__builtin__.open') + else: + return mock.patch('builtins.open') + + class MiscFunctionTestCase(unittest.TestCase): @mock.patch('os.path.exists') @@ -82,21 +90,14 @@ class MiscFunctionTestCase(unittest.TestCase): islink.assert_called_once_with(dst) move.assert_not_called() + @mock_open() @mock.patch('six.moves.urllib.request.urlopen') @mock.patch('tempfile.TemporaryFile') @mock.patch('shutil.copyfileobj') def test_openRemoteFile(self, m_copyfileobj, m_TemporaryFile, - m_urlopen): + m_urlopen, m_open): """Test openRemoteFile function""" - if six.PY2: - import __builtin__ - __builtin__.open = mock.MagicMock() - m_open = __builtin__.open - else: - import builtins - builtins.open = mock.MagicMock() - m_open = builtins.open mocks = [m_open, m_copyfileobj, m_TemporaryFile, m_urlopen] topurl = 'http://example.com/koji' From c4a48efd8349de05d384b429420a5b7b1700e248 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 46/61] move lib tests into subdir --- diff --git a/tests/data/maven/bad_empty_config.ini b/tests/data/maven/bad_empty_config.ini deleted file mode 100644 index e69de29..0000000 --- a/tests/data/maven/bad_empty_config.ini +++ /dev/null diff --git a/tests/data/maven/bad_scmurl_config.ini b/tests/data/maven/bad_scmurl_config.ini deleted file mode 100644 index 5e8bb9c..0000000 --- a/tests/data/maven/bad_scmurl_config.ini +++ /dev/null @@ -1,16 +0,0 @@ -[pkg] -type=maven -patches=patchurl -specfile=specfile -goals=goal1 goal2 -profiles=profile1 profile2 -packages=pkg1 pkg2 -jvm_options=--opt1 --opt2=val -maven_options=--opt1 --opt2=val -properties: p1=1 - p2 - p3=ppp3 -envs:e1=1 - e2=2 -buildrequires=r1 r2 -otheropts=others \ No newline at end of file diff --git a/tests/data/maven/bad_type_config.ini b/tests/data/maven/bad_type_config.ini deleted file mode 100644 index a26f990..0000000 --- a/tests/data/maven/bad_type_config.ini +++ /dev/null @@ -1,17 +0,0 @@ -[pkg] -type=other -scmurl=scmurl -patches=patchurl -specfile=specfile -goals=goal1 goal2 -profiles=profile1 profile2 -packages=pkg1 pkg2 -jvm_options=--opt1 --opt2=val -maven_options=--opt1 --opt2=val -properties: p1=1 - p2 - p3=ppp3 -envs:e1=1 - e2=2 -buildrequires=r1 r2 -otheropts=others \ No newline at end of file diff --git a/tests/data/maven/bad_wrapper_config.ini b/tests/data/maven/bad_wrapper_config.ini deleted file mode 100644 index 7bd8050..0000000 --- a/tests/data/maven/bad_wrapper_config.ini +++ /dev/null @@ -1,17 +0,0 @@ -[pkg] -type=wrapper -scmurl=scmurl -patches=patchurl -specfile=specfile -goals=goal1 goal2 -profiles=profile1 profile2 -packages=pkg1 pkg2 -jvm_options=--opt1 --opt2=val -maven_options=--opt1 --opt2=val -properties: p1=1 - p2 - p3=ppp3 -envs:e1=1 - e2=2 -buildrequires=r1 r2 -otheropts=others \ No newline at end of file diff --git a/tests/data/maven/config.ini b/tests/data/maven/config.ini deleted file mode 100644 index 1bc3511..0000000 --- a/tests/data/maven/config.ini +++ /dev/null @@ -1,52 +0,0 @@ -[pkg1] -scmurl=scmurl -patches=patchurl -specfile=specfile -goals=goal1 goal2 -profiles=profile1 profile2 -packages=pkg1 pkg2 -jvm_options=--opt1 --opt2=val -maven_options=--opt1 --opt2=val -properties: p1=1 - p2 - p3=ppp3 -envs:e1=1 - e2=2 -buildrequires=r1 r2 -otheropts=others - -[pkg2] -type=maven -scmurl=scmurl -patches=patchurl -specfile=specfile -goals=goal1 goal2 -profiles=profile1 profile2 -packages=pkg1 pkg2 -jvm_options=--opt1 --opt2=val -maven_options=--opt1 --opt2=val -properties: p1=1 - p2 - p3=ppp3 -envs:e1=1 - e2=2 -buildrequires=r1 r2 -otheropts=others - -[pkg3] -type=wrapper -scmurl=scmurl -patches=patchurl -specfile=specfile -goals=goal1 goal2 -profiles=profile1 profile2 -packages=pkg1 pkg2 -jvm_options=--opt1 --opt2=val -maven_options=--opt1 --opt2=val -properties: p1=1 - p2 - p3=ppp3 -envs:e1=1 - e2=2 -buildrequires=r1 -otheropts=others diff --git a/tests/data/maven/good_config.ini b/tests/data/maven/good_config.ini deleted file mode 100644 index e45861c..0000000 --- a/tests/data/maven/good_config.ini +++ /dev/null @@ -1,16 +0,0 @@ -[pkg4] -scmurl=scmurl -patches=patchurl -specfile=specfile -goals=goal1 goal2 -profiles=profile1 profile2 -packages=pkg1 pkg2 -jvm_options=--opt1 --opt2=val -maven_options=--opt1 --opt2=val -properties: p1=1 - p2 - p3=ppp3 -envs:e1=1 - e2=2 -buildrequires=r1 r2 -otheropts=others \ No newline at end of file diff --git a/tests/data/rpms/test-deps-1-1.fc24.x86_64.rpm b/tests/data/rpms/test-deps-1-1.fc24.x86_64.rpm deleted file mode 100644 index 975b2ea..0000000 Binary files a/tests/data/rpms/test-deps-1-1.fc24.x86_64.rpm and /dev/null differ diff --git a/tests/data/rpms/test-nopatch-1-1.fc24.nosrc.rpm b/tests/data/rpms/test-nopatch-1-1.fc24.nosrc.rpm deleted file mode 100644 index 52105d4..0000000 Binary files a/tests/data/rpms/test-nopatch-1-1.fc24.nosrc.rpm and /dev/null differ diff --git a/tests/data/rpms/test-nosrc-1-1.fc24.nosrc.rpm b/tests/data/rpms/test-nosrc-1-1.fc24.nosrc.rpm deleted file mode 100644 index 500eeb2..0000000 Binary files a/tests/data/rpms/test-nosrc-1-1.fc24.nosrc.rpm and /dev/null differ diff --git a/tests/data/rpms/test-src-1-1.fc24.src.rpm b/tests/data/rpms/test-src-1-1.fc24.src.rpm deleted file mode 100644 index 98f4c0d..0000000 Binary files a/tests/data/rpms/test-src-1-1.fc24.src.rpm and /dev/null differ diff --git a/tests/data/specs/test-deps._spec b/tests/data/specs/test-deps._spec deleted file mode 100644 index d31312d..0000000 --- a/tests/data/specs/test-deps._spec +++ /dev/null @@ -1,28 +0,0 @@ -Name: test-deps -Version: 1 -Release: 1%{?dist} -Summary: Testing dependency header fields - -License: none - -Requires: require1 -Requires: require2 -Provides: provide1 -Provides: provide2 -Obsoletes: obsoletes1 -Obsoletes: obsoletes2 -Conflicts: conflicts1 -Conflicts: conflicts2 -Suggests: suggests1 -Suggests: suggests2 -Enhances: enhances1 -Enhances: enhances2 -Supplements: supplements1 -Supplements: supplements2 -Recommends: recommends1 -Recommends: recommends2 - -%description -Testing dependency header fields - -%files diff --git a/tests/data/specs/test-nopatch._spec b/tests/data/specs/test-nopatch._spec deleted file mode 100644 index 33e19bd..0000000 --- a/tests/data/specs/test-nopatch._spec +++ /dev/null @@ -1,13 +0,0 @@ -Name: test-nopatch -Version: 1 -Release: 1%{?dist} -Summary: Testing source arch header fields - -License: none -Patch0: secret.patch -Nopatch: 0 - -%description -... - -%files diff --git a/tests/data/specs/test-nosrc._spec b/tests/data/specs/test-nosrc._spec deleted file mode 100644 index 9ce1885..0000000 --- a/tests/data/specs/test-nosrc._spec +++ /dev/null @@ -1,13 +0,0 @@ -Name: test-nosrc -Version: 1 -Release: 1%{?dist} -Summary: Testing source arch header fields - -License: none -Source0: secret.key -Nosource: 0 - -%description -... - -%files diff --git a/tests/data/specs/test-src._spec b/tests/data/specs/test-src._spec deleted file mode 100644 index 3c5859a..0000000 --- a/tests/data/specs/test-src._spec +++ /dev/null @@ -1,11 +0,0 @@ -Name: test-src -Version: 1 -Release: 1%{?dist} -Summary: Testing source arch header fields - -License: none - -%description -... - -%files diff --git a/tests/test_client_session.py b/tests/test_client_session.py deleted file mode 100644 index 5edab10..0000000 --- a/tests/test_client_session.py +++ /dev/null @@ -1,182 +0,0 @@ -from __future__ import absolute_import -import mock -import unittest -import six - -import koji - - -class TestClientSession(unittest.TestCase): - - @mock.patch('socket.getfqdn') - def test_server_principal_rdns(self, getfqdn): - opts = {'krb_rdns': True} - session = koji.ClientSession('http://koji.example.com:30/kojihub', opts) - cprinc = mock.MagicMock() - cprinc.realm = "REALM" - getfqdn.return_value = 'koji02.example.com' - - princ = session._serverPrincipal(cprinc) - self.assertEqual(princ, 'host/koji02.example.com@REALM') - getfqdn.assert_called_with('koji.example.com') - - @mock.patch('socket.getfqdn') - def test_server_principal_no_rdns(self, getfqdn): - opts = {'krb_rdns': False} - session = koji.ClientSession('http://koji.example.com/kojihub', opts) - cprinc = mock.MagicMock() - cprinc.realm = "REALM" - getfqdn.return_value = 'koji02.example.com' - - princ = session._serverPrincipal(cprinc) - self.assertEqual(princ, 'host/koji.example.com@REALM') - getfqdn.assert_not_called() - - @mock.patch('requests.Session') - def test_new_session(self, rsession): - opts = {'use_old_ssl': False} - ksession = koji.ClientSession('http://koji.example.com/kojihub', opts) - - # init should have called new_session for us - - rsession.assert_called_once() - - @mock.patch('requests.Session') - def test_new_session_old(self, rsession): - if six.PY3: - return - opts = {'use_old_ssl': True} - ksession = koji.ClientSession('http://koji.example.com/kojihub', opts) - - # init should have called new_session for us - - rsession.assert_not_called() - - @mock.patch('requests.Session') - def test_new_session_close(self, rsession): - if six.PY3: - return - opts = {'use_old_ssl': True} - ksession = koji.ClientSession('http://koji.example.com/kojihub', opts) - my_rsession = mock.MagicMock() - ksession.rsession = my_rsession - - ksession.new_session() - my_rsession.close.assert_called() - self.assertNotEqual(ksession.rsession, my_rsession) - - -class TestFastUpload(unittest.TestCase): - - def setUp(self): - self.ksession = koji.ClientSession('http://koji.example.com/kojihub', {}) - self.do_fake_login() - # mocks - self.ksession._callMethod = mock.MagicMock() - self.ksession.retries = 1 - self.rsession = mock.patch('requests.Session').start() - if six.PY2: - self.file_mock = mock.patch('__builtin__.open').start() - else: - self.file_mock = mock.patch('builtins.open').start() - self.getsize_mock = mock.patch('os.path.getsize').start() - - def tearDown(self): - del self.ksession - mock.patch.stopall() - - def do_fake_login(self): - self.ksession.logged_in = True - self.ksession.sinfo = {} - self.ksession.callnum = 1 - - def test_fastUpload_nologin(self): - # without login (ActionNotAllowed) - self.ksession.logged_in = False - with self.assertRaises(koji.ActionNotAllowed): - self.ksession.fastUpload('nonexistent_file', 'target') - - def test_fastUpload_nofile(self): - - # fail with nonexistent file (IOError) - self.file_mock.side_effect = IOError('mocked exception') - with self.assertRaises(IOError): - self.ksession.fastUpload('file', 'target') - - def test_fastUpload_empty_file(self): - # upload empty file (success) - fileobj = mock.MagicMock() - fileobj.read.return_value = '' - self.file_mock.return_value = fileobj - self.ksession._callMethod.return_value = { - 'size': 0, - 'hexdigest': koji.util.adler32_constructor().hexdigest() - } - self.ksession.fastUpload('file', 'target') - - def test_fastUpload_regular_file(self): - # upload regular file (success) - fileobj = mock.MagicMock() - fileobj.read.side_effect = ['123123', ''] - self.file_mock.return_value = fileobj - self.ksession._callMethod.side_effect = [ - {'size': 6, 'hexdigest': '041c012d'}, # rawUpload - {'size': 6, 'hexdigest': '041c012d'}, # checkUpload - ] - self.ksession.fastUpload('file', 'target', blocksize=1024) - - def test_fastUpload_size_change(self): - # change file size during upload (success) - fileobj = mock.MagicMock() - fileobj.read.side_effect = ['123123', ''] - self.file_mock.return_value = fileobj - self.getsize_mock.return_value = 123456 - self.ksession._callMethod.side_effect = [ - {'size': 6, 'hexdigest': '041c012d'}, # rawUpload - {'size': 6, 'hexdigest': '041c012d'}, # checkUpload - ] - self.ksession.fastUpload('file', 'target', blocksize=1024) - - def test_fastUpload_wrong_length(self): - # uploaded file is corrupted (length) (GenericError) - fileobj = mock.MagicMock() - fileobj.read.side_effect = ['123123', ''] - self.file_mock.return_value = fileobj - self.getsize_mock.return_value = 123456 - self.ksession._callMethod.side_effect = [ - {'size': 6, 'hexdigest': '041c012d'}, # rawUpload - {'size': 3, 'hexdigest': '041c012d'}, # checkUpload - ] - with self.assertRaises(koji.GenericError): - self.ksession.fastUpload('file', 'target', blocksize=1024) - - def test_fastUpload_wrong_checksum(self): - # uploaded file is corrupted (checksum) (GenericError) - fileobj = mock.MagicMock() - fileobj.read.side_effect = ['123123', ''] - self.file_mock.return_value = fileobj - self.getsize_mock.return_value = 123456 - self.ksession._callMethod.side_effect = [ - {'size': 6, 'hexdigest': '041c012d'}, # rawUpload - {'size': 3, 'hexdigest': 'deadbeef'}, # checkUpload - ] - with self.assertRaises(koji.GenericError): - self.ksession.fastUpload('file', 'target', blocksize=1024) - - def test_fastUpload_nondefault_volume(self): - # upload regular file (success) - fileobj = mock.MagicMock() - fileobj.read.side_effect = ['123123', ''] - self.file_mock.return_value = fileobj - self.ksession._callMethod.side_effect = [ - {'size': 6, 'hexdigest': '041c012d'}, # rawUpload - {'size': 6, 'hexdigest': '041c012d'}, # checkUpload - ] - self.ksession.fastUpload('file', 'target', blocksize=1024, volume='foobar') - for call in self.ksession._callMethod.call_args_list: - # both calls should pass volume as a named arg to the method - # (note: not literally a named arg to _callMethod) - # _callMethod args are: method, method_args, method_kwargs - kwargs = call[0][2] - self.assertTrue('volume' in kwargs) - self.assertEqual(kwargs['volume'], 'foobar') diff --git a/tests/test_compatrequests.py b/tests/test_compatrequests.py deleted file mode 100644 index dfd9226..0000000 --- a/tests/test_compatrequests.py +++ /dev/null @@ -1,268 +0,0 @@ -from __future__ import absolute_import -import six.moves.http_client -import mock -import unittest -import six.moves.urllib - -import koji.compatrequests - - -class TestResponse(unittest.TestCase): - - def setUp(self): - session = mock.MagicMock() - response = mock.MagicMock() - self.response = koji.compatrequests.Response(session, response) - - def tearDown(self): - del self.response - - def test_read(self): - self.response.response.status = 200 - data = [ - "Here's some data", - "Here's some mooore data", - "And look!", - "Here's a nice block of lorem text", - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " - "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " - "enim ad minim veniam, quis nostrud exercitation ullamco laboris " - "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " - "in reprehenderit in voluptate velit esse cillum dolore eu fugiat " - "nulla pariatur. Excepteur sint occaecat cupidatat non proident, " - "sunt in culpa qui officia deserunt mollit anim id est laborum.", - "", #eof - ] - self.response.response.read.side_effect = data - - result = list(self.response.iter_content(blocksize=10240)) - - self.assertEqual(result, data[:-1]) - rcalls = [mock.call(10240) for s in data] - self.response.response.read.assert_has_calls(rcalls) - - self.response.close() - self.response.response.close.assert_called_once() - - def test_error(self): - self.response.response.status = 404 - self.response.response.getheader.return_value = 0 - with self.assertRaises(Exception): - list(self.response.iter_content(8192)) - self.response.response.read.assert_not_called() - - self.response.response.status = 404 - self.response.response.getheader.return_value = 42 - with self.assertRaises(Exception): - list(self.response.iter_content(8192)) - self.response.response.read.assert_called_once() - - self.response.response.status = 404 - self.response.response.reason = 'Not Found' - self.response.response.getheader.return_value = 42 - with self.assertRaises(six.moves.http_client.HTTPException): - self.response.raise_for_status() - - - -class TestSessionPost(unittest.TestCase): - - def test_simple(self): - session = koji.compatrequests.Session() - url = 'https://www.fakedomain.org/KOJIHUB' - cnx = mock.MagicMock() - session.get_connection = mock.MagicMock() - session.get_connection.return_value = cnx - response = mock.MagicMock() - cnx.getresponse.return_value = response - - ret = session.post(url, data="data", headers={"foo": "bar"}) - cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB') - cnx.putheader.assert_called_once_with('foo', 'bar') - cnx.send.assert_called_once_with("data") - self.assertEqual(ret.response, response) - - def test_less_simple(self): - session = koji.compatrequests.Session() - url = 'https://www.fakedomain.org/KOJIHUB?a=1&b=2' - cnx = mock.MagicMock() - session.get_connection = mock.MagicMock() - session.get_connection.return_value = cnx - response = mock.MagicMock() - cnx.getresponse.return_value = response - - ret = session.post(url, data="data", headers={"foo": "bar"}, - cert="cert", verify="verify", stream=True, timeout=1701) - cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB?a=1&b=2') - cnx.putheader.assert_called_once_with('foo', 'bar') - cnx.send.assert_called_once_with("data") - self.assertEqual(ret.response, response) - - -class TestSessionConnection(unittest.TestCase): - - @mock.patch('httplib.HTTPConnection') - def test_http(self, HTTPConnection): - # no cert, no verify, no timeout - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - - cnx = session.get_connection(uri, None, None, None) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) - key = ('http', 'www.fakedomain234234.org', None, None, None) - self.assertEqual(session.connection, (key, cnx)) - - # and close it - session.close() - self.assertEqual(session.connection, None) - cnx.close.assert_called_with() - - # double close should not error - session.close() - - def test_cached(self): - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - key = ('http', 'www.fakedomain234234.org', None, None, None) - cnx = mock.MagicMock() - session.connection = (key, cnx) - - ret = session.get_connection(uri, None, None, None) - self.assertEqual(ret, cnx) - - def test_badproto(self): - session = koji.compatrequests.Session() - url = 'nosuchproto://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - - with self.assertRaises(IOError): - session.get_connection(uri, None, None, None) - - @mock.patch('httplib.HTTPConnection') - @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) - def test_timeout(self, HTTPConnection): - # no cert, no verify - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - timeout = 1701 - - cnx = session.get_connection(uri, None, None, timeout) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=timeout) - key = ('http', 'www.fakedomain234234.org', None, None, timeout) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('httplib.HTTPConnection') - @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) - def test_timeout_compat(self, HTTPConnection): - # no cert, no verify - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - timeout = 1701 - - cnx = session.get_connection(uri, None, None, timeout) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) - key = ('http', 'www.fakedomain234234.org', None, None, timeout) - self.assertEqual(session.connection, (key, cnx)) - cnx.connect.assert_called_once() - cnx.sock.settimeout.assert_called_with(timeout) - - @mock.patch('httplib.HTTPSConnection') - def test_https(self, HTTPSConnection): - # no cert, no verify, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - - cnx = session.get_connection(uri, None, None, None) - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) - key = ('https', 'www.fakedomain234234.org', None, None, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('koji.ssl.SSLCommon.CreateSSLContext') - @mock.patch('koji.ssl.SSLCommon.PlgHTTPSConnection') - def test_cert(self, PlgHTTPSConnection, CreateSSLContext): - # no verify, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - cert = '/path/to/cert/file' - context = mock.MagicMock() - CreateSSLContext.return_value = context - - cnx = session.get_connection(uri, cert, None, None) - PlgHTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, ssl_context=context) - key = ('https', 'www.fakedomain234234.org', cert, None, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('ssl._create_unverified_context') - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) - def test_unverified(self, HTTPSConnection, create_unverified_context): - # no cert, verify=False, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - context = mock.MagicMock() - create_unverified_context.return_value = context - - cnx = session.get_connection(uri, None, False, None) - create_unverified_context.assert_called_once() - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) - key = ('https', 'www.fakedomain234234.org', None, False, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) - def test_unverified_compat(self, HTTPSConnection): - # no cert, verify=False, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - - cnx = session.get_connection(uri, None, False, None) - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) - key = ('https', 'www.fakedomain234234.org', None, False, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('ssl._create_unverified_context') - @mock.patch('ssl.SSLContext') - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) - def test_verify(self, HTTPSConnection, SSLContext, create_unverified_context): - # no cert, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - context = mock.MagicMock() - SSLContext.return_value = context - verify = '/path/to/verify/cert' - - cnx = session.get_connection(uri, None, verify, None) - create_unverified_context.assert_not_called() - SSLContext.assert_called_once() - context.load_verify_locations.called_once_with(cafile=verify) - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) - key = ('https', 'www.fakedomain234234.org', None, verify, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('ssl._create_unverified_context') - @mock.patch('ssl.SSLContext') - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) - def test_verify_compat(self, HTTPSConnection, SSLContext, create_unverified_context): - # no cert, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) - verify = '/path/to/verify/cert' - - cnx = session.get_connection(uri, None, verify, None) - create_unverified_context.assert_not_called() - SSLContext.assert_not_called() - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, cert_file=verify) - key = ('https', 'www.fakedomain234234.org', None, verify, None) - self.assertEqual(session.connection, (key, cnx)) diff --git a/tests/test_fixEncoding.py b/tests/test_fixEncoding.py deleted file mode 100644 index ee8e089..0000000 --- a/tests/test_fixEncoding.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/python -# coding=utf-8 - -"""Test the __init__.py module""" - -from __future__ import absolute_import -import koji -import unittest - -class FixEncodingTestCase(unittest.TestCase): - """Main test case container""" - - simple_values = [ - # [ value, fixed ] - ['', ''], - [u'', ''], - [u'góðan daginn', 'g\xc3\xb3\xc3\xb0an daginn'], - [u'hej', 'hej'], - [u'zdravstvuite', 'zdravstvuite'], - [u'céad míle fáilte', 'c\xc3\xa9ad m\xc3\xadle f\xc3\xa1ilte'], - [u'dobrý den', 'dobr\xc3\xbd den'], - [u'hylô', 'hyl\xc3\xb4'], - [u'jó napot', 'j\xc3\xb3 napot'], - [u'tervehdys', 'tervehdys'], - [u'olá', 'ol\xc3\xa1'], - [u'grüezi', 'gr\xc3\xbcezi'], - [u'dobre dan', 'dobre dan'], - [u'hello', 'hello'], - [u'bună ziua', 'bun\xc4\x83 ziua'], - [u'こんにちは', '\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf'], - [u'你好', '\xe4\xbd\xa0\xe5\xa5\xbd'], - [u'नमस्कार', '\xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\x95\xe0\xa4\xbe\xe0\xa4\xb0'], - [u'안녕하세요', '\xec\x95\x88\xeb\x85\x95\xed\x95\x98\xec\x84\xb8\xec\x9a\x94'], - ] - - def test_fixEncoding(self): - """Test the fixEncoding function""" - for a, b in self.simple_values: - self.assertEqual(koji.fixEncoding(a), b) - self.assertEqual(koji.fixEncoding(b), b) - c = a.encode('utf16') - self.assertEqual(koji.fixEncoding(c, fallback='utf16'), b) - d = a[:-3] + u'\x00\x01' + a[-3:] - self.assertEqual(koji.fixEncoding(d, remove_nonprintable=True), b) - - complex_values = [ - # [ value, fixed ] - [{}, {}], - [(), ()], - [None, None], - [[], []], - [{u'a': 'a' , 'b' : {'c': u'c\x00'}}, - { 'a': 'a' , 'b' : {'c': 'c\x00'}}], - # iso8859-15 fallback - ['g\xf3\xf0an daginn', 'g\xc3\xb3\xc3\xb0an daginn'], - ] - - nonprint = [ - ['hello\0world\0', 'helloworld'], - [u'hello\0world\0', 'helloworld'], - [[u'hello\0world\0'], ['helloworld']], - [{0: u'hello\0world\0'}, {0: 'helloworld'}], - [[{0: u'hello\0world\0'}], [{0: 'helloworld'}]], - ] - - def test_fixEncodingRecurse(self): - """Test the fixEncodingRecurse function""" - for a, b in self.simple_values: - self.assertEqual(koji.fixEncoding(a), b) - for a, b in self.complex_values: - self.assertEqual(koji.fixEncodingRecurse(a), b) - for a, b in self.nonprint: - self.assertEqual(koji.fixEncodingRecurse(a, remove_nonprintable=True), b) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_hub/test_getRPMDeps.py b/tests/test_hub/test_getRPMDeps.py index 6bfcfcc..f4931a4 100644 --- a/tests/test_hub/test_getRPMDeps.py +++ b/tests/test_hub/test_getRPMDeps.py @@ -12,7 +12,7 @@ class TestGetRPMDeps(unittest.TestCase): @mock.patch('kojihub.get_build') @mock.patch('koji.pathinfo') def test_getRPMDeps(self, pi, build, rpm): - pi.build.return_value = os.path.join(os.path.dirname(__file__), '../data/rpms') + pi.build.return_value = os.path.join(os.path.dirname(__file__), '../test_lib/data/rpms') pi.rpm.return_value = 'test-deps-1-1.fc24.x86_64.rpm' getRPMDeps = kojihub.RootExports().getRPMDeps res = getRPMDeps('') diff --git a/tests/test_krbv.py b/tests/test_krbv.py deleted file mode 100644 index f96b525..0000000 --- a/tests/test_krbv.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import absolute_import -import unittest - -# This is python-mock, not the rpm mock tool we know and love -import mock - -import koji - - -class KrbVTestCase(unittest.TestCase): - - @mock.patch('koji.krbV', new=None) - def test_krbv_disabled(self): - """ Test that when krbV is absent, we behave rationally. """ - self.assertEquals(koji.krbV, None) - session = koji.ClientSession('whatever') - with self.assertRaises(ImportError): - session.krb_login() diff --git a/tests/test_lib/data/maven/bad_empty_config.ini b/tests/test_lib/data/maven/bad_empty_config.ini new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/test_lib/data/maven/bad_empty_config.ini diff --git a/tests/test_lib/data/maven/bad_scmurl_config.ini b/tests/test_lib/data/maven/bad_scmurl_config.ini new file mode 100644 index 0000000..5e8bb9c --- /dev/null +++ b/tests/test_lib/data/maven/bad_scmurl_config.ini @@ -0,0 +1,16 @@ +[pkg] +type=maven +patches=patchurl +specfile=specfile +goals=goal1 goal2 +profiles=profile1 profile2 +packages=pkg1 pkg2 +jvm_options=--opt1 --opt2=val +maven_options=--opt1 --opt2=val +properties: p1=1 + p2 + p3=ppp3 +envs:e1=1 + e2=2 +buildrequires=r1 r2 +otheropts=others \ No newline at end of file diff --git a/tests/test_lib/data/maven/bad_type_config.ini b/tests/test_lib/data/maven/bad_type_config.ini new file mode 100644 index 0000000..a26f990 --- /dev/null +++ b/tests/test_lib/data/maven/bad_type_config.ini @@ -0,0 +1,17 @@ +[pkg] +type=other +scmurl=scmurl +patches=patchurl +specfile=specfile +goals=goal1 goal2 +profiles=profile1 profile2 +packages=pkg1 pkg2 +jvm_options=--opt1 --opt2=val +maven_options=--opt1 --opt2=val +properties: p1=1 + p2 + p3=ppp3 +envs:e1=1 + e2=2 +buildrequires=r1 r2 +otheropts=others \ No newline at end of file diff --git a/tests/test_lib/data/maven/bad_wrapper_config.ini b/tests/test_lib/data/maven/bad_wrapper_config.ini new file mode 100644 index 0000000..7bd8050 --- /dev/null +++ b/tests/test_lib/data/maven/bad_wrapper_config.ini @@ -0,0 +1,17 @@ +[pkg] +type=wrapper +scmurl=scmurl +patches=patchurl +specfile=specfile +goals=goal1 goal2 +profiles=profile1 profile2 +packages=pkg1 pkg2 +jvm_options=--opt1 --opt2=val +maven_options=--opt1 --opt2=val +properties: p1=1 + p2 + p3=ppp3 +envs:e1=1 + e2=2 +buildrequires=r1 r2 +otheropts=others \ No newline at end of file diff --git a/tests/test_lib/data/maven/config.ini b/tests/test_lib/data/maven/config.ini new file mode 100644 index 0000000..1bc3511 --- /dev/null +++ b/tests/test_lib/data/maven/config.ini @@ -0,0 +1,52 @@ +[pkg1] +scmurl=scmurl +patches=patchurl +specfile=specfile +goals=goal1 goal2 +profiles=profile1 profile2 +packages=pkg1 pkg2 +jvm_options=--opt1 --opt2=val +maven_options=--opt1 --opt2=val +properties: p1=1 + p2 + p3=ppp3 +envs:e1=1 + e2=2 +buildrequires=r1 r2 +otheropts=others + +[pkg2] +type=maven +scmurl=scmurl +patches=patchurl +specfile=specfile +goals=goal1 goal2 +profiles=profile1 profile2 +packages=pkg1 pkg2 +jvm_options=--opt1 --opt2=val +maven_options=--opt1 --opt2=val +properties: p1=1 + p2 + p3=ppp3 +envs:e1=1 + e2=2 +buildrequires=r1 r2 +otheropts=others + +[pkg3] +type=wrapper +scmurl=scmurl +patches=patchurl +specfile=specfile +goals=goal1 goal2 +profiles=profile1 profile2 +packages=pkg1 pkg2 +jvm_options=--opt1 --opt2=val +maven_options=--opt1 --opt2=val +properties: p1=1 + p2 + p3=ppp3 +envs:e1=1 + e2=2 +buildrequires=r1 +otheropts=others diff --git a/tests/test_lib/data/maven/good_config.ini b/tests/test_lib/data/maven/good_config.ini new file mode 100644 index 0000000..e45861c --- /dev/null +++ b/tests/test_lib/data/maven/good_config.ini @@ -0,0 +1,16 @@ +[pkg4] +scmurl=scmurl +patches=patchurl +specfile=specfile +goals=goal1 goal2 +profiles=profile1 profile2 +packages=pkg1 pkg2 +jvm_options=--opt1 --opt2=val +maven_options=--opt1 --opt2=val +properties: p1=1 + p2 + p3=ppp3 +envs:e1=1 + e2=2 +buildrequires=r1 r2 +otheropts=others \ No newline at end of file diff --git a/tests/test_lib/data/rpms/test-deps-1-1.fc24.x86_64.rpm b/tests/test_lib/data/rpms/test-deps-1-1.fc24.x86_64.rpm new file mode 100644 index 0000000..975b2ea Binary files /dev/null and b/tests/test_lib/data/rpms/test-deps-1-1.fc24.x86_64.rpm differ diff --git a/tests/test_lib/data/rpms/test-nopatch-1-1.fc24.nosrc.rpm b/tests/test_lib/data/rpms/test-nopatch-1-1.fc24.nosrc.rpm new file mode 100644 index 0000000..52105d4 Binary files /dev/null and b/tests/test_lib/data/rpms/test-nopatch-1-1.fc24.nosrc.rpm differ diff --git a/tests/test_lib/data/rpms/test-nosrc-1-1.fc24.nosrc.rpm b/tests/test_lib/data/rpms/test-nosrc-1-1.fc24.nosrc.rpm new file mode 100644 index 0000000..500eeb2 Binary files /dev/null and b/tests/test_lib/data/rpms/test-nosrc-1-1.fc24.nosrc.rpm differ diff --git a/tests/test_lib/data/rpms/test-src-1-1.fc24.src.rpm b/tests/test_lib/data/rpms/test-src-1-1.fc24.src.rpm new file mode 100644 index 0000000..98f4c0d Binary files /dev/null and b/tests/test_lib/data/rpms/test-src-1-1.fc24.src.rpm differ diff --git a/tests/test_lib/data/specs/test-deps._spec b/tests/test_lib/data/specs/test-deps._spec new file mode 100644 index 0000000..d31312d --- /dev/null +++ b/tests/test_lib/data/specs/test-deps._spec @@ -0,0 +1,28 @@ +Name: test-deps +Version: 1 +Release: 1%{?dist} +Summary: Testing dependency header fields + +License: none + +Requires: require1 +Requires: require2 +Provides: provide1 +Provides: provide2 +Obsoletes: obsoletes1 +Obsoletes: obsoletes2 +Conflicts: conflicts1 +Conflicts: conflicts2 +Suggests: suggests1 +Suggests: suggests2 +Enhances: enhances1 +Enhances: enhances2 +Supplements: supplements1 +Supplements: supplements2 +Recommends: recommends1 +Recommends: recommends2 + +%description +Testing dependency header fields + +%files diff --git a/tests/test_lib/data/specs/test-nopatch._spec b/tests/test_lib/data/specs/test-nopatch._spec new file mode 100644 index 0000000..33e19bd --- /dev/null +++ b/tests/test_lib/data/specs/test-nopatch._spec @@ -0,0 +1,13 @@ +Name: test-nopatch +Version: 1 +Release: 1%{?dist} +Summary: Testing source arch header fields + +License: none +Patch0: secret.patch +Nopatch: 0 + +%description +... + +%files diff --git a/tests/test_lib/data/specs/test-nosrc._spec b/tests/test_lib/data/specs/test-nosrc._spec new file mode 100644 index 0000000..9ce1885 --- /dev/null +++ b/tests/test_lib/data/specs/test-nosrc._spec @@ -0,0 +1,13 @@ +Name: test-nosrc +Version: 1 +Release: 1%{?dist} +Summary: Testing source arch header fields + +License: none +Source0: secret.key +Nosource: 0 + +%description +... + +%files diff --git a/tests/test_lib/data/specs/test-src._spec b/tests/test_lib/data/specs/test-src._spec new file mode 100644 index 0000000..3c5859a --- /dev/null +++ b/tests/test_lib/data/specs/test-src._spec @@ -0,0 +1,11 @@ +Name: test-src +Version: 1 +Release: 1%{?dist} +Summary: Testing source arch header fields + +License: none + +%description +... + +%files diff --git a/tests/test_lib/test_client_session.py b/tests/test_lib/test_client_session.py new file mode 100644 index 0000000..5edab10 --- /dev/null +++ b/tests/test_lib/test_client_session.py @@ -0,0 +1,182 @@ +from __future__ import absolute_import +import mock +import unittest +import six + +import koji + + +class TestClientSession(unittest.TestCase): + + @mock.patch('socket.getfqdn') + def test_server_principal_rdns(self, getfqdn): + opts = {'krb_rdns': True} + session = koji.ClientSession('http://koji.example.com:30/kojihub', opts) + cprinc = mock.MagicMock() + cprinc.realm = "REALM" + getfqdn.return_value = 'koji02.example.com' + + princ = session._serverPrincipal(cprinc) + self.assertEqual(princ, 'host/koji02.example.com@REALM') + getfqdn.assert_called_with('koji.example.com') + + @mock.patch('socket.getfqdn') + def test_server_principal_no_rdns(self, getfqdn): + opts = {'krb_rdns': False} + session = koji.ClientSession('http://koji.example.com/kojihub', opts) + cprinc = mock.MagicMock() + cprinc.realm = "REALM" + getfqdn.return_value = 'koji02.example.com' + + princ = session._serverPrincipal(cprinc) + self.assertEqual(princ, 'host/koji.example.com@REALM') + getfqdn.assert_not_called() + + @mock.patch('requests.Session') + def test_new_session(self, rsession): + opts = {'use_old_ssl': False} + ksession = koji.ClientSession('http://koji.example.com/kojihub', opts) + + # init should have called new_session for us + + rsession.assert_called_once() + + @mock.patch('requests.Session') + def test_new_session_old(self, rsession): + if six.PY3: + return + opts = {'use_old_ssl': True} + ksession = koji.ClientSession('http://koji.example.com/kojihub', opts) + + # init should have called new_session for us + + rsession.assert_not_called() + + @mock.patch('requests.Session') + def test_new_session_close(self, rsession): + if six.PY3: + return + opts = {'use_old_ssl': True} + ksession = koji.ClientSession('http://koji.example.com/kojihub', opts) + my_rsession = mock.MagicMock() + ksession.rsession = my_rsession + + ksession.new_session() + my_rsession.close.assert_called() + self.assertNotEqual(ksession.rsession, my_rsession) + + +class TestFastUpload(unittest.TestCase): + + def setUp(self): + self.ksession = koji.ClientSession('http://koji.example.com/kojihub', {}) + self.do_fake_login() + # mocks + self.ksession._callMethod = mock.MagicMock() + self.ksession.retries = 1 + self.rsession = mock.patch('requests.Session').start() + if six.PY2: + self.file_mock = mock.patch('__builtin__.open').start() + else: + self.file_mock = mock.patch('builtins.open').start() + self.getsize_mock = mock.patch('os.path.getsize').start() + + def tearDown(self): + del self.ksession + mock.patch.stopall() + + def do_fake_login(self): + self.ksession.logged_in = True + self.ksession.sinfo = {} + self.ksession.callnum = 1 + + def test_fastUpload_nologin(self): + # without login (ActionNotAllowed) + self.ksession.logged_in = False + with self.assertRaises(koji.ActionNotAllowed): + self.ksession.fastUpload('nonexistent_file', 'target') + + def test_fastUpload_nofile(self): + + # fail with nonexistent file (IOError) + self.file_mock.side_effect = IOError('mocked exception') + with self.assertRaises(IOError): + self.ksession.fastUpload('file', 'target') + + def test_fastUpload_empty_file(self): + # upload empty file (success) + fileobj = mock.MagicMock() + fileobj.read.return_value = '' + self.file_mock.return_value = fileobj + self.ksession._callMethod.return_value = { + 'size': 0, + 'hexdigest': koji.util.adler32_constructor().hexdigest() + } + self.ksession.fastUpload('file', 'target') + + def test_fastUpload_regular_file(self): + # upload regular file (success) + fileobj = mock.MagicMock() + fileobj.read.side_effect = ['123123', ''] + self.file_mock.return_value = fileobj + self.ksession._callMethod.side_effect = [ + {'size': 6, 'hexdigest': '041c012d'}, # rawUpload + {'size': 6, 'hexdigest': '041c012d'}, # checkUpload + ] + self.ksession.fastUpload('file', 'target', blocksize=1024) + + def test_fastUpload_size_change(self): + # change file size during upload (success) + fileobj = mock.MagicMock() + fileobj.read.side_effect = ['123123', ''] + self.file_mock.return_value = fileobj + self.getsize_mock.return_value = 123456 + self.ksession._callMethod.side_effect = [ + {'size': 6, 'hexdigest': '041c012d'}, # rawUpload + {'size': 6, 'hexdigest': '041c012d'}, # checkUpload + ] + self.ksession.fastUpload('file', 'target', blocksize=1024) + + def test_fastUpload_wrong_length(self): + # uploaded file is corrupted (length) (GenericError) + fileobj = mock.MagicMock() + fileobj.read.side_effect = ['123123', ''] + self.file_mock.return_value = fileobj + self.getsize_mock.return_value = 123456 + self.ksession._callMethod.side_effect = [ + {'size': 6, 'hexdigest': '041c012d'}, # rawUpload + {'size': 3, 'hexdigest': '041c012d'}, # checkUpload + ] + with self.assertRaises(koji.GenericError): + self.ksession.fastUpload('file', 'target', blocksize=1024) + + def test_fastUpload_wrong_checksum(self): + # uploaded file is corrupted (checksum) (GenericError) + fileobj = mock.MagicMock() + fileobj.read.side_effect = ['123123', ''] + self.file_mock.return_value = fileobj + self.getsize_mock.return_value = 123456 + self.ksession._callMethod.side_effect = [ + {'size': 6, 'hexdigest': '041c012d'}, # rawUpload + {'size': 3, 'hexdigest': 'deadbeef'}, # checkUpload + ] + with self.assertRaises(koji.GenericError): + self.ksession.fastUpload('file', 'target', blocksize=1024) + + def test_fastUpload_nondefault_volume(self): + # upload regular file (success) + fileobj = mock.MagicMock() + fileobj.read.side_effect = ['123123', ''] + self.file_mock.return_value = fileobj + self.ksession._callMethod.side_effect = [ + {'size': 6, 'hexdigest': '041c012d'}, # rawUpload + {'size': 6, 'hexdigest': '041c012d'}, # checkUpload + ] + self.ksession.fastUpload('file', 'target', blocksize=1024, volume='foobar') + for call in self.ksession._callMethod.call_args_list: + # both calls should pass volume as a named arg to the method + # (note: not literally a named arg to _callMethod) + # _callMethod args are: method, method_args, method_kwargs + kwargs = call[0][2] + self.assertTrue('volume' in kwargs) + self.assertEqual(kwargs['volume'], 'foobar') diff --git a/tests/test_lib/test_compatrequests.py b/tests/test_lib/test_compatrequests.py new file mode 100644 index 0000000..dfd9226 --- /dev/null +++ b/tests/test_lib/test_compatrequests.py @@ -0,0 +1,268 @@ +from __future__ import absolute_import +import six.moves.http_client +import mock +import unittest +import six.moves.urllib + +import koji.compatrequests + + +class TestResponse(unittest.TestCase): + + def setUp(self): + session = mock.MagicMock() + response = mock.MagicMock() + self.response = koji.compatrequests.Response(session, response) + + def tearDown(self): + del self.response + + def test_read(self): + self.response.response.status = 200 + data = [ + "Here's some data", + "Here's some mooore data", + "And look!", + "Here's a nice block of lorem text", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " + "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " + "enim ad minim veniam, quis nostrud exercitation ullamco laboris " + "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " + "in reprehenderit in voluptate velit esse cillum dolore eu fugiat " + "nulla pariatur. Excepteur sint occaecat cupidatat non proident, " + "sunt in culpa qui officia deserunt mollit anim id est laborum.", + "", #eof + ] + self.response.response.read.side_effect = data + + result = list(self.response.iter_content(blocksize=10240)) + + self.assertEqual(result, data[:-1]) + rcalls = [mock.call(10240) for s in data] + self.response.response.read.assert_has_calls(rcalls) + + self.response.close() + self.response.response.close.assert_called_once() + + def test_error(self): + self.response.response.status = 404 + self.response.response.getheader.return_value = 0 + with self.assertRaises(Exception): + list(self.response.iter_content(8192)) + self.response.response.read.assert_not_called() + + self.response.response.status = 404 + self.response.response.getheader.return_value = 42 + with self.assertRaises(Exception): + list(self.response.iter_content(8192)) + self.response.response.read.assert_called_once() + + self.response.response.status = 404 + self.response.response.reason = 'Not Found' + self.response.response.getheader.return_value = 42 + with self.assertRaises(six.moves.http_client.HTTPException): + self.response.raise_for_status() + + + +class TestSessionPost(unittest.TestCase): + + def test_simple(self): + session = koji.compatrequests.Session() + url = 'https://www.fakedomain.org/KOJIHUB' + cnx = mock.MagicMock() + session.get_connection = mock.MagicMock() + session.get_connection.return_value = cnx + response = mock.MagicMock() + cnx.getresponse.return_value = response + + ret = session.post(url, data="data", headers={"foo": "bar"}) + cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB') + cnx.putheader.assert_called_once_with('foo', 'bar') + cnx.send.assert_called_once_with("data") + self.assertEqual(ret.response, response) + + def test_less_simple(self): + session = koji.compatrequests.Session() + url = 'https://www.fakedomain.org/KOJIHUB?a=1&b=2' + cnx = mock.MagicMock() + session.get_connection = mock.MagicMock() + session.get_connection.return_value = cnx + response = mock.MagicMock() + cnx.getresponse.return_value = response + + ret = session.post(url, data="data", headers={"foo": "bar"}, + cert="cert", verify="verify", stream=True, timeout=1701) + cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB?a=1&b=2') + cnx.putheader.assert_called_once_with('foo', 'bar') + cnx.send.assert_called_once_with("data") + self.assertEqual(ret.response, response) + + +class TestSessionConnection(unittest.TestCase): + + @mock.patch('httplib.HTTPConnection') + def test_http(self, HTTPConnection): + # no cert, no verify, no timeout + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + + cnx = session.get_connection(uri, None, None, None) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) + key = ('http', 'www.fakedomain234234.org', None, None, None) + self.assertEqual(session.connection, (key, cnx)) + + # and close it + session.close() + self.assertEqual(session.connection, None) + cnx.close.assert_called_with() + + # double close should not error + session.close() + + def test_cached(self): + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + key = ('http', 'www.fakedomain234234.org', None, None, None) + cnx = mock.MagicMock() + session.connection = (key, cnx) + + ret = session.get_connection(uri, None, None, None) + self.assertEqual(ret, cnx) + + def test_badproto(self): + session = koji.compatrequests.Session() + url = 'nosuchproto://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + + with self.assertRaises(IOError): + session.get_connection(uri, None, None, None) + + @mock.patch('httplib.HTTPConnection') + @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) + def test_timeout(self, HTTPConnection): + # no cert, no verify + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + timeout = 1701 + + cnx = session.get_connection(uri, None, None, timeout) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=timeout) + key = ('http', 'www.fakedomain234234.org', None, None, timeout) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('httplib.HTTPConnection') + @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) + def test_timeout_compat(self, HTTPConnection): + # no cert, no verify + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + timeout = 1701 + + cnx = session.get_connection(uri, None, None, timeout) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) + key = ('http', 'www.fakedomain234234.org', None, None, timeout) + self.assertEqual(session.connection, (key, cnx)) + cnx.connect.assert_called_once() + cnx.sock.settimeout.assert_called_with(timeout) + + @mock.patch('httplib.HTTPSConnection') + def test_https(self, HTTPSConnection): + # no cert, no verify, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + + cnx = session.get_connection(uri, None, None, None) + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) + key = ('https', 'www.fakedomain234234.org', None, None, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('koji.ssl.SSLCommon.CreateSSLContext') + @mock.patch('koji.ssl.SSLCommon.PlgHTTPSConnection') + def test_cert(self, PlgHTTPSConnection, CreateSSLContext): + # no verify, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + cert = '/path/to/cert/file' + context = mock.MagicMock() + CreateSSLContext.return_value = context + + cnx = session.get_connection(uri, cert, None, None) + PlgHTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, ssl_context=context) + key = ('https', 'www.fakedomain234234.org', cert, None, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('ssl._create_unverified_context') + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) + def test_unverified(self, HTTPSConnection, create_unverified_context): + # no cert, verify=False, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + context = mock.MagicMock() + create_unverified_context.return_value = context + + cnx = session.get_connection(uri, None, False, None) + create_unverified_context.assert_called_once() + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) + key = ('https', 'www.fakedomain234234.org', None, False, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) + def test_unverified_compat(self, HTTPSConnection): + # no cert, verify=False, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + + cnx = session.get_connection(uri, None, False, None) + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) + key = ('https', 'www.fakedomain234234.org', None, False, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('ssl._create_unverified_context') + @mock.patch('ssl.SSLContext') + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) + def test_verify(self, HTTPSConnection, SSLContext, create_unverified_context): + # no cert, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + context = mock.MagicMock() + SSLContext.return_value = context + verify = '/path/to/verify/cert' + + cnx = session.get_connection(uri, None, verify, None) + create_unverified_context.assert_not_called() + SSLContext.assert_called_once() + context.load_verify_locations.called_once_with(cafile=verify) + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) + key = ('https', 'www.fakedomain234234.org', None, verify, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('ssl._create_unverified_context') + @mock.patch('ssl.SSLContext') + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) + def test_verify_compat(self, HTTPSConnection, SSLContext, create_unverified_context): + # no cert, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = six.moves.urllib.parse.urlsplit(url) + verify = '/path/to/verify/cert' + + cnx = session.get_connection(uri, None, verify, None) + create_unverified_context.assert_not_called() + SSLContext.assert_not_called() + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, cert_file=verify) + key = ('https', 'www.fakedomain234234.org', None, verify, None) + self.assertEqual(session.connection, (key, cnx)) diff --git a/tests/test_lib/test_fixEncoding.py b/tests/test_lib/test_fixEncoding.py new file mode 100644 index 0000000..ee8e089 --- /dev/null +++ b/tests/test_lib/test_fixEncoding.py @@ -0,0 +1,77 @@ +#!/usr/bin/python +# coding=utf-8 + +"""Test the __init__.py module""" + +from __future__ import absolute_import +import koji +import unittest + +class FixEncodingTestCase(unittest.TestCase): + """Main test case container""" + + simple_values = [ + # [ value, fixed ] + ['', ''], + [u'', ''], + [u'góðan daginn', 'g\xc3\xb3\xc3\xb0an daginn'], + [u'hej', 'hej'], + [u'zdravstvuite', 'zdravstvuite'], + [u'céad míle fáilte', 'c\xc3\xa9ad m\xc3\xadle f\xc3\xa1ilte'], + [u'dobrý den', 'dobr\xc3\xbd den'], + [u'hylô', 'hyl\xc3\xb4'], + [u'jó napot', 'j\xc3\xb3 napot'], + [u'tervehdys', 'tervehdys'], + [u'olá', 'ol\xc3\xa1'], + [u'grüezi', 'gr\xc3\xbcezi'], + [u'dobre dan', 'dobre dan'], + [u'hello', 'hello'], + [u'bună ziua', 'bun\xc4\x83 ziua'], + [u'こんにちは', '\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf'], + [u'你好', '\xe4\xbd\xa0\xe5\xa5\xbd'], + [u'नमस्कार', '\xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\x95\xe0\xa4\xbe\xe0\xa4\xb0'], + [u'안녕하세요', '\xec\x95\x88\xeb\x85\x95\xed\x95\x98\xec\x84\xb8\xec\x9a\x94'], + ] + + def test_fixEncoding(self): + """Test the fixEncoding function""" + for a, b in self.simple_values: + self.assertEqual(koji.fixEncoding(a), b) + self.assertEqual(koji.fixEncoding(b), b) + c = a.encode('utf16') + self.assertEqual(koji.fixEncoding(c, fallback='utf16'), b) + d = a[:-3] + u'\x00\x01' + a[-3:] + self.assertEqual(koji.fixEncoding(d, remove_nonprintable=True), b) + + complex_values = [ + # [ value, fixed ] + [{}, {}], + [(), ()], + [None, None], + [[], []], + [{u'a': 'a' , 'b' : {'c': u'c\x00'}}, + { 'a': 'a' , 'b' : {'c': 'c\x00'}}], + # iso8859-15 fallback + ['g\xf3\xf0an daginn', 'g\xc3\xb3\xc3\xb0an daginn'], + ] + + nonprint = [ + ['hello\0world\0', 'helloworld'], + [u'hello\0world\0', 'helloworld'], + [[u'hello\0world\0'], ['helloworld']], + [{0: u'hello\0world\0'}, {0: 'helloworld'}], + [[{0: u'hello\0world\0'}], [{0: 'helloworld'}]], + ] + + def test_fixEncodingRecurse(self): + """Test the fixEncodingRecurse function""" + for a, b in self.simple_values: + self.assertEqual(koji.fixEncoding(a), b) + for a, b in self.complex_values: + self.assertEqual(koji.fixEncodingRecurse(a), b) + for a, b in self.nonprint: + self.assertEqual(koji.fixEncodingRecurse(a, remove_nonprintable=True), b) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_lib/test_krbv.py b/tests/test_lib/test_krbv.py new file mode 100644 index 0000000..f96b525 --- /dev/null +++ b/tests/test_lib/test_krbv.py @@ -0,0 +1,18 @@ +from __future__ import absolute_import +import unittest + +# This is python-mock, not the rpm mock tool we know and love +import mock + +import koji + + +class KrbVTestCase(unittest.TestCase): + + @mock.patch('koji.krbV', new=None) + def test_krbv_disabled(self): + """ Test that when krbV is absent, we behave rationally. """ + self.assertEquals(koji.krbV, None) + session = koji.ClientSession('whatever') + with self.assertRaises(ImportError): + session.krb_login() diff --git a/tests/test_lib/test_parsers.py b/tests/test_lib/test_parsers.py new file mode 100644 index 0000000..02ff1c2 --- /dev/null +++ b/tests/test_lib/test_parsers.py @@ -0,0 +1,191 @@ +#!/usr/bin/python + +"""Test the __init__.py module""" + +from __future__ import absolute_import +import mock +import os +import rpm +import unittest + +import koji + +class INITTestCase(unittest.TestCase): + """Main test case container""" + + def test_parse_NVR(self): + """Test the parse_NVR method""" + + self.assertRaises(AttributeError, koji.parse_NVR, None) + self.assertRaises(AttributeError, koji.parse_NVR, 1) + self.assertRaises(AttributeError, koji.parse_NVR, {}) + self.assertRaises(AttributeError, koji.parse_NVR, []) + self.assertRaises(koji.GenericError, koji.parse_NVR, "") + self.assertRaises(koji.GenericError, koji.parse_NVR, "foo") + self.assertRaises(koji.GenericError, koji.parse_NVR, "foo-1") + self.assertRaises(koji.GenericError, koji.parse_NVR, "foo-1-") + self.assertRaises(koji.GenericError, koji.parse_NVR, "foo--1") + self.assertRaises(koji.GenericError, koji.parse_NVR, "--1") + ret = koji.parse_NVR("foo-1-2") + self.assertEqual(ret['name'], "foo") + self.assertEqual(ret['version'], "1") + self.assertEqual(ret['release'], "2") + self.assertEqual(ret['epoch'], "") + ret = koji.parse_NVR("12:foo-1-2") + self.assertEqual(ret['name'], "foo") + self.assertEqual(ret['version'], "1") + self.assertEqual(ret['release'], "2") + self.assertEqual(ret['epoch'], "12") + + def test_parse_NVRA(self): + """Test the parse_NVRA method""" + + self.assertRaises(AttributeError, koji.parse_NVRA, None) + self.assertRaises(AttributeError, koji.parse_NVRA, 1) + self.assertRaises(AttributeError, koji.parse_NVRA, {}) + self.assertRaises(AttributeError, koji.parse_NVRA, []) + self.assertRaises(koji.GenericError, koji.parse_NVRA, "") + self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo") + self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1") + self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1-") + self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo--1") + self.assertRaises(koji.GenericError, koji.parse_NVRA, "--1") + self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1-1") + self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1-1.") + self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1.-1") + ret = koji.parse_NVRA("foo-1-2.i386") + self.assertEqual(ret['name'], "foo") + self.assertEqual(ret['version'], "1") + self.assertEqual(ret['release'], "2") + self.assertEqual(ret['epoch'], "") + self.assertEqual(ret['arch'], "i386") + self.assertEqual(ret['src'], False) + ret = koji.parse_NVRA("12:foo-1-2.src") + self.assertEqual(ret['name'], "foo") + self.assertEqual(ret['version'], "1") + self.assertEqual(ret['release'], "2") + self.assertEqual(ret['epoch'], "12") + self.assertEqual(ret['arch'], "src") + self.assertEqual(ret['src'], True) + + def test_check_NVR(self): + """Test the check_NVR function""" + good = [ + "name-version-release", + "fnord-5.23-17", + {'name': 'foo', 'version': '2.2.2', 'release': '1.1'}, + ] + bad = [ + "this is not an NVR", + {'name': 'foo', 'version': '2.2.2-a', 'release': '1.1'}, + {'name': 'foo', 'version': '2.2.2', 'release': '1.1-b'}, + ] + for value in good: + self.assertEqual(koji.check_NVR(value), True) + for value in bad: + self.assertEqual(koji.check_NVR(value), False) + self.assertRaises(koji.GenericError, + koji.check_NVR, value, strict=True) + + def test_check_NVRA(self): + """Test the check_NVRA function""" + good = [ + "name-version-release.arch", + "fnord-5.23-17.x86_64", + {'name': 'foo', 'version': '2.2.2', 'release': '1.1', + 'arch': 'i686'}, + ] + bad = [ + "this is not an NVRA", + "fnord-5.23-17", + {'name': 'foo', 'version': '2.2.2-a', 'release': '1.1', + 'arch': 'ppc64'}, + {'name': 'foo', 'version': '2.2.2', 'release': '1.1-b', + 'arch': 'x86_64'}, + {'name': 'foo', 'version': '2.2.2', 'release': '1.1', + 'arch': 'x.86.64'}, + ] + for value in good: + self.assertEqual(koji.check_NVRA(value), True) + for value in bad: + self.assertEqual(koji.check_NVRA(value), False) + self.assertRaises(koji.GenericError, + koji.check_NVRA, value, strict=True) + + +class HeaderTestCase(unittest.TestCase): + rpm_path = os.path.join(os.path.dirname(__file__), 'data/rpms/test-deps-1-1.fc24.x86_64.rpm') + rpmdir = os.path.join(os.path.dirname(__file__), 'data/rpms') + + def setUp(self): + self.fd = open(self.rpm_path) + + def tearDown(self): + self.fd.close() + + def test_get_rpm_header(self): + self.assertRaises(IOError, koji.get_rpm_header, 'nonexistent_path') + self.assertRaises(AttributeError, koji.get_rpm_header, None) + self.assertIsInstance(koji.get_rpm_header(self.rpm_path), rpm.hdr) + self.assertIsInstance(koji.get_rpm_header(self.fd), rpm.hdr) + # TODO: + # test ts + + def test_get_header_fields(self): + # incorrect + self.assertRaises(IOError, koji.get_header_fields, 'nonexistent_path', []) + self.assertRaises(koji.GenericError, koji.get_header_fields, self.rpm_path, 'nonexistent_header') + self.assertEqual(koji.get_header_fields(self.rpm_path, []), {}) + + # correct + self.assertEqual(['REQUIRES'], list(koji.get_header_fields(self.rpm_path, ['REQUIRES']).keys())) + self.assertEqual(['PROVIDES', 'REQUIRES'], sorted(koji.get_header_fields(self.rpm_path, ['REQUIRES', 'PROVIDES']))) + hdr = koji.get_rpm_header(self.rpm_path) + self.assertEqual(['REQUIRES'], list(koji.get_header_fields(hdr, ['REQUIRES']).keys())) + + + def test_get_header_field_src(self): + srpm = os.path.join(self.rpmdir, 'test-src-1-1.fc24.src.rpm') + + # without src_arch, should return the build arch (x86_64) + data = koji.get_header_fields(srpm, ['arch']) + self.assertEqual(data['arch'], 'x86_64') + + # with src_arch, should return src + data = koji.get_header_fields(srpm, ['arch'], src_arch=True) + self.assertEqual(data['arch'], 'src') + + + def test_get_header_field_nosrc(self): + srpm1 = os.path.join(self.rpmdir, 'test-nosrc-1-1.fc24.nosrc.rpm') + srpm2 = os.path.join(self.rpmdir, 'test-nopatch-1-1.fc24.nosrc.rpm') + + # without src_arch, should return the build arch (x86_64) + for srpm in srpm1, srpm2: + data = koji.get_header_fields(srpm, ['arch']) + self.assertEqual(data['arch'], 'x86_64') + + # with src_arch, should return nosrc + for srpm in srpm1, srpm2: + data = koji.get_header_fields(srpm, ['arch'], src_arch=True) + self.assertEqual(data['arch'], 'nosrc') + + + @mock.patch('rpm.RPMTAG_NOSOURCE', new=None) + @mock.patch('rpm.RPMTAG_NOPATCH', new=None) + @mock.patch('koji.RPM_SUPPORTS_OPTIONAL_DEPS', new=False) + def test_get_header_field_workarounds(self): + srpm0 = os.path.join(self.rpmdir, 'test-src-1-1.fc24.src.rpm') + srpm1 = os.path.join(self.rpmdir, 'test-nosrc-1-1.fc24.nosrc.rpm') + srpm2 = os.path.join(self.rpmdir, 'test-nopatch-1-1.fc24.nosrc.rpm') + + # should still work even with rpm constants set to None + self.assertEqual([0], koji.get_header_fields(srpm1, ['nosource'])['nosource']) + self.assertEqual([0], koji.get_header_fields(srpm2, ['nopatch'])['nopatch']) + + # should return [] with optional dep support off + self.assertEqual([], koji.get_header_fields(srpm0, ['suggestname'])['suggestname']) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_lib/test_policy.py b/tests/test_lib/test_policy.py new file mode 100644 index 0000000..d228df7 --- /dev/null +++ b/tests/test_lib/test_policy.py @@ -0,0 +1,299 @@ +from __future__ import absolute_import +import unittest + +from nose.tools import raises + +import koji.policy + + +class MyBoolTest(koji.policy.BoolTest): + name = 'bool_check' + field = 'bool_field' + + +class MyMatchTest(koji.policy.MatchTest): + name = 'match_check' + field = 'match_field' + + +class myvarTest(koji.policy.CompareTest): + name = None + field = 'myvar' + allow_float = False + + +class TestBasicTests(unittest.TestCase): + + @raises(NotImplementedError) + def test_base_test(self): + obj = koji.policy.BaseSimpleTest('something') + obj.run({}) + + def test_true_test(self): + obj = koji.policy.TrueTest('something') + self.assertTrue(obj.run({})) + + def test_false_test(self): + obj = koji.policy.FalseTest('something') + self.assertFalse(obj.run({})) + + def test_all_test(self): + obj = koji.policy.AllTest('something') + self.assertTrue(obj.run({})) + + def test_none_test(self): + obj = koji.policy.NoneTest('something') + self.assertFalse(obj.run({})) + + def test_has_test(self): + obj = koji.policy.HasTest('some thing') + self.assertFalse(obj.run({})) + self.assertFalse(obj.run({'blah': 'blah'})) + self.assertTrue(obj.run({'thing': 'blah'})) + self.assertRaises(koji.GenericError, koji.policy.HasTest, 'something') + + def test_bool_test(self): + obj = koji.policy.BoolTest('some thing') + self.assertFalse(obj.run({'thing': None})) + self.assertFalse(obj.run({'thing': []})) + self.assertTrue(obj.run({'thing': 'yes'})) + + def test_match_test(self): + obj = koji.policy.MatchTest('some thing else') + self.assertFalse(obj.run({'thing': 'elseplus'})) + obj = koji.policy.MatchTest('some thing else*') + self.assertTrue(obj.run({'thing': 'elseplus'})) + + def test_compare_test(self): + obj = koji.policy.CompareTest('compare thing > 2') + self.assertFalse(obj.run({'thing': 1})) + self.assertFalse(obj.run({'thing': 2})) + self.assertTrue(obj.run({'thing': 3})) + + obj = koji.policy.CompareTest('compare thing < 1.5') + self.assertFalse(obj.run({'thing': 3.2})) + self.assertTrue(obj.run({'thing': 1.0})) + + obj = koji.policy.CompareTest('compare thing = 42') + self.assertFalse(obj.run({'thing': 54})) + self.assertTrue(obj.run({'thing': 42})) + + obj = koji.policy.CompareTest('compare thing != 99') + self.assertFalse(obj.run({'thing': 99})) + self.assertTrue(obj.run({'thing': 100})) + + obj = koji.policy.CompareTest('compare thing >= 2') + self.assertFalse(obj.run({'thing': 1})) + self.assertTrue(obj.run({'thing': 2})) + self.assertTrue(obj.run({'thing': 3})) + + obj = koji.policy.CompareTest('compare thing <= 5') + self.assertFalse(obj.run({'thing': 23})) + self.assertTrue(obj.run({'thing': 5})) + self.assertTrue(obj.run({'thing': 0})) + + @raises(koji.GenericError) + def test_invalid_compare_test(self): + koji.policy.CompareTest('some thing LOL 2') + + +class TestDiscovery(unittest.TestCase): + + def test_find_simple_tests(self): + actual = koji.policy.findSimpleTests(koji.policy.__dict__) + expected = { + 'all': koji.policy.AllTest, + 'bool': koji.policy.BoolTest, + 'compare': koji.policy.CompareTest, + 'false': koji.policy.FalseTest, + 'has': koji.policy.HasTest, + 'match': koji.policy.MatchTest, + 'none': koji.policy.NoneTest, + 'true': koji.policy.TrueTest, + } + self.assertDictEqual(expected, actual) + + +class TestRuleHandling(unittest.TestCase): + + def test_simple_rule_set_instantiation(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + rules = ['true :: allow'] + koji.policy.SimpleRuleSet(rules, tests) + + def test_simple_rule_set_all_actions(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + rules = ['true :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + result = obj.all_actions() + self.assertEquals(result, ['allow']) + + def test_simple_rule_set_apply(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + rules = ['true :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, 'allow') + + rules = ['false :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, None) + + def test_custom_rules(self): + tests = koji.policy.findSimpleTests([globals(), koji.policy.__dict__]) + + rules = ['bool_check :: True', 'all :: False'] + for val in True, False: + data = {'bool_field' : val} + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, str(val)) + + rules = ['match_check foo* :: foo', 'match_check * :: bar'] + data = {'match_field' : 'foo1234'} + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, 'foo') + + data = {'match_field' : 'not foo'} + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, 'bar') + + data = {'myvar': 37} + rules = ['myvar = 37 :: get back here'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, 'get back here') + + rules = ['myvar = 2.718281828 :: euler'] + with self.assertRaises(ValueError): + obj = koji.policy.SimpleRuleSet(rules, tests) + + def test_last_rule(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + # no match + rules = ['none :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + self.assertEquals(obj.last_rule(), None) + action = obj.apply(data) + self.assertEquals(obj.last_rule(), '(no match)') + + # simple rule + rules = ['all :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEquals(obj.last_rule(), rules[0]) + + # negate rule + rules = ['none !! allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEquals(obj.last_rule(), rules[0]) + + # nested rule + policy = ''' +all :: { + all :: { + all :: allow + } +} +''' + rules = policy.splitlines() + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + expected = 'all :: ... all :: ... all :: allow' + self.assertEquals(obj.last_rule(), expected) + + def test_unclosed_brace(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + lines = ['true :: {'] + with self.assertRaises(koji.GenericError): + obj = koji.policy.SimpleRuleSet(lines, tests) + + def test_unmatched_brace(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + lines = ['true :: }'] + with self.assertRaises(koji.GenericError): + obj = koji.policy.SimpleRuleSet(lines, tests) + + def test_no_action(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + lines = ['true && true'] + with self.assertRaises(Exception): + obj = koji.policy.SimpleRuleSet(lines, tests) + + def test_missing_handler(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + lines = ['NOSUCHHANDLER && true :: allow'] + with self.assertRaises(koji.GenericError): + obj = koji.policy.SimpleRuleSet(lines, tests) + + def test_complex_policy(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + policy = ''' +# This is a comment in the test policy + +#^blank line +# commented test && true :: some result + +# First some rules that should never match +false :: ERROR +none :: ERROR + +true !! ERROR +all !! ERROR + +false && true && true :: ERROR +none && true && true :: ERROR + +has NOSUCHFIELD :: ERROR + +# nesting +has DEPTH :: { + match DEPTH 1 :: 1 + all :: { + match DEPTH 2 :: 2 + all :: { + match DEPTH 3 :: 3 + all :: { + match DEPTH 4 :: 4 + all :: END + } + } + } +} +''' + + lines = policy.splitlines() + + for depth in ['1', '2', '3', '4']: + data = {'DEPTH': depth} + obj = koji.policy.SimpleRuleSet(lines, tests) + action = obj.apply(data) + self.assertEqual(action, depth) + + data = {'DEPTH': '99'} + obj = koji.policy.SimpleRuleSet(lines, tests) + action = obj.apply(data) + self.assertEqual(action, 'END') + + actions = set(obj.all_actions()) + self.assertEquals(actions, set(['1', '2', '3', '4', 'ERROR', 'END'])) + + diff --git a/tests/test_lib/test_profiles.py b/tests/test_lib/test_profiles.py new file mode 100644 index 0000000..3903db1 --- /dev/null +++ b/tests/test_lib/test_profiles.py @@ -0,0 +1,43 @@ +from __future__ import absolute_import +import unittest + +import koji +import sys +import threading +import traceback +from six.moves import range + + +class ProfilesTestCase(unittest.TestCase): + + def test_profile_threading(self): + """ Test that profiles thread safe""" + # see: https://pagure.io/koji/issue/58 and https://pagure.io/pungi/issue/253 + # loop a few times to increase chances of hitting race conditions + for i in range(20): + errors = {} + threads = [threading.Thread(target=stress, args=(errors, _)) for _ in range(100)] + for t in threads: + t.start() + for t in threads: + t.join(30) + for n in errors: + err = errors[n] + if err is not None: + print(err) + assert False + + +def stress(errors, n): + errors[n] = "Failed to start" + try: + koji.get_profile_module('koji') + except Exception: + # if we don't catch this, nose seems to ignore the test + errors[n] = ''.join(traceback.format_exception(*sys.exc_info())) + return + else: + errors[n] = None + + + diff --git a/tests/test_lib/test_tasks.py b/tests/test_lib/test_tasks.py new file mode 100644 index 0000000..551cb05 --- /dev/null +++ b/tests/test_lib/test_tasks.py @@ -0,0 +1,715 @@ +from __future__ import absolute_import +import random +from os import path, makedirs +from shutil import rmtree +from tempfile import gettempdir +from unittest import TestCase +from mock import patch, Mock, call + +import koji +from koji.tasks import BaseTaskHandler, FakeTask, ForkTask, SleepTask, \ + WaitTestTask, scan_mounts, umount_all, \ + safe_rmtree +import six + + +def get_fake_mounts_file(): + """ Returns contents of /prc/mounts in a file-like object + """ + return six.StringIO(six.text_type(( + 'sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' + 'proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0\n' + 'devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=238836k,nr_inodes=59709,mode=755 0 0\n' + 'securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0\n' + 'tmpfs /dev/shm\040(deleted) tmpfs rw,seclabel,nosuid,nodev 0 0\n' + 'devpts /dev/pts devpts rw,seclabel,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0\n' + 'tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0\n' + 'tmpfs /sys/fs/cgroup tmpfs ro,seclabel,nosuid,nodev,noexec,mode=755 0 0\n' + 'pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' + 'cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0\n' + 'cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0\n' + 'cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0\n' + 'cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0\n' + 'cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0\n' + 'cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0\n' + 'cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0\n' + 'cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0\n' + 'cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0\n' + 'configfs /sys/kernel/config configfs rw,relatime 0 0\n' + ))) + + +def get_temp_dir_root(): + return path.join(gettempdir(), 'koji_tests') + + +def get_tmp_dir_path(folder_starts_with): + return path.join(get_temp_dir_root(), ('{0}{1}'.format(folder_starts_with, random.randint(1, 999999999999)))) + + +class TestTask(BaseTaskHandler): + Methods = ['some_method'] + _taskWeight = 5.2 + + def handler(self, *args): + return 42 + + +class TestTaskNoWeight(BaseTaskHandler): + Methods = ['some_method'] + + def handler(self, *args): + return 42 + + +class BadTask(BaseTaskHandler): + Methods = ['some_method'] + + +class TasksTestCase(TestCase): + + def tearDown(self): + temp_dir_root = get_temp_dir_root() + + if path.isdir(temp_dir_root): + rmtree(get_temp_dir_root()) + + def test_scan_mounts_results(self): + """ Tests the scan_mounts function with a mocked /proc/mounts file. A list containing mount points + starting with /dev are expected to be returned from the function based on the function input of /dev. + """ + fake_mounts_file_contents = get_fake_mounts_file() + + with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True): + self.assertIn(scan_mounts('/dev'), [['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/hugepages', '/dev'], + ['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/console', '/dev']]) + + def test_scan_mounts_no_results(self): + """ Tests the scan_mounts function with a mocked /proc/mounts file. An argument of /nonexistent/path + to the function should return an empty list. + """ + fake_mounts_file_contents = get_fake_mounts_file() + + with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True): + self.assertEquals(scan_mounts('/nonexistent/path'), []) + + # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all + @patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], []]) + @patch('os.spawnvp', return_value=0) + def test_umount_all(self, mocked_spawnvp, mocked_scan_mounts): + """ Tests that umount_all returns nothing when successful. + """ + self.assertEquals(umount_all('/test'), None) + + # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all + @patch('koji.tasks.scan_mounts', return_value=['/dev/shm', '/dev/pts', '/dev/mqueue']) + @patch('os.spawnvp', return_value=1) + def test_umount_all_failure(self, mocked_spawnvp, mocked_scan_mounts): + """ Tests that umount_all raises an exception when a mount point can't be unmounted. + """ + try: + umount_all('/dev') + raise Exception('A GenericError was not raised during the test') + except koji.GenericError as e: + self.assertEquals(e.args[0], + 'umount failed (exit code 1) for /dev/shm') + + # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all + @patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], ['/dev/shm', '/dev/mqueue']]) + @patch('os.spawnvp', return_value=0) + def test_umount_all_unexpected_failure(self, mocked_spawnvp, mocked_scan_mounts): + """ Tests that umount_all will fail if the command to unmount the mount points was successful + but a second run of scan_mounts still shows some of the unmount mount points still mounted. + """ + try: + umount_all('/dev') + raise Exception('A GenericError was not raised during the test') + except koji.GenericError as e: + self.assertEquals(e.args[0], 'Unmounting incomplete: [\'/dev/shm\', \'/dev/mqueue\']') + + @patch('os.path.isfile', return_value=True) + @patch('os.remove') + def test_safe_rmtree_file(self, mock_remove, mock_isfile): + """ Tests that the safe_rmtree function returns nothing when the path parameter is a file. + """ + self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None) + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=True) + @patch('os.remove') + def test_safe_rmtree_link(self, mock_remove, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns nothing when the path parameter is a link. + """ + self.assertEquals(safe_rmtree('/mnt/folder/some_link', False, True), None) + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=False) + @patch('os.path.exists', return_value=False) + def test_safe_rmtree_does_not_exist(self, mock_exists, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns nothing if the path does not exist. + """ + self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None) + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=False) + @patch('os.path.exists', return_value=True) + @patch('os.system', side_effect=[0, 0]) + def test_safe_rmtree_directory(self, mock_os_system, mock_exists, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns nothing when the path is a directory. + """ + self.assertEquals(safe_rmtree('/mnt/folder', False, True), 0) + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=False) + @patch('os.path.exists', return_value=True) + @patch('os.system', side_effect=[1, 0]) + def test_safe_rmtree_directory_scrub_file_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory + and the scrub of the files in the directory fails. + """ + try: + safe_rmtree('/mnt/folder', False, True) + raise Exception('A GenericError was not raised during the test') + except koji.GenericError as e: + self.assertEquals(e.args[0], 'file removal failed (code 1) for /mnt/folder') + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=False) + @patch('os.path.exists', return_value=True) + @patch('os.system', side_effect=[0, 1]) + def test_safe_rmtree_directory_scrub_directory_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory + and the scrub of the directories in the directory fails. + """ + try: + safe_rmtree('/mnt/folder', False, True) + raise Exception('A GenericError was not raised during the test') + except koji.GenericError as e: + self.assertEquals(e.args[0], 'dir removal failed (code 1) for /mnt/folder') + + def test_BaseTaskHandler_handler_not_set(self): + """ Tests that an exception is thrown when the handler function is not overwritten by the child class. + """ + obj = BadTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('BadTask'))) + try: + obj.handler() + raise Exception('The NotImplementedError exception was not raised') + except NotImplementedError as e: + self.assertEquals(e.__class__.__name__, 'NotImplementedError') + + def test_BaseTaskHandler_weight_default(self): + """ Tests that the weight function returns 1.0 when _taskWeight is not set in the child class' definition. + """ + obj = TestTaskNoWeight(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTaskNoWeight'))) + self.assertEquals(obj.weight(), 1.0) + + def test_BaseTaskHandler_weight_set(self): + """ Tests that the weight function returns the value of _taskWeight when it is set in the + child class' definition. + """ + obj = TestTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTask'))) + self.assertEquals(obj.weight(), 5.2) + + def test_BaseTaskHandler_createWorkdir_workdir_not_defined(self): + """ Tests that the createWorkdir function does nothing when the workdir member variable is set to None. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.workdir = None + obj.createWorkdir() + self.assertEquals(path.isdir(temp_path), False) + + # This patch removes the dependence on removeWorkdir functioning + @patch('{0}.TestTask.removeWorkdir'.format(__name__)) + def test_BaseTaskHandler_createWorkdir(self, mock_removeWorkDir): + """ Tests that the createWorkdir function creates a folder based on the path given to the + workdir member variable. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.createWorkdir() + self.assertEquals(path.isdir(temp_path), True) + rmtree(get_temp_dir_root()) + + def test_BaseTaskHandler_removeWorkdir(self): + """ Tests that the removeWOrkdir function deletes a folder based on the path given to the + workdir member variable. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + self.assertEquals(path.isdir(temp_path), True) + obj.removeWorkdir() + self.assertEquals(path.isdir(temp_path), False) + + def test_BaseTaskHandler_wait_all_done(self): + """ Tests that the wait function returns the subtask results of when the taskWait function returns only + two finished tasks + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + obj.session = Mock() + obj.session.host.taskSetWait.return_value = None + obj.session.host.taskWait.return_value = [[1551234, 1591234], []] + taskWaitResults = [ + ['1551234', { + 'brootid': 2342345, + 'logs': ['tasks/5678/12345678/root.log', + 'tasks/5678/12345678/state.log', + 'tasks/5678/12345678/build.log'], + 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' + }], + + ['1591234', { + 'brootid': 1231234, + 'logs': ['tasks/6789/2345678/root.log', + 'tasks/6789/2345678/state.log', + 'tasks/6789/2345678/build.log'], + 'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'], + 'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm'] + }] + ] + + obj.session.host.taskWaitResults.return_value = taskWaitResults + self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults)) + obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) + obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[]) + + def test_BaseTaskHandler_wait_some_not_done(self): + """ Tests that the wait function returns the one finished subtask results of + when the taskWait function returns one finished task and one unfinished + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + obj.session = Mock() + obj.session.host.taskSetWait.return_value = None + obj.session.host.taskWait.return_value = [[1551234], [1591234]] + taskWaitResults = [ + ['1551234', { + 'brootid': 2342345, + 'logs': ['tasks/5678/12345678/root.log', + 'tasks/5678/12345678/state.log', + 'tasks/5678/12345678/build.log'], + 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' + }] + ] + + obj.session.host.taskWaitResults.return_value = taskWaitResults + self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults)) + obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) + obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234], canfail=[]) + + @patch('signal.pause', return_value=None) + def test_BaseTaskHandler_wait_some_not_done_all_set(self, mock_signal_pause): + """ Tests that the wait function returns the two subtask results since the all kwarg is set to True. + The taskWait function should first return one finished and one unfinished task, then the second time it should + return two finished tasks. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + obj.session = Mock() + obj.session.host.taskSetWait.return_value = None + obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]] + taskWaitResults = [ + ['1551234', { + 'brootid': 2342345, + 'logs': ['tasks/5678/12345678/root.log', + 'tasks/5678/12345678/state.log', + 'tasks/5678/12345678/build.log'], + 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' + }], + + ['1591234', { + 'brootid': 1231234, + 'logs': ['tasks/6789/2345678/root.log', + 'tasks/6789/2345678/state.log', + 'tasks/6789/2345678/build.log'], + 'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'], + 'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm'] + }] + ] + + obj.session.getTaskResult.side_effect + + obj.session.host.taskWaitResults.return_value = taskWaitResults + self.assertEquals(obj.wait([1551234, 1591234], all=True), dict(taskWaitResults)) + obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) + obj.session.host.taskWait.assert_has_calls([call(12345678), call(12345678)]) + mock_signal_pause.assert_called_once_with() + obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[]) + + def test_BaseTaskHandler_wait_some_not_done_all_set_failany_set_failed_task(self): + """ Tests that the wait function raises an exception when one of the subtask fails when the failany flag is set + to True. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + obj.session = Mock() + obj.session.host.taskSetWait.return_value = None + obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]] + obj.session.getTaskResult.side_effect = koji.GenericError('Uh oh, we\'ve got a problem here!') + try: + obj.wait([1551234, 1591234], all=True, failany=True) + raise Exception('A GeneralError was not raised.') + except koji.GenericError as e: + self.assertEquals(e.args[0], 'Uh oh, we\'ve got a problem here!') + obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) + + def test_BaseTaskHandler_getUploadDir(self): + """ Tests that the getUploadDir function returns the appropriate path based on the id of the handler. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + self.assertEquals(obj.getUploadDir(), 'tasks/123/123') + + # This patch removes the dependence on getUploadDir functioning + @patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123') + def test_BaseTaskHandler_uploadFile(self, mock_getUploadDir): + """ Tests that the uploadFile function calls the uploadWrapper function on the session member variable + with the correct input + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + temp_file = path.join(temp_path, 'test.txt') + with open(temp_file, 'w') as temp_file_handler: + temp_file_handler.write('Test') + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + self.assertEquals(obj.uploadFile(temp_file), None) + obj.session.uploadWrapper.assert_called_once_with(temp_file, 'tasks/123/123', None, volume=None) + + # This patch removes the dependence on getUploadDir functioning + @patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123') + def test_BaseTaskHandler_uploadFile_no_content(self, mock_getUploadDir): + """ Tests that the uploadFile function calls the uploadWrapper function on the session member variable + without including empty files. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + temp_file = path.join(temp_path, 'test.txt') + temp_file_handler = open(temp_file, 'w') + temp_file_handler.close() + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + self.assertEquals(obj.uploadFile(temp_file), None) + self.assertEquals(obj.session.uploadWrapper.called, False) + + def test_BaseTaskHandler_uploadTree(self): + """ Tests that the uploadTree function calls the uploadFile function with the correct parameters. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + dummy_dir = path.join(temp_path, 'some_directory') + makedirs(dummy_dir) + + dummy_file = path.join(temp_path, 'test.txt') + with open(dummy_file, 'w') as temp_file_handler: + temp_file_handler.write('Test') + + dummy_file2 = path.join(dummy_dir, 'test2.txt') + with open(dummy_file2, 'w') as temp_file_handler2: + temp_file_handler2.write('Test2') + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.uploadFile = Mock() + obj.uploadFile.return_value = None + self.assertEquals(obj.uploadTree(temp_path), None) + obj.uploadFile.assert_has_calls([call(dummy_file, '', volume=None), call(dummy_file2, 'some_directory', volume=None)]) + + @patch('os.lchown', return_value=None) + def test_BaseTaskHandler_chownTree(self, mock_lchown): + """ Tests that the chownTree functions as expected on dummy files created in a temp directory + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + dummy_file = path.join(temp_path, 'test.txt') + dummy_file_handler = open(dummy_file, 'w') + dummy_file_handler.close() + + dummy_file2 = path.join(temp_path, 'test2.txt') + dummy_file_handler2 = open(dummy_file2, 'w') + dummy_file_handler2.close() + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + self.assertEquals(obj.chownTree(temp_path, 2, 0), None) + mock_lchown.assert_has_calls([call(temp_path, 2, 0), call(dummy_file2, 2, 0), call(dummy_file, 2, 0)], any_order=True) + + def test_BaseTaskHandler_localPath_file_exists(self): + """ Tests the localPath function to ensure that when a file exists, it returns that path without + trying to download it. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + local_folder = path.join(temp_path, 'local') + makedirs(local_folder) + + dummy_file = path.join(local_folder, 'test.txt') + dummy_file_handler = open(dummy_file, 'w') + dummy_file_handler.close() + options = Mock() + options.topurl = 'https://www.domain.local' + obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) + self.assertEquals(obj.localPath('test.txt'), dummy_file) + + @patch('six.moves.urllib.request.urlopen', return_value=six.StringIO(six.text_type('Important things\nSome more important things\n'))) + def test_BaseTaskHandler_localPath_no_file(self, mock_urlopen): + """ + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + local_folder = path.join(temp_path, 'local') + makedirs(local_folder) + + target_file_path = path.join(local_folder, 'test.txt') + + options = Mock() + options.topurl = 'https://www.domain.local' + obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) + + self.assertEquals(obj.localPath('test.txt'), target_file_path) + mock_urlopen.assert_called_once_with('https://www.domain.local/test.txt') + + def test_BaseTaskHandler_localPath_no_topurl(self): + """ Tests that the localPath function returns a path when options.topurl is not defined. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + options = Mock() + options.topurl = None + options.topdir = get_temp_dir_root() + obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) + + self.assertEquals(obj.localPath('test.txt'), path.join(get_temp_dir_root(), 'test.txt')) + + def test_BaseTaskHandler_find_arch(self): + """ Tests that the find_arch function returns the input for arch when the input is not "noarch". + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + self.assertEquals(obj.find_arch('x86_64', None, None), 'x86_64') + + def test_BaseTaskHandler_find_arch_noarch_bad_host(self): + """ Tests that the find_arch function raises an exception when the host parameter doesn't contain a + value for the arches key. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + host = {'arches': None, 'name': 'test.domain.local'} + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + try: + obj.find_arch('noarch', host, None) + raise Exception('The BuildError Exception was not raised') + except koji.BuildError as e: + self.assertEquals(e.args[0], 'No arch list for this host: test.domain.local') + + def test_BaseTaskHandler_find_arch_noarch_bad_tag(self): + """ Tests that the find_arch function raises an exception when the tag parameter doesn't contain a + value for the arches key. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + host = {'arches': 'x86_64', 'name': 'test.domain.local'} + tag = {'arches': None, 'name': 'some_package-1.2-build'} + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + try: + obj.find_arch('noarch', host, tag) + raise Exception('The BuildError Exception was not raised') + except koji.BuildError as e: + self.assertEquals(e.args[0], 'No arch list for tag: some_package-1.2-build') + + def test_BaseTaskHandler_find_arch_noarch(self): + """ Tests that the find_arch function finds a match of x86_64 when the host only supports x86_64 + and the tag supports x86_64 and aarch64. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + host = {'arches': 'x86_64', 'name': 'test.domain.local'} + tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'} + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + self.assertEquals(obj.find_arch('noarch', host, tag), 'x86_64') + + def test_BaseTaskHandler_find_arch__noarch_no_match(self): + """ Tests that the find_arch function raises an exception when there isn't a common arch supported between + the host and the tag. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + host = {'arches': 'i386', 'name': 'test.domain.local'} + tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'} + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + try: + obj.find_arch('noarch', host, tag) + raise Exception('The BuildError Exception was not raised') + except koji.BuildError as e: + self.assertEquals(e.args[0], ('host test.domain.local (i386) does not support ' + 'any arches of tag some_package-1.2-build (aarch64, x86_64)')) + + def test_getRepo_tied_to_session(self): + """ Tests that the getRepo function calls session.getRepo(), and returns the result when successful + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + repo_dict = { + 'create_event': 13635166, + 'create_ts': 1469039671.5743899, + 'creation_time': '2016-07-20 18:34:31.574386', + 'id': 1630631, + 'state': 1 + } + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + obj.session.getRepo.return_value = repo_dict + + self.assertEquals(obj.getRepo(8472), repo_dict) + + @patch('{0}.TestTask.wait'.format(__name__)) + def test_getRepo_not_tied_to_session(self, mock_wait): + """ Tests that the getRepo function waits until the results are available for session.getRepo, when it is + not available at the start of the function call. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + repo_dict = { + 'create_event': 13413120, + 'create_ts': 1466140834.9119599, + 'creation_time': '2016-06-17 05:20:34.911962', + 'id': 1592850, + 'state': 1 + } + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + obj.session.getRepo.return_value = None + obj.session.getTag.return_value = { + 'arches': 'i386 ia64 x86_64 ppc s390 s390x ppc64', + 'extra': {}, + 'id': 851, + 'locked': True, + 'maven_include_all': False, + 'maven_support': False, + 'name': 'dist-3.0E-build', + 'perm': None, + 'perm_id': None + } + obj.session.getBuildTargets.return_value = [{ + 'build_tag': 3093, + 'build_tag_name': 'dist-6E-dsrv-9-build', + 'dest_tag': 3092, + 'dest_tag_name': 'dist-6E-dsrv-9-qu-candidate', + 'id': 851, + 'name': 'dist-6E-dsrv-9-qu-candidate' + }] + + obj.session.host.subtask.return_value = 123 + mock_wait.return_value = {123: repo_dict} + + self.assertEquals(obj.getRepo(851), repo_dict) + obj.session.getRepo.assert_called_once_with(851) + obj.session.getTag.assert_called_once_with(851, strict=True) + + @patch('{0}.TestTask.wait'.format(__name__)) + def test_getRepo_not_tied_to_session_no_build_targets(self, mock_wait): + """ Tests that the getRepo function raises an exception when session.getBuildTargets returns an empty list + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + obj.session.getRepo.return_value = None + obj.session.getTag.return_value = { + 'arches': 'i686 x86_64 ppc ppc64 ppc64le s390 s390x aarch64', + 'extra': {}, + 'id': 8472, + 'locked': False, + 'maven_include_all': False, + 'maven_support': False, + 'name': 'rhel-7.3-build', + 'perm': 'admin', + 'perm_id': 1 + } + obj.session.getBuildTargets.return_value = [] + + try: + obj.getRepo(8472) + raise Exception('The BuildError Exception was not raised') + except koji.BuildError as e: + obj.session.getRepo.assert_called_once_with(8472) + self.assertEquals(e.args[0], 'no repo (and no target) for tag rhel-7.3-build') + + def test_FakeTask_handler(self): + """ Tests that the FakeTest handler can be instantiated and returns 42 when run + """ + obj = FakeTask(123, 'someMethod', ['random_arg'], None, None, (get_tmp_dir_path('FakeTask'))) + self.assertEquals(obj.run(), 42) + + @patch('time.sleep') + def test_SleepTask_handler(self, mock_sleep): + """ Tests that the SleepTask handler can be instantiated and runs appropriately based on the input + """ + obj = SleepTask(123, 'sleep', [5], None, None, (get_tmp_dir_path('SleepTask'))) + obj.run() + mock_sleep.assert_called_once_with(5) + + @patch('os.spawnvp') + def test_ForkTask_handler(self, mock_spawnvp): + """ Tests that the ForkTask handler can be instantiated and runs appropriately based on the input + """ + obj = ForkTask(123, 'fork', [1, 20], None, None, (get_tmp_dir_path('ForkTask'))) + obj.run() + mock_spawnvp.assert_called_once_with(1, 'sleep', ['sleep', '20']) + + @patch('signal.pause', return_value=None) + @patch('time.sleep') + def test_WaitTestTask_handler(self, mock_sleep, mock_signal_pause): + """ Tests that the WaitTestTask handler can be instantiated and runs appropriately based on the input + Specifically, that forking works and canfail behaves correctly. + """ + self.mock_subtask_id = 1 + def mock_subtask(method, arglist, id, **opts): + self.assertEqual(method, 'sleep') + task_id = self.mock_subtask_id + self.mock_subtask_id += 1 + obj = SleepTask(task_id, 'sleep', arglist, None, None, (get_tmp_dir_path('SleepTask'))) + obj.run() + return task_id + + mock_taskWait = [ + [[], [1, 2, 3, 4]], + [[3, 4], [1, 2]], + [[1, 2, 3, 4], []], + ] + def mock_getTaskResult(task_id): + if task_id == 4: + raise koji.GenericError() + + + obj = WaitTestTask(123, 'waittest', [3], None, None, (get_tmp_dir_path('WaitTestTask'))) + obj.session = Mock() + obj.session.host.subtask.side_effect = mock_subtask + obj.session.getTaskResult.side_effect = mock_getTaskResult + obj.session.host.taskWait.side_effect = mock_taskWait + obj.session.host.taskWaitResults.return_value = [ ['1', {}], ['2', {}], ['3', {}], ['4', {}], ] + obj.run() + #self.assertEqual(mock_sleep.call_count, 4) + obj.session.host.taskSetWait.assert_called_once() + obj.session.host.taskWait.assert_has_calls([call(123), call(123), call(123)]) + # getTaskResult should be called in 2nd round only for task 3, as 4 + # will be skipped as 'canfail' + obj.session.getTaskResult.assert_has_calls([call(3)]) diff --git a/tests/test_lib/test_utils.py b/tests/test_lib/test_utils.py new file mode 100644 index 0000000..1ff221c --- /dev/null +++ b/tests/test_lib/test_utils.py @@ -0,0 +1,493 @@ +from __future__ import absolute_import +import mock +import unittest +from mock import call + +import os +import optparse +import six.moves.configparser +import koji +import koji.util + + +class EnumTestCase(unittest.TestCase): + + def test_enum_create_alpha(self): + """ Test that we can create an Enum with alphabet names """ + koji.Enum(('one', 'two', 'three')) + + def test_enum_bracket_access(self): + """ Test bracket access. """ + test = koji.Enum(('one', 'two', 'three')) + self.assertEquals(test['one'], 0) + self.assertEquals(test['two'], 1) + self.assertEquals(test['three'], 2) + + with self.assertRaises(KeyError): + test['does not exist'] + + def test_enum_getter_access(self): + """ Test getter access. """ + test = koji.Enum(('one', 'two', 'three')) + self.assertEquals(test.get('one'), 0) + self.assertEquals(test.get('two'), 1) + self.assertEquals(test.get('three'), 2) + self.assertEquals(test.get('does not exist'), None) + + def test_enum_slice_access(self): + """ Test slice access. """ + test = koji.Enum(('one', 'two', 'three')) + self.assertEquals(test[1:], ('two', 'three')) + + +def mock_open(): + """Return the right patch decorator for open""" + if six.PY2: + return mock.patch('__builtin__.open') + else: + return mock.patch('builtins.open') + + +class MiscFunctionTestCase(unittest.TestCase): + + @mock.patch('os.path.exists') + @mock.patch('os.path.islink') + @mock.patch('shutil.move') + def test_safer_move(self, move, islink, exists): + """Test safer_move function""" + src = '/FAKEPATH/SRC' + dst = '/FAKEPATH/DST' + + # good args + exists.return_value = False + islink.return_value = False + koji.util.safer_move(src, dst) + exists.assert_called_once_with(dst) + islink.assert_called_once_with(dst) + move.assert_called_once_with(src, dst) + + move.reset_mock() + islink.reset_mock() + exists.reset_mock() + + # existing dst + exists.return_value = True + with self.assertRaises(koji.GenericError): + koji.util.safer_move(src, dst) + exists.assert_called_once_with(dst) + move.assert_not_called() + + move.reset_mock() + islink.reset_mock() + exists.reset_mock() + + # symlink dst + exists.return_value = False + islink.return_value = True + with self.assertRaises(koji.GenericError): + koji.util.safer_move(src, dst) + exists.assert_called_once_with(dst) + islink.assert_called_once_with(dst) + move.assert_not_called() + + @mock_open() + @mock.patch('six.moves.urllib.request.urlopen') + @mock.patch('tempfile.TemporaryFile') + @mock.patch('shutil.copyfileobj') + def test_openRemoteFile(self, m_copyfileobj, m_TemporaryFile, + m_urlopen, m_open): + """Test openRemoteFile function""" + + mocks = [m_open, m_copyfileobj, m_TemporaryFile, m_urlopen] + + topurl = 'http://example.com/koji' + path = 'relative/file/path' + url = 'http://example.com/koji/relative/file/path' + + # using topurl, no tempfile + fo = koji.openRemoteFile(path, topurl) + m_urlopen.assert_called_once_with(url) + m_urlopen.return_value.close.assert_called_once() + m_TemporaryFile.assert_called_once_with(dir=None) + m_copyfileobj.assert_called_once() + m_open.assert_not_called() + assert fo is m_TemporaryFile.return_value + + for m in mocks: + m.reset_mock() + + # using topurl + tempfile + tempdir = '/tmp/koji/1234' + fo = koji.openRemoteFile(path, topurl, tempdir=tempdir) + m_urlopen.assert_called_once_with(url) + m_urlopen.return_value.close.assert_called_once() + m_TemporaryFile.assert_called_once_with(dir=tempdir) + m_copyfileobj.assert_called_once() + m_open.assert_not_called() + assert fo is m_TemporaryFile.return_value + + for m in mocks: + m.reset_mock() + + # using topdir + topdir = '/mnt/mykojidir' + filename = '/mnt/mykojidir/relative/file/path' + fo = koji.openRemoteFile(path, topdir=topdir) + m_urlopen.assert_not_called() + m_TemporaryFile.assert_not_called() + m_copyfileobj.assert_not_called() + m_open.assert_called_once_with(filename) + assert fo is m_open.return_value + + for m in mocks: + m.reset_mock() + + # using neither + with self.assertRaises(koji.GenericError): + koji.openRemoteFile(path) + for m in mocks: + m.assert_not_called() + + +class MavenUtilTestCase(unittest.TestCase): + """Test maven relative functions""" + maxDiff = None + + def test_maven_config_opt_adapter(self): + """Test class MavenConfigOptAdapter""" + conf = mock.MagicMock() + section = 'section' + adapter = koji.util.MavenConfigOptAdapter(conf, section) + self.assertIs(adapter._conf, conf) + self.assertIs(adapter._section, section) + conf.has_option.return_value = True + adapter.goals + adapter.properties + adapter.someattr + conf.has_option.return_value = False + with self.assertRaises(AttributeError) as cm: + adapter.noexistsattr + self.assertEquals(cm.exception.args[0], 'noexistsattr') + self.assertEquals(conf.mock_calls, [call.has_option(section, 'goals'), + call.get(section, 'goals'), + call.get().split(), + call.has_option(section, 'properties'), + call.get(section, 'properties'), + call.get().splitlines(), + call.has_option(section, 'someattr'), + call.get('section', 'someattr'), + call.has_option(section, 'noexistsattr')]) + + def test_maven_opts(self): + """Test maven_opts function""" + values = optparse.Values({ + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': ['p1=1', 'p2', 'p3=ppp3'], + 'envs': ['e1=1', 'e2=2'], + 'buildrequires': ['r1', 'r2'], + 'otheropts': 'others'}) + self.assertEqual(koji.util.maven_opts(values), { + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, + 'envs': {'e1': '1', 'e2': '2'}}) + self.assertEqual(koji.util.maven_opts(values, chain=True, scratch=True), { + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, + 'envs': {'e1': '1', 'e2': '2'}, + 'buildrequires': ['r1', 'r2']}) + self.assertEqual(koji.util.maven_opts(values, chain=False, scratch=True), { + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, + 'envs': {'e1': '1', 'e2': '2'}, + 'scratch': True}) + values = optparse.Values({'envs': ['e1']}) + with self.assertRaises(ValueError) as cm: + koji.util.maven_opts(values) + self.assertEqual( + cm.exception.args[0], + "Environment variables must be in NAME=VALUE format") + + def test_maven_params(self): + """Test maven_params function""" + config = self._read_conf('/data/maven/config.ini') + self.assertEqual(koji.util.maven_params(config, 'pkg1'), { + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, + 'envs': {'e1': '1', 'e2': '2'}}) + + def test_wrapper_params(self): + """Test wrapper_params function""" + config = self._read_conf('/data/maven/config.ini') + self.assertEqual(koji.util.wrapper_params(config, 'pkg2'), { + 'type': 'maven', + 'scmurl': 'scmurl', + 'buildrequires': ['r1', 'r2'], + 'create_build': True}) + self.assertEqual(koji.util.wrapper_params(config, 'pkg2', scratch=True), { + 'type': 'maven', + 'scmurl': 'scmurl', + 'buildrequires': ['r1', 'r2']}) + + def test_parse_maven_params(self): + """Test parse_maven_params function""" + path = os.path.dirname(__file__) + # single conf file, and chain=False, scratch=False + confs = path + '/data/maven/config.ini' + self.assertEqual(koji.util.parse_maven_params(confs), { + 'pkg1': { + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, + 'envs': {'e1': '1', 'e2': '2'}}, + 'pkg2': { + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, + 'envs': {'e1': '1', 'e2': '2'}}, + 'pkg3': { + 'type': 'wrapper', + 'scmurl': 'scmurl', + 'buildrequires': ['r1'], + 'create_build': True}}) + + # multiple conf file, and chain=True, scratch=False + confs = [confs, path + '/data/maven/good_config.ini'] + self.assertEqual(koji.util.parse_maven_params(confs, chain=True), { + 'pkg1': { + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, + 'envs': {'e1': '1', 'e2': '2'}, + 'buildrequires': ['r1', 'r2']}, + 'pkg2': { + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, + 'envs': {'e1': '1', 'e2': '2'}, + 'buildrequires': ['r1', 'r2']}, + 'pkg3': { + 'type': 'wrapper', + 'scmurl': 'scmurl', + 'buildrequires': ['r1'], + 'create_build': True}, + 'pkg4': { + 'scmurl': 'scmurl', + 'patches': 'patchurl', + 'specfile': 'specfile', + 'goals': ['goal1', 'goal2'], + 'profiles': ['profile1', 'profile2'], + 'packages': ['pkg1', 'pkg2'], + 'jvm_options': ['--opt1', '--opt2=val'], + 'maven_options': ['--opt1', '--opt2=val'], + 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, + 'envs': {'e1': '1', 'e2': '2'}, + 'buildrequires': ['r1', 'r2']}, + }) + + # bad conf file - type=wrapper and len(params.get('buildrequires')!=1) + confs = path + '/data/maven/bad_wrapper_config.ini' + with self.assertRaises(ValueError) as cm: + koji.util.parse_maven_params(confs) + self.assertEqual( + cm.exception.args[0], + 'A wrapper-rpm must depend on exactly one package') + + # bad conf file - type is neither 'maven' nor 'wrapper') + confs = path + '/data/maven/bad_type_config.ini' + with self.assertRaises(ValueError) as cm: + koji.util.parse_maven_params(confs) + self.assertEqual(cm.exception.args[0], 'Unsupported build type: other') + + # bad conf file - no scmurl param + confs = path + '/data/maven/bad_scmurl_config.ini' + with self.assertRaises(ValueError) as cm: + koji.util.parse_maven_params(confs) + self.assertEqual( + cm.exception.args[0], + 'pkg is missing the scmurl parameter') + + # bad conf file - empty dict returned + confs = path + '/data/maven/bad_empty_config.ini' + with self.assertRaises(ValueError) as cm: + koji.util.parse_maven_params(confs) + self.assertEqual( + cm.exception.args[0], + 'No sections found in: %s' % + confs) + + def test_parse_maven_param(self): + """Test parse_maven_param function""" + path = os.path.dirname(__file__) + # single conf file, and chain=False, scratch=False + confs = path + '/data/maven/config.ini' + with mock.patch('koji.util.parse_maven_params', + return_value={ + 'pkg1': {'sth': 'pkg1'}, + 'pkg2': {'sth': 'pkg2'}, + 'pkg3': {'sth': 'pkg3'}}): + self.assertEqual( + koji.util.parse_maven_param( + confs, section='pkg1'), { + 'pkg1': { + 'sth': 'pkg1'}}) + with self.assertRaises(ValueError) as cm: + koji.util.parse_maven_param(confs, section='pkg4') + self.assertEqual( + cm.exception.args[0], + 'Section pkg4 does not exist in: %s' % + confs) + with self.assertRaises(ValueError) as cm: + koji.util.parse_maven_param(confs) + self.assertEqual( + cm.exception.args[0], + 'Multiple sections in: %s, you must specify the section' % + confs) + with mock.patch('koji.util.parse_maven_params', return_value={ + 'pkg': {'sth': 'pkg'}}): + self.assertEqual(koji.util.parse_maven_param(confs), + {'pkg': {'sth': 'pkg'}}) + + def test_parse_maven_chain(self): + """Test parse_maven_chain function""" + path = os.path.dirname(__file__) + confs = path + '/data/maven/config.ini' + with mock.patch('koji.util.parse_maven_params', + return_value={ + 'pkg1': {'buildrequires': ['pkg2', 'pkg3']}, + 'pkg2': {'buildrequires': ['pkg3']}, + 'pkg3': {'sth': 'sth'}}): + self.assertEqual(koji.util.parse_maven_chain(confs), + {'pkg1': {'buildrequires': ['pkg2', 'pkg3']}, + 'pkg2': {'buildrequires': ['pkg3']}, + 'pkg3': {'sth': 'sth'}}) + # circular deps + with mock.patch('koji.util.parse_maven_params', + return_value={ + 'pkg1': {'buildrequires': ['pkg2', 'pkg3']}, + 'pkg2': {'buildrequires': ['pkg3']}, + 'pkg3': {'buildrequires': ['pkg1']}}): + with self.assertRaises(ValueError) as cm: + koji.util.parse_maven_chain(confs) + self.assertEqual( + cm.exception.args[0], + 'No possible build order, missing/circular dependencies') + # missing deps + with mock.patch('koji.util.parse_maven_params', + return_value={ + 'pkg1': {'buildrequires': ['pkg2', 'pkg3']}, + 'pkg2': {'buildrequires': ['pkg3']}, + 'pkg3': {'buildrequires': ['pkg4']}}): + with self.assertRaises(ValueError) as cm: + koji.util.parse_maven_chain(confs) + self.assertEqual( + cm.exception.args[0], + 'No possible build order, missing/circular dependencies') + + def test_tsort(self): + # success, one path + parts = { + 'p1': {'p2', 'p3'}, + 'p2': {'p3'}, + 'p3': set() + } + self.assertEqual(koji.util.tsort(parts), + [{'p3'}, {'p2'}, {'p1'}]) + # success, multi-path + parts = { + 'p1': {'p2'}, + 'p2': {'p4'}, + 'p3': {'p4'}, + 'p4': set(), + 'p5': set() + } + self.assertEqual(koji.util.tsort(parts), + [{'p4', 'p5'}, {'p2', 'p3'}, {'p1'}]) + # failed, missing child 'p4' + parts = { + 'p1': {'p2'}, + 'p2': {'p3'}, + 'p3': {'p4'} + } + with self.assertRaises(ValueError) as cm: + koji.util.tsort(parts) + self.assertEqual(cm.exception.args[0], 'total ordering not possible') + + # failed, circular + parts = { + 'p1': {'p2'}, + 'p2': {'p3'}, + 'p3': {'p1'} + } + with self.assertRaises(ValueError) as cm: + koji.util.tsort(parts) + self.assertEqual(cm.exception.args[0], 'total ordering not possible') + + def _read_conf(self, cfile): + config = six.moves.configparser.ConfigParser() + path = os.path.dirname(__file__) + with open(path + cfile, 'r') as conf_file: + config.readfp(conf_file) + return config + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_parsers.py b/tests/test_parsers.py deleted file mode 100644 index 02ff1c2..0000000 --- a/tests/test_parsers.py +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/python - -"""Test the __init__.py module""" - -from __future__ import absolute_import -import mock -import os -import rpm -import unittest - -import koji - -class INITTestCase(unittest.TestCase): - """Main test case container""" - - def test_parse_NVR(self): - """Test the parse_NVR method""" - - self.assertRaises(AttributeError, koji.parse_NVR, None) - self.assertRaises(AttributeError, koji.parse_NVR, 1) - self.assertRaises(AttributeError, koji.parse_NVR, {}) - self.assertRaises(AttributeError, koji.parse_NVR, []) - self.assertRaises(koji.GenericError, koji.parse_NVR, "") - self.assertRaises(koji.GenericError, koji.parse_NVR, "foo") - self.assertRaises(koji.GenericError, koji.parse_NVR, "foo-1") - self.assertRaises(koji.GenericError, koji.parse_NVR, "foo-1-") - self.assertRaises(koji.GenericError, koji.parse_NVR, "foo--1") - self.assertRaises(koji.GenericError, koji.parse_NVR, "--1") - ret = koji.parse_NVR("foo-1-2") - self.assertEqual(ret['name'], "foo") - self.assertEqual(ret['version'], "1") - self.assertEqual(ret['release'], "2") - self.assertEqual(ret['epoch'], "") - ret = koji.parse_NVR("12:foo-1-2") - self.assertEqual(ret['name'], "foo") - self.assertEqual(ret['version'], "1") - self.assertEqual(ret['release'], "2") - self.assertEqual(ret['epoch'], "12") - - def test_parse_NVRA(self): - """Test the parse_NVRA method""" - - self.assertRaises(AttributeError, koji.parse_NVRA, None) - self.assertRaises(AttributeError, koji.parse_NVRA, 1) - self.assertRaises(AttributeError, koji.parse_NVRA, {}) - self.assertRaises(AttributeError, koji.parse_NVRA, []) - self.assertRaises(koji.GenericError, koji.parse_NVRA, "") - self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo") - self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1") - self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1-") - self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo--1") - self.assertRaises(koji.GenericError, koji.parse_NVRA, "--1") - self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1-1") - self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1-1.") - self.assertRaises(koji.GenericError, koji.parse_NVRA, "foo-1.-1") - ret = koji.parse_NVRA("foo-1-2.i386") - self.assertEqual(ret['name'], "foo") - self.assertEqual(ret['version'], "1") - self.assertEqual(ret['release'], "2") - self.assertEqual(ret['epoch'], "") - self.assertEqual(ret['arch'], "i386") - self.assertEqual(ret['src'], False) - ret = koji.parse_NVRA("12:foo-1-2.src") - self.assertEqual(ret['name'], "foo") - self.assertEqual(ret['version'], "1") - self.assertEqual(ret['release'], "2") - self.assertEqual(ret['epoch'], "12") - self.assertEqual(ret['arch'], "src") - self.assertEqual(ret['src'], True) - - def test_check_NVR(self): - """Test the check_NVR function""" - good = [ - "name-version-release", - "fnord-5.23-17", - {'name': 'foo', 'version': '2.2.2', 'release': '1.1'}, - ] - bad = [ - "this is not an NVR", - {'name': 'foo', 'version': '2.2.2-a', 'release': '1.1'}, - {'name': 'foo', 'version': '2.2.2', 'release': '1.1-b'}, - ] - for value in good: - self.assertEqual(koji.check_NVR(value), True) - for value in bad: - self.assertEqual(koji.check_NVR(value), False) - self.assertRaises(koji.GenericError, - koji.check_NVR, value, strict=True) - - def test_check_NVRA(self): - """Test the check_NVRA function""" - good = [ - "name-version-release.arch", - "fnord-5.23-17.x86_64", - {'name': 'foo', 'version': '2.2.2', 'release': '1.1', - 'arch': 'i686'}, - ] - bad = [ - "this is not an NVRA", - "fnord-5.23-17", - {'name': 'foo', 'version': '2.2.2-a', 'release': '1.1', - 'arch': 'ppc64'}, - {'name': 'foo', 'version': '2.2.2', 'release': '1.1-b', - 'arch': 'x86_64'}, - {'name': 'foo', 'version': '2.2.2', 'release': '1.1', - 'arch': 'x.86.64'}, - ] - for value in good: - self.assertEqual(koji.check_NVRA(value), True) - for value in bad: - self.assertEqual(koji.check_NVRA(value), False) - self.assertRaises(koji.GenericError, - koji.check_NVRA, value, strict=True) - - -class HeaderTestCase(unittest.TestCase): - rpm_path = os.path.join(os.path.dirname(__file__), 'data/rpms/test-deps-1-1.fc24.x86_64.rpm') - rpmdir = os.path.join(os.path.dirname(__file__), 'data/rpms') - - def setUp(self): - self.fd = open(self.rpm_path) - - def tearDown(self): - self.fd.close() - - def test_get_rpm_header(self): - self.assertRaises(IOError, koji.get_rpm_header, 'nonexistent_path') - self.assertRaises(AttributeError, koji.get_rpm_header, None) - self.assertIsInstance(koji.get_rpm_header(self.rpm_path), rpm.hdr) - self.assertIsInstance(koji.get_rpm_header(self.fd), rpm.hdr) - # TODO: - # test ts - - def test_get_header_fields(self): - # incorrect - self.assertRaises(IOError, koji.get_header_fields, 'nonexistent_path', []) - self.assertRaises(koji.GenericError, koji.get_header_fields, self.rpm_path, 'nonexistent_header') - self.assertEqual(koji.get_header_fields(self.rpm_path, []), {}) - - # correct - self.assertEqual(['REQUIRES'], list(koji.get_header_fields(self.rpm_path, ['REQUIRES']).keys())) - self.assertEqual(['PROVIDES', 'REQUIRES'], sorted(koji.get_header_fields(self.rpm_path, ['REQUIRES', 'PROVIDES']))) - hdr = koji.get_rpm_header(self.rpm_path) - self.assertEqual(['REQUIRES'], list(koji.get_header_fields(hdr, ['REQUIRES']).keys())) - - - def test_get_header_field_src(self): - srpm = os.path.join(self.rpmdir, 'test-src-1-1.fc24.src.rpm') - - # without src_arch, should return the build arch (x86_64) - data = koji.get_header_fields(srpm, ['arch']) - self.assertEqual(data['arch'], 'x86_64') - - # with src_arch, should return src - data = koji.get_header_fields(srpm, ['arch'], src_arch=True) - self.assertEqual(data['arch'], 'src') - - - def test_get_header_field_nosrc(self): - srpm1 = os.path.join(self.rpmdir, 'test-nosrc-1-1.fc24.nosrc.rpm') - srpm2 = os.path.join(self.rpmdir, 'test-nopatch-1-1.fc24.nosrc.rpm') - - # without src_arch, should return the build arch (x86_64) - for srpm in srpm1, srpm2: - data = koji.get_header_fields(srpm, ['arch']) - self.assertEqual(data['arch'], 'x86_64') - - # with src_arch, should return nosrc - for srpm in srpm1, srpm2: - data = koji.get_header_fields(srpm, ['arch'], src_arch=True) - self.assertEqual(data['arch'], 'nosrc') - - - @mock.patch('rpm.RPMTAG_NOSOURCE', new=None) - @mock.patch('rpm.RPMTAG_NOPATCH', new=None) - @mock.patch('koji.RPM_SUPPORTS_OPTIONAL_DEPS', new=False) - def test_get_header_field_workarounds(self): - srpm0 = os.path.join(self.rpmdir, 'test-src-1-1.fc24.src.rpm') - srpm1 = os.path.join(self.rpmdir, 'test-nosrc-1-1.fc24.nosrc.rpm') - srpm2 = os.path.join(self.rpmdir, 'test-nopatch-1-1.fc24.nosrc.rpm') - - # should still work even with rpm constants set to None - self.assertEqual([0], koji.get_header_fields(srpm1, ['nosource'])['nosource']) - self.assertEqual([0], koji.get_header_fields(srpm2, ['nopatch'])['nopatch']) - - # should return [] with optional dep support off - self.assertEqual([], koji.get_header_fields(srpm0, ['suggestname'])['suggestname']) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_policy.py b/tests/test_policy.py deleted file mode 100644 index d228df7..0000000 --- a/tests/test_policy.py +++ /dev/null @@ -1,299 +0,0 @@ -from __future__ import absolute_import -import unittest - -from nose.tools import raises - -import koji.policy - - -class MyBoolTest(koji.policy.BoolTest): - name = 'bool_check' - field = 'bool_field' - - -class MyMatchTest(koji.policy.MatchTest): - name = 'match_check' - field = 'match_field' - - -class myvarTest(koji.policy.CompareTest): - name = None - field = 'myvar' - allow_float = False - - -class TestBasicTests(unittest.TestCase): - - @raises(NotImplementedError) - def test_base_test(self): - obj = koji.policy.BaseSimpleTest('something') - obj.run({}) - - def test_true_test(self): - obj = koji.policy.TrueTest('something') - self.assertTrue(obj.run({})) - - def test_false_test(self): - obj = koji.policy.FalseTest('something') - self.assertFalse(obj.run({})) - - def test_all_test(self): - obj = koji.policy.AllTest('something') - self.assertTrue(obj.run({})) - - def test_none_test(self): - obj = koji.policy.NoneTest('something') - self.assertFalse(obj.run({})) - - def test_has_test(self): - obj = koji.policy.HasTest('some thing') - self.assertFalse(obj.run({})) - self.assertFalse(obj.run({'blah': 'blah'})) - self.assertTrue(obj.run({'thing': 'blah'})) - self.assertRaises(koji.GenericError, koji.policy.HasTest, 'something') - - def test_bool_test(self): - obj = koji.policy.BoolTest('some thing') - self.assertFalse(obj.run({'thing': None})) - self.assertFalse(obj.run({'thing': []})) - self.assertTrue(obj.run({'thing': 'yes'})) - - def test_match_test(self): - obj = koji.policy.MatchTest('some thing else') - self.assertFalse(obj.run({'thing': 'elseplus'})) - obj = koji.policy.MatchTest('some thing else*') - self.assertTrue(obj.run({'thing': 'elseplus'})) - - def test_compare_test(self): - obj = koji.policy.CompareTest('compare thing > 2') - self.assertFalse(obj.run({'thing': 1})) - self.assertFalse(obj.run({'thing': 2})) - self.assertTrue(obj.run({'thing': 3})) - - obj = koji.policy.CompareTest('compare thing < 1.5') - self.assertFalse(obj.run({'thing': 3.2})) - self.assertTrue(obj.run({'thing': 1.0})) - - obj = koji.policy.CompareTest('compare thing = 42') - self.assertFalse(obj.run({'thing': 54})) - self.assertTrue(obj.run({'thing': 42})) - - obj = koji.policy.CompareTest('compare thing != 99') - self.assertFalse(obj.run({'thing': 99})) - self.assertTrue(obj.run({'thing': 100})) - - obj = koji.policy.CompareTest('compare thing >= 2') - self.assertFalse(obj.run({'thing': 1})) - self.assertTrue(obj.run({'thing': 2})) - self.assertTrue(obj.run({'thing': 3})) - - obj = koji.policy.CompareTest('compare thing <= 5') - self.assertFalse(obj.run({'thing': 23})) - self.assertTrue(obj.run({'thing': 5})) - self.assertTrue(obj.run({'thing': 0})) - - @raises(koji.GenericError) - def test_invalid_compare_test(self): - koji.policy.CompareTest('some thing LOL 2') - - -class TestDiscovery(unittest.TestCase): - - def test_find_simple_tests(self): - actual = koji.policy.findSimpleTests(koji.policy.__dict__) - expected = { - 'all': koji.policy.AllTest, - 'bool': koji.policy.BoolTest, - 'compare': koji.policy.CompareTest, - 'false': koji.policy.FalseTest, - 'has': koji.policy.HasTest, - 'match': koji.policy.MatchTest, - 'none': koji.policy.NoneTest, - 'true': koji.policy.TrueTest, - } - self.assertDictEqual(expected, actual) - - -class TestRuleHandling(unittest.TestCase): - - def test_simple_rule_set_instantiation(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - rules = ['true :: allow'] - koji.policy.SimpleRuleSet(rules, tests) - - def test_simple_rule_set_all_actions(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - rules = ['true :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - result = obj.all_actions() - self.assertEquals(result, ['allow']) - - def test_simple_rule_set_apply(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - rules = ['true :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, 'allow') - - rules = ['false :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, None) - - def test_custom_rules(self): - tests = koji.policy.findSimpleTests([globals(), koji.policy.__dict__]) - - rules = ['bool_check :: True', 'all :: False'] - for val in True, False: - data = {'bool_field' : val} - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, str(val)) - - rules = ['match_check foo* :: foo', 'match_check * :: bar'] - data = {'match_field' : 'foo1234'} - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, 'foo') - - data = {'match_field' : 'not foo'} - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, 'bar') - - data = {'myvar': 37} - rules = ['myvar = 37 :: get back here'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, 'get back here') - - rules = ['myvar = 2.718281828 :: euler'] - with self.assertRaises(ValueError): - obj = koji.policy.SimpleRuleSet(rules, tests) - - def test_last_rule(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - # no match - rules = ['none :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - self.assertEquals(obj.last_rule(), None) - action = obj.apply(data) - self.assertEquals(obj.last_rule(), '(no match)') - - # simple rule - rules = ['all :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEquals(obj.last_rule(), rules[0]) - - # negate rule - rules = ['none !! allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEquals(obj.last_rule(), rules[0]) - - # nested rule - policy = ''' -all :: { - all :: { - all :: allow - } -} -''' - rules = policy.splitlines() - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - expected = 'all :: ... all :: ... all :: allow' - self.assertEquals(obj.last_rule(), expected) - - def test_unclosed_brace(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - lines = ['true :: {'] - with self.assertRaises(koji.GenericError): - obj = koji.policy.SimpleRuleSet(lines, tests) - - def test_unmatched_brace(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - lines = ['true :: }'] - with self.assertRaises(koji.GenericError): - obj = koji.policy.SimpleRuleSet(lines, tests) - - def test_no_action(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - lines = ['true && true'] - with self.assertRaises(Exception): - obj = koji.policy.SimpleRuleSet(lines, tests) - - def test_missing_handler(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - lines = ['NOSUCHHANDLER && true :: allow'] - with self.assertRaises(koji.GenericError): - obj = koji.policy.SimpleRuleSet(lines, tests) - - def test_complex_policy(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - policy = ''' -# This is a comment in the test policy - -#^blank line -# commented test && true :: some result - -# First some rules that should never match -false :: ERROR -none :: ERROR - -true !! ERROR -all !! ERROR - -false && true && true :: ERROR -none && true && true :: ERROR - -has NOSUCHFIELD :: ERROR - -# nesting -has DEPTH :: { - match DEPTH 1 :: 1 - all :: { - match DEPTH 2 :: 2 - all :: { - match DEPTH 3 :: 3 - all :: { - match DEPTH 4 :: 4 - all :: END - } - } - } -} -''' - - lines = policy.splitlines() - - for depth in ['1', '2', '3', '4']: - data = {'DEPTH': depth} - obj = koji.policy.SimpleRuleSet(lines, tests) - action = obj.apply(data) - self.assertEqual(action, depth) - - data = {'DEPTH': '99'} - obj = koji.policy.SimpleRuleSet(lines, tests) - action = obj.apply(data) - self.assertEqual(action, 'END') - - actions = set(obj.all_actions()) - self.assertEquals(actions, set(['1', '2', '3', '4', 'ERROR', 'END'])) - - diff --git a/tests/test_profiles.py b/tests/test_profiles.py deleted file mode 100644 index 3903db1..0000000 --- a/tests/test_profiles.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import absolute_import -import unittest - -import koji -import sys -import threading -import traceback -from six.moves import range - - -class ProfilesTestCase(unittest.TestCase): - - def test_profile_threading(self): - """ Test that profiles thread safe""" - # see: https://pagure.io/koji/issue/58 and https://pagure.io/pungi/issue/253 - # loop a few times to increase chances of hitting race conditions - for i in range(20): - errors = {} - threads = [threading.Thread(target=stress, args=(errors, _)) for _ in range(100)] - for t in threads: - t.start() - for t in threads: - t.join(30) - for n in errors: - err = errors[n] - if err is not None: - print(err) - assert False - - -def stress(errors, n): - errors[n] = "Failed to start" - try: - koji.get_profile_module('koji') - except Exception: - # if we don't catch this, nose seems to ignore the test - errors[n] = ''.join(traceback.format_exception(*sys.exc_info())) - return - else: - errors[n] = None - - - diff --git a/tests/test_tasks.py b/tests/test_tasks.py deleted file mode 100644 index 551cb05..0000000 --- a/tests/test_tasks.py +++ /dev/null @@ -1,715 +0,0 @@ -from __future__ import absolute_import -import random -from os import path, makedirs -from shutil import rmtree -from tempfile import gettempdir -from unittest import TestCase -from mock import patch, Mock, call - -import koji -from koji.tasks import BaseTaskHandler, FakeTask, ForkTask, SleepTask, \ - WaitTestTask, scan_mounts, umount_all, \ - safe_rmtree -import six - - -def get_fake_mounts_file(): - """ Returns contents of /prc/mounts in a file-like object - """ - return six.StringIO(six.text_type(( - 'sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' - 'proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0\n' - 'devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=238836k,nr_inodes=59709,mode=755 0 0\n' - 'securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0\n' - 'tmpfs /dev/shm\040(deleted) tmpfs rw,seclabel,nosuid,nodev 0 0\n' - 'devpts /dev/pts devpts rw,seclabel,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0\n' - 'tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0\n' - 'tmpfs /sys/fs/cgroup tmpfs ro,seclabel,nosuid,nodev,noexec,mode=755 0 0\n' - 'pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' - 'cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0\n' - 'cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0\n' - 'cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0\n' - 'cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0\n' - 'cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0\n' - 'cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0\n' - 'cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0\n' - 'cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0\n' - 'cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0\n' - 'configfs /sys/kernel/config configfs rw,relatime 0 0\n' - ))) - - -def get_temp_dir_root(): - return path.join(gettempdir(), 'koji_tests') - - -def get_tmp_dir_path(folder_starts_with): - return path.join(get_temp_dir_root(), ('{0}{1}'.format(folder_starts_with, random.randint(1, 999999999999)))) - - -class TestTask(BaseTaskHandler): - Methods = ['some_method'] - _taskWeight = 5.2 - - def handler(self, *args): - return 42 - - -class TestTaskNoWeight(BaseTaskHandler): - Methods = ['some_method'] - - def handler(self, *args): - return 42 - - -class BadTask(BaseTaskHandler): - Methods = ['some_method'] - - -class TasksTestCase(TestCase): - - def tearDown(self): - temp_dir_root = get_temp_dir_root() - - if path.isdir(temp_dir_root): - rmtree(get_temp_dir_root()) - - def test_scan_mounts_results(self): - """ Tests the scan_mounts function with a mocked /proc/mounts file. A list containing mount points - starting with /dev are expected to be returned from the function based on the function input of /dev. - """ - fake_mounts_file_contents = get_fake_mounts_file() - - with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True): - self.assertIn(scan_mounts('/dev'), [['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/hugepages', '/dev'], - ['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/console', '/dev']]) - - def test_scan_mounts_no_results(self): - """ Tests the scan_mounts function with a mocked /proc/mounts file. An argument of /nonexistent/path - to the function should return an empty list. - """ - fake_mounts_file_contents = get_fake_mounts_file() - - with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True): - self.assertEquals(scan_mounts('/nonexistent/path'), []) - - # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all - @patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], []]) - @patch('os.spawnvp', return_value=0) - def test_umount_all(self, mocked_spawnvp, mocked_scan_mounts): - """ Tests that umount_all returns nothing when successful. - """ - self.assertEquals(umount_all('/test'), None) - - # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all - @patch('koji.tasks.scan_mounts', return_value=['/dev/shm', '/dev/pts', '/dev/mqueue']) - @patch('os.spawnvp', return_value=1) - def test_umount_all_failure(self, mocked_spawnvp, mocked_scan_mounts): - """ Tests that umount_all raises an exception when a mount point can't be unmounted. - """ - try: - umount_all('/dev') - raise Exception('A GenericError was not raised during the test') - except koji.GenericError as e: - self.assertEquals(e.args[0], - 'umount failed (exit code 1) for /dev/shm') - - # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all - @patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], ['/dev/shm', '/dev/mqueue']]) - @patch('os.spawnvp', return_value=0) - def test_umount_all_unexpected_failure(self, mocked_spawnvp, mocked_scan_mounts): - """ Tests that umount_all will fail if the command to unmount the mount points was successful - but a second run of scan_mounts still shows some of the unmount mount points still mounted. - """ - try: - umount_all('/dev') - raise Exception('A GenericError was not raised during the test') - except koji.GenericError as e: - self.assertEquals(e.args[0], 'Unmounting incomplete: [\'/dev/shm\', \'/dev/mqueue\']') - - @patch('os.path.isfile', return_value=True) - @patch('os.remove') - def test_safe_rmtree_file(self, mock_remove, mock_isfile): - """ Tests that the safe_rmtree function returns nothing when the path parameter is a file. - """ - self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None) - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=True) - @patch('os.remove') - def test_safe_rmtree_link(self, mock_remove, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns nothing when the path parameter is a link. - """ - self.assertEquals(safe_rmtree('/mnt/folder/some_link', False, True), None) - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=False) - @patch('os.path.exists', return_value=False) - def test_safe_rmtree_does_not_exist(self, mock_exists, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns nothing if the path does not exist. - """ - self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None) - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=False) - @patch('os.path.exists', return_value=True) - @patch('os.system', side_effect=[0, 0]) - def test_safe_rmtree_directory(self, mock_os_system, mock_exists, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns nothing when the path is a directory. - """ - self.assertEquals(safe_rmtree('/mnt/folder', False, True), 0) - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=False) - @patch('os.path.exists', return_value=True) - @patch('os.system', side_effect=[1, 0]) - def test_safe_rmtree_directory_scrub_file_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory - and the scrub of the files in the directory fails. - """ - try: - safe_rmtree('/mnt/folder', False, True) - raise Exception('A GenericError was not raised during the test') - except koji.GenericError as e: - self.assertEquals(e.args[0], 'file removal failed (code 1) for /mnt/folder') - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=False) - @patch('os.path.exists', return_value=True) - @patch('os.system', side_effect=[0, 1]) - def test_safe_rmtree_directory_scrub_directory_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory - and the scrub of the directories in the directory fails. - """ - try: - safe_rmtree('/mnt/folder', False, True) - raise Exception('A GenericError was not raised during the test') - except koji.GenericError as e: - self.assertEquals(e.args[0], 'dir removal failed (code 1) for /mnt/folder') - - def test_BaseTaskHandler_handler_not_set(self): - """ Tests that an exception is thrown when the handler function is not overwritten by the child class. - """ - obj = BadTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('BadTask'))) - try: - obj.handler() - raise Exception('The NotImplementedError exception was not raised') - except NotImplementedError as e: - self.assertEquals(e.__class__.__name__, 'NotImplementedError') - - def test_BaseTaskHandler_weight_default(self): - """ Tests that the weight function returns 1.0 when _taskWeight is not set in the child class' definition. - """ - obj = TestTaskNoWeight(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTaskNoWeight'))) - self.assertEquals(obj.weight(), 1.0) - - def test_BaseTaskHandler_weight_set(self): - """ Tests that the weight function returns the value of _taskWeight when it is set in the - child class' definition. - """ - obj = TestTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTask'))) - self.assertEquals(obj.weight(), 5.2) - - def test_BaseTaskHandler_createWorkdir_workdir_not_defined(self): - """ Tests that the createWorkdir function does nothing when the workdir member variable is set to None. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.workdir = None - obj.createWorkdir() - self.assertEquals(path.isdir(temp_path), False) - - # This patch removes the dependence on removeWorkdir functioning - @patch('{0}.TestTask.removeWorkdir'.format(__name__)) - def test_BaseTaskHandler_createWorkdir(self, mock_removeWorkDir): - """ Tests that the createWorkdir function creates a folder based on the path given to the - workdir member variable. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.createWorkdir() - self.assertEquals(path.isdir(temp_path), True) - rmtree(get_temp_dir_root()) - - def test_BaseTaskHandler_removeWorkdir(self): - """ Tests that the removeWOrkdir function deletes a folder based on the path given to the - workdir member variable. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - self.assertEquals(path.isdir(temp_path), True) - obj.removeWorkdir() - self.assertEquals(path.isdir(temp_path), False) - - def test_BaseTaskHandler_wait_all_done(self): - """ Tests that the wait function returns the subtask results of when the taskWait function returns only - two finished tasks - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - obj.session = Mock() - obj.session.host.taskSetWait.return_value = None - obj.session.host.taskWait.return_value = [[1551234, 1591234], []] - taskWaitResults = [ - ['1551234', { - 'brootid': 2342345, - 'logs': ['tasks/5678/12345678/root.log', - 'tasks/5678/12345678/state.log', - 'tasks/5678/12345678/build.log'], - 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' - }], - - ['1591234', { - 'brootid': 1231234, - 'logs': ['tasks/6789/2345678/root.log', - 'tasks/6789/2345678/state.log', - 'tasks/6789/2345678/build.log'], - 'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'], - 'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm'] - }] - ] - - obj.session.host.taskWaitResults.return_value = taskWaitResults - self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults)) - obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) - obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[]) - - def test_BaseTaskHandler_wait_some_not_done(self): - """ Tests that the wait function returns the one finished subtask results of - when the taskWait function returns one finished task and one unfinished - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - obj.session = Mock() - obj.session.host.taskSetWait.return_value = None - obj.session.host.taskWait.return_value = [[1551234], [1591234]] - taskWaitResults = [ - ['1551234', { - 'brootid': 2342345, - 'logs': ['tasks/5678/12345678/root.log', - 'tasks/5678/12345678/state.log', - 'tasks/5678/12345678/build.log'], - 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' - }] - ] - - obj.session.host.taskWaitResults.return_value = taskWaitResults - self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults)) - obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) - obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234], canfail=[]) - - @patch('signal.pause', return_value=None) - def test_BaseTaskHandler_wait_some_not_done_all_set(self, mock_signal_pause): - """ Tests that the wait function returns the two subtask results since the all kwarg is set to True. - The taskWait function should first return one finished and one unfinished task, then the second time it should - return two finished tasks. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - obj.session = Mock() - obj.session.host.taskSetWait.return_value = None - obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]] - taskWaitResults = [ - ['1551234', { - 'brootid': 2342345, - 'logs': ['tasks/5678/12345678/root.log', - 'tasks/5678/12345678/state.log', - 'tasks/5678/12345678/build.log'], - 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' - }], - - ['1591234', { - 'brootid': 1231234, - 'logs': ['tasks/6789/2345678/root.log', - 'tasks/6789/2345678/state.log', - 'tasks/6789/2345678/build.log'], - 'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'], - 'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm'] - }] - ] - - obj.session.getTaskResult.side_effect - - obj.session.host.taskWaitResults.return_value = taskWaitResults - self.assertEquals(obj.wait([1551234, 1591234], all=True), dict(taskWaitResults)) - obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) - obj.session.host.taskWait.assert_has_calls([call(12345678), call(12345678)]) - mock_signal_pause.assert_called_once_with() - obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[]) - - def test_BaseTaskHandler_wait_some_not_done_all_set_failany_set_failed_task(self): - """ Tests that the wait function raises an exception when one of the subtask fails when the failany flag is set - to True. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - obj.session = Mock() - obj.session.host.taskSetWait.return_value = None - obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]] - obj.session.getTaskResult.side_effect = koji.GenericError('Uh oh, we\'ve got a problem here!') - try: - obj.wait([1551234, 1591234], all=True, failany=True) - raise Exception('A GeneralError was not raised.') - except koji.GenericError as e: - self.assertEquals(e.args[0], 'Uh oh, we\'ve got a problem here!') - obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) - - def test_BaseTaskHandler_getUploadDir(self): - """ Tests that the getUploadDir function returns the appropriate path based on the id of the handler. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - self.assertEquals(obj.getUploadDir(), 'tasks/123/123') - - # This patch removes the dependence on getUploadDir functioning - @patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123') - def test_BaseTaskHandler_uploadFile(self, mock_getUploadDir): - """ Tests that the uploadFile function calls the uploadWrapper function on the session member variable - with the correct input - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - temp_file = path.join(temp_path, 'test.txt') - with open(temp_file, 'w') as temp_file_handler: - temp_file_handler.write('Test') - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - self.assertEquals(obj.uploadFile(temp_file), None) - obj.session.uploadWrapper.assert_called_once_with(temp_file, 'tasks/123/123', None, volume=None) - - # This patch removes the dependence on getUploadDir functioning - @patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123') - def test_BaseTaskHandler_uploadFile_no_content(self, mock_getUploadDir): - """ Tests that the uploadFile function calls the uploadWrapper function on the session member variable - without including empty files. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - temp_file = path.join(temp_path, 'test.txt') - temp_file_handler = open(temp_file, 'w') - temp_file_handler.close() - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - self.assertEquals(obj.uploadFile(temp_file), None) - self.assertEquals(obj.session.uploadWrapper.called, False) - - def test_BaseTaskHandler_uploadTree(self): - """ Tests that the uploadTree function calls the uploadFile function with the correct parameters. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - dummy_dir = path.join(temp_path, 'some_directory') - makedirs(dummy_dir) - - dummy_file = path.join(temp_path, 'test.txt') - with open(dummy_file, 'w') as temp_file_handler: - temp_file_handler.write('Test') - - dummy_file2 = path.join(dummy_dir, 'test2.txt') - with open(dummy_file2, 'w') as temp_file_handler2: - temp_file_handler2.write('Test2') - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.uploadFile = Mock() - obj.uploadFile.return_value = None - self.assertEquals(obj.uploadTree(temp_path), None) - obj.uploadFile.assert_has_calls([call(dummy_file, '', volume=None), call(dummy_file2, 'some_directory', volume=None)]) - - @patch('os.lchown', return_value=None) - def test_BaseTaskHandler_chownTree(self, mock_lchown): - """ Tests that the chownTree functions as expected on dummy files created in a temp directory - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - dummy_file = path.join(temp_path, 'test.txt') - dummy_file_handler = open(dummy_file, 'w') - dummy_file_handler.close() - - dummy_file2 = path.join(temp_path, 'test2.txt') - dummy_file_handler2 = open(dummy_file2, 'w') - dummy_file_handler2.close() - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - self.assertEquals(obj.chownTree(temp_path, 2, 0), None) - mock_lchown.assert_has_calls([call(temp_path, 2, 0), call(dummy_file2, 2, 0), call(dummy_file, 2, 0)], any_order=True) - - def test_BaseTaskHandler_localPath_file_exists(self): - """ Tests the localPath function to ensure that when a file exists, it returns that path without - trying to download it. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - local_folder = path.join(temp_path, 'local') - makedirs(local_folder) - - dummy_file = path.join(local_folder, 'test.txt') - dummy_file_handler = open(dummy_file, 'w') - dummy_file_handler.close() - options = Mock() - options.topurl = 'https://www.domain.local' - obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) - self.assertEquals(obj.localPath('test.txt'), dummy_file) - - @patch('six.moves.urllib.request.urlopen', return_value=six.StringIO(six.text_type('Important things\nSome more important things\n'))) - def test_BaseTaskHandler_localPath_no_file(self, mock_urlopen): - """ - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - local_folder = path.join(temp_path, 'local') - makedirs(local_folder) - - target_file_path = path.join(local_folder, 'test.txt') - - options = Mock() - options.topurl = 'https://www.domain.local' - obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) - - self.assertEquals(obj.localPath('test.txt'), target_file_path) - mock_urlopen.assert_called_once_with('https://www.domain.local/test.txt') - - def test_BaseTaskHandler_localPath_no_topurl(self): - """ Tests that the localPath function returns a path when options.topurl is not defined. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - options = Mock() - options.topurl = None - options.topdir = get_temp_dir_root() - obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) - - self.assertEquals(obj.localPath('test.txt'), path.join(get_temp_dir_root(), 'test.txt')) - - def test_BaseTaskHandler_find_arch(self): - """ Tests that the find_arch function returns the input for arch when the input is not "noarch". - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - self.assertEquals(obj.find_arch('x86_64', None, None), 'x86_64') - - def test_BaseTaskHandler_find_arch_noarch_bad_host(self): - """ Tests that the find_arch function raises an exception when the host parameter doesn't contain a - value for the arches key. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - host = {'arches': None, 'name': 'test.domain.local'} - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - try: - obj.find_arch('noarch', host, None) - raise Exception('The BuildError Exception was not raised') - except koji.BuildError as e: - self.assertEquals(e.args[0], 'No arch list for this host: test.domain.local') - - def test_BaseTaskHandler_find_arch_noarch_bad_tag(self): - """ Tests that the find_arch function raises an exception when the tag parameter doesn't contain a - value for the arches key. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - host = {'arches': 'x86_64', 'name': 'test.domain.local'} - tag = {'arches': None, 'name': 'some_package-1.2-build'} - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - try: - obj.find_arch('noarch', host, tag) - raise Exception('The BuildError Exception was not raised') - except koji.BuildError as e: - self.assertEquals(e.args[0], 'No arch list for tag: some_package-1.2-build') - - def test_BaseTaskHandler_find_arch_noarch(self): - """ Tests that the find_arch function finds a match of x86_64 when the host only supports x86_64 - and the tag supports x86_64 and aarch64. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - host = {'arches': 'x86_64', 'name': 'test.domain.local'} - tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'} - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - self.assertEquals(obj.find_arch('noarch', host, tag), 'x86_64') - - def test_BaseTaskHandler_find_arch__noarch_no_match(self): - """ Tests that the find_arch function raises an exception when there isn't a common arch supported between - the host and the tag. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - host = {'arches': 'i386', 'name': 'test.domain.local'} - tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'} - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - try: - obj.find_arch('noarch', host, tag) - raise Exception('The BuildError Exception was not raised') - except koji.BuildError as e: - self.assertEquals(e.args[0], ('host test.domain.local (i386) does not support ' - 'any arches of tag some_package-1.2-build (aarch64, x86_64)')) - - def test_getRepo_tied_to_session(self): - """ Tests that the getRepo function calls session.getRepo(), and returns the result when successful - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - repo_dict = { - 'create_event': 13635166, - 'create_ts': 1469039671.5743899, - 'creation_time': '2016-07-20 18:34:31.574386', - 'id': 1630631, - 'state': 1 - } - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - obj.session.getRepo.return_value = repo_dict - - self.assertEquals(obj.getRepo(8472), repo_dict) - - @patch('{0}.TestTask.wait'.format(__name__)) - def test_getRepo_not_tied_to_session(self, mock_wait): - """ Tests that the getRepo function waits until the results are available for session.getRepo, when it is - not available at the start of the function call. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - repo_dict = { - 'create_event': 13413120, - 'create_ts': 1466140834.9119599, - 'creation_time': '2016-06-17 05:20:34.911962', - 'id': 1592850, - 'state': 1 - } - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - obj.session.getRepo.return_value = None - obj.session.getTag.return_value = { - 'arches': 'i386 ia64 x86_64 ppc s390 s390x ppc64', - 'extra': {}, - 'id': 851, - 'locked': True, - 'maven_include_all': False, - 'maven_support': False, - 'name': 'dist-3.0E-build', - 'perm': None, - 'perm_id': None - } - obj.session.getBuildTargets.return_value = [{ - 'build_tag': 3093, - 'build_tag_name': 'dist-6E-dsrv-9-build', - 'dest_tag': 3092, - 'dest_tag_name': 'dist-6E-dsrv-9-qu-candidate', - 'id': 851, - 'name': 'dist-6E-dsrv-9-qu-candidate' - }] - - obj.session.host.subtask.return_value = 123 - mock_wait.return_value = {123: repo_dict} - - self.assertEquals(obj.getRepo(851), repo_dict) - obj.session.getRepo.assert_called_once_with(851) - obj.session.getTag.assert_called_once_with(851, strict=True) - - @patch('{0}.TestTask.wait'.format(__name__)) - def test_getRepo_not_tied_to_session_no_build_targets(self, mock_wait): - """ Tests that the getRepo function raises an exception when session.getBuildTargets returns an empty list - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - obj.session.getRepo.return_value = None - obj.session.getTag.return_value = { - 'arches': 'i686 x86_64 ppc ppc64 ppc64le s390 s390x aarch64', - 'extra': {}, - 'id': 8472, - 'locked': False, - 'maven_include_all': False, - 'maven_support': False, - 'name': 'rhel-7.3-build', - 'perm': 'admin', - 'perm_id': 1 - } - obj.session.getBuildTargets.return_value = [] - - try: - obj.getRepo(8472) - raise Exception('The BuildError Exception was not raised') - except koji.BuildError as e: - obj.session.getRepo.assert_called_once_with(8472) - self.assertEquals(e.args[0], 'no repo (and no target) for tag rhel-7.3-build') - - def test_FakeTask_handler(self): - """ Tests that the FakeTest handler can be instantiated and returns 42 when run - """ - obj = FakeTask(123, 'someMethod', ['random_arg'], None, None, (get_tmp_dir_path('FakeTask'))) - self.assertEquals(obj.run(), 42) - - @patch('time.sleep') - def test_SleepTask_handler(self, mock_sleep): - """ Tests that the SleepTask handler can be instantiated and runs appropriately based on the input - """ - obj = SleepTask(123, 'sleep', [5], None, None, (get_tmp_dir_path('SleepTask'))) - obj.run() - mock_sleep.assert_called_once_with(5) - - @patch('os.spawnvp') - def test_ForkTask_handler(self, mock_spawnvp): - """ Tests that the ForkTask handler can be instantiated and runs appropriately based on the input - """ - obj = ForkTask(123, 'fork', [1, 20], None, None, (get_tmp_dir_path('ForkTask'))) - obj.run() - mock_spawnvp.assert_called_once_with(1, 'sleep', ['sleep', '20']) - - @patch('signal.pause', return_value=None) - @patch('time.sleep') - def test_WaitTestTask_handler(self, mock_sleep, mock_signal_pause): - """ Tests that the WaitTestTask handler can be instantiated and runs appropriately based on the input - Specifically, that forking works and canfail behaves correctly. - """ - self.mock_subtask_id = 1 - def mock_subtask(method, arglist, id, **opts): - self.assertEqual(method, 'sleep') - task_id = self.mock_subtask_id - self.mock_subtask_id += 1 - obj = SleepTask(task_id, 'sleep', arglist, None, None, (get_tmp_dir_path('SleepTask'))) - obj.run() - return task_id - - mock_taskWait = [ - [[], [1, 2, 3, 4]], - [[3, 4], [1, 2]], - [[1, 2, 3, 4], []], - ] - def mock_getTaskResult(task_id): - if task_id == 4: - raise koji.GenericError() - - - obj = WaitTestTask(123, 'waittest', [3], None, None, (get_tmp_dir_path('WaitTestTask'))) - obj.session = Mock() - obj.session.host.subtask.side_effect = mock_subtask - obj.session.getTaskResult.side_effect = mock_getTaskResult - obj.session.host.taskWait.side_effect = mock_taskWait - obj.session.host.taskWaitResults.return_value = [ ['1', {}], ['2', {}], ['3', {}], ['4', {}], ] - obj.run() - #self.assertEqual(mock_sleep.call_count, 4) - obj.session.host.taskSetWait.assert_called_once() - obj.session.host.taskWait.assert_has_calls([call(123), call(123), call(123)]) - # getTaskResult should be called in 2nd round only for task 3, as 4 - # will be skipped as 'canfail' - obj.session.getTaskResult.assert_has_calls([call(3)]) diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index 1ff221c..0000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,493 +0,0 @@ -from __future__ import absolute_import -import mock -import unittest -from mock import call - -import os -import optparse -import six.moves.configparser -import koji -import koji.util - - -class EnumTestCase(unittest.TestCase): - - def test_enum_create_alpha(self): - """ Test that we can create an Enum with alphabet names """ - koji.Enum(('one', 'two', 'three')) - - def test_enum_bracket_access(self): - """ Test bracket access. """ - test = koji.Enum(('one', 'two', 'three')) - self.assertEquals(test['one'], 0) - self.assertEquals(test['two'], 1) - self.assertEquals(test['three'], 2) - - with self.assertRaises(KeyError): - test['does not exist'] - - def test_enum_getter_access(self): - """ Test getter access. """ - test = koji.Enum(('one', 'two', 'three')) - self.assertEquals(test.get('one'), 0) - self.assertEquals(test.get('two'), 1) - self.assertEquals(test.get('three'), 2) - self.assertEquals(test.get('does not exist'), None) - - def test_enum_slice_access(self): - """ Test slice access. """ - test = koji.Enum(('one', 'two', 'three')) - self.assertEquals(test[1:], ('two', 'three')) - - -def mock_open(): - """Return the right patch decorator for open""" - if six.PY2: - return mock.patch('__builtin__.open') - else: - return mock.patch('builtins.open') - - -class MiscFunctionTestCase(unittest.TestCase): - - @mock.patch('os.path.exists') - @mock.patch('os.path.islink') - @mock.patch('shutil.move') - def test_safer_move(self, move, islink, exists): - """Test safer_move function""" - src = '/FAKEPATH/SRC' - dst = '/FAKEPATH/DST' - - # good args - exists.return_value = False - islink.return_value = False - koji.util.safer_move(src, dst) - exists.assert_called_once_with(dst) - islink.assert_called_once_with(dst) - move.assert_called_once_with(src, dst) - - move.reset_mock() - islink.reset_mock() - exists.reset_mock() - - # existing dst - exists.return_value = True - with self.assertRaises(koji.GenericError): - koji.util.safer_move(src, dst) - exists.assert_called_once_with(dst) - move.assert_not_called() - - move.reset_mock() - islink.reset_mock() - exists.reset_mock() - - # symlink dst - exists.return_value = False - islink.return_value = True - with self.assertRaises(koji.GenericError): - koji.util.safer_move(src, dst) - exists.assert_called_once_with(dst) - islink.assert_called_once_with(dst) - move.assert_not_called() - - @mock_open() - @mock.patch('six.moves.urllib.request.urlopen') - @mock.patch('tempfile.TemporaryFile') - @mock.patch('shutil.copyfileobj') - def test_openRemoteFile(self, m_copyfileobj, m_TemporaryFile, - m_urlopen, m_open): - """Test openRemoteFile function""" - - mocks = [m_open, m_copyfileobj, m_TemporaryFile, m_urlopen] - - topurl = 'http://example.com/koji' - path = 'relative/file/path' - url = 'http://example.com/koji/relative/file/path' - - # using topurl, no tempfile - fo = koji.openRemoteFile(path, topurl) - m_urlopen.assert_called_once_with(url) - m_urlopen.return_value.close.assert_called_once() - m_TemporaryFile.assert_called_once_with(dir=None) - m_copyfileobj.assert_called_once() - m_open.assert_not_called() - assert fo is m_TemporaryFile.return_value - - for m in mocks: - m.reset_mock() - - # using topurl + tempfile - tempdir = '/tmp/koji/1234' - fo = koji.openRemoteFile(path, topurl, tempdir=tempdir) - m_urlopen.assert_called_once_with(url) - m_urlopen.return_value.close.assert_called_once() - m_TemporaryFile.assert_called_once_with(dir=tempdir) - m_copyfileobj.assert_called_once() - m_open.assert_not_called() - assert fo is m_TemporaryFile.return_value - - for m in mocks: - m.reset_mock() - - # using topdir - topdir = '/mnt/mykojidir' - filename = '/mnt/mykojidir/relative/file/path' - fo = koji.openRemoteFile(path, topdir=topdir) - m_urlopen.assert_not_called() - m_TemporaryFile.assert_not_called() - m_copyfileobj.assert_not_called() - m_open.assert_called_once_with(filename) - assert fo is m_open.return_value - - for m in mocks: - m.reset_mock() - - # using neither - with self.assertRaises(koji.GenericError): - koji.openRemoteFile(path) - for m in mocks: - m.assert_not_called() - - -class MavenUtilTestCase(unittest.TestCase): - """Test maven relative functions""" - maxDiff = None - - def test_maven_config_opt_adapter(self): - """Test class MavenConfigOptAdapter""" - conf = mock.MagicMock() - section = 'section' - adapter = koji.util.MavenConfigOptAdapter(conf, section) - self.assertIs(adapter._conf, conf) - self.assertIs(adapter._section, section) - conf.has_option.return_value = True - adapter.goals - adapter.properties - adapter.someattr - conf.has_option.return_value = False - with self.assertRaises(AttributeError) as cm: - adapter.noexistsattr - self.assertEquals(cm.exception.args[0], 'noexistsattr') - self.assertEquals(conf.mock_calls, [call.has_option(section, 'goals'), - call.get(section, 'goals'), - call.get().split(), - call.has_option(section, 'properties'), - call.get(section, 'properties'), - call.get().splitlines(), - call.has_option(section, 'someattr'), - call.get('section', 'someattr'), - call.has_option(section, 'noexistsattr')]) - - def test_maven_opts(self): - """Test maven_opts function""" - values = optparse.Values({ - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': ['p1=1', 'p2', 'p3=ppp3'], - 'envs': ['e1=1', 'e2=2'], - 'buildrequires': ['r1', 'r2'], - 'otheropts': 'others'}) - self.assertEqual(koji.util.maven_opts(values), { - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, - 'envs': {'e1': '1', 'e2': '2'}}) - self.assertEqual(koji.util.maven_opts(values, chain=True, scratch=True), { - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, - 'envs': {'e1': '1', 'e2': '2'}, - 'buildrequires': ['r1', 'r2']}) - self.assertEqual(koji.util.maven_opts(values, chain=False, scratch=True), { - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, - 'envs': {'e1': '1', 'e2': '2'}, - 'scratch': True}) - values = optparse.Values({'envs': ['e1']}) - with self.assertRaises(ValueError) as cm: - koji.util.maven_opts(values) - self.assertEqual( - cm.exception.args[0], - "Environment variables must be in NAME=VALUE format") - - def test_maven_params(self): - """Test maven_params function""" - config = self._read_conf('/data/maven/config.ini') - self.assertEqual(koji.util.maven_params(config, 'pkg1'), { - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, - 'envs': {'e1': '1', 'e2': '2'}}) - - def test_wrapper_params(self): - """Test wrapper_params function""" - config = self._read_conf('/data/maven/config.ini') - self.assertEqual(koji.util.wrapper_params(config, 'pkg2'), { - 'type': 'maven', - 'scmurl': 'scmurl', - 'buildrequires': ['r1', 'r2'], - 'create_build': True}) - self.assertEqual(koji.util.wrapper_params(config, 'pkg2', scratch=True), { - 'type': 'maven', - 'scmurl': 'scmurl', - 'buildrequires': ['r1', 'r2']}) - - def test_parse_maven_params(self): - """Test parse_maven_params function""" - path = os.path.dirname(__file__) - # single conf file, and chain=False, scratch=False - confs = path + '/data/maven/config.ini' - self.assertEqual(koji.util.parse_maven_params(confs), { - 'pkg1': { - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, - 'envs': {'e1': '1', 'e2': '2'}}, - 'pkg2': { - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, - 'envs': {'e1': '1', 'e2': '2'}}, - 'pkg3': { - 'type': 'wrapper', - 'scmurl': 'scmurl', - 'buildrequires': ['r1'], - 'create_build': True}}) - - # multiple conf file, and chain=True, scratch=False - confs = [confs, path + '/data/maven/good_config.ini'] - self.assertEqual(koji.util.parse_maven_params(confs, chain=True), { - 'pkg1': { - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, - 'envs': {'e1': '1', 'e2': '2'}, - 'buildrequires': ['r1', 'r2']}, - 'pkg2': { - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, - 'envs': {'e1': '1', 'e2': '2'}, - 'buildrequires': ['r1', 'r2']}, - 'pkg3': { - 'type': 'wrapper', - 'scmurl': 'scmurl', - 'buildrequires': ['r1'], - 'create_build': True}, - 'pkg4': { - 'scmurl': 'scmurl', - 'patches': 'patchurl', - 'specfile': 'specfile', - 'goals': ['goal1', 'goal2'], - 'profiles': ['profile1', 'profile2'], - 'packages': ['pkg1', 'pkg2'], - 'jvm_options': ['--opt1', '--opt2=val'], - 'maven_options': ['--opt1', '--opt2=val'], - 'properties': {'p2': None, 'p3': 'ppp3', 'p1': '1'}, - 'envs': {'e1': '1', 'e2': '2'}, - 'buildrequires': ['r1', 'r2']}, - }) - - # bad conf file - type=wrapper and len(params.get('buildrequires')!=1) - confs = path + '/data/maven/bad_wrapper_config.ini' - with self.assertRaises(ValueError) as cm: - koji.util.parse_maven_params(confs) - self.assertEqual( - cm.exception.args[0], - 'A wrapper-rpm must depend on exactly one package') - - # bad conf file - type is neither 'maven' nor 'wrapper') - confs = path + '/data/maven/bad_type_config.ini' - with self.assertRaises(ValueError) as cm: - koji.util.parse_maven_params(confs) - self.assertEqual(cm.exception.args[0], 'Unsupported build type: other') - - # bad conf file - no scmurl param - confs = path + '/data/maven/bad_scmurl_config.ini' - with self.assertRaises(ValueError) as cm: - koji.util.parse_maven_params(confs) - self.assertEqual( - cm.exception.args[0], - 'pkg is missing the scmurl parameter') - - # bad conf file - empty dict returned - confs = path + '/data/maven/bad_empty_config.ini' - with self.assertRaises(ValueError) as cm: - koji.util.parse_maven_params(confs) - self.assertEqual( - cm.exception.args[0], - 'No sections found in: %s' % - confs) - - def test_parse_maven_param(self): - """Test parse_maven_param function""" - path = os.path.dirname(__file__) - # single conf file, and chain=False, scratch=False - confs = path + '/data/maven/config.ini' - with mock.patch('koji.util.parse_maven_params', - return_value={ - 'pkg1': {'sth': 'pkg1'}, - 'pkg2': {'sth': 'pkg2'}, - 'pkg3': {'sth': 'pkg3'}}): - self.assertEqual( - koji.util.parse_maven_param( - confs, section='pkg1'), { - 'pkg1': { - 'sth': 'pkg1'}}) - with self.assertRaises(ValueError) as cm: - koji.util.parse_maven_param(confs, section='pkg4') - self.assertEqual( - cm.exception.args[0], - 'Section pkg4 does not exist in: %s' % - confs) - with self.assertRaises(ValueError) as cm: - koji.util.parse_maven_param(confs) - self.assertEqual( - cm.exception.args[0], - 'Multiple sections in: %s, you must specify the section' % - confs) - with mock.patch('koji.util.parse_maven_params', return_value={ - 'pkg': {'sth': 'pkg'}}): - self.assertEqual(koji.util.parse_maven_param(confs), - {'pkg': {'sth': 'pkg'}}) - - def test_parse_maven_chain(self): - """Test parse_maven_chain function""" - path = os.path.dirname(__file__) - confs = path + '/data/maven/config.ini' - with mock.patch('koji.util.parse_maven_params', - return_value={ - 'pkg1': {'buildrequires': ['pkg2', 'pkg3']}, - 'pkg2': {'buildrequires': ['pkg3']}, - 'pkg3': {'sth': 'sth'}}): - self.assertEqual(koji.util.parse_maven_chain(confs), - {'pkg1': {'buildrequires': ['pkg2', 'pkg3']}, - 'pkg2': {'buildrequires': ['pkg3']}, - 'pkg3': {'sth': 'sth'}}) - # circular deps - with mock.patch('koji.util.parse_maven_params', - return_value={ - 'pkg1': {'buildrequires': ['pkg2', 'pkg3']}, - 'pkg2': {'buildrequires': ['pkg3']}, - 'pkg3': {'buildrequires': ['pkg1']}}): - with self.assertRaises(ValueError) as cm: - koji.util.parse_maven_chain(confs) - self.assertEqual( - cm.exception.args[0], - 'No possible build order, missing/circular dependencies') - # missing deps - with mock.patch('koji.util.parse_maven_params', - return_value={ - 'pkg1': {'buildrequires': ['pkg2', 'pkg3']}, - 'pkg2': {'buildrequires': ['pkg3']}, - 'pkg3': {'buildrequires': ['pkg4']}}): - with self.assertRaises(ValueError) as cm: - koji.util.parse_maven_chain(confs) - self.assertEqual( - cm.exception.args[0], - 'No possible build order, missing/circular dependencies') - - def test_tsort(self): - # success, one path - parts = { - 'p1': {'p2', 'p3'}, - 'p2': {'p3'}, - 'p3': set() - } - self.assertEqual(koji.util.tsort(parts), - [{'p3'}, {'p2'}, {'p1'}]) - # success, multi-path - parts = { - 'p1': {'p2'}, - 'p2': {'p4'}, - 'p3': {'p4'}, - 'p4': set(), - 'p5': set() - } - self.assertEqual(koji.util.tsort(parts), - [{'p4', 'p5'}, {'p2', 'p3'}, {'p1'}]) - # failed, missing child 'p4' - parts = { - 'p1': {'p2'}, - 'p2': {'p3'}, - 'p3': {'p4'} - } - with self.assertRaises(ValueError) as cm: - koji.util.tsort(parts) - self.assertEqual(cm.exception.args[0], 'total ordering not possible') - - # failed, circular - parts = { - 'p1': {'p2'}, - 'p2': {'p3'}, - 'p3': {'p1'} - } - with self.assertRaises(ValueError) as cm: - koji.util.tsort(parts) - self.assertEqual(cm.exception.args[0], 'total ordering not possible') - - def _read_conf(self, cfile): - config = six.moves.configparser.ConfigParser() - path = os.path.dirname(__file__) - with open(path + cfile, 'r') as conf_file: - config.readfp(conf_file) - return config - - -if __name__ == '__main__': - unittest.main() From c976c3f2b24e958161b89a3c4e0356dac6d23128 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 47/61] test3 Makefile target --- diff --git a/Makefile b/Makefile index bc8767f..594824d 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,10 @@ test: coverage html @echo Coverage report in htmlcov/index.html +test3: + PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. nosetests-3 tests/test_lib tests/test_cli + @echo Coverage not working for py3 tests yet + subdirs: for d in $(SUBDIRS); do make -C $$d; [ $$? = 0 ] || exit 1; done From 96532de199490fead1470f323dc47b40118a4b3d Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:24 +0000 Subject: [PATCH 48/61] no need to port compatrequests or old ssl code --- diff --git a/koji/compatrequests.py b/koji/compatrequests.py index 3422907..d56f0f2 100644 --- a/koji/compatrequests.py +++ b/koji/compatrequests.py @@ -7,14 +7,13 @@ module that is based on the older codepaths in koji. It only provides the bits that koji needs. """ -from __future__ import absolute_import -import six.moves.http_client -import six.moves.urllib +import httplib +import urlparse +import urllib import sys -from .ssl import SSLCommon -import six +import ssl.SSLCommon try: - from .ssl import ssl as pyssl + from ssl import ssl as pyssl except ImportError: # pragma: no cover pass @@ -26,7 +25,7 @@ class Session(object): def post(self, url, data=None, headers=None, stream=None, verify=None, cert=None, timeout=None): - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) if uri[3]: handler = "%s?%s" % (uri[2], uri[3]) else: @@ -45,11 +44,7 @@ class Session(object): def get_connection(self, uri, cert, verify, timeout): scheme = uri[0] - # TODO: unnecessary remerging of values - parsed = six.moves.urllib.parse.urlparse('%s://%s' % (uri[0], uri[1])) - host = parsed.hostname - port = parsed.port - #host, port = six.moves.urllib.splitport(uri[1]) + host, port = urllib.splitport(uri[1]) key = (scheme, host, cert, verify, timeout) #if self.connection and self.opts.get('keepalive'): if self.connection: # XXX honor keepalive @@ -60,13 +55,13 @@ class Session(object): # Otherwise we make a new one default_port = 80 certs = {} - if isinstance(verify, six.string_types): + if isinstance(verify, basestring): certs['peer_ca_cert'] = verify if cert: certs['key_and_cert'] = cert - ctx = SSLCommon.CreateSSLContext(certs) + ctx = ssl.SSLCommon.CreateSSLContext(certs) cnxOpts = {'ssl_context' : ctx} - cnxClass = SSLCommon.PlgHTTPSConnection + cnxClass = ssl.SSLCommon.PlgHTTPSConnection default_port = 443 elif scheme == 'https': cnxOpts = {} @@ -89,11 +84,11 @@ class Session(object): # no verify ctx = pyssl._create_unverified_context() cnxOpts['context'] = ctx - cnxClass = six.moves.http_client.HTTPSConnection + cnxClass = httplib.HTTPSConnection default_port = 443 elif scheme == 'http': cnxOpts = {} - cnxClass = six.moves.http_client.HTTPConnection + cnxClass = httplib.HTTPConnection else: raise IOError("unsupported protocol: %s" % scheme) @@ -128,7 +123,7 @@ class Response(object): def raise_for_status(self): if self.response.status >= 400: - raise six.moves.http_client.HTTPException("HTTP %s: %s" % (self.response.status, + raise httplib.HTTPException("HTTP %s: %s" % (self.response.status, self.response.reason)) diff --git a/koji/ssl/SSLCommon.py b/koji/ssl/SSLCommon.py index 0cff1ee..a1ab2bb 100644 --- a/koji/ssl/SSLCommon.py +++ b/koji/ssl/SSLCommon.py @@ -14,11 +14,10 @@ # # Copyright 2005 Dan Williams and Red Hat, Inc. -from __future__ import absolute_import import os, sys from OpenSSL import SSL -from . import SSLConnection -import six.moves.http_client +import SSLConnection +import httplib import socket def our_verify(connection, x509, errNum, errDepth, preverifyOK): @@ -47,13 +46,13 @@ def CreateSSLContext(certs): return ctx -class PlgHTTPSConnection(six.moves.http_client.HTTPConnection): +class PlgHTTPSConnection(httplib.HTTPConnection): "This class allows communication via SSL." - response_class = six.moves.http_client.HTTPResponse + response_class = httplib.HTTPResponse def __init__(self, host, port=None, ssl_context=None, strict=None, timeout=None): - six.moves.http_client.HTTPConnection.__init__(self, host, port, strict) + httplib.HTTPConnection.__init__(self, host, port, strict) self.ssl_ctx = ssl_context self._timeout = timeout diff --git a/koji/ssl/SSLConnection.py b/koji/ssl/SSLConnection.py index 92de572..d854770 100644 --- a/koji/ssl/SSLConnection.py +++ b/koji/ssl/SSLConnection.py @@ -6,7 +6,6 @@ # Modifications by Dan Williams -from __future__ import absolute_import from OpenSSL import SSL import time, socket, select @@ -107,7 +106,7 @@ class SSLConnection: try: sent = con.send(data, flags) - except SSL.SysCallError as e: + except SSL.SysCallError, e: if e[0] == 32: # Broken Pipe self.close() sent = 0 @@ -143,7 +142,7 @@ class SSLConnection: return None except SSL.WantReadError: time.sleep(0.2) - except SSL.SysCallError as e: + except SSL.SysCallError, e: if e.args == (-1, 'Unexpected EOF'): break raise diff --git a/koji/ssl/__init__.py b/koji/ssl/__init__.py index fb2e3c7..7b4c2b3 100644 --- a/koji/ssl/__init__.py +++ b/koji/ssl/__init__.py @@ -1,7 +1,6 @@ # identify this as the ssl module # our own ssl submodule masks python's in the main lib, so we import this here -from __future__ import absolute_import try: import ssl # python's ssl module except ImportError: # pragma: no cover diff --git a/tests/test_lib/test_compatrequests.py b/tests/test_lib/test_compatrequests.py index dfd9226..c67f585 100644 --- a/tests/test_lib/test_compatrequests.py +++ b/tests/test_lib/test_compatrequests.py @@ -1,8 +1,7 @@ -from __future__ import absolute_import -import six.moves.http_client +import httplib import mock import unittest -import six.moves.urllib +import urlparse import koji.compatrequests @@ -60,7 +59,7 @@ class TestResponse(unittest.TestCase): self.response.response.status = 404 self.response.response.reason = 'Not Found' self.response.response.getheader.return_value = 42 - with self.assertRaises(six.moves.http_client.HTTPException): + with self.assertRaises(httplib.HTTPException): self.response.raise_for_status() @@ -106,7 +105,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, no verify, no timeout session = koji.compatrequests.Session() url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) cnx = session.get_connection(uri, None, None, None) HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) @@ -124,7 +123,7 @@ class TestSessionConnection(unittest.TestCase): def test_cached(self): session = koji.compatrequests.Session() url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) key = ('http', 'www.fakedomain234234.org', None, None, None) cnx = mock.MagicMock() session.connection = (key, cnx) @@ -135,10 +134,10 @@ class TestSessionConnection(unittest.TestCase): def test_badproto(self): session = koji.compatrequests.Session() url = 'nosuchproto://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) with self.assertRaises(IOError): - session.get_connection(uri, None, None, None) + ret = session.get_connection(uri, None, None, None) @mock.patch('httplib.HTTPConnection') @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) @@ -146,12 +145,12 @@ class TestSessionConnection(unittest.TestCase): # no cert, no verify session = koji.compatrequests.Session() url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) timeout = 1701 - cnx = session.get_connection(uri, None, None, timeout) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=timeout) - key = ('http', 'www.fakedomain234234.org', None, None, timeout) + cnx = session.get_connection(uri, None, None, 1701) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=1701) + key = ('http', 'www.fakedomain234234.org', None, None, 1701) self.assertEqual(session.connection, (key, cnx)) @mock.patch('httplib.HTTPConnection') @@ -160,22 +159,22 @@ class TestSessionConnection(unittest.TestCase): # no cert, no verify session = koji.compatrequests.Session() url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) timeout = 1701 - cnx = session.get_connection(uri, None, None, timeout) + cnx = session.get_connection(uri, None, None, 1701) HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) - key = ('http', 'www.fakedomain234234.org', None, None, timeout) + key = ('http', 'www.fakedomain234234.org', None, None, 1701) self.assertEqual(session.connection, (key, cnx)) cnx.connect.assert_called_once() - cnx.sock.settimeout.assert_called_with(timeout) + cnx.sock.settimeout.assert_called_with(1701) @mock.patch('httplib.HTTPSConnection') def test_https(self, HTTPSConnection): # no cert, no verify, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) cnx = session.get_connection(uri, None, None, None) HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) @@ -188,7 +187,7 @@ class TestSessionConnection(unittest.TestCase): # no verify, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) cert = '/path/to/cert/file' context = mock.MagicMock() CreateSSLContext.return_value = context @@ -205,7 +204,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, verify=False, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) context = mock.MagicMock() create_unverified_context.return_value = context @@ -221,7 +220,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, verify=False, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) cnx = session.get_connection(uri, None, False, None) HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) @@ -236,7 +235,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) context = mock.MagicMock() SSLContext.return_value = context verify = '/path/to/verify/cert' @@ -257,7 +256,7 @@ class TestSessionConnection(unittest.TestCase): # no cert, no timeout session = koji.compatrequests.Session() url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = six.moves.urllib.parse.urlsplit(url) + uri = urlparse.urlsplit(url) verify = '/path/to/verify/cert' cnx = session.get_connection(uri, None, verify, None) From 560dddd22f64399265d6f55150abb636faeb28b5 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 49/61] use_old_ssl is only supported on python2 --- diff --git a/koji/__init__.py b/koji/__init__.py index 799adfd..02abe6e 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -2051,6 +2051,8 @@ class ClientSession(object): if self.rsession: self.rsession.close() if self.opts.get('use_old_ssl', False) or requests is None: + if not six.PY2: + raise GenericError('use_old_ssl is only supported on python2') import koji.compatrequests self.rsession = koji.compatrequests.Session() else: From 9132b1106eeed41673e30c10d17be946a470729f Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 50/61] avoid test_compatrequests on py3 --- diff --git a/tests/test_lib/test_compatrequests.py b/tests/test_lib/test_compatrequests.py deleted file mode 100644 index c67f585..0000000 --- a/tests/test_lib/test_compatrequests.py +++ /dev/null @@ -1,267 +0,0 @@ -import httplib -import mock -import unittest -import urlparse - -import koji.compatrequests - - -class TestResponse(unittest.TestCase): - - def setUp(self): - session = mock.MagicMock() - response = mock.MagicMock() - self.response = koji.compatrequests.Response(session, response) - - def tearDown(self): - del self.response - - def test_read(self): - self.response.response.status = 200 - data = [ - "Here's some data", - "Here's some mooore data", - "And look!", - "Here's a nice block of lorem text", - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " - "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " - "enim ad minim veniam, quis nostrud exercitation ullamco laboris " - "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " - "in reprehenderit in voluptate velit esse cillum dolore eu fugiat " - "nulla pariatur. Excepteur sint occaecat cupidatat non proident, " - "sunt in culpa qui officia deserunt mollit anim id est laborum.", - "", #eof - ] - self.response.response.read.side_effect = data - - result = list(self.response.iter_content(blocksize=10240)) - - self.assertEqual(result, data[:-1]) - rcalls = [mock.call(10240) for s in data] - self.response.response.read.assert_has_calls(rcalls) - - self.response.close() - self.response.response.close.assert_called_once() - - def test_error(self): - self.response.response.status = 404 - self.response.response.getheader.return_value = 0 - with self.assertRaises(Exception): - list(self.response.iter_content(8192)) - self.response.response.read.assert_not_called() - - self.response.response.status = 404 - self.response.response.getheader.return_value = 42 - with self.assertRaises(Exception): - list(self.response.iter_content(8192)) - self.response.response.read.assert_called_once() - - self.response.response.status = 404 - self.response.response.reason = 'Not Found' - self.response.response.getheader.return_value = 42 - with self.assertRaises(httplib.HTTPException): - self.response.raise_for_status() - - - -class TestSessionPost(unittest.TestCase): - - def test_simple(self): - session = koji.compatrequests.Session() - url = 'https://www.fakedomain.org/KOJIHUB' - cnx = mock.MagicMock() - session.get_connection = mock.MagicMock() - session.get_connection.return_value = cnx - response = mock.MagicMock() - cnx.getresponse.return_value = response - - ret = session.post(url, data="data", headers={"foo": "bar"}) - cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB') - cnx.putheader.assert_called_once_with('foo', 'bar') - cnx.send.assert_called_once_with("data") - self.assertEqual(ret.response, response) - - def test_less_simple(self): - session = koji.compatrequests.Session() - url = 'https://www.fakedomain.org/KOJIHUB?a=1&b=2' - cnx = mock.MagicMock() - session.get_connection = mock.MagicMock() - session.get_connection.return_value = cnx - response = mock.MagicMock() - cnx.getresponse.return_value = response - - ret = session.post(url, data="data", headers={"foo": "bar"}, - cert="cert", verify="verify", stream=True, timeout=1701) - cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB?a=1&b=2') - cnx.putheader.assert_called_once_with('foo', 'bar') - cnx.send.assert_called_once_with("data") - self.assertEqual(ret.response, response) - - -class TestSessionConnection(unittest.TestCase): - - @mock.patch('httplib.HTTPConnection') - def test_http(self, HTTPConnection): - # no cert, no verify, no timeout - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - - cnx = session.get_connection(uri, None, None, None) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) - key = ('http', 'www.fakedomain234234.org', None, None, None) - self.assertEqual(session.connection, (key, cnx)) - - # and close it - session.close() - self.assertEqual(session.connection, None) - cnx.close.assert_called_with() - - # double close should not error - session.close() - - def test_cached(self): - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - key = ('http', 'www.fakedomain234234.org', None, None, None) - cnx = mock.MagicMock() - session.connection = (key, cnx) - - ret = session.get_connection(uri, None, None, None) - self.assertEqual(ret, cnx) - - def test_badproto(self): - session = koji.compatrequests.Session() - url = 'nosuchproto://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - - with self.assertRaises(IOError): - ret = session.get_connection(uri, None, None, None) - - @mock.patch('httplib.HTTPConnection') - @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) - def test_timeout(self, HTTPConnection): - # no cert, no verify - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - timeout = 1701 - - cnx = session.get_connection(uri, None, None, 1701) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=1701) - key = ('http', 'www.fakedomain234234.org', None, None, 1701) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('httplib.HTTPConnection') - @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) - def test_timeout_compat(self, HTTPConnection): - # no cert, no verify - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - timeout = 1701 - - cnx = session.get_connection(uri, None, None, 1701) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) - key = ('http', 'www.fakedomain234234.org', None, None, 1701) - self.assertEqual(session.connection, (key, cnx)) - cnx.connect.assert_called_once() - cnx.sock.settimeout.assert_called_with(1701) - - @mock.patch('httplib.HTTPSConnection') - def test_https(self, HTTPSConnection): - # no cert, no verify, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - - cnx = session.get_connection(uri, None, None, None) - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) - key = ('https', 'www.fakedomain234234.org', None, None, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('koji.ssl.SSLCommon.CreateSSLContext') - @mock.patch('koji.ssl.SSLCommon.PlgHTTPSConnection') - def test_cert(self, PlgHTTPSConnection, CreateSSLContext): - # no verify, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - cert = '/path/to/cert/file' - context = mock.MagicMock() - CreateSSLContext.return_value = context - - cnx = session.get_connection(uri, cert, None, None) - PlgHTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, ssl_context=context) - key = ('https', 'www.fakedomain234234.org', cert, None, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('ssl._create_unverified_context') - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) - def test_unverified(self, HTTPSConnection, create_unverified_context): - # no cert, verify=False, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - context = mock.MagicMock() - create_unverified_context.return_value = context - - cnx = session.get_connection(uri, None, False, None) - create_unverified_context.assert_called_once() - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) - key = ('https', 'www.fakedomain234234.org', None, False, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) - def test_unverified_compat(self, HTTPSConnection): - # no cert, verify=False, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - - cnx = session.get_connection(uri, None, False, None) - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) - key = ('https', 'www.fakedomain234234.org', None, False, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('ssl._create_unverified_context') - @mock.patch('ssl.SSLContext') - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) - def test_verify(self, HTTPSConnection, SSLContext, create_unverified_context): - # no cert, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - context = mock.MagicMock() - SSLContext.return_value = context - verify = '/path/to/verify/cert' - - cnx = session.get_connection(uri, None, verify, None) - create_unverified_context.assert_not_called() - SSLContext.assert_called_once() - context.load_verify_locations.called_once_with(cafile=verify) - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) - key = ('https', 'www.fakedomain234234.org', None, verify, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('ssl._create_unverified_context') - @mock.patch('ssl.SSLContext') - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) - def test_verify_compat(self, HTTPSConnection, SSLContext, create_unverified_context): - # no cert, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - verify = '/path/to/verify/cert' - - cnx = session.get_connection(uri, None, verify, None) - create_unverified_context.assert_not_called() - SSLContext.assert_not_called() - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, cert_file=verify) - key = ('https', 'www.fakedomain234234.org', None, verify, None) - self.assertEqual(session.connection, (key, cnx)) diff --git a/tests/test_lib_compat/test_compatrequests.py b/tests/test_lib_compat/test_compatrequests.py new file mode 100644 index 0000000..c67f585 --- /dev/null +++ b/tests/test_lib_compat/test_compatrequests.py @@ -0,0 +1,267 @@ +import httplib +import mock +import unittest +import urlparse + +import koji.compatrequests + + +class TestResponse(unittest.TestCase): + + def setUp(self): + session = mock.MagicMock() + response = mock.MagicMock() + self.response = koji.compatrequests.Response(session, response) + + def tearDown(self): + del self.response + + def test_read(self): + self.response.response.status = 200 + data = [ + "Here's some data", + "Here's some mooore data", + "And look!", + "Here's a nice block of lorem text", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " + "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " + "enim ad minim veniam, quis nostrud exercitation ullamco laboris " + "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " + "in reprehenderit in voluptate velit esse cillum dolore eu fugiat " + "nulla pariatur. Excepteur sint occaecat cupidatat non proident, " + "sunt in culpa qui officia deserunt mollit anim id est laborum.", + "", #eof + ] + self.response.response.read.side_effect = data + + result = list(self.response.iter_content(blocksize=10240)) + + self.assertEqual(result, data[:-1]) + rcalls = [mock.call(10240) for s in data] + self.response.response.read.assert_has_calls(rcalls) + + self.response.close() + self.response.response.close.assert_called_once() + + def test_error(self): + self.response.response.status = 404 + self.response.response.getheader.return_value = 0 + with self.assertRaises(Exception): + list(self.response.iter_content(8192)) + self.response.response.read.assert_not_called() + + self.response.response.status = 404 + self.response.response.getheader.return_value = 42 + with self.assertRaises(Exception): + list(self.response.iter_content(8192)) + self.response.response.read.assert_called_once() + + self.response.response.status = 404 + self.response.response.reason = 'Not Found' + self.response.response.getheader.return_value = 42 + with self.assertRaises(httplib.HTTPException): + self.response.raise_for_status() + + + +class TestSessionPost(unittest.TestCase): + + def test_simple(self): + session = koji.compatrequests.Session() + url = 'https://www.fakedomain.org/KOJIHUB' + cnx = mock.MagicMock() + session.get_connection = mock.MagicMock() + session.get_connection.return_value = cnx + response = mock.MagicMock() + cnx.getresponse.return_value = response + + ret = session.post(url, data="data", headers={"foo": "bar"}) + cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB') + cnx.putheader.assert_called_once_with('foo', 'bar') + cnx.send.assert_called_once_with("data") + self.assertEqual(ret.response, response) + + def test_less_simple(self): + session = koji.compatrequests.Session() + url = 'https://www.fakedomain.org/KOJIHUB?a=1&b=2' + cnx = mock.MagicMock() + session.get_connection = mock.MagicMock() + session.get_connection.return_value = cnx + response = mock.MagicMock() + cnx.getresponse.return_value = response + + ret = session.post(url, data="data", headers={"foo": "bar"}, + cert="cert", verify="verify", stream=True, timeout=1701) + cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB?a=1&b=2') + cnx.putheader.assert_called_once_with('foo', 'bar') + cnx.send.assert_called_once_with("data") + self.assertEqual(ret.response, response) + + +class TestSessionConnection(unittest.TestCase): + + @mock.patch('httplib.HTTPConnection') + def test_http(self, HTTPConnection): + # no cert, no verify, no timeout + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + + cnx = session.get_connection(uri, None, None, None) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) + key = ('http', 'www.fakedomain234234.org', None, None, None) + self.assertEqual(session.connection, (key, cnx)) + + # and close it + session.close() + self.assertEqual(session.connection, None) + cnx.close.assert_called_with() + + # double close should not error + session.close() + + def test_cached(self): + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + key = ('http', 'www.fakedomain234234.org', None, None, None) + cnx = mock.MagicMock() + session.connection = (key, cnx) + + ret = session.get_connection(uri, None, None, None) + self.assertEqual(ret, cnx) + + def test_badproto(self): + session = koji.compatrequests.Session() + url = 'nosuchproto://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + + with self.assertRaises(IOError): + ret = session.get_connection(uri, None, None, None) + + @mock.patch('httplib.HTTPConnection') + @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) + def test_timeout(self, HTTPConnection): + # no cert, no verify + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + timeout = 1701 + + cnx = session.get_connection(uri, None, None, 1701) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=1701) + key = ('http', 'www.fakedomain234234.org', None, None, 1701) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('httplib.HTTPConnection') + @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) + def test_timeout_compat(self, HTTPConnection): + # no cert, no verify + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + timeout = 1701 + + cnx = session.get_connection(uri, None, None, 1701) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) + key = ('http', 'www.fakedomain234234.org', None, None, 1701) + self.assertEqual(session.connection, (key, cnx)) + cnx.connect.assert_called_once() + cnx.sock.settimeout.assert_called_with(1701) + + @mock.patch('httplib.HTTPSConnection') + def test_https(self, HTTPSConnection): + # no cert, no verify, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + + cnx = session.get_connection(uri, None, None, None) + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) + key = ('https', 'www.fakedomain234234.org', None, None, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('koji.ssl.SSLCommon.CreateSSLContext') + @mock.patch('koji.ssl.SSLCommon.PlgHTTPSConnection') + def test_cert(self, PlgHTTPSConnection, CreateSSLContext): + # no verify, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + cert = '/path/to/cert/file' + context = mock.MagicMock() + CreateSSLContext.return_value = context + + cnx = session.get_connection(uri, cert, None, None) + PlgHTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, ssl_context=context) + key = ('https', 'www.fakedomain234234.org', cert, None, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('ssl._create_unverified_context') + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) + def test_unverified(self, HTTPSConnection, create_unverified_context): + # no cert, verify=False, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + context = mock.MagicMock() + create_unverified_context.return_value = context + + cnx = session.get_connection(uri, None, False, None) + create_unverified_context.assert_called_once() + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) + key = ('https', 'www.fakedomain234234.org', None, False, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) + def test_unverified_compat(self, HTTPSConnection): + # no cert, verify=False, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + + cnx = session.get_connection(uri, None, False, None) + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) + key = ('https', 'www.fakedomain234234.org', None, False, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('ssl._create_unverified_context') + @mock.patch('ssl.SSLContext') + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) + def test_verify(self, HTTPSConnection, SSLContext, create_unverified_context): + # no cert, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + context = mock.MagicMock() + SSLContext.return_value = context + verify = '/path/to/verify/cert' + + cnx = session.get_connection(uri, None, verify, None) + create_unverified_context.assert_not_called() + SSLContext.assert_called_once() + context.load_verify_locations.called_once_with(cafile=verify) + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) + key = ('https', 'www.fakedomain234234.org', None, verify, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('ssl._create_unverified_context') + @mock.patch('ssl.SSLContext') + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) + def test_verify_compat(self, HTTPSConnection, SSLContext, create_unverified_context): + # no cert, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + verify = '/path/to/verify/cert' + + cnx = session.get_connection(uri, None, verify, None) + create_unverified_context.assert_not_called() + SSLContext.assert_not_called() + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, cert_file=verify) + key = ('https', 'www.fakedomain234234.org', None, verify, None) + self.assertEqual(session.connection, (key, cnx)) From efe59699c62d0bdaf4c69df248dd95ca95ee1447 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 51/61] fix some test constants --- diff --git a/tests/test_lib/test_fixEncoding.py b/tests/test_lib/test_fixEncoding.py index ee8e089..008ef2a 100644 --- a/tests/test_lib/test_fixEncoding.py +++ b/tests/test_lib/test_fixEncoding.py @@ -5,6 +5,7 @@ from __future__ import absolute_import import koji +import six import unittest class FixEncodingTestCase(unittest.TestCase): @@ -14,23 +15,23 @@ class FixEncodingTestCase(unittest.TestCase): # [ value, fixed ] ['', ''], [u'', ''], - [u'góðan daginn', 'g\xc3\xb3\xc3\xb0an daginn'], - [u'hej', 'hej'], - [u'zdravstvuite', 'zdravstvuite'], - [u'céad míle fáilte', 'c\xc3\xa9ad m\xc3\xadle f\xc3\xa1ilte'], - [u'dobrý den', 'dobr\xc3\xbd den'], - [u'hylô', 'hyl\xc3\xb4'], - [u'jó napot', 'j\xc3\xb3 napot'], - [u'tervehdys', 'tervehdys'], - [u'olá', 'ol\xc3\xa1'], - [u'grüezi', 'gr\xc3\xbcezi'], - [u'dobre dan', 'dobre dan'], - [u'hello', 'hello'], - [u'bună ziua', 'bun\xc4\x83 ziua'], - [u'こんにちは', '\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf'], - [u'你好', '\xe4\xbd\xa0\xe5\xa5\xbd'], - [u'नमस्कार', '\xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\x95\xe0\xa4\xbe\xe0\xa4\xb0'], - [u'안녕하세요', '\xec\x95\x88\xeb\x85\x95\xed\x95\x98\xec\x84\xb8\xec\x9a\x94'], + [u'góðan daginn', six.b('g\xc3\xb3\xc3\xb0an daginn')], + [u'hej', six.b('hej')], + [u'zdravstvuite', six.b('zdravstvuite')], + [u'céad míle fáilte', six.b('c\xc3\xa9ad m\xc3\xadle f\xc3\xa1ilte')], + [u'dobrý den', six.b('dobr\xc3\xbd den')], + [u'hylô', six.b('hyl\xc3\xb4')], + [u'jó napot', six.b('j\xc3\xb3 napot')], + [u'tervehdys', six.b('tervehdys')], + [u'olá', six.b('ol\xc3\xa1')], + [u'grüezi', six.b('gr\xc3\xbcezi')], + [u'dobre dan', six.b('dobre dan')], + [u'hello', six.b('hello')], + [u'bună ziua', six.b('bun\xc4\x83 ziua')], + [u'こんにちは', six.b('\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf')], + [u'你好', six.b('\xe4\xbd\xa0\xe5\xa5\xbd')], + [u'नमस्कार', six.b('\xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\x95\xe0\xa4\xbe\xe0\xa4\xb0')], + [u'안녕하세요', six.b('\xec\x95\x88\xeb\x85\x95\xed\x95\x98\xec\x84\xb8\xec\x9a\x94')], ] def test_fixEncoding(self): From 01a0894ee5bd4e53b9f95a0ee6c9c3cbfb3191ef Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 52/61] test_lib_py2only dir --- diff --git a/tests/test_lib/test_krbv.py b/tests/test_lib/test_krbv.py deleted file mode 100644 index f96b525..0000000 --- a/tests/test_lib/test_krbv.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import absolute_import -import unittest - -# This is python-mock, not the rpm mock tool we know and love -import mock - -import koji - - -class KrbVTestCase(unittest.TestCase): - - @mock.patch('koji.krbV', new=None) - def test_krbv_disabled(self): - """ Test that when krbV is absent, we behave rationally. """ - self.assertEquals(koji.krbV, None) - session = koji.ClientSession('whatever') - with self.assertRaises(ImportError): - session.krb_login() diff --git a/tests/test_lib/test_policy.py b/tests/test_lib/test_policy.py deleted file mode 100644 index d228df7..0000000 --- a/tests/test_lib/test_policy.py +++ /dev/null @@ -1,299 +0,0 @@ -from __future__ import absolute_import -import unittest - -from nose.tools import raises - -import koji.policy - - -class MyBoolTest(koji.policy.BoolTest): - name = 'bool_check' - field = 'bool_field' - - -class MyMatchTest(koji.policy.MatchTest): - name = 'match_check' - field = 'match_field' - - -class myvarTest(koji.policy.CompareTest): - name = None - field = 'myvar' - allow_float = False - - -class TestBasicTests(unittest.TestCase): - - @raises(NotImplementedError) - def test_base_test(self): - obj = koji.policy.BaseSimpleTest('something') - obj.run({}) - - def test_true_test(self): - obj = koji.policy.TrueTest('something') - self.assertTrue(obj.run({})) - - def test_false_test(self): - obj = koji.policy.FalseTest('something') - self.assertFalse(obj.run({})) - - def test_all_test(self): - obj = koji.policy.AllTest('something') - self.assertTrue(obj.run({})) - - def test_none_test(self): - obj = koji.policy.NoneTest('something') - self.assertFalse(obj.run({})) - - def test_has_test(self): - obj = koji.policy.HasTest('some thing') - self.assertFalse(obj.run({})) - self.assertFalse(obj.run({'blah': 'blah'})) - self.assertTrue(obj.run({'thing': 'blah'})) - self.assertRaises(koji.GenericError, koji.policy.HasTest, 'something') - - def test_bool_test(self): - obj = koji.policy.BoolTest('some thing') - self.assertFalse(obj.run({'thing': None})) - self.assertFalse(obj.run({'thing': []})) - self.assertTrue(obj.run({'thing': 'yes'})) - - def test_match_test(self): - obj = koji.policy.MatchTest('some thing else') - self.assertFalse(obj.run({'thing': 'elseplus'})) - obj = koji.policy.MatchTest('some thing else*') - self.assertTrue(obj.run({'thing': 'elseplus'})) - - def test_compare_test(self): - obj = koji.policy.CompareTest('compare thing > 2') - self.assertFalse(obj.run({'thing': 1})) - self.assertFalse(obj.run({'thing': 2})) - self.assertTrue(obj.run({'thing': 3})) - - obj = koji.policy.CompareTest('compare thing < 1.5') - self.assertFalse(obj.run({'thing': 3.2})) - self.assertTrue(obj.run({'thing': 1.0})) - - obj = koji.policy.CompareTest('compare thing = 42') - self.assertFalse(obj.run({'thing': 54})) - self.assertTrue(obj.run({'thing': 42})) - - obj = koji.policy.CompareTest('compare thing != 99') - self.assertFalse(obj.run({'thing': 99})) - self.assertTrue(obj.run({'thing': 100})) - - obj = koji.policy.CompareTest('compare thing >= 2') - self.assertFalse(obj.run({'thing': 1})) - self.assertTrue(obj.run({'thing': 2})) - self.assertTrue(obj.run({'thing': 3})) - - obj = koji.policy.CompareTest('compare thing <= 5') - self.assertFalse(obj.run({'thing': 23})) - self.assertTrue(obj.run({'thing': 5})) - self.assertTrue(obj.run({'thing': 0})) - - @raises(koji.GenericError) - def test_invalid_compare_test(self): - koji.policy.CompareTest('some thing LOL 2') - - -class TestDiscovery(unittest.TestCase): - - def test_find_simple_tests(self): - actual = koji.policy.findSimpleTests(koji.policy.__dict__) - expected = { - 'all': koji.policy.AllTest, - 'bool': koji.policy.BoolTest, - 'compare': koji.policy.CompareTest, - 'false': koji.policy.FalseTest, - 'has': koji.policy.HasTest, - 'match': koji.policy.MatchTest, - 'none': koji.policy.NoneTest, - 'true': koji.policy.TrueTest, - } - self.assertDictEqual(expected, actual) - - -class TestRuleHandling(unittest.TestCase): - - def test_simple_rule_set_instantiation(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - rules = ['true :: allow'] - koji.policy.SimpleRuleSet(rules, tests) - - def test_simple_rule_set_all_actions(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - rules = ['true :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - result = obj.all_actions() - self.assertEquals(result, ['allow']) - - def test_simple_rule_set_apply(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - rules = ['true :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, 'allow') - - rules = ['false :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, None) - - def test_custom_rules(self): - tests = koji.policy.findSimpleTests([globals(), koji.policy.__dict__]) - - rules = ['bool_check :: True', 'all :: False'] - for val in True, False: - data = {'bool_field' : val} - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, str(val)) - - rules = ['match_check foo* :: foo', 'match_check * :: bar'] - data = {'match_field' : 'foo1234'} - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, 'foo') - - data = {'match_field' : 'not foo'} - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, 'bar') - - data = {'myvar': 37} - rules = ['myvar = 37 :: get back here'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEqual(action, 'get back here') - - rules = ['myvar = 2.718281828 :: euler'] - with self.assertRaises(ValueError): - obj = koji.policy.SimpleRuleSet(rules, tests) - - def test_last_rule(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - # no match - rules = ['none :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - self.assertEquals(obj.last_rule(), None) - action = obj.apply(data) - self.assertEquals(obj.last_rule(), '(no match)') - - # simple rule - rules = ['all :: allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEquals(obj.last_rule(), rules[0]) - - # negate rule - rules = ['none !! allow'] - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - self.assertEquals(obj.last_rule(), rules[0]) - - # nested rule - policy = ''' -all :: { - all :: { - all :: allow - } -} -''' - rules = policy.splitlines() - obj = koji.policy.SimpleRuleSet(rules, tests) - action = obj.apply(data) - expected = 'all :: ... all :: ... all :: allow' - self.assertEquals(obj.last_rule(), expected) - - def test_unclosed_brace(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - lines = ['true :: {'] - with self.assertRaises(koji.GenericError): - obj = koji.policy.SimpleRuleSet(lines, tests) - - def test_unmatched_brace(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - lines = ['true :: }'] - with self.assertRaises(koji.GenericError): - obj = koji.policy.SimpleRuleSet(lines, tests) - - def test_no_action(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - lines = ['true && true'] - with self.assertRaises(Exception): - obj = koji.policy.SimpleRuleSet(lines, tests) - - def test_missing_handler(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - lines = ['NOSUCHHANDLER && true :: allow'] - with self.assertRaises(koji.GenericError): - obj = koji.policy.SimpleRuleSet(lines, tests) - - def test_complex_policy(self): - tests = koji.policy.findSimpleTests(koji.policy.__dict__) - data = {} - - policy = ''' -# This is a comment in the test policy - -#^blank line -# commented test && true :: some result - -# First some rules that should never match -false :: ERROR -none :: ERROR - -true !! ERROR -all !! ERROR - -false && true && true :: ERROR -none && true && true :: ERROR - -has NOSUCHFIELD :: ERROR - -# nesting -has DEPTH :: { - match DEPTH 1 :: 1 - all :: { - match DEPTH 2 :: 2 - all :: { - match DEPTH 3 :: 3 - all :: { - match DEPTH 4 :: 4 - all :: END - } - } - } -} -''' - - lines = policy.splitlines() - - for depth in ['1', '2', '3', '4']: - data = {'DEPTH': depth} - obj = koji.policy.SimpleRuleSet(lines, tests) - action = obj.apply(data) - self.assertEqual(action, depth) - - data = {'DEPTH': '99'} - obj = koji.policy.SimpleRuleSet(lines, tests) - action = obj.apply(data) - self.assertEqual(action, 'END') - - actions = set(obj.all_actions()) - self.assertEquals(actions, set(['1', '2', '3', '4', 'ERROR', 'END'])) - - diff --git a/tests/test_lib/test_tasks.py b/tests/test_lib/test_tasks.py deleted file mode 100644 index 551cb05..0000000 --- a/tests/test_lib/test_tasks.py +++ /dev/null @@ -1,715 +0,0 @@ -from __future__ import absolute_import -import random -from os import path, makedirs -from shutil import rmtree -from tempfile import gettempdir -from unittest import TestCase -from mock import patch, Mock, call - -import koji -from koji.tasks import BaseTaskHandler, FakeTask, ForkTask, SleepTask, \ - WaitTestTask, scan_mounts, umount_all, \ - safe_rmtree -import six - - -def get_fake_mounts_file(): - """ Returns contents of /prc/mounts in a file-like object - """ - return six.StringIO(six.text_type(( - 'sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' - 'proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0\n' - 'devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=238836k,nr_inodes=59709,mode=755 0 0\n' - 'securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0\n' - 'tmpfs /dev/shm\040(deleted) tmpfs rw,seclabel,nosuid,nodev 0 0\n' - 'devpts /dev/pts devpts rw,seclabel,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0\n' - 'tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0\n' - 'tmpfs /sys/fs/cgroup tmpfs ro,seclabel,nosuid,nodev,noexec,mode=755 0 0\n' - 'pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' - 'cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0\n' - 'cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0\n' - 'cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0\n' - 'cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0\n' - 'cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0\n' - 'cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0\n' - 'cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0\n' - 'cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0\n' - 'cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0\n' - 'configfs /sys/kernel/config configfs rw,relatime 0 0\n' - ))) - - -def get_temp_dir_root(): - return path.join(gettempdir(), 'koji_tests') - - -def get_tmp_dir_path(folder_starts_with): - return path.join(get_temp_dir_root(), ('{0}{1}'.format(folder_starts_with, random.randint(1, 999999999999)))) - - -class TestTask(BaseTaskHandler): - Methods = ['some_method'] - _taskWeight = 5.2 - - def handler(self, *args): - return 42 - - -class TestTaskNoWeight(BaseTaskHandler): - Methods = ['some_method'] - - def handler(self, *args): - return 42 - - -class BadTask(BaseTaskHandler): - Methods = ['some_method'] - - -class TasksTestCase(TestCase): - - def tearDown(self): - temp_dir_root = get_temp_dir_root() - - if path.isdir(temp_dir_root): - rmtree(get_temp_dir_root()) - - def test_scan_mounts_results(self): - """ Tests the scan_mounts function with a mocked /proc/mounts file. A list containing mount points - starting with /dev are expected to be returned from the function based on the function input of /dev. - """ - fake_mounts_file_contents = get_fake_mounts_file() - - with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True): - self.assertIn(scan_mounts('/dev'), [['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/hugepages', '/dev'], - ['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/console', '/dev']]) - - def test_scan_mounts_no_results(self): - """ Tests the scan_mounts function with a mocked /proc/mounts file. An argument of /nonexistent/path - to the function should return an empty list. - """ - fake_mounts_file_contents = get_fake_mounts_file() - - with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True): - self.assertEquals(scan_mounts('/nonexistent/path'), []) - - # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all - @patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], []]) - @patch('os.spawnvp', return_value=0) - def test_umount_all(self, mocked_spawnvp, mocked_scan_mounts): - """ Tests that umount_all returns nothing when successful. - """ - self.assertEquals(umount_all('/test'), None) - - # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all - @patch('koji.tasks.scan_mounts', return_value=['/dev/shm', '/dev/pts', '/dev/mqueue']) - @patch('os.spawnvp', return_value=1) - def test_umount_all_failure(self, mocked_spawnvp, mocked_scan_mounts): - """ Tests that umount_all raises an exception when a mount point can't be unmounted. - """ - try: - umount_all('/dev') - raise Exception('A GenericError was not raised during the test') - except koji.GenericError as e: - self.assertEquals(e.args[0], - 'umount failed (exit code 1) for /dev/shm') - - # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all - @patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], ['/dev/shm', '/dev/mqueue']]) - @patch('os.spawnvp', return_value=0) - def test_umount_all_unexpected_failure(self, mocked_spawnvp, mocked_scan_mounts): - """ Tests that umount_all will fail if the command to unmount the mount points was successful - but a second run of scan_mounts still shows some of the unmount mount points still mounted. - """ - try: - umount_all('/dev') - raise Exception('A GenericError was not raised during the test') - except koji.GenericError as e: - self.assertEquals(e.args[0], 'Unmounting incomplete: [\'/dev/shm\', \'/dev/mqueue\']') - - @patch('os.path.isfile', return_value=True) - @patch('os.remove') - def test_safe_rmtree_file(self, mock_remove, mock_isfile): - """ Tests that the safe_rmtree function returns nothing when the path parameter is a file. - """ - self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None) - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=True) - @patch('os.remove') - def test_safe_rmtree_link(self, mock_remove, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns nothing when the path parameter is a link. - """ - self.assertEquals(safe_rmtree('/mnt/folder/some_link', False, True), None) - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=False) - @patch('os.path.exists', return_value=False) - def test_safe_rmtree_does_not_exist(self, mock_exists, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns nothing if the path does not exist. - """ - self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None) - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=False) - @patch('os.path.exists', return_value=True) - @patch('os.system', side_effect=[0, 0]) - def test_safe_rmtree_directory(self, mock_os_system, mock_exists, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns nothing when the path is a directory. - """ - self.assertEquals(safe_rmtree('/mnt/folder', False, True), 0) - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=False) - @patch('os.path.exists', return_value=True) - @patch('os.system', side_effect=[1, 0]) - def test_safe_rmtree_directory_scrub_file_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory - and the scrub of the files in the directory fails. - """ - try: - safe_rmtree('/mnt/folder', False, True) - raise Exception('A GenericError was not raised during the test') - except koji.GenericError as e: - self.assertEquals(e.args[0], 'file removal failed (code 1) for /mnt/folder') - - @patch('os.path.isfile', return_value=False) - @patch('os.path.islink', return_value=False) - @patch('os.path.exists', return_value=True) - @patch('os.system', side_effect=[0, 1]) - def test_safe_rmtree_directory_scrub_directory_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile): - """ Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory - and the scrub of the directories in the directory fails. - """ - try: - safe_rmtree('/mnt/folder', False, True) - raise Exception('A GenericError was not raised during the test') - except koji.GenericError as e: - self.assertEquals(e.args[0], 'dir removal failed (code 1) for /mnt/folder') - - def test_BaseTaskHandler_handler_not_set(self): - """ Tests that an exception is thrown when the handler function is not overwritten by the child class. - """ - obj = BadTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('BadTask'))) - try: - obj.handler() - raise Exception('The NotImplementedError exception was not raised') - except NotImplementedError as e: - self.assertEquals(e.__class__.__name__, 'NotImplementedError') - - def test_BaseTaskHandler_weight_default(self): - """ Tests that the weight function returns 1.0 when _taskWeight is not set in the child class' definition. - """ - obj = TestTaskNoWeight(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTaskNoWeight'))) - self.assertEquals(obj.weight(), 1.0) - - def test_BaseTaskHandler_weight_set(self): - """ Tests that the weight function returns the value of _taskWeight when it is set in the - child class' definition. - """ - obj = TestTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTask'))) - self.assertEquals(obj.weight(), 5.2) - - def test_BaseTaskHandler_createWorkdir_workdir_not_defined(self): - """ Tests that the createWorkdir function does nothing when the workdir member variable is set to None. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.workdir = None - obj.createWorkdir() - self.assertEquals(path.isdir(temp_path), False) - - # This patch removes the dependence on removeWorkdir functioning - @patch('{0}.TestTask.removeWorkdir'.format(__name__)) - def test_BaseTaskHandler_createWorkdir(self, mock_removeWorkDir): - """ Tests that the createWorkdir function creates a folder based on the path given to the - workdir member variable. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.createWorkdir() - self.assertEquals(path.isdir(temp_path), True) - rmtree(get_temp_dir_root()) - - def test_BaseTaskHandler_removeWorkdir(self): - """ Tests that the removeWOrkdir function deletes a folder based on the path given to the - workdir member variable. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - self.assertEquals(path.isdir(temp_path), True) - obj.removeWorkdir() - self.assertEquals(path.isdir(temp_path), False) - - def test_BaseTaskHandler_wait_all_done(self): - """ Tests that the wait function returns the subtask results of when the taskWait function returns only - two finished tasks - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - obj.session = Mock() - obj.session.host.taskSetWait.return_value = None - obj.session.host.taskWait.return_value = [[1551234, 1591234], []] - taskWaitResults = [ - ['1551234', { - 'brootid': 2342345, - 'logs': ['tasks/5678/12345678/root.log', - 'tasks/5678/12345678/state.log', - 'tasks/5678/12345678/build.log'], - 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' - }], - - ['1591234', { - 'brootid': 1231234, - 'logs': ['tasks/6789/2345678/root.log', - 'tasks/6789/2345678/state.log', - 'tasks/6789/2345678/build.log'], - 'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'], - 'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm'] - }] - ] - - obj.session.host.taskWaitResults.return_value = taskWaitResults - self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults)) - obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) - obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[]) - - def test_BaseTaskHandler_wait_some_not_done(self): - """ Tests that the wait function returns the one finished subtask results of - when the taskWait function returns one finished task and one unfinished - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - obj.session = Mock() - obj.session.host.taskSetWait.return_value = None - obj.session.host.taskWait.return_value = [[1551234], [1591234]] - taskWaitResults = [ - ['1551234', { - 'brootid': 2342345, - 'logs': ['tasks/5678/12345678/root.log', - 'tasks/5678/12345678/state.log', - 'tasks/5678/12345678/build.log'], - 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' - }] - ] - - obj.session.host.taskWaitResults.return_value = taskWaitResults - self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults)) - obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) - obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234], canfail=[]) - - @patch('signal.pause', return_value=None) - def test_BaseTaskHandler_wait_some_not_done_all_set(self, mock_signal_pause): - """ Tests that the wait function returns the two subtask results since the all kwarg is set to True. - The taskWait function should first return one finished and one unfinished task, then the second time it should - return two finished tasks. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - obj.session = Mock() - obj.session.host.taskSetWait.return_value = None - obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]] - taskWaitResults = [ - ['1551234', { - 'brootid': 2342345, - 'logs': ['tasks/5678/12345678/root.log', - 'tasks/5678/12345678/state.log', - 'tasks/5678/12345678/build.log'], - 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' - }], - - ['1591234', { - 'brootid': 1231234, - 'logs': ['tasks/6789/2345678/root.log', - 'tasks/6789/2345678/state.log', - 'tasks/6789/2345678/build.log'], - 'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'], - 'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm'] - }] - ] - - obj.session.getTaskResult.side_effect - - obj.session.host.taskWaitResults.return_value = taskWaitResults - self.assertEquals(obj.wait([1551234, 1591234], all=True), dict(taskWaitResults)) - obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) - obj.session.host.taskWait.assert_has_calls([call(12345678), call(12345678)]) - mock_signal_pause.assert_called_once_with() - obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[]) - - def test_BaseTaskHandler_wait_some_not_done_all_set_failany_set_failed_task(self): - """ Tests that the wait function raises an exception when one of the subtask fails when the failany flag is set - to True. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) - makedirs(temp_path) - obj.session = Mock() - obj.session.host.taskSetWait.return_value = None - obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]] - obj.session.getTaskResult.side_effect = koji.GenericError('Uh oh, we\'ve got a problem here!') - try: - obj.wait([1551234, 1591234], all=True, failany=True) - raise Exception('A GeneralError was not raised.') - except koji.GenericError as e: - self.assertEquals(e.args[0], 'Uh oh, we\'ve got a problem here!') - obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) - - def test_BaseTaskHandler_getUploadDir(self): - """ Tests that the getUploadDir function returns the appropriate path based on the id of the handler. - """ - temp_path = get_tmp_dir_path('TestTask') - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - self.assertEquals(obj.getUploadDir(), 'tasks/123/123') - - # This patch removes the dependence on getUploadDir functioning - @patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123') - def test_BaseTaskHandler_uploadFile(self, mock_getUploadDir): - """ Tests that the uploadFile function calls the uploadWrapper function on the session member variable - with the correct input - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - temp_file = path.join(temp_path, 'test.txt') - with open(temp_file, 'w') as temp_file_handler: - temp_file_handler.write('Test') - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - self.assertEquals(obj.uploadFile(temp_file), None) - obj.session.uploadWrapper.assert_called_once_with(temp_file, 'tasks/123/123', None, volume=None) - - # This patch removes the dependence on getUploadDir functioning - @patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123') - def test_BaseTaskHandler_uploadFile_no_content(self, mock_getUploadDir): - """ Tests that the uploadFile function calls the uploadWrapper function on the session member variable - without including empty files. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - temp_file = path.join(temp_path, 'test.txt') - temp_file_handler = open(temp_file, 'w') - temp_file_handler.close() - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - self.assertEquals(obj.uploadFile(temp_file), None) - self.assertEquals(obj.session.uploadWrapper.called, False) - - def test_BaseTaskHandler_uploadTree(self): - """ Tests that the uploadTree function calls the uploadFile function with the correct parameters. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - dummy_dir = path.join(temp_path, 'some_directory') - makedirs(dummy_dir) - - dummy_file = path.join(temp_path, 'test.txt') - with open(dummy_file, 'w') as temp_file_handler: - temp_file_handler.write('Test') - - dummy_file2 = path.join(dummy_dir, 'test2.txt') - with open(dummy_file2, 'w') as temp_file_handler2: - temp_file_handler2.write('Test2') - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.uploadFile = Mock() - obj.uploadFile.return_value = None - self.assertEquals(obj.uploadTree(temp_path), None) - obj.uploadFile.assert_has_calls([call(dummy_file, '', volume=None), call(dummy_file2, 'some_directory', volume=None)]) - - @patch('os.lchown', return_value=None) - def test_BaseTaskHandler_chownTree(self, mock_lchown): - """ Tests that the chownTree functions as expected on dummy files created in a temp directory - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - dummy_file = path.join(temp_path, 'test.txt') - dummy_file_handler = open(dummy_file, 'w') - dummy_file_handler.close() - - dummy_file2 = path.join(temp_path, 'test2.txt') - dummy_file_handler2 = open(dummy_file2, 'w') - dummy_file_handler2.close() - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - self.assertEquals(obj.chownTree(temp_path, 2, 0), None) - mock_lchown.assert_has_calls([call(temp_path, 2, 0), call(dummy_file2, 2, 0), call(dummy_file, 2, 0)], any_order=True) - - def test_BaseTaskHandler_localPath_file_exists(self): - """ Tests the localPath function to ensure that when a file exists, it returns that path without - trying to download it. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - local_folder = path.join(temp_path, 'local') - makedirs(local_folder) - - dummy_file = path.join(local_folder, 'test.txt') - dummy_file_handler = open(dummy_file, 'w') - dummy_file_handler.close() - options = Mock() - options.topurl = 'https://www.domain.local' - obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) - self.assertEquals(obj.localPath('test.txt'), dummy_file) - - @patch('six.moves.urllib.request.urlopen', return_value=six.StringIO(six.text_type('Important things\nSome more important things\n'))) - def test_BaseTaskHandler_localPath_no_file(self, mock_urlopen): - """ - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - local_folder = path.join(temp_path, 'local') - makedirs(local_folder) - - target_file_path = path.join(local_folder, 'test.txt') - - options = Mock() - options.topurl = 'https://www.domain.local' - obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) - - self.assertEquals(obj.localPath('test.txt'), target_file_path) - mock_urlopen.assert_called_once_with('https://www.domain.local/test.txt') - - def test_BaseTaskHandler_localPath_no_topurl(self): - """ Tests that the localPath function returns a path when options.topurl is not defined. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - options = Mock() - options.topurl = None - options.topdir = get_temp_dir_root() - obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) - - self.assertEquals(obj.localPath('test.txt'), path.join(get_temp_dir_root(), 'test.txt')) - - def test_BaseTaskHandler_find_arch(self): - """ Tests that the find_arch function returns the input for arch when the input is not "noarch". - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - self.assertEquals(obj.find_arch('x86_64', None, None), 'x86_64') - - def test_BaseTaskHandler_find_arch_noarch_bad_host(self): - """ Tests that the find_arch function raises an exception when the host parameter doesn't contain a - value for the arches key. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - host = {'arches': None, 'name': 'test.domain.local'} - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - try: - obj.find_arch('noarch', host, None) - raise Exception('The BuildError Exception was not raised') - except koji.BuildError as e: - self.assertEquals(e.args[0], 'No arch list for this host: test.domain.local') - - def test_BaseTaskHandler_find_arch_noarch_bad_tag(self): - """ Tests that the find_arch function raises an exception when the tag parameter doesn't contain a - value for the arches key. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - host = {'arches': 'x86_64', 'name': 'test.domain.local'} - tag = {'arches': None, 'name': 'some_package-1.2-build'} - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - try: - obj.find_arch('noarch', host, tag) - raise Exception('The BuildError Exception was not raised') - except koji.BuildError as e: - self.assertEquals(e.args[0], 'No arch list for tag: some_package-1.2-build') - - def test_BaseTaskHandler_find_arch_noarch(self): - """ Tests that the find_arch function finds a match of x86_64 when the host only supports x86_64 - and the tag supports x86_64 and aarch64. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - host = {'arches': 'x86_64', 'name': 'test.domain.local'} - tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'} - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - self.assertEquals(obj.find_arch('noarch', host, tag), 'x86_64') - - def test_BaseTaskHandler_find_arch__noarch_no_match(self): - """ Tests that the find_arch function raises an exception when there isn't a common arch supported between - the host and the tag. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - host = {'arches': 'i386', 'name': 'test.domain.local'} - tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'} - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - try: - obj.find_arch('noarch', host, tag) - raise Exception('The BuildError Exception was not raised') - except koji.BuildError as e: - self.assertEquals(e.args[0], ('host test.domain.local (i386) does not support ' - 'any arches of tag some_package-1.2-build (aarch64, x86_64)')) - - def test_getRepo_tied_to_session(self): - """ Tests that the getRepo function calls session.getRepo(), and returns the result when successful - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - repo_dict = { - 'create_event': 13635166, - 'create_ts': 1469039671.5743899, - 'creation_time': '2016-07-20 18:34:31.574386', - 'id': 1630631, - 'state': 1 - } - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - obj.session.getRepo.return_value = repo_dict - - self.assertEquals(obj.getRepo(8472), repo_dict) - - @patch('{0}.TestTask.wait'.format(__name__)) - def test_getRepo_not_tied_to_session(self, mock_wait): - """ Tests that the getRepo function waits until the results are available for session.getRepo, when it is - not available at the start of the function call. - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - repo_dict = { - 'create_event': 13413120, - 'create_ts': 1466140834.9119599, - 'creation_time': '2016-06-17 05:20:34.911962', - 'id': 1592850, - 'state': 1 - } - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - obj.session.getRepo.return_value = None - obj.session.getTag.return_value = { - 'arches': 'i386 ia64 x86_64 ppc s390 s390x ppc64', - 'extra': {}, - 'id': 851, - 'locked': True, - 'maven_include_all': False, - 'maven_support': False, - 'name': 'dist-3.0E-build', - 'perm': None, - 'perm_id': None - } - obj.session.getBuildTargets.return_value = [{ - 'build_tag': 3093, - 'build_tag_name': 'dist-6E-dsrv-9-build', - 'dest_tag': 3092, - 'dest_tag_name': 'dist-6E-dsrv-9-qu-candidate', - 'id': 851, - 'name': 'dist-6E-dsrv-9-qu-candidate' - }] - - obj.session.host.subtask.return_value = 123 - mock_wait.return_value = {123: repo_dict} - - self.assertEquals(obj.getRepo(851), repo_dict) - obj.session.getRepo.assert_called_once_with(851) - obj.session.getTag.assert_called_once_with(851, strict=True) - - @patch('{0}.TestTask.wait'.format(__name__)) - def test_getRepo_not_tied_to_session_no_build_targets(self, mock_wait): - """ Tests that the getRepo function raises an exception when session.getBuildTargets returns an empty list - """ - temp_path = get_tmp_dir_path('TestTask') - makedirs(temp_path) - - obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) - obj.session = Mock() - obj.session.getRepo.return_value = None - obj.session.getTag.return_value = { - 'arches': 'i686 x86_64 ppc ppc64 ppc64le s390 s390x aarch64', - 'extra': {}, - 'id': 8472, - 'locked': False, - 'maven_include_all': False, - 'maven_support': False, - 'name': 'rhel-7.3-build', - 'perm': 'admin', - 'perm_id': 1 - } - obj.session.getBuildTargets.return_value = [] - - try: - obj.getRepo(8472) - raise Exception('The BuildError Exception was not raised') - except koji.BuildError as e: - obj.session.getRepo.assert_called_once_with(8472) - self.assertEquals(e.args[0], 'no repo (and no target) for tag rhel-7.3-build') - - def test_FakeTask_handler(self): - """ Tests that the FakeTest handler can be instantiated and returns 42 when run - """ - obj = FakeTask(123, 'someMethod', ['random_arg'], None, None, (get_tmp_dir_path('FakeTask'))) - self.assertEquals(obj.run(), 42) - - @patch('time.sleep') - def test_SleepTask_handler(self, mock_sleep): - """ Tests that the SleepTask handler can be instantiated and runs appropriately based on the input - """ - obj = SleepTask(123, 'sleep', [5], None, None, (get_tmp_dir_path('SleepTask'))) - obj.run() - mock_sleep.assert_called_once_with(5) - - @patch('os.spawnvp') - def test_ForkTask_handler(self, mock_spawnvp): - """ Tests that the ForkTask handler can be instantiated and runs appropriately based on the input - """ - obj = ForkTask(123, 'fork', [1, 20], None, None, (get_tmp_dir_path('ForkTask'))) - obj.run() - mock_spawnvp.assert_called_once_with(1, 'sleep', ['sleep', '20']) - - @patch('signal.pause', return_value=None) - @patch('time.sleep') - def test_WaitTestTask_handler(self, mock_sleep, mock_signal_pause): - """ Tests that the WaitTestTask handler can be instantiated and runs appropriately based on the input - Specifically, that forking works and canfail behaves correctly. - """ - self.mock_subtask_id = 1 - def mock_subtask(method, arglist, id, **opts): - self.assertEqual(method, 'sleep') - task_id = self.mock_subtask_id - self.mock_subtask_id += 1 - obj = SleepTask(task_id, 'sleep', arglist, None, None, (get_tmp_dir_path('SleepTask'))) - obj.run() - return task_id - - mock_taskWait = [ - [[], [1, 2, 3, 4]], - [[3, 4], [1, 2]], - [[1, 2, 3, 4], []], - ] - def mock_getTaskResult(task_id): - if task_id == 4: - raise koji.GenericError() - - - obj = WaitTestTask(123, 'waittest', [3], None, None, (get_tmp_dir_path('WaitTestTask'))) - obj.session = Mock() - obj.session.host.subtask.side_effect = mock_subtask - obj.session.getTaskResult.side_effect = mock_getTaskResult - obj.session.host.taskWait.side_effect = mock_taskWait - obj.session.host.taskWaitResults.return_value = [ ['1', {}], ['2', {}], ['3', {}], ['4', {}], ] - obj.run() - #self.assertEqual(mock_sleep.call_count, 4) - obj.session.host.taskSetWait.assert_called_once() - obj.session.host.taskWait.assert_has_calls([call(123), call(123), call(123)]) - # getTaskResult should be called in 2nd round only for task 3, as 4 - # will be skipped as 'canfail' - obj.session.getTaskResult.assert_has_calls([call(3)]) diff --git a/tests/test_lib_compat/test_compatrequests.py b/tests/test_lib_compat/test_compatrequests.py deleted file mode 100644 index c67f585..0000000 --- a/tests/test_lib_compat/test_compatrequests.py +++ /dev/null @@ -1,267 +0,0 @@ -import httplib -import mock -import unittest -import urlparse - -import koji.compatrequests - - -class TestResponse(unittest.TestCase): - - def setUp(self): - session = mock.MagicMock() - response = mock.MagicMock() - self.response = koji.compatrequests.Response(session, response) - - def tearDown(self): - del self.response - - def test_read(self): - self.response.response.status = 200 - data = [ - "Here's some data", - "Here's some mooore data", - "And look!", - "Here's a nice block of lorem text", - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " - "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " - "enim ad minim veniam, quis nostrud exercitation ullamco laboris " - "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " - "in reprehenderit in voluptate velit esse cillum dolore eu fugiat " - "nulla pariatur. Excepteur sint occaecat cupidatat non proident, " - "sunt in culpa qui officia deserunt mollit anim id est laborum.", - "", #eof - ] - self.response.response.read.side_effect = data - - result = list(self.response.iter_content(blocksize=10240)) - - self.assertEqual(result, data[:-1]) - rcalls = [mock.call(10240) for s in data] - self.response.response.read.assert_has_calls(rcalls) - - self.response.close() - self.response.response.close.assert_called_once() - - def test_error(self): - self.response.response.status = 404 - self.response.response.getheader.return_value = 0 - with self.assertRaises(Exception): - list(self.response.iter_content(8192)) - self.response.response.read.assert_not_called() - - self.response.response.status = 404 - self.response.response.getheader.return_value = 42 - with self.assertRaises(Exception): - list(self.response.iter_content(8192)) - self.response.response.read.assert_called_once() - - self.response.response.status = 404 - self.response.response.reason = 'Not Found' - self.response.response.getheader.return_value = 42 - with self.assertRaises(httplib.HTTPException): - self.response.raise_for_status() - - - -class TestSessionPost(unittest.TestCase): - - def test_simple(self): - session = koji.compatrequests.Session() - url = 'https://www.fakedomain.org/KOJIHUB' - cnx = mock.MagicMock() - session.get_connection = mock.MagicMock() - session.get_connection.return_value = cnx - response = mock.MagicMock() - cnx.getresponse.return_value = response - - ret = session.post(url, data="data", headers={"foo": "bar"}) - cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB') - cnx.putheader.assert_called_once_with('foo', 'bar') - cnx.send.assert_called_once_with("data") - self.assertEqual(ret.response, response) - - def test_less_simple(self): - session = koji.compatrequests.Session() - url = 'https://www.fakedomain.org/KOJIHUB?a=1&b=2' - cnx = mock.MagicMock() - session.get_connection = mock.MagicMock() - session.get_connection.return_value = cnx - response = mock.MagicMock() - cnx.getresponse.return_value = response - - ret = session.post(url, data="data", headers={"foo": "bar"}, - cert="cert", verify="verify", stream=True, timeout=1701) - cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB?a=1&b=2') - cnx.putheader.assert_called_once_with('foo', 'bar') - cnx.send.assert_called_once_with("data") - self.assertEqual(ret.response, response) - - -class TestSessionConnection(unittest.TestCase): - - @mock.patch('httplib.HTTPConnection') - def test_http(self, HTTPConnection): - # no cert, no verify, no timeout - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - - cnx = session.get_connection(uri, None, None, None) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) - key = ('http', 'www.fakedomain234234.org', None, None, None) - self.assertEqual(session.connection, (key, cnx)) - - # and close it - session.close() - self.assertEqual(session.connection, None) - cnx.close.assert_called_with() - - # double close should not error - session.close() - - def test_cached(self): - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - key = ('http', 'www.fakedomain234234.org', None, None, None) - cnx = mock.MagicMock() - session.connection = (key, cnx) - - ret = session.get_connection(uri, None, None, None) - self.assertEqual(ret, cnx) - - def test_badproto(self): - session = koji.compatrequests.Session() - url = 'nosuchproto://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - - with self.assertRaises(IOError): - ret = session.get_connection(uri, None, None, None) - - @mock.patch('httplib.HTTPConnection') - @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) - def test_timeout(self, HTTPConnection): - # no cert, no verify - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - timeout = 1701 - - cnx = session.get_connection(uri, None, None, 1701) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=1701) - key = ('http', 'www.fakedomain234234.org', None, None, 1701) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('httplib.HTTPConnection') - @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) - def test_timeout_compat(self, HTTPConnection): - # no cert, no verify - session = koji.compatrequests.Session() - url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - timeout = 1701 - - cnx = session.get_connection(uri, None, None, 1701) - HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) - key = ('http', 'www.fakedomain234234.org', None, None, 1701) - self.assertEqual(session.connection, (key, cnx)) - cnx.connect.assert_called_once() - cnx.sock.settimeout.assert_called_with(1701) - - @mock.patch('httplib.HTTPSConnection') - def test_https(self, HTTPSConnection): - # no cert, no verify, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - - cnx = session.get_connection(uri, None, None, None) - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) - key = ('https', 'www.fakedomain234234.org', None, None, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('koji.ssl.SSLCommon.CreateSSLContext') - @mock.patch('koji.ssl.SSLCommon.PlgHTTPSConnection') - def test_cert(self, PlgHTTPSConnection, CreateSSLContext): - # no verify, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - cert = '/path/to/cert/file' - context = mock.MagicMock() - CreateSSLContext.return_value = context - - cnx = session.get_connection(uri, cert, None, None) - PlgHTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, ssl_context=context) - key = ('https', 'www.fakedomain234234.org', cert, None, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('ssl._create_unverified_context') - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) - def test_unverified(self, HTTPSConnection, create_unverified_context): - # no cert, verify=False, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - context = mock.MagicMock() - create_unverified_context.return_value = context - - cnx = session.get_connection(uri, None, False, None) - create_unverified_context.assert_called_once() - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) - key = ('https', 'www.fakedomain234234.org', None, False, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) - def test_unverified_compat(self, HTTPSConnection): - # no cert, verify=False, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - - cnx = session.get_connection(uri, None, False, None) - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) - key = ('https', 'www.fakedomain234234.org', None, False, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('ssl._create_unverified_context') - @mock.patch('ssl.SSLContext') - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) - def test_verify(self, HTTPSConnection, SSLContext, create_unverified_context): - # no cert, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - context = mock.MagicMock() - SSLContext.return_value = context - verify = '/path/to/verify/cert' - - cnx = session.get_connection(uri, None, verify, None) - create_unverified_context.assert_not_called() - SSLContext.assert_called_once() - context.load_verify_locations.called_once_with(cafile=verify) - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) - key = ('https', 'www.fakedomain234234.org', None, verify, None) - self.assertEqual(session.connection, (key, cnx)) - - @mock.patch('ssl._create_unverified_context') - @mock.patch('ssl.SSLContext') - @mock.patch('httplib.HTTPSConnection') - @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) - def test_verify_compat(self, HTTPSConnection, SSLContext, create_unverified_context): - # no cert, no timeout - session = koji.compatrequests.Session() - url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' - uri = urlparse.urlsplit(url) - verify = '/path/to/verify/cert' - - cnx = session.get_connection(uri, None, verify, None) - create_unverified_context.assert_not_called() - SSLContext.assert_not_called() - HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, cert_file=verify) - key = ('https', 'www.fakedomain234234.org', None, verify, None) - self.assertEqual(session.connection, (key, cnx)) diff --git a/tests/test_lib_py2only/test_compatrequests.py b/tests/test_lib_py2only/test_compatrequests.py new file mode 100644 index 0000000..c67f585 --- /dev/null +++ b/tests/test_lib_py2only/test_compatrequests.py @@ -0,0 +1,267 @@ +import httplib +import mock +import unittest +import urlparse + +import koji.compatrequests + + +class TestResponse(unittest.TestCase): + + def setUp(self): + session = mock.MagicMock() + response = mock.MagicMock() + self.response = koji.compatrequests.Response(session, response) + + def tearDown(self): + del self.response + + def test_read(self): + self.response.response.status = 200 + data = [ + "Here's some data", + "Here's some mooore data", + "And look!", + "Here's a nice block of lorem text", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " + "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " + "enim ad minim veniam, quis nostrud exercitation ullamco laboris " + "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " + "in reprehenderit in voluptate velit esse cillum dolore eu fugiat " + "nulla pariatur. Excepteur sint occaecat cupidatat non proident, " + "sunt in culpa qui officia deserunt mollit anim id est laborum.", + "", #eof + ] + self.response.response.read.side_effect = data + + result = list(self.response.iter_content(blocksize=10240)) + + self.assertEqual(result, data[:-1]) + rcalls = [mock.call(10240) for s in data] + self.response.response.read.assert_has_calls(rcalls) + + self.response.close() + self.response.response.close.assert_called_once() + + def test_error(self): + self.response.response.status = 404 + self.response.response.getheader.return_value = 0 + with self.assertRaises(Exception): + list(self.response.iter_content(8192)) + self.response.response.read.assert_not_called() + + self.response.response.status = 404 + self.response.response.getheader.return_value = 42 + with self.assertRaises(Exception): + list(self.response.iter_content(8192)) + self.response.response.read.assert_called_once() + + self.response.response.status = 404 + self.response.response.reason = 'Not Found' + self.response.response.getheader.return_value = 42 + with self.assertRaises(httplib.HTTPException): + self.response.raise_for_status() + + + +class TestSessionPost(unittest.TestCase): + + def test_simple(self): + session = koji.compatrequests.Session() + url = 'https://www.fakedomain.org/KOJIHUB' + cnx = mock.MagicMock() + session.get_connection = mock.MagicMock() + session.get_connection.return_value = cnx + response = mock.MagicMock() + cnx.getresponse.return_value = response + + ret = session.post(url, data="data", headers={"foo": "bar"}) + cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB') + cnx.putheader.assert_called_once_with('foo', 'bar') + cnx.send.assert_called_once_with("data") + self.assertEqual(ret.response, response) + + def test_less_simple(self): + session = koji.compatrequests.Session() + url = 'https://www.fakedomain.org/KOJIHUB?a=1&b=2' + cnx = mock.MagicMock() + session.get_connection = mock.MagicMock() + session.get_connection.return_value = cnx + response = mock.MagicMock() + cnx.getresponse.return_value = response + + ret = session.post(url, data="data", headers={"foo": "bar"}, + cert="cert", verify="verify", stream=True, timeout=1701) + cnx.putrequest.assert_called_once_with('POST', '/KOJIHUB?a=1&b=2') + cnx.putheader.assert_called_once_with('foo', 'bar') + cnx.send.assert_called_once_with("data") + self.assertEqual(ret.response, response) + + +class TestSessionConnection(unittest.TestCase): + + @mock.patch('httplib.HTTPConnection') + def test_http(self, HTTPConnection): + # no cert, no verify, no timeout + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + + cnx = session.get_connection(uri, None, None, None) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) + key = ('http', 'www.fakedomain234234.org', None, None, None) + self.assertEqual(session.connection, (key, cnx)) + + # and close it + session.close() + self.assertEqual(session.connection, None) + cnx.close.assert_called_with() + + # double close should not error + session.close() + + def test_cached(self): + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + key = ('http', 'www.fakedomain234234.org', None, None, None) + cnx = mock.MagicMock() + session.connection = (key, cnx) + + ret = session.get_connection(uri, None, None, None) + self.assertEqual(ret, cnx) + + def test_badproto(self): + session = koji.compatrequests.Session() + url = 'nosuchproto://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + + with self.assertRaises(IOError): + ret = session.get_connection(uri, None, None, None) + + @mock.patch('httplib.HTTPConnection') + @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) + def test_timeout(self, HTTPConnection): + # no cert, no verify + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + timeout = 1701 + + cnx = session.get_connection(uri, None, None, 1701) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80, timeout=1701) + key = ('http', 'www.fakedomain234234.org', None, None, 1701) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('httplib.HTTPConnection') + @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) + def test_timeout_compat(self, HTTPConnection): + # no cert, no verify + session = koji.compatrequests.Session() + url = 'http://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + timeout = 1701 + + cnx = session.get_connection(uri, None, None, 1701) + HTTPConnection.assert_called_once_with('www.fakedomain234234.org', 80) + key = ('http', 'www.fakedomain234234.org', None, None, 1701) + self.assertEqual(session.connection, (key, cnx)) + cnx.connect.assert_called_once() + cnx.sock.settimeout.assert_called_with(1701) + + @mock.patch('httplib.HTTPSConnection') + def test_https(self, HTTPSConnection): + # no cert, no verify, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + + cnx = session.get_connection(uri, None, None, None) + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) + key = ('https', 'www.fakedomain234234.org', None, None, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('koji.ssl.SSLCommon.CreateSSLContext') + @mock.patch('koji.ssl.SSLCommon.PlgHTTPSConnection') + def test_cert(self, PlgHTTPSConnection, CreateSSLContext): + # no verify, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + cert = '/path/to/cert/file' + context = mock.MagicMock() + CreateSSLContext.return_value = context + + cnx = session.get_connection(uri, cert, None, None) + PlgHTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, ssl_context=context) + key = ('https', 'www.fakedomain234234.org', cert, None, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('ssl._create_unverified_context') + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) + def test_unverified(self, HTTPSConnection, create_unverified_context): + # no cert, verify=False, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + context = mock.MagicMock() + create_unverified_context.return_value = context + + cnx = session.get_connection(uri, None, False, None) + create_unverified_context.assert_called_once() + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) + key = ('https', 'www.fakedomain234234.org', None, False, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) + def test_unverified_compat(self, HTTPSConnection): + # no cert, verify=False, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + + cnx = session.get_connection(uri, None, False, None) + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443) + key = ('https', 'www.fakedomain234234.org', None, False, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('ssl._create_unverified_context') + @mock.patch('ssl.SSLContext') + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 7, 12, 'final', 0)) + def test_verify(self, HTTPSConnection, SSLContext, create_unverified_context): + # no cert, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + context = mock.MagicMock() + SSLContext.return_value = context + verify = '/path/to/verify/cert' + + cnx = session.get_connection(uri, None, verify, None) + create_unverified_context.assert_not_called() + SSLContext.assert_called_once() + context.load_verify_locations.called_once_with(cafile=verify) + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, context=context) + key = ('https', 'www.fakedomain234234.org', None, verify, None) + self.assertEqual(session.connection, (key, cnx)) + + @mock.patch('ssl._create_unverified_context') + @mock.patch('ssl.SSLContext') + @mock.patch('httplib.HTTPSConnection') + @mock.patch('sys.version_info', new=(2, 4, 3, 'final', 0)) + def test_verify_compat(self, HTTPSConnection, SSLContext, create_unverified_context): + # no cert, no timeout + session = koji.compatrequests.Session() + url = 'https://www.fakedomain234234.org/KOJIHUB?a=1&b=2' + uri = urlparse.urlsplit(url) + verify = '/path/to/verify/cert' + + cnx = session.get_connection(uri, None, verify, None) + create_unverified_context.assert_not_called() + SSLContext.assert_not_called() + HTTPSConnection.assert_called_once_with('www.fakedomain234234.org', 443, cert_file=verify) + key = ('https', 'www.fakedomain234234.org', None, verify, None) + self.assertEqual(session.connection, (key, cnx)) diff --git a/tests/test_lib_py2only/test_krbv.py b/tests/test_lib_py2only/test_krbv.py new file mode 100644 index 0000000..f96b525 --- /dev/null +++ b/tests/test_lib_py2only/test_krbv.py @@ -0,0 +1,18 @@ +from __future__ import absolute_import +import unittest + +# This is python-mock, not the rpm mock tool we know and love +import mock + +import koji + + +class KrbVTestCase(unittest.TestCase): + + @mock.patch('koji.krbV', new=None) + def test_krbv_disabled(self): + """ Test that when krbV is absent, we behave rationally. """ + self.assertEquals(koji.krbV, None) + session = koji.ClientSession('whatever') + with self.assertRaises(ImportError): + session.krb_login() diff --git a/tests/test_lib_py2only/test_policy.py b/tests/test_lib_py2only/test_policy.py new file mode 100644 index 0000000..d228df7 --- /dev/null +++ b/tests/test_lib_py2only/test_policy.py @@ -0,0 +1,299 @@ +from __future__ import absolute_import +import unittest + +from nose.tools import raises + +import koji.policy + + +class MyBoolTest(koji.policy.BoolTest): + name = 'bool_check' + field = 'bool_field' + + +class MyMatchTest(koji.policy.MatchTest): + name = 'match_check' + field = 'match_field' + + +class myvarTest(koji.policy.CompareTest): + name = None + field = 'myvar' + allow_float = False + + +class TestBasicTests(unittest.TestCase): + + @raises(NotImplementedError) + def test_base_test(self): + obj = koji.policy.BaseSimpleTest('something') + obj.run({}) + + def test_true_test(self): + obj = koji.policy.TrueTest('something') + self.assertTrue(obj.run({})) + + def test_false_test(self): + obj = koji.policy.FalseTest('something') + self.assertFalse(obj.run({})) + + def test_all_test(self): + obj = koji.policy.AllTest('something') + self.assertTrue(obj.run({})) + + def test_none_test(self): + obj = koji.policy.NoneTest('something') + self.assertFalse(obj.run({})) + + def test_has_test(self): + obj = koji.policy.HasTest('some thing') + self.assertFalse(obj.run({})) + self.assertFalse(obj.run({'blah': 'blah'})) + self.assertTrue(obj.run({'thing': 'blah'})) + self.assertRaises(koji.GenericError, koji.policy.HasTest, 'something') + + def test_bool_test(self): + obj = koji.policy.BoolTest('some thing') + self.assertFalse(obj.run({'thing': None})) + self.assertFalse(obj.run({'thing': []})) + self.assertTrue(obj.run({'thing': 'yes'})) + + def test_match_test(self): + obj = koji.policy.MatchTest('some thing else') + self.assertFalse(obj.run({'thing': 'elseplus'})) + obj = koji.policy.MatchTest('some thing else*') + self.assertTrue(obj.run({'thing': 'elseplus'})) + + def test_compare_test(self): + obj = koji.policy.CompareTest('compare thing > 2') + self.assertFalse(obj.run({'thing': 1})) + self.assertFalse(obj.run({'thing': 2})) + self.assertTrue(obj.run({'thing': 3})) + + obj = koji.policy.CompareTest('compare thing < 1.5') + self.assertFalse(obj.run({'thing': 3.2})) + self.assertTrue(obj.run({'thing': 1.0})) + + obj = koji.policy.CompareTest('compare thing = 42') + self.assertFalse(obj.run({'thing': 54})) + self.assertTrue(obj.run({'thing': 42})) + + obj = koji.policy.CompareTest('compare thing != 99') + self.assertFalse(obj.run({'thing': 99})) + self.assertTrue(obj.run({'thing': 100})) + + obj = koji.policy.CompareTest('compare thing >= 2') + self.assertFalse(obj.run({'thing': 1})) + self.assertTrue(obj.run({'thing': 2})) + self.assertTrue(obj.run({'thing': 3})) + + obj = koji.policy.CompareTest('compare thing <= 5') + self.assertFalse(obj.run({'thing': 23})) + self.assertTrue(obj.run({'thing': 5})) + self.assertTrue(obj.run({'thing': 0})) + + @raises(koji.GenericError) + def test_invalid_compare_test(self): + koji.policy.CompareTest('some thing LOL 2') + + +class TestDiscovery(unittest.TestCase): + + def test_find_simple_tests(self): + actual = koji.policy.findSimpleTests(koji.policy.__dict__) + expected = { + 'all': koji.policy.AllTest, + 'bool': koji.policy.BoolTest, + 'compare': koji.policy.CompareTest, + 'false': koji.policy.FalseTest, + 'has': koji.policy.HasTest, + 'match': koji.policy.MatchTest, + 'none': koji.policy.NoneTest, + 'true': koji.policy.TrueTest, + } + self.assertDictEqual(expected, actual) + + +class TestRuleHandling(unittest.TestCase): + + def test_simple_rule_set_instantiation(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + rules = ['true :: allow'] + koji.policy.SimpleRuleSet(rules, tests) + + def test_simple_rule_set_all_actions(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + rules = ['true :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + result = obj.all_actions() + self.assertEquals(result, ['allow']) + + def test_simple_rule_set_apply(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + rules = ['true :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, 'allow') + + rules = ['false :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, None) + + def test_custom_rules(self): + tests = koji.policy.findSimpleTests([globals(), koji.policy.__dict__]) + + rules = ['bool_check :: True', 'all :: False'] + for val in True, False: + data = {'bool_field' : val} + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, str(val)) + + rules = ['match_check foo* :: foo', 'match_check * :: bar'] + data = {'match_field' : 'foo1234'} + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, 'foo') + + data = {'match_field' : 'not foo'} + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, 'bar') + + data = {'myvar': 37} + rules = ['myvar = 37 :: get back here'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEqual(action, 'get back here') + + rules = ['myvar = 2.718281828 :: euler'] + with self.assertRaises(ValueError): + obj = koji.policy.SimpleRuleSet(rules, tests) + + def test_last_rule(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + # no match + rules = ['none :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + self.assertEquals(obj.last_rule(), None) + action = obj.apply(data) + self.assertEquals(obj.last_rule(), '(no match)') + + # simple rule + rules = ['all :: allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEquals(obj.last_rule(), rules[0]) + + # negate rule + rules = ['none !! allow'] + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + self.assertEquals(obj.last_rule(), rules[0]) + + # nested rule + policy = ''' +all :: { + all :: { + all :: allow + } +} +''' + rules = policy.splitlines() + obj = koji.policy.SimpleRuleSet(rules, tests) + action = obj.apply(data) + expected = 'all :: ... all :: ... all :: allow' + self.assertEquals(obj.last_rule(), expected) + + def test_unclosed_brace(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + lines = ['true :: {'] + with self.assertRaises(koji.GenericError): + obj = koji.policy.SimpleRuleSet(lines, tests) + + def test_unmatched_brace(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + lines = ['true :: }'] + with self.assertRaises(koji.GenericError): + obj = koji.policy.SimpleRuleSet(lines, tests) + + def test_no_action(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + lines = ['true && true'] + with self.assertRaises(Exception): + obj = koji.policy.SimpleRuleSet(lines, tests) + + def test_missing_handler(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + lines = ['NOSUCHHANDLER && true :: allow'] + with self.assertRaises(koji.GenericError): + obj = koji.policy.SimpleRuleSet(lines, tests) + + def test_complex_policy(self): + tests = koji.policy.findSimpleTests(koji.policy.__dict__) + data = {} + + policy = ''' +# This is a comment in the test policy + +#^blank line +# commented test && true :: some result + +# First some rules that should never match +false :: ERROR +none :: ERROR + +true !! ERROR +all !! ERROR + +false && true && true :: ERROR +none && true && true :: ERROR + +has NOSUCHFIELD :: ERROR + +# nesting +has DEPTH :: { + match DEPTH 1 :: 1 + all :: { + match DEPTH 2 :: 2 + all :: { + match DEPTH 3 :: 3 + all :: { + match DEPTH 4 :: 4 + all :: END + } + } + } +} +''' + + lines = policy.splitlines() + + for depth in ['1', '2', '3', '4']: + data = {'DEPTH': depth} + obj = koji.policy.SimpleRuleSet(lines, tests) + action = obj.apply(data) + self.assertEqual(action, depth) + + data = {'DEPTH': '99'} + obj = koji.policy.SimpleRuleSet(lines, tests) + action = obj.apply(data) + self.assertEqual(action, 'END') + + actions = set(obj.all_actions()) + self.assertEquals(actions, set(['1', '2', '3', '4', 'ERROR', 'END'])) + + diff --git a/tests/test_lib_py2only/test_tasks.py b/tests/test_lib_py2only/test_tasks.py new file mode 100644 index 0000000..551cb05 --- /dev/null +++ b/tests/test_lib_py2only/test_tasks.py @@ -0,0 +1,715 @@ +from __future__ import absolute_import +import random +from os import path, makedirs +from shutil import rmtree +from tempfile import gettempdir +from unittest import TestCase +from mock import patch, Mock, call + +import koji +from koji.tasks import BaseTaskHandler, FakeTask, ForkTask, SleepTask, \ + WaitTestTask, scan_mounts, umount_all, \ + safe_rmtree +import six + + +def get_fake_mounts_file(): + """ Returns contents of /prc/mounts in a file-like object + """ + return six.StringIO(six.text_type(( + 'sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' + 'proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0\n' + 'devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=238836k,nr_inodes=59709,mode=755 0 0\n' + 'securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0\n' + 'tmpfs /dev/shm\040(deleted) tmpfs rw,seclabel,nosuid,nodev 0 0\n' + 'devpts /dev/pts devpts rw,seclabel,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0\n' + 'tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0\n' + 'tmpfs /sys/fs/cgroup tmpfs ro,seclabel,nosuid,nodev,noexec,mode=755 0 0\n' + 'pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0\n' + 'cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0\n' + 'cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0\n' + 'cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0\n' + 'cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0\n' + 'cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0\n' + 'cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0\n' + 'cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0\n' + 'cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0\n' + 'cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0\n' + 'configfs /sys/kernel/config configfs rw,relatime 0 0\n' + ))) + + +def get_temp_dir_root(): + return path.join(gettempdir(), 'koji_tests') + + +def get_tmp_dir_path(folder_starts_with): + return path.join(get_temp_dir_root(), ('{0}{1}'.format(folder_starts_with, random.randint(1, 999999999999)))) + + +class TestTask(BaseTaskHandler): + Methods = ['some_method'] + _taskWeight = 5.2 + + def handler(self, *args): + return 42 + + +class TestTaskNoWeight(BaseTaskHandler): + Methods = ['some_method'] + + def handler(self, *args): + return 42 + + +class BadTask(BaseTaskHandler): + Methods = ['some_method'] + + +class TasksTestCase(TestCase): + + def tearDown(self): + temp_dir_root = get_temp_dir_root() + + if path.isdir(temp_dir_root): + rmtree(get_temp_dir_root()) + + def test_scan_mounts_results(self): + """ Tests the scan_mounts function with a mocked /proc/mounts file. A list containing mount points + starting with /dev are expected to be returned from the function based on the function input of /dev. + """ + fake_mounts_file_contents = get_fake_mounts_file() + + with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True): + self.assertIn(scan_mounts('/dev'), [['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/hugepages', '/dev'], + ['/dev/shm', '/dev/pts', '/dev/mqueue', '/dev/console', '/dev']]) + + def test_scan_mounts_no_results(self): + """ Tests the scan_mounts function with a mocked /proc/mounts file. An argument of /nonexistent/path + to the function should return an empty list. + """ + fake_mounts_file_contents = get_fake_mounts_file() + + with patch('{0}.open'.format(__name__), return_value=fake_mounts_file_contents, create=True): + self.assertEquals(scan_mounts('/nonexistent/path'), []) + + # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all + @patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], []]) + @patch('os.spawnvp', return_value=0) + def test_umount_all(self, mocked_spawnvp, mocked_scan_mounts): + """ Tests that umount_all returns nothing when successful. + """ + self.assertEquals(umount_all('/test'), None) + + # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all + @patch('koji.tasks.scan_mounts', return_value=['/dev/shm', '/dev/pts', '/dev/mqueue']) + @patch('os.spawnvp', return_value=1) + def test_umount_all_failure(self, mocked_spawnvp, mocked_scan_mounts): + """ Tests that umount_all raises an exception when a mount point can't be unmounted. + """ + try: + umount_all('/dev') + raise Exception('A GenericError was not raised during the test') + except koji.GenericError as e: + self.assertEquals(e.args[0], + 'umount failed (exit code 1) for /dev/shm') + + # Patching the scan_mounts function instead of the built-in open function because this is only testing umount_all + @patch('koji.tasks.scan_mounts', side_effect=[['/dev/shm', '/dev/pts', '/dev/mqueue'], ['/dev/shm', '/dev/mqueue']]) + @patch('os.spawnvp', return_value=0) + def test_umount_all_unexpected_failure(self, mocked_spawnvp, mocked_scan_mounts): + """ Tests that umount_all will fail if the command to unmount the mount points was successful + but a second run of scan_mounts still shows some of the unmount mount points still mounted. + """ + try: + umount_all('/dev') + raise Exception('A GenericError was not raised during the test') + except koji.GenericError as e: + self.assertEquals(e.args[0], 'Unmounting incomplete: [\'/dev/shm\', \'/dev/mqueue\']') + + @patch('os.path.isfile', return_value=True) + @patch('os.remove') + def test_safe_rmtree_file(self, mock_remove, mock_isfile): + """ Tests that the safe_rmtree function returns nothing when the path parameter is a file. + """ + self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None) + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=True) + @patch('os.remove') + def test_safe_rmtree_link(self, mock_remove, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns nothing when the path parameter is a link. + """ + self.assertEquals(safe_rmtree('/mnt/folder/some_link', False, True), None) + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=False) + @patch('os.path.exists', return_value=False) + def test_safe_rmtree_does_not_exist(self, mock_exists, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns nothing if the path does not exist. + """ + self.assertEquals(safe_rmtree('/mnt/folder/some_file', False, True), None) + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=False) + @patch('os.path.exists', return_value=True) + @patch('os.system', side_effect=[0, 0]) + def test_safe_rmtree_directory(self, mock_os_system, mock_exists, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns nothing when the path is a directory. + """ + self.assertEquals(safe_rmtree('/mnt/folder', False, True), 0) + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=False) + @patch('os.path.exists', return_value=True) + @patch('os.system', side_effect=[1, 0]) + def test_safe_rmtree_directory_scrub_file_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory + and the scrub of the files in the directory fails. + """ + try: + safe_rmtree('/mnt/folder', False, True) + raise Exception('A GenericError was not raised during the test') + except koji.GenericError as e: + self.assertEquals(e.args[0], 'file removal failed (code 1) for /mnt/folder') + + @patch('os.path.isfile', return_value=False) + @patch('os.path.islink', return_value=False) + @patch('os.path.exists', return_value=True) + @patch('os.system', side_effect=[0, 1]) + def test_safe_rmtree_directory_scrub_directory_failure(self, mock_os_system, mock_exists, mock_islink, mock_isfile): + """ Tests that the safe_rmtree function returns a GeneralException when the path parameter is a directory + and the scrub of the directories in the directory fails. + """ + try: + safe_rmtree('/mnt/folder', False, True) + raise Exception('A GenericError was not raised during the test') + except koji.GenericError as e: + self.assertEquals(e.args[0], 'dir removal failed (code 1) for /mnt/folder') + + def test_BaseTaskHandler_handler_not_set(self): + """ Tests that an exception is thrown when the handler function is not overwritten by the child class. + """ + obj = BadTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('BadTask'))) + try: + obj.handler() + raise Exception('The NotImplementedError exception was not raised') + except NotImplementedError as e: + self.assertEquals(e.__class__.__name__, 'NotImplementedError') + + def test_BaseTaskHandler_weight_default(self): + """ Tests that the weight function returns 1.0 when _taskWeight is not set in the child class' definition. + """ + obj = TestTaskNoWeight(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTaskNoWeight'))) + self.assertEquals(obj.weight(), 1.0) + + def test_BaseTaskHandler_weight_set(self): + """ Tests that the weight function returns the value of _taskWeight when it is set in the + child class' definition. + """ + obj = TestTask(123, 'some_method', ['random_arg'], None, None, (get_tmp_dir_path('TestTask'))) + self.assertEquals(obj.weight(), 5.2) + + def test_BaseTaskHandler_createWorkdir_workdir_not_defined(self): + """ Tests that the createWorkdir function does nothing when the workdir member variable is set to None. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.workdir = None + obj.createWorkdir() + self.assertEquals(path.isdir(temp_path), False) + + # This patch removes the dependence on removeWorkdir functioning + @patch('{0}.TestTask.removeWorkdir'.format(__name__)) + def test_BaseTaskHandler_createWorkdir(self, mock_removeWorkDir): + """ Tests that the createWorkdir function creates a folder based on the path given to the + workdir member variable. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.createWorkdir() + self.assertEquals(path.isdir(temp_path), True) + rmtree(get_temp_dir_root()) + + def test_BaseTaskHandler_removeWorkdir(self): + """ Tests that the removeWOrkdir function deletes a folder based on the path given to the + workdir member variable. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + self.assertEquals(path.isdir(temp_path), True) + obj.removeWorkdir() + self.assertEquals(path.isdir(temp_path), False) + + def test_BaseTaskHandler_wait_all_done(self): + """ Tests that the wait function returns the subtask results of when the taskWait function returns only + two finished tasks + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + obj.session = Mock() + obj.session.host.taskSetWait.return_value = None + obj.session.host.taskWait.return_value = [[1551234, 1591234], []] + taskWaitResults = [ + ['1551234', { + 'brootid': 2342345, + 'logs': ['tasks/5678/12345678/root.log', + 'tasks/5678/12345678/state.log', + 'tasks/5678/12345678/build.log'], + 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' + }], + + ['1591234', { + 'brootid': 1231234, + 'logs': ['tasks/6789/2345678/root.log', + 'tasks/6789/2345678/state.log', + 'tasks/6789/2345678/build.log'], + 'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'], + 'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm'] + }] + ] + + obj.session.host.taskWaitResults.return_value = taskWaitResults + self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults)) + obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) + obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[]) + + def test_BaseTaskHandler_wait_some_not_done(self): + """ Tests that the wait function returns the one finished subtask results of + when the taskWait function returns one finished task and one unfinished + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + obj.session = Mock() + obj.session.host.taskSetWait.return_value = None + obj.session.host.taskWait.return_value = [[1551234], [1591234]] + taskWaitResults = [ + ['1551234', { + 'brootid': 2342345, + 'logs': ['tasks/5678/12345678/root.log', + 'tasks/5678/12345678/state.log', + 'tasks/5678/12345678/build.log'], + 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' + }] + ] + + obj.session.host.taskWaitResults.return_value = taskWaitResults + self.assertEquals(obj.wait([1551234, 1591234]), dict(taskWaitResults)) + obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) + obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234], canfail=[]) + + @patch('signal.pause', return_value=None) + def test_BaseTaskHandler_wait_some_not_done_all_set(self, mock_signal_pause): + """ Tests that the wait function returns the two subtask results since the all kwarg is set to True. + The taskWait function should first return one finished and one unfinished task, then the second time it should + return two finished tasks. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + obj.session = Mock() + obj.session.host.taskSetWait.return_value = None + obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]] + taskWaitResults = [ + ['1551234', { + 'brootid': 2342345, + 'logs': ['tasks/5678/12345678/root.log', + 'tasks/5678/12345678/state.log', + 'tasks/5678/12345678/build.log'], + 'srpm': 'tasks/5678/12345678/some_package-1.2.3p5-25.src.rpm' + }], + + ['1591234', { + 'brootid': 1231234, + 'logs': ['tasks/6789/2345678/root.log', + 'tasks/6789/2345678/state.log', + 'tasks/6789/2345678/build.log'], + 'rpms': ['tasks/6789/2345678/some_other_package-doc-1.2.3p5-25.el7.noarch.rpm'], + 'srpms': ['tasks/6789/2345678/some_other_package-1.2.3p5-25.el7.src.rpm'] + }] + ] + + obj.session.getTaskResult.side_effect + + obj.session.host.taskWaitResults.return_value = taskWaitResults + self.assertEquals(obj.wait([1551234, 1591234], all=True), dict(taskWaitResults)) + obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) + obj.session.host.taskWait.assert_has_calls([call(12345678), call(12345678)]) + mock_signal_pause.assert_called_once_with() + obj.session.host.taskWaitResults.assert_called_once_with(12345678, [1551234, 1591234], canfail=[]) + + def test_BaseTaskHandler_wait_some_not_done_all_set_failany_set_failed_task(self): + """ Tests that the wait function raises an exception when one of the subtask fails when the failany flag is set + to True. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(12345678, 'some_method', ['random_arg'], None, None, temp_path) + makedirs(temp_path) + obj.session = Mock() + obj.session.host.taskSetWait.return_value = None + obj.session.host.taskWait.side_effect = [[[1551234], [1591234]], [[1551234, 1591234], []]] + obj.session.getTaskResult.side_effect = koji.GenericError('Uh oh, we\'ve got a problem here!') + try: + obj.wait([1551234, 1591234], all=True, failany=True) + raise Exception('A GeneralError was not raised.') + except koji.GenericError as e: + self.assertEquals(e.args[0], 'Uh oh, we\'ve got a problem here!') + obj.session.host.taskSetWait.assert_called_once_with(12345678, [1551234, 1591234]) + + def test_BaseTaskHandler_getUploadDir(self): + """ Tests that the getUploadDir function returns the appropriate path based on the id of the handler. + """ + temp_path = get_tmp_dir_path('TestTask') + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + self.assertEquals(obj.getUploadDir(), 'tasks/123/123') + + # This patch removes the dependence on getUploadDir functioning + @patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123') + def test_BaseTaskHandler_uploadFile(self, mock_getUploadDir): + """ Tests that the uploadFile function calls the uploadWrapper function on the session member variable + with the correct input + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + temp_file = path.join(temp_path, 'test.txt') + with open(temp_file, 'w') as temp_file_handler: + temp_file_handler.write('Test') + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + self.assertEquals(obj.uploadFile(temp_file), None) + obj.session.uploadWrapper.assert_called_once_with(temp_file, 'tasks/123/123', None, volume=None) + + # This patch removes the dependence on getUploadDir functioning + @patch('{0}.TestTask.getUploadDir'.format(__name__), return_value='tasks/123/123') + def test_BaseTaskHandler_uploadFile_no_content(self, mock_getUploadDir): + """ Tests that the uploadFile function calls the uploadWrapper function on the session member variable + without including empty files. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + temp_file = path.join(temp_path, 'test.txt') + temp_file_handler = open(temp_file, 'w') + temp_file_handler.close() + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + self.assertEquals(obj.uploadFile(temp_file), None) + self.assertEquals(obj.session.uploadWrapper.called, False) + + def test_BaseTaskHandler_uploadTree(self): + """ Tests that the uploadTree function calls the uploadFile function with the correct parameters. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + dummy_dir = path.join(temp_path, 'some_directory') + makedirs(dummy_dir) + + dummy_file = path.join(temp_path, 'test.txt') + with open(dummy_file, 'w') as temp_file_handler: + temp_file_handler.write('Test') + + dummy_file2 = path.join(dummy_dir, 'test2.txt') + with open(dummy_file2, 'w') as temp_file_handler2: + temp_file_handler2.write('Test2') + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.uploadFile = Mock() + obj.uploadFile.return_value = None + self.assertEquals(obj.uploadTree(temp_path), None) + obj.uploadFile.assert_has_calls([call(dummy_file, '', volume=None), call(dummy_file2, 'some_directory', volume=None)]) + + @patch('os.lchown', return_value=None) + def test_BaseTaskHandler_chownTree(self, mock_lchown): + """ Tests that the chownTree functions as expected on dummy files created in a temp directory + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + dummy_file = path.join(temp_path, 'test.txt') + dummy_file_handler = open(dummy_file, 'w') + dummy_file_handler.close() + + dummy_file2 = path.join(temp_path, 'test2.txt') + dummy_file_handler2 = open(dummy_file2, 'w') + dummy_file_handler2.close() + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + self.assertEquals(obj.chownTree(temp_path, 2, 0), None) + mock_lchown.assert_has_calls([call(temp_path, 2, 0), call(dummy_file2, 2, 0), call(dummy_file, 2, 0)], any_order=True) + + def test_BaseTaskHandler_localPath_file_exists(self): + """ Tests the localPath function to ensure that when a file exists, it returns that path without + trying to download it. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + local_folder = path.join(temp_path, 'local') + makedirs(local_folder) + + dummy_file = path.join(local_folder, 'test.txt') + dummy_file_handler = open(dummy_file, 'w') + dummy_file_handler.close() + options = Mock() + options.topurl = 'https://www.domain.local' + obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) + self.assertEquals(obj.localPath('test.txt'), dummy_file) + + @patch('six.moves.urllib.request.urlopen', return_value=six.StringIO(six.text_type('Important things\nSome more important things\n'))) + def test_BaseTaskHandler_localPath_no_file(self, mock_urlopen): + """ + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + local_folder = path.join(temp_path, 'local') + makedirs(local_folder) + + target_file_path = path.join(local_folder, 'test.txt') + + options = Mock() + options.topurl = 'https://www.domain.local' + obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) + + self.assertEquals(obj.localPath('test.txt'), target_file_path) + mock_urlopen.assert_called_once_with('https://www.domain.local/test.txt') + + def test_BaseTaskHandler_localPath_no_topurl(self): + """ Tests that the localPath function returns a path when options.topurl is not defined. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + options = Mock() + options.topurl = None + options.topdir = get_temp_dir_root() + obj = TestTask(123, 'some_method', ['random_arg'], None, options, temp_path) + + self.assertEquals(obj.localPath('test.txt'), path.join(get_temp_dir_root(), 'test.txt')) + + def test_BaseTaskHandler_find_arch(self): + """ Tests that the find_arch function returns the input for arch when the input is not "noarch". + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + self.assertEquals(obj.find_arch('x86_64', None, None), 'x86_64') + + def test_BaseTaskHandler_find_arch_noarch_bad_host(self): + """ Tests that the find_arch function raises an exception when the host parameter doesn't contain a + value for the arches key. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + host = {'arches': None, 'name': 'test.domain.local'} + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + try: + obj.find_arch('noarch', host, None) + raise Exception('The BuildError Exception was not raised') + except koji.BuildError as e: + self.assertEquals(e.args[0], 'No arch list for this host: test.domain.local') + + def test_BaseTaskHandler_find_arch_noarch_bad_tag(self): + """ Tests that the find_arch function raises an exception when the tag parameter doesn't contain a + value for the arches key. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + host = {'arches': 'x86_64', 'name': 'test.domain.local'} + tag = {'arches': None, 'name': 'some_package-1.2-build'} + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + try: + obj.find_arch('noarch', host, tag) + raise Exception('The BuildError Exception was not raised') + except koji.BuildError as e: + self.assertEquals(e.args[0], 'No arch list for tag: some_package-1.2-build') + + def test_BaseTaskHandler_find_arch_noarch(self): + """ Tests that the find_arch function finds a match of x86_64 when the host only supports x86_64 + and the tag supports x86_64 and aarch64. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + host = {'arches': 'x86_64', 'name': 'test.domain.local'} + tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'} + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + self.assertEquals(obj.find_arch('noarch', host, tag), 'x86_64') + + def test_BaseTaskHandler_find_arch__noarch_no_match(self): + """ Tests that the find_arch function raises an exception when there isn't a common arch supported between + the host and the tag. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + host = {'arches': 'i386', 'name': 'test.domain.local'} + tag = {'arches': 'x86_64 aarch64', 'name': 'some_package-1.2-build'} + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + try: + obj.find_arch('noarch', host, tag) + raise Exception('The BuildError Exception was not raised') + except koji.BuildError as e: + self.assertEquals(e.args[0], ('host test.domain.local (i386) does not support ' + 'any arches of tag some_package-1.2-build (aarch64, x86_64)')) + + def test_getRepo_tied_to_session(self): + """ Tests that the getRepo function calls session.getRepo(), and returns the result when successful + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + repo_dict = { + 'create_event': 13635166, + 'create_ts': 1469039671.5743899, + 'creation_time': '2016-07-20 18:34:31.574386', + 'id': 1630631, + 'state': 1 + } + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + obj.session.getRepo.return_value = repo_dict + + self.assertEquals(obj.getRepo(8472), repo_dict) + + @patch('{0}.TestTask.wait'.format(__name__)) + def test_getRepo_not_tied_to_session(self, mock_wait): + """ Tests that the getRepo function waits until the results are available for session.getRepo, when it is + not available at the start of the function call. + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + repo_dict = { + 'create_event': 13413120, + 'create_ts': 1466140834.9119599, + 'creation_time': '2016-06-17 05:20:34.911962', + 'id': 1592850, + 'state': 1 + } + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + obj.session.getRepo.return_value = None + obj.session.getTag.return_value = { + 'arches': 'i386 ia64 x86_64 ppc s390 s390x ppc64', + 'extra': {}, + 'id': 851, + 'locked': True, + 'maven_include_all': False, + 'maven_support': False, + 'name': 'dist-3.0E-build', + 'perm': None, + 'perm_id': None + } + obj.session.getBuildTargets.return_value = [{ + 'build_tag': 3093, + 'build_tag_name': 'dist-6E-dsrv-9-build', + 'dest_tag': 3092, + 'dest_tag_name': 'dist-6E-dsrv-9-qu-candidate', + 'id': 851, + 'name': 'dist-6E-dsrv-9-qu-candidate' + }] + + obj.session.host.subtask.return_value = 123 + mock_wait.return_value = {123: repo_dict} + + self.assertEquals(obj.getRepo(851), repo_dict) + obj.session.getRepo.assert_called_once_with(851) + obj.session.getTag.assert_called_once_with(851, strict=True) + + @patch('{0}.TestTask.wait'.format(__name__)) + def test_getRepo_not_tied_to_session_no_build_targets(self, mock_wait): + """ Tests that the getRepo function raises an exception when session.getBuildTargets returns an empty list + """ + temp_path = get_tmp_dir_path('TestTask') + makedirs(temp_path) + + obj = TestTask(123, 'some_method', ['random_arg'], None, None, temp_path) + obj.session = Mock() + obj.session.getRepo.return_value = None + obj.session.getTag.return_value = { + 'arches': 'i686 x86_64 ppc ppc64 ppc64le s390 s390x aarch64', + 'extra': {}, + 'id': 8472, + 'locked': False, + 'maven_include_all': False, + 'maven_support': False, + 'name': 'rhel-7.3-build', + 'perm': 'admin', + 'perm_id': 1 + } + obj.session.getBuildTargets.return_value = [] + + try: + obj.getRepo(8472) + raise Exception('The BuildError Exception was not raised') + except koji.BuildError as e: + obj.session.getRepo.assert_called_once_with(8472) + self.assertEquals(e.args[0], 'no repo (and no target) for tag rhel-7.3-build') + + def test_FakeTask_handler(self): + """ Tests that the FakeTest handler can be instantiated and returns 42 when run + """ + obj = FakeTask(123, 'someMethod', ['random_arg'], None, None, (get_tmp_dir_path('FakeTask'))) + self.assertEquals(obj.run(), 42) + + @patch('time.sleep') + def test_SleepTask_handler(self, mock_sleep): + """ Tests that the SleepTask handler can be instantiated and runs appropriately based on the input + """ + obj = SleepTask(123, 'sleep', [5], None, None, (get_tmp_dir_path('SleepTask'))) + obj.run() + mock_sleep.assert_called_once_with(5) + + @patch('os.spawnvp') + def test_ForkTask_handler(self, mock_spawnvp): + """ Tests that the ForkTask handler can be instantiated and runs appropriately based on the input + """ + obj = ForkTask(123, 'fork', [1, 20], None, None, (get_tmp_dir_path('ForkTask'))) + obj.run() + mock_spawnvp.assert_called_once_with(1, 'sleep', ['sleep', '20']) + + @patch('signal.pause', return_value=None) + @patch('time.sleep') + def test_WaitTestTask_handler(self, mock_sleep, mock_signal_pause): + """ Tests that the WaitTestTask handler can be instantiated and runs appropriately based on the input + Specifically, that forking works and canfail behaves correctly. + """ + self.mock_subtask_id = 1 + def mock_subtask(method, arglist, id, **opts): + self.assertEqual(method, 'sleep') + task_id = self.mock_subtask_id + self.mock_subtask_id += 1 + obj = SleepTask(task_id, 'sleep', arglist, None, None, (get_tmp_dir_path('SleepTask'))) + obj.run() + return task_id + + mock_taskWait = [ + [[], [1, 2, 3, 4]], + [[3, 4], [1, 2]], + [[1, 2, 3, 4], []], + ] + def mock_getTaskResult(task_id): + if task_id == 4: + raise koji.GenericError() + + + obj = WaitTestTask(123, 'waittest', [3], None, None, (get_tmp_dir_path('WaitTestTask'))) + obj.session = Mock() + obj.session.host.subtask.side_effect = mock_subtask + obj.session.getTaskResult.side_effect = mock_getTaskResult + obj.session.host.taskWait.side_effect = mock_taskWait + obj.session.host.taskWaitResults.return_value = [ ['1', {}], ['2', {}], ['3', {}], ['4', {}], ] + obj.run() + #self.assertEqual(mock_sleep.call_count, 4) + obj.session.host.taskSetWait.assert_called_once() + obj.session.host.taskWait.assert_has_calls([call(123), call(123), call(123)]) + # getTaskResult should be called in 2nd round only for task 3, as 4 + # will be skipped as 'canfail' + obj.session.getTaskResult.assert_has_calls([call(3)]) From 5eea74aa7120690bf4f4651e52d09ac55f936e77 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 53/61] use python3 -m nose --- diff --git a/Makefile b/Makefile index 594824d..7132fe3 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ test: @echo Coverage report in htmlcov/index.html test3: - PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. nosetests-3 tests/test_lib tests/test_cli + PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. python3 -m nose tests/test_lib tests/test_cli @echo Coverage not working for py3 tests yet subdirs: From 6092f9e2ae01116a83979c81ff48b5a474e4cb48 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 54/61] coverage for py3 unit tests --- diff --git a/Makefile b/Makefile index 7132fe3..e8062bb 100644 --- a/Makefile +++ b/Makefile @@ -71,8 +71,13 @@ test: @echo Coverage report in htmlcov/index.html test3: - PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. python3 -m nose tests/test_lib tests/test_cli - @echo Coverage not working for py3 tests yet + coverage erase + PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. nosetests-3 \ + --with-coverage --cover-package . tests/test_lib tests/test_cli + @echo Sleeping to work around an issue + sleep 10 + coverage html + @echo Coverage report in htmlcov/index.html subdirs: for d in $(SUBDIRS); do make -C $$d; [ $$? = 0 ] || exit 1; done diff --git a/tests/test_cli/test_list_commands.py b/tests/test_cli/test_list_commands.py index b73ade0..a26d1a6 100644 --- a/tests/test_cli/test_list_commands.py +++ b/tests/test_cli/test_list_commands.py @@ -31,7 +31,7 @@ class TestListCommands(unittest.TestCase): if six.PY2: actual = actual.replace('nosetests', 'koji') else: - actual = actual.replace('python3 -m nose', 'koji') + actual = actual.replace('nosetests-3', 'koji') filename = os.path.dirname(__file__) + '/data/list-commands.txt' with open(filename, 'rb') as f: expected = f.read().decode('ascii') @@ -47,7 +47,7 @@ class TestListCommands(unittest.TestCase): if six.PY2: actual = actual.replace('nosetests', 'koji') else: - actual = actual.replace('python3 -m nose', 'koji') + actual = actual.replace('nosetests-3', 'koji') filename = os.path.dirname(__file__) + '/data/list-commands-admin.txt' with open(filename, 'rb') as f: expected = f.read().decode('ascii') From cf3dd9040d6b64de26b4757f6a803359cad29e80 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 55/61] no hub test changes for now --- diff --git a/tests/test_hub/test_add_btype.py b/tests/test_hub/test_add_btype.py index 6a73b0d..e64cc0f 100644 --- a/tests/test_hub/test_add_btype.py +++ b/tests/test_hub/test_add_btype.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_apply_query_opts.py b/tests/test_hub/test_apply_query_opts.py index 6d23d6a..653723c 100644 --- a/tests/test_hub/test_apply_query_opts.py +++ b/tests/test_hub/test_apply_query_opts.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import copy import unittest diff --git a/tests/test_hub/test_cg_importer.py b/tests/test_hub/test_cg_importer.py index f891610..f77ce67 100644 --- a/tests/test_hub/test_cg_importer.py +++ b/tests/test_hub/test_cg_importer.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock import os diff --git a/tests/test_hub/test_create_tag.py b/tests/test_hub/test_create_tag.py index 4635658..91dea25 100644 --- a/tests/test_hub/test_create_tag.py +++ b/tests/test_hub/test_create_tag.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import copy import mock import shutil diff --git a/tests/test_hub/test_delete_build.py b/tests/test_hub/test_delete_build.py index 91e497f..2cd2dae 100644 --- a/tests/test_hub/test_delete_build.py +++ b/tests/test_hub/test_delete_build.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import mock import unittest import kojihub diff --git a/tests/test_hub/test_dist_repo.py b/tests/test_hub/test_dist_repo.py index 50b6057..33f1b6c 100644 --- a/tests/test_hub/test_dist_repo.py +++ b/tests/test_hub/test_dist_repo.py @@ -1,5 +1,4 @@ -from __future__ import absolute_import import unittest import mock import os diff --git a/tests/test_hub/test_edit_tag.py b/tests/test_hub/test_edit_tag.py index 0c57e75..65d6dc6 100644 --- a/tests/test_hub/test_edit_tag.py +++ b/tests/test_hub/test_edit_tag.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import mock import unittest diff --git a/tests/test_hub/test_get_build_type.py b/tests/test_hub/test_get_build_type.py index e4a0862..b4013e9 100644 --- a/tests/test_hub/test_get_build_type.py +++ b/tests/test_hub/test_get_build_type.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_get_next_release.py b/tests/test_hub/test_get_next_release.py index 92a3e14..adfeea3 100644 --- a/tests/test_hub/test_get_next_release.py +++ b/tests/test_hub/test_get_next_release.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import mock import unittest diff --git a/tests/test_hub/test_get_upload_path.py b/tests/test_hub/test_get_upload_path.py index d11e1b1..f789192 100644 --- a/tests/test_hub/test_get_upload_path.py +++ b/tests/test_hub/test_get_upload_path.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import os import mock import shutil @@ -37,7 +36,7 @@ class TestGetUploadPath(unittest.TestCase): fullpath = '{0}/{1}'.format(work.return_value, reldir) os.makedirs(fullpath) - with open('{0}/.user'.format(fullpath), 'wb') as f: + with file('{0}/.user'.format(fullpath), 'wb') as f: f.write('1') with self.assertRaises(GenericError): diff --git a/tests/test_hub/test_get_verify_class.py b/tests/test_hub/test_get_verify_class.py index 57809e8..ae94ed6 100644 --- a/tests/test_hub/test_get_verify_class.py +++ b/tests/test_hub/test_get_verify_class.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import kojihub from koji import GenericError diff --git a/tests/test_hub/test_import_build.py b/tests/test_hub/test_import_build.py index 7abea63..108f911 100644 --- a/tests/test_hub/test_import_build.py +++ b/tests/test_hub/test_import_build.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import copy import mock import shutil diff --git a/tests/test_hub/test_import_image_internal.py b/tests/test_hub/test_import_image_internal.py index 9dcb3d3..b23f728 100644 --- a/tests/test_hub/test_import_image_internal.py +++ b/tests/test_hub/test_import_image_internal.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock import os diff --git a/tests/test_hub/test_insert_processor.py b/tests/test_hub/test_insert_processor.py index ae45fb9..1771681 100644 --- a/tests/test_hub/test_insert_processor.py +++ b/tests/test_hub/test_insert_processor.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock @@ -69,11 +68,9 @@ class TestInsertProcessor(unittest.TestCase): proc.dup_check() args = cursor.execute.call_args actual = ' '.join(args[0][0].split()) - expected1 = 'SELECT foo, active FROM sometable WHERE ' + \ - '(foo = %(foo)s) AND (active = %(active)s)' - expected2 = 'SELECT active, foo FROM sometable WHERE ' + \ + expected = 'SELECT active, foo FROM sometable WHERE ' + \ '(active = %(active)s) AND (foo = %(foo)s)' - self.assertIn(actual, (expected1, expected2)) + self.assertEquals(actual, expected) proc.set(onething='another') proc.rawset(something='something else') diff --git a/tests/test_hub/test_list_btypes.py b/tests/test_hub/test_list_btypes.py index 6649e89..b5f4bc5 100644 --- a/tests/test_hub/test_list_btypes.py +++ b/tests/test_hub/test_list_btypes.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_list_task_output.py b/tests/test_hub/test_list_task_output.py index 6a5f15c..0b27af1 100644 --- a/tests/test_hub/test_list_task_output.py +++ b/tests/test_hub/test_list_task_output.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_listing.py b/tests/test_hub/test_listing.py index 1647934..a39f2b0 100644 --- a/tests/test_hub/test_listing.py +++ b/tests/test_hub/test_listing.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_models/test_host.py b/tests/test_hub/test_models/test_host.py index 80f6667..c1bc6e5 100644 --- a/tests/test_hub/test_models/test_host.py +++ b/tests/test_hub/test_models/test_host.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_new_typed_build.py b/tests/test_hub/test_new_typed_build.py index b7b6ccf..a1ae47f 100644 --- a/tests/test_hub/test_new_typed_build.py +++ b/tests/test_hub/test_new_typed_build.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_query_processor.py b/tests/test_hub/test_query_processor.py index e7c7cb8..7b229bd 100644 --- a/tests/test_hub/test_query_processor.py +++ b/tests/test_hub/test_query_processor.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock diff --git a/tests/test_hub/test_recycle_build.py b/tests/test_hub/test_recycle_build.py index 5de0d70..2179b04 100644 --- a/tests/test_hub/test_recycle_build.py +++ b/tests/test_hub/test_recycle_build.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import mock import koji diff --git a/tests/test_hub/test_rpmdiff.py b/tests/test_hub/test_rpmdiff.py index 4f94f38..277902f 100644 --- a/tests/test_hub/test_rpmdiff.py +++ b/tests/test_hub/test_rpmdiff.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import copy import unittest import mock diff --git a/tests/test_hub/test_tag_operations.py b/tests/test_hub/test_tag_operations.py index 1b05efb..2f0d10c 100644 --- a/tests/test_hub/test_tag_operations.py +++ b/tests/test_hub/test_tag_operations.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import copy import mock import shutil diff --git a/tests/test_hub/test_update_processor.py b/tests/test_hub/test_update_processor.py index b31956a..e765b3b 100644 --- a/tests/test_hub/test_update_processor.py +++ b/tests/test_hub/test_update_processor.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock From 9508bb164ccbffd2e7158d5b141632b9e027ebe7 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 56/61] no hub plugins changes either --- diff --git a/tests/test_plugins/test_protonmsg.py b/tests/test_plugins/test_protonmsg.py index e73da5a..02583b7 100644 --- a/tests/test_plugins/test_protonmsg.py +++ b/tests/test_plugins/test_protonmsg.py @@ -1,11 +1,10 @@ -from __future__ import absolute_import import unittest from mock import patch, MagicMock import protonmsg from koji.context import context import tempfile -from six.moves.configparser import SafeConfigParser -import six +from StringIO import StringIO +from ConfigParser import SafeConfigParser class TestProtonMsg(unittest.TestCase): def tearDown(self): @@ -205,7 +204,7 @@ send_timeout = 60 class TestTimeoutHandler(unittest.TestCase): def setUp(self): - confdata = six.StringIO("""[broker] + confdata = StringIO("""[broker] urls = amqps://broker1.example.com:5671 amqps://broker2.example.com:5671 cert = /etc/koji-hub/plugins/client.pem cacert = /etc/koji-hub/plugins/ca.pem @@ -228,7 +227,7 @@ send_timeout = 60 @patch('protonmsg.SSLDomain') def test_on_start_no_ssl(self, SSLDomain): - confdata = six.StringIO("""[broker] + confdata = StringIO("""[broker] urls = amqp://broker1.example.com:5672 amqp://broker2.example.com:5672 topic_prefix = koji connect_timeout = 10 diff --git a/tests/test_plugins/test_runroot_hub.py b/tests/test_plugins/test_runroot_hub.py index 4f129c8..79b5696 100644 --- a/tests/test_plugins/test_runroot_hub.py +++ b/tests/test_plugins/test_runroot_hub.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import unittest import mock From b2bfc28c862fedd1dcd5261156ee2c9d63aaefe9 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 57/61] don't warn at load time if krbV module is missing --- diff --git a/koji/__init__.py b/koji/__init__.py index 02abe6e..72ca8ce 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -26,11 +26,11 @@ import sys from six.moves import range from six.moves import zip import six +krbV = None try: import krbV except ImportError: # pragma: no cover - sys.stderr.write("Warning: Could not install krbV module. Kerberos support will be disabled.\n") - sys.stderr.flush() + pass import base64 import datetime import six.moves.configparser From 95f012b27d19298562a7709a51329a28343ec088 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 58/61] fixEncoding tests --- diff --git a/koji/__init__.py b/koji/__init__.py index 72ca8ce..3b5c56e 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -2912,7 +2912,7 @@ def _taskLabel(taskInfo): return '%s (%s)' % (method, arch) CONTROL_CHARS = [chr(i) for i in range(32)] -NONPRINTABLE_CHARS = ''.join([c for c in CONTROL_CHARS if c not in '\r\n\t']) +NONPRINTABLE_CHARS = six.b(''.join([c for c in CONTROL_CHARS if c not in '\r\n\t'])) def removeNonprintable(value): # expects raw-encoded string, not unicode return value.translate(None, NONPRINTABLE_CHARS) @@ -2924,7 +2924,7 @@ def fixEncoding(value, fallback='iso8859-15', remove_nonprintable=False): encoded in the 'fallback' charset. """ if not value: - return '' + return six.b('') if isinstance(value, six.text_type): # value is already unicode, so just convert it diff --git a/tests/test_lib/test_fixEncoding.py b/tests/test_lib/test_fixEncoding.py index 008ef2a..4072724 100644 --- a/tests/test_lib/test_fixEncoding.py +++ b/tests/test_lib/test_fixEncoding.py @@ -13,8 +13,8 @@ class FixEncodingTestCase(unittest.TestCase): simple_values = [ # [ value, fixed ] - ['', ''], - [u'', ''], + ['', six.b('')], + [u'', six.b('')], [u'góðan daginn', six.b('g\xc3\xb3\xc3\xb0an daginn')], [u'hej', six.b('hej')], [u'zdravstvuite', six.b('zdravstvuite')], @@ -51,17 +51,17 @@ class FixEncodingTestCase(unittest.TestCase): [None, None], [[], []], [{u'a': 'a' , 'b' : {'c': u'c\x00'}}, - { 'a': 'a' , 'b' : {'c': 'c\x00'}}], + {six.b('a'): six.b('a') , six.b('b') : {six.b('c'): six.b('c\x00')}}], # iso8859-15 fallback - ['g\xf3\xf0an daginn', 'g\xc3\xb3\xc3\xb0an daginn'], + ['g\xf3\xf0an daginn', six.b('g\xc3\xb3\xc3\xb0an daginn')], ] nonprint = [ - ['hello\0world\0', 'helloworld'], - [u'hello\0world\0', 'helloworld'], - [[u'hello\0world\0'], ['helloworld']], - [{0: u'hello\0world\0'}, {0: 'helloworld'}], - [[{0: u'hello\0world\0'}], [{0: 'helloworld'}]], + ['hello\0world\0', six.b('helloworld')], + [u'hello\0world\0', six.b('helloworld')], + [[u'hello\0world\0'], [six.b('helloworld')]], + [{0: u'hello\0world\0'}, {0: six.b('helloworld')}], + [[{0: u'hello\0world\0'}], [{0: six.b('helloworld')}]], ] def test_fixEncodingRecurse(self): From 0661e0e3eb6a4b328c6f5c2ff62159c9628d98ac Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 59/61] Work around coverage bug in py3 on Fedora --- diff --git a/Makefile b/Makefile index e8062bb..221d0e5 100644 --- a/Makefile +++ b/Makefile @@ -74,8 +74,6 @@ test3: coverage erase PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. nosetests-3 \ --with-coverage --cover-package . tests/test_lib tests/test_cli - @echo Sleeping to work around an issue - sleep 10 coverage html @echo Coverage report in htmlcov/index.html diff --git a/koji/__init__.py b/koji/__init__.py index 3b5c56e..9e1e5ce 100644 --- a/koji/__init__.py +++ b/koji/__init__.py @@ -21,6 +21,7 @@ # Mike McLean # Mike Bonnet + from __future__ import absolute_import import sys from six.moves import range diff --git a/tests/test_lib/test_profiles.py b/tests/test_lib/test_profiles.py index 3903db1..0417023 100644 --- a/tests/test_lib/test_profiles.py +++ b/tests/test_lib/test_profiles.py @@ -6,8 +6,10 @@ import sys import threading import traceback from six.moves import range +import six - +# XXX remove skip when Fedora bug is fixed +@unittest.skipIf(six.PY3, "coverage bug Fedora, see rhbz#1452339") class ProfilesTestCase(unittest.TestCase): def test_profile_threading(self): From 88ea9926ab4b13b69a0391c0f3030c8c67bd281b Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 60/61] use coverage directly. adjust coverage config for py3 tests --- diff --git a/.coveragerc b/.coveragerc index 087bddf..f375367 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,5 @@ [run] omit = - /usr/lib/* + /usr/* tests/* diff --git a/.coveragerc3 b/.coveragerc3 new file mode 100644 index 0000000..236173b --- /dev/null +++ b/.coveragerc3 @@ -0,0 +1,12 @@ +[run] + +; extra omissions for py3 for now + +omit = + /usr/* + tests/* + hub/* + util/* + koji/ssl/* + koji/daemon.py + koji/tasks.py diff --git a/Makefile b/Makefile index 221d0e5..2a6ff55 100644 --- a/Makefile +++ b/Makefile @@ -66,16 +66,21 @@ git-clean: test: coverage erase - PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. nosetests --with-coverage --cover-package . + PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. coverage run \ + --source . /usr/bin/nosetests + coverage report coverage html - @echo Coverage report in htmlcov/index.html + @echo Full coverage report in htmlcov/index.html test3: coverage erase - PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. nosetests-3 \ - --with-coverage --cover-package . tests/test_lib tests/test_cli + PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. coverage3 run \ + --rcfile .coveragerc3 --source . \ + /usr/bin/nosetests-3 \ + tests/test_lib tests/test_cli + coverage report coverage html - @echo Coverage report in htmlcov/index.html + @echo Full coverage report in htmlcov/index.html subdirs: for d in $(SUBDIRS); do make -C $$d; [ $$? = 0 ] || exit 1; done From 9dcc0a4032eec54ab885952f0fd70280351329b6 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 01 2017 07:39:25 +0000 Subject: [PATCH 61/61] spec update --- diff --git a/cli/Makefile b/cli/Makefile index 3573aef..073b24b 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -15,5 +15,5 @@ install: mkdir -p $(DESTDIR)/usr/bin install -p -m 755 $(FILES) $(DESTDIR)/usr/bin - install -p -m 644 koji.conf $(DESTDIR)/etc/koji.conf mkdir -p $(DESTDIR)/etc/koji.conf.d + install -p -m 644 koji.conf $(DESTDIR)/etc/koji.conf diff --git a/koji.spec b/koji.spec index a391910..694a940 100644 --- a/koji.spec +++ b/koji.spec @@ -1,4 +1,21 @@ -%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from %distutils.sysconfig import get_python_lib; print(get_python_lib())")} +# Enable Python 3 builds for Fedora + EPEL >5 +# NOTE: do **NOT** change 'epel' to 'rhel' here, as this spec is also +%if 0%{?fedora} || 0%{?epel} > 5 +%bcond_without python3 +# If the definition isn't available for python3_pkgversion, define it +%{?!python3_pkgversion:%global python3_pkgversion 3} +%else +%bcond_with python3 +%endif + +# Compatibility with RHEL. These macros have been added to EPEL but +# not yet to RHEL proper. +# https://bugzilla.redhat.com/show_bug.cgi?id=1307190 +%{!?__python2: %global __python2 /usr/bin/python2} +%{!?python2_sitelib: %global python2_sitelib %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")} +%{!?python2_sitearch: %global python2_sitearch %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")} +%{!?py2_build: %global py2_build %{expand: CFLAGS="%{optflags}" %{__python2} setup.py %{?py_setup_args} build --executable="%{__python2} -s"}} +%{!?py2_install: %global py2_install %{expand: CFLAGS="%{optflags}" %{__python2} setup.py %{?py_setup_args} install -O1 --skip-build --root %{buildroot}}} %if 0%{?fedora} >= 21 || 0%{?redhat} >= 7 %global use_systemd 1 @@ -25,27 +42,57 @@ URL: https://pagure.io/koji Source: https://releases.pagure.org/koji/koji-%{version}.tar.bz2 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildArch: noarch -Requires: python-krbV >= 1.0.13 -Requires: rpm-python -Requires: pyOpenSSL -Requires: python-requests -Requires: python-requests-kerberos -Requires: python-pycurl -Requires: python-dateutil -Requires: python-six -BuildRequires: python +%if 0%{with python3} +Requires: python3-%{name} = %{version}-%{release} +Requires: python3-pycurl +Requires: python3-libcomps +%else +Requires: python2-%{name} = %{version}-%{release} +Requires: python2-pycurl +%if 0%{?fedora} || 0%{?rhel} >= 7 +Requires: python2-libcomps +%endif +%endif %if %{use_systemd} 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 contains shared libraries and the command-line interface. +%package -n python2-%{name} +Summary: Build system tools python library +%{?python_provide:%python_provide python2-%{name}} +BuildRequires: python2-devel +Requires: python-krbV >= 1.0.13 +Requires: rpm-python +Requires: pyOpenSSL +Requires: python-requests +Requires: python-requests-kerberos +Requires: python-dateutil +Requires: python-six + +%description -n python2-%{name} +desc + +%if 0%{with python3} +%package -n python3-%{name} +Summary: Build system tools python library +%{?python_provide:%python_provide python3-%{name}} +BuildRequires: python3-devel +Requires: python3-rpm +Requires: python3-pyOpenSSL +Requires: python3-requests +Requires: python3-requests-kerberos +Requires: python3-dateutil +Requires: python3-six + +%description -n python3-%{name} +desc +%endif + %package hub Summary: Koji XMLRPC interface Group: Applications/Internet @@ -190,6 +237,12 @@ koji-web is a web UI to the Koji system. %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT %{?install_opt} install +%if 0%{with python3} +cd koji +make DESTDIR=$RPM_BUILD_ROOT PYTHON=python3 %{?install_opt} install +# alter python interpreter in koji CLI +sed -i 's/\#\!\/usr\/bin\/python/\#\!\/usr\/bin\/python3/' $RPM_BUILD_ROOT/usr/bin/koji +%endif %clean rm -rf $RPM_BUILD_ROOT @@ -197,11 +250,19 @@ rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %{_bindir}/* -%{python_sitelib}/%{name} %config(noreplace) /etc/koji.conf %dir /etc/koji.conf.d %doc docs Authors COPYING LGPL +%files -n python2-%{name} +%defattr(-,root,root) +%{python2_sitelib}/%{name} + +%if 0%{with python3} +%files -n python3-koji +%{python3_sitelib}/%{name} +%endif + %files hub %defattr(-,root,root) %{_datadir}/koji-hub diff --git a/koji/Makefile b/koji/Makefile index 857100d..f1ae8d4 100644 --- a/koji/Makefile +++ b/koji/Makefile @@ -1,9 +1,15 @@ -SUBDIRS = ssl - PYTHON=python PACKAGE = $(shell basename `pwd`) -PYFILES = $(wildcard *.py) -PYSCRIPTS = context.py +ifeq ($(PYTHON), python3) + # for python3 we fully support only basic library + CLI + PYFILES = __init__.py util.py + PYSCRIPTS = + SUBDIRS = +else + PYFILES = $(wildcard *.py) + PYSCRIPTS = context.py + SUBDIRS = ssl +endif PYVER := $(shell $(PYTHON) -c 'import sys; print("%.3s" % (sys.version))') PYSYSDIR := $(shell $(PYTHON) -c 'import sys; print(sys.prefix)') PYLIBDIR = $(PYSYSDIR)/lib/python$(PYVER)