summaryrefslogtreecommitdiffstats
path: root/src/software/test/rpmcache.py
diff options
context:
space:
mode:
authorMichal Minar <miminar@redhat.com>2013-02-12 15:54:14 +0100
committerMichal Minar <miminar@redhat.com>2013-02-13 20:02:50 +0100
commit46aacac8e2aabed5582f5c7da70a5acb5b679569 (patch)
tree8190c55b05f02108620732232ef5c080d5529f35 /src/software/test/rpmcache.py
parent1d60a267af3eb94f8f158b4cf8abf3cc254611a1 (diff)
downloadopenlmi-providers-46aacac8e2aabed5582f5c7da70a5acb5b679569.tar.gz
openlmi-providers-46aacac8e2aabed5582f5c7da70a5acb5b679569.tar.xz
openlmi-providers-46aacac8e2aabed5582f5c7da70a5acb5b679569.zip
initial phase of rewrite for SMASH profile
currently only a subset of Software Inventory profile is supported * listing available packages
Diffstat (limited to 'src/software/test/rpmcache.py')
-rw-r--r--src/software/test/rpmcache.py422
1 files changed, 234 insertions, 188 deletions
diff --git a/src/software/test/rpmcache.py b/src/software/test/rpmcache.py
index 9a0e98a..c2dde24 100644
--- a/src/software/test/rpmcache.py
+++ b/src/software/test/rpmcache.py
@@ -18,49 +18,59 @@
#
# Authors: Radek Novacek <rnovacek@redhat.com>
# Authors: Michal Minar <miminar@redhat.com>
+
"""
Creation and manipulation utilities with rpm cache for software tests.
"""
+
import copy
import datetime
import os
import pickle
+import random
import re
from collections import defaultdict
from subprocess import call, check_output, CalledProcessError
+from package import Package
+import util
+
DB_BACKUP_FILE = 'lmi_software_test_cache'
RE_AVAIL_PKG = re.compile(
r'^(?P<name>[^\s]+)\.(?P<arch>[a-zA-Z0-9_]+)'
- r'\s+(?P<epoch>([0-9]+:)?)(?P<version>[a-zA-Z0-9._+-]+)'
- r'-(?P<release>[a-zA-Z0-9_.]+)\s+'
- r'(?P<repository>[a-zA-Z0-9_-]+)\s*$', re.MULTILINE)
+ r'\s+((?P<epoch>[0-9]+):)?(?P<ver>[a-zA-Z0-9._+-]+)'
+ r'-(?P<rel>[a-zA-Z0-9_.]+)\s+'
+ r'(?P<repo>[a-zA-Z0-9_-]+)\s*$', re.MULTILINE)
# this won't match the last entry, unless "package\n" is not appended
# at the end of the string
RE_PKG_DEPS = re.compile(
r'^package:\s*(?P<name>[^\s]+)\.(?P<arch>[a-zA-Z0-9_]+)'
- r'\s+(?P<epoch>([0-9]+:)?)(?P<version>[a-zA-Z0-9._+-]+)'
- r'-(?P<release>[a-zA-Z0-9_.]+)\s+(?P<dep_list>.*?)'
+ r'\s+((?P<epoch>[0-9]+):)?(?P<ver>[a-zA-Z0-9._+-]+)'
+ r'-(?P<rel>[a-zA-Z0-9_.]+)\s+(?P<dep_list>.*?)'
r'(?=^package|\Z)', re.MULTILINE | re.DOTALL)
RE_DEPS_PROVIDERS = re.compile(
r'^\s*dependency:\s*(?P<dependency>.+?)\s*'
- r'(?P<providers>(^\s+provider:.+?$)+)', re.MULTILINE | re.IGNORECASE)
+ r'(?P<providers>(^\s+unsatisfied\s+dependency$)|(^\s+provider:.+?$)+)',
+ re.MULTILINE | re.IGNORECASE)
+RE_DEPS_UNSATISFIED = re.compile(r'^\s+unsatisfied\s+dep.*$', re.IGNORECASE)
RE_PROVIDER = re.compile(
r'^\s+provider:\s*(?P<name>[^\s]+)\.(?P<arch>[a-zA-Z0-9_]+)'
- r'\s+(?P<epoch>([0-9]+:)?)(?P<version>[a-zA-Z0-9._+-]+)'
- r'-(?P<release>[a-zA-Z0-9_.]+)\s*$', re.IGNORECASE | re.MULTILINE)
+ r'\s+((?P<epoch>[0-9]+):)?(?P<ver>[a-zA-Z0-9._+-]+)'
+ r'-(?P<rel>[a-zA-Z0-9_.]+)\s*$', re.IGNORECASE | re.MULTILINE)
RE_PKG_INFO = re.compile(
r'^Name\s*:\s*(?P<name>[^\s]+).*?'
r'^(Epoch\s*:\s*(?P<epoch>[0-9]+)\s+)?'
- r'^Version\s*:\s*(?P<version>[a-zA-Z0-9._+-]+)\s+'
- r'^Release\s*:\s*(?P<release>[^\s]+)\s+.*?'
+ r'^Version\s*:\s*(?P<ver>[a-zA-Z0-9._+-]+)\s+'
+ r'^Release\s*:\s*(?P<rel>[^\s]+)\s+.*?'
r'^Size\s*:\s*(?P<size>\d+(\.\d+)?)( *(?P<units>[kMG]))?',
re.MULTILINE | re.DOTALL | re.IGNORECASE)
RE_REPO = re.compile(
r'(?:^\*?)(?P<name>[^\s/]+\b)(?!\s+id)', re.MULTILINE | re.IGNORECASE)
-# maximum number of packages, that will be selected for testing
+# Maximum number of packages, that will be selected for testing / 2
+# There are 2 sets of test packages (safe and dangerous). When running
+# in dangerous mode, the resulting number will be twice as much.
MAX_PKG_DB_SIZE = 10
# step used to iterate over package names used to check for thery dependencies
# it's a number of packages, that will be passed to yum command at once
@@ -78,104 +88,6 @@ class MissingRPM(InvalidTestCache):
InvalidTestCache.__init__(self,
"Missing package '%s' in test cache!"%pkg_name)
-def make_nevra(name, epoch, ver, rel, arch, with_epoch='NOT_ZERO'):
- """
- @param with_epoch may be one of:
- "NOT_ZERO" - include epoch only if it's not zero
- "ALWAYS" - include epoch always
- "NEVER" - do not include epoch at all
- """
- estr = ''
- if with_epoch.lower() == "always":
- estr = epoch
- elif with_epoch.lower() == "not_zero":
- if epoch != "0":
- estr = epoch
- if len(estr):
- estr += ":"
- return "%s-%s%s-%s.%s" % (name, estr, ver, rel, arch)
-
-def run_yum(*params, **kwargs):
- """
- Runs yum with params and returns its output
- It's here especially to allow pass a repolist argument, that
- specifies list of repositories, to run the command on.
- """
- cmd = ['yum'] + list(params)
- repolist = kwargs.get('repolist', [])
- if repolist:
- cmd += ['--disablerepo=*']
- cmd += ['--enablerepo='+r for r in repolist]
- try:
- return check_output(cmd)
- except Exception:
- import pdb;pdb.set_trace()
-
-class Package(object): #pylint: disable=R0902
- """
- Element of test package database. It's a container for package
- informations. It contains two sets of versions for single package.
- That's meant for updating tests.
- """
- def __init__(self, name, epoch, ver, rel, arch, repo,
- up_epoch, up_ver, up_rel, up_repo):
- """
- Arguments prefixed with 'up_' are for newer package.
- """
- self._name = name
- self._epoch = epoch
- self._ver = ver
- self._rel = rel
- self._arch = arch
- self._repo = repo
- self._up_epoch = up_epoch
- self._up_ver = up_ver
- self._up_rel = up_rel
- self._up_repo = up_repo
-
- def __str__(self):
- return self.get_nevra()
-
- @property
- def name(self): return self._name #pylint: disable=C0111,C0321
- @property
- def epoch(self): return self._epoch #pylint: disable=C0111,C0321
- @property
- def ver(self): return self._ver #pylint: disable=C0111,C0321
- @property
- def rel(self): return self._rel #pylint: disable=C0111,C0321
- @property
- def arch(self): return self._arch #pylint: disable=C0111,C0321
- @property
- def repo(self): return self._repo #pylint: disable=C0111,C0321
- @property
- def nevra(self): #pylint: disable=C0111,C0321
- return self.get_nevra(True)
-
- @property
- def up_epoch(self): return self._up_epoch #pylint: disable=C0111,C0321
- @property
- def up_ver(self): return self._up_ver #pylint: disable=C0111,C0321
- @property
- def up_rel(self): return self._up_rel #pylint: disable=C0111,C0321
- @property
- def up_repo(self): return self._up_repo #pylint: disable=C0111,C0321
- @property
- def up_nevra(self): #pylint: disable=C0111,C0321
- return self.get_nevra(True)
-
- def get_nevra(self, newer=True, with_epoch='NOT_ZERO'):
- """
- @newer if True, evr part is made from properties prefixed with 'up_'
- @return pkg nevra string
- """
- if newer:
- attrs = ['name', 'up_epoch', 'up_ver', 'up_rel', 'arch']
- else:
- attrs = ['name', 'epoch', 'ver', 'rel', 'arch']
- return make_nevra(*[getattr(self, '_'+a) for a in attrs],
- with_epoch=with_epoch)
-
def _match_nevr(match):
"""
@param match is a regexp match object with parsed rpm package
@@ -183,22 +95,33 @@ def _match_nevr(match):
"""
epoch = match.group('epoch')
return ( match.group('name')
- , epoch[:-1] if epoch else "0"
- , match.group('version')
- , match.group('release'))
+ , epoch if epoch and epoch.lower() != "(none)" else "0"
+ , match.group('ver')
+ , match.group('rel'))
-def _match2pkg(match):
+def _match2pkg(match, safe=False):
"""
@param match is a regexp match object with attributes:
name, epoch, version, release, arch
+ @param safe if True, the packe will have up_* properties equal to
+ non-prefixed ones, otherwise they will be set to None
@return instance of Package
"""
+ kwargs = {}
+ if safe is True:
+ kwargs['safe'] = True
+ else:
+ for attr in ('epoch', 'ver', 'rel', 'repo'):
+ kwargs['up_'+attr] = None
+ epoch = match.group('epoch')
+ if not epoch or epoch.lower() == "(none)":
+ epoch = '0'
return Package(
match.group('name'),
- match.group('epoch')[:-1] if match.group('epoch') else '0',
- match.group('version'), match.group('release'),
- match.group('arch'), match.groupdict().get('repository', None),
- None, None, None, None)
+ epoch,
+ match.group('ver'), match.group('rel'),
+ match.group('arch'), match.groupdict().get('repo', None),
+ **kwargs)
def _filter_duplicates(installed, avail_str):
"""
@@ -213,7 +136,7 @@ def _filter_duplicates(installed, avail_str):
dups_list = []
cur_package_matches = []
prev_match = None
- system_arch = get_system_architecture()
+ system_arch = util.get_system_architecture()
for match in RE_AVAIL_PKG.finditer(avail_str):
if ( _match_nevr(match) in [ _match_nevr(m)
for m in cur_package_matches]
@@ -246,12 +169,14 @@ def _check_single_pkg_deps(
"""
for match_deps in RE_DEPS_PROVIDERS.finditer(dependencies_str):
providers = []
+ if RE_DEPS_UNSATISFIED.search(match_deps.group('providers')):
+ return False
for match_dep in RE_PROVIDER.finditer(match_deps.group('providers')):
if match_dep.group('name') not in installed:
continue
providers.append(_match2pkg(match_dep))
for provider in providers:
- if is_installed(provider, False):
+ if is_pkg_installed(provider, False):
break
else: # no provider is installed
return False
@@ -261,7 +186,7 @@ def _check_pkg_dependencies(
installed,
dup_list,
number_of_packages=MAX_PKG_DB_SIZE,
- repolist=[]):
+ repolist=None):
"""
Finds packages from dup_list with satisfied (installed) dependencies.
@param installed is a set of installed package names
@@ -274,7 +199,7 @@ def _check_pkg_dependencies(
yum_params = yum_params[:1]
for dups in dups_part:
yum_params.extend([d.get_nevra(newer=False) for d in dups])
- deplist_str = run_yum(*yum_params, repolist=repolist)
+ deplist_str = util.run_yum(*yum_params, repolist=repolist)
matches = RE_PKG_DEPS.finditer(deplist_str)
prev_match = None
for pkgs in dups_part:
@@ -300,14 +225,14 @@ def _check_pkg_dependencies(
break
return dups_no_deps
-def _sorted_db_by_size(pkgdb, repolist=[]):
+def _sorted_db_by_size(pkgdb, repolist=None):
"""
@param pkgdb is a list of lists of packages with common name
@return sorted instances of Package according to their size
"""
yum_params = ['info', '--showduplicates']
yum_params.extend([ps[0].name for ps in pkgdb])
- info_str = run_yum(*yum_params, repolist=repolist)
+ info_str = util.run_yum(*yum_params, repolist=repolist)
pkg_sizes = {}
# to get correct ordering from "yum info" command
# { pkg_name : [(epoch, version, release), ... ] }
@@ -329,7 +254,7 @@ def _sorted_db_by_size(pkgdb, repolist=[]):
if not epoch:
epoch = "0"
pkg_version_order[pkg_name].append((
- epoch, info_match.group('version'), info_match.group('release')))
+ epoch, info_match.group('ver'), info_match.group('rel')))
pkgdb = sorted(pkgdb, key=lambda pkgs: pkg_sizes[pkgs[0].name])[
:MAX_PKG_DB_SIZE]
@@ -350,7 +275,7 @@ def _get_repo_list():
repos_str = check_output(['yum', 'repolist', '-q'])
return RE_REPO.findall(repos_str)
-def _download_pkgdb(repolist, pkgdb, cache_dir=None):
+def _download_dangerous(repolist, pkgdb, cache_dir=None):
"""
Downloads all rpm packages (old and newer versions) from package database
to current directory.
@@ -385,32 +310,6 @@ def _make_rpm_path(pkg, cache_dir='', newer=True, without_epoch=False):
with_epoch='NEVER' if without_epoch else 'NOT_ZERO')
return os.path.join(cache_dir, nevra) + '.rpm'
-def is_installed(pkg, newer=True):
- """
- Check, whether package is installed.
- """
- if not isinstance(pkg, Package):
- return call(["rpm", "--quiet", "-q", pkg]) == 0
- else:
- try:
- cmd = [ "rpm", "-q", "--qf", "%{EPOCH}:%{NVRA}", pkg.get_nevra(
- newer, with_epoch='NEVER') ]
- out = check_output(cmd)
- epoch, nvra = out.split(':') #pylint: disable=E1103
- if not epoch or epoch == "(none)":
- epoch = "0"
- return ( epoch == pkg.epoch
- and nvra == pkg.get_nevra(newer=newer, with_epoch="NEVER"))
- except CalledProcessError:
- return False
-
-def rpm_exists(pkg, cache_dir='', newer=True):
- """
- @return True, when rpm package is in cache.
- """
- return ( os.path.exists(_make_rpm_path(pkg, cache_dir, newer))
- or os.path.exists(_make_rpm_path(pkg, cache_dir, newer, True)))
-
def get_rpm_name(pkg, cache_dir='', newer=True):
"""
Some packages do not have epoch in their name, even if it's higher than
@@ -425,56 +324,126 @@ def get_rpm_name(pkg, cache_dir='', newer=True):
return path
raise MissingRPM(pkg.name)
-def get_system_architecture():
+def rpm_exists(pkg, cache_dir='', newer=True):
+ """
+ @return True, when rpm package is in cache.
+ """
+ return ( os.path.exists(_make_rpm_path(pkg, cache_dir, newer))
+ or os.path.exists(_make_rpm_path(pkg, cache_dir, newer, True)))
+
+
+def remove_pkg(pkg, *args):
+ """
+ Remove package with rpm command.
+ @param pkg is either instance of Package or package name
+ @param args is a list of parameters for rpm command
+ """
+ if isinstance(pkg, Package):
+ pkg = pkg.name
+ call(["rpm", "--quiet"] + list(args) + ["-e", pkg])
+
+def install_pkg(pkg, newer=True, repolist=None):
"""
- @return the system architecture name as seen by rpm
+ Install a specific package.
+ @param pkg is either package name or instance of Package
+ In latter case, a specific version is installed.
+ @param repolist is a list of repositories, that should be
+ used for downloading, if using yum
+ when empty, all enabled repositories are used
"""
- return check_output(['rpm', '-q', '--qf', '%{ARCH}\n', 'rpm'])
+ if isinstance(pkg, Package):
+ try:
+ rpm_name = get_rpm_name(pkg, newer=newer)
+ call(["rpm", "--quiet", "-i", rpm_name])
+ return
+ except MissingRPM:
+ pass
+ pkg = pkg.name
+ util.run_yum('-q', '-y', 'install', pkg, repolist=repolist)
+
+def ensure_pkg_installed(pkg, newer=True, repolist=None):
+ """
+ Ensures, that specific version of package is installed. If other
+ version is installed, it is removed and reinstalled.
+ """
+ if not isinstance(pkg, Package):
+ raise TypeError("pkg must be a Package instance")
+ if not is_pkg_installed(pkg, newer):
+ if is_pkg_installed(pkg.name):
+ remove_pkg(pkg.name)
+ install_pkg(pkg, newer, repolist)
-def write_pkgdb(pkgdb, cache_dir=''):
+def verify_pkg(pkg):
+ """
+ @return output of command rpm, with verification output for package
+ """
+ if isinstance(pkg, basestring):
+ name = pkg
+ elif isinstance(pkg, Package):
+ name = pkg.name
+ else:
+ raise TypeError("pkg must be either package name or Package instance")
+ return call(["rpm", "--quiet", "-Va", name]) == 0
+
+def has_pkg_config_file(pkg, file_path):
+ """
+ @return True, if file_path is a configuration file of package pkg.
+ """
+ cmd = ['rpm', '-qc', pkg.name]
+ out = check_output(cmd)
+ return file_path in set(out.splitlines()) #pylint: disable=E1103
+
+def has_pkg_doc_file(pkg, file_path):
+ """
+ @return True, if file_path is a documentation file of package pkg.
+ """
+ cmd = ['rpm', '-qd', pkg.name]
+ out = check_output(cmd)
+ return file_path in set(out.splitlines()) #pylint: disable=E1103
+
+def is_pkg_installed(pkg, newer=True):
+ """
+ Check, whether package is installed.
+ """
+ if not isinstance(pkg, Package):
+ return call(["rpm", "--quiet", "-q", pkg]) == 0
+ else:
+ cmd = [ "rpm", "-q", "--qf", "%{EPOCH}:%{NVRA}\n", pkg.get_nevra(
+ newer, with_epoch='NEVER') ]
+ try:
+ out = check_output(cmd).splitlines()[0]
+ epoch, nvra = out.split(':') #pylint: disable=E1103
+ if not epoch or epoch.lower() == "(none)":
+ epoch = "0"
+ return ( epoch == getattr(pkg, 'up_epoch' if newer else 'epoch')
+ and nvra == pkg.get_nevra(newer=newer, with_epoch="NEVER"))
+ except CalledProcessError:
+ return False
+
+def write_pkgdb(safe_pkgs, dangerous_pkgs, cache_dir=''):
"""
Writes package database into a file named DB_BACKUP_FILE.
"""
with open(os.path.join(cache_dir, DB_BACKUP_FILE), 'w') as db_file:
- pickle.dump((datetime.datetime.now(), pkgdb), db_file)
+ data = (datetime.datetime.now(), safe_pkgs, dangerous_pkgs)
+ pickle.dump(data, db_file)
def load_pkgdb(cache_dir=''):
"""
This is inverse function to _write_pkgdb().
- @return package database loaded from file
+ @return (safe, dangerous) package lists loaded from file
"""
with open(os.path.join(cache_dir, DB_BACKUP_FILE), 'r') as db_file:
- date_time, pkgdb = pickle.load(db_file)
+ _, safe, dangerous = pickle.load(db_file)
#print "Loaded package database from: %s" % date_time
- return pkgdb
+ return safe, dangerous
-def get_pkg_database(force_update=False, use_cache=True,
- cache_dir='',
- repolist=[]):
+def make_dangerous_list(installed, repolist=None):
"""
- Checks yum database for available packages, that have at least two
- different versions in repositories. Only not installed ones with
- all of their dependencies intalled are selected.
- And from those, few of the smallest are downloaded as rpms.
- @return list of instances of Package of selected packages
+ This makes a list of instances of Package for dangerous tests.
"""
- if ( use_cache and not force_update
- and os.path.exists(os.path.join(cache_dir, DB_BACKUP_FILE))):
- pkgdb = load_pkgdb(cache_dir)
- valid_db = True
- for pkg in pkgdb:
- if ( not rpm_exists(pkg, cache_dir, False)
- or not rpm_exists(pkg, cache_dir, True)):
- valid_db = False
- #print "Old package database is not valid"
- break
- if valid_db:
- return pkgdb
- #print "Getting installed packages"
- installed = set(check_output( #pylint: disable=E1103
- ['rpm', '-qa', '--qf=%{NAME}\n']).splitlines())
#print "Getting all available packages"
- avail_str = run_yum('list', 'available', '--showduplicates',
+ avail_str = util.run_yum('list', 'available', '--showduplicates',
repolist=repolist)
# list of lists of packages with the same name, longer than 2
#print "Finding duplicates"
@@ -485,11 +454,88 @@ def get_pkg_database(force_update=False, use_cache=True,
number_of_packages=MAX_PKG_DB_SIZE*5,
repolist=repolist)
#print "Selecting the smallest ones"
- pkgdb = _sorted_db_by_size(selected, repolist=repolist)
+ return _sorted_db_by_size(selected, repolist=repolist)
+
+def make_safe_list(installed, exclude=None):
+ """
+ Makes list of installed packages for non-dangerous tests.
+ @param installed is a list of installed packages names
+ @param exclude is a list of package names, that won't appear in result
+ """
+ if exclude is None:
+ exclude = set()
+ base = list(installed)
+ random.shuffle(base)
+ res = []
+ i = 0
+ while len(res) < MAX_PKG_DB_SIZE and i < len(base):
+ name = base[i]
+ i += 1
+ if name in exclude:
+ continue
+ cmd = [ "rpm", "-q", "--qf", "%{EPOCH}:%{NVRA}\n", name ]
+ envra = check_output(cmd).splitlines()[0]
+ res.append(_match2pkg(util.RE_ENVRA.match(envra), safe=True))
+ return res
+
+def get_pkg_database(
+ force_update=False,
+ use_cache=True,
+ dangerous=False,
+ cache_dir='',
+ repolist=None):
+ """
+ Checks yum database for available packages, that have at least two
+ different versions in repositories. Only not installed ones with
+ all of their dependencies intalled are selected.
+ And from those, few of the smallest are downloaded as rpms.
+ @param dangerous whether to load available, not installed
+ packages for dangerous tests
+ @return (safe, dangerous)
+ where
+ safe is a list of instances of Package, representing installed
+ software, these should be used for not-dangerous tests;
+ both older
+ dangerous is a list of instances of Package of selected packages,
+ that are not installed, but available; instances contain
+ both newer and older version of package
+ """
+ dangerous_pkgs = []
+ if ( use_cache and not force_update
+ and os.path.exists(os.path.join(cache_dir, DB_BACKUP_FILE))):
+ safe_pkgs, dangerous_pkgs = load_pkgdb(cache_dir)
+ valid_db = True
+ if len(safe_pkgs) < MAX_PKG_DB_SIZE:
+ valid_db = False
+ elif not dangerous and len(dangerous_pkgs) > 0:
+ dangerous_pkgs = []
+ elif dangerous and len(dangerous_pkgs) == 0:
+ valid_db = False
+ else:
+ for pkg in safe_pkgs:
+ if not is_pkg_installed(pkg):
+ valid_db = False
+ break
+ for pkg in dangerous_pkgs:
+ if ( not rpm_exists(pkg, cache_dir, False)
+ or not rpm_exists(pkg, cache_dir, True)):
+ valid_db = False
+ #print "Old package database is not valid"
+ break
+ if valid_db:
+ return (safe_pkgs, dangerous_pkgs)
+ #print "Getting installed packages"
+ installed = set(check_output( #pylint: disable=E1103
+ ['rpm', '-qa', '--qf=%{NAME}\n']).splitlines())
+ if dangerous:
+ dangerous_pkgs = make_dangerous_list(installed)
+ safe_pkgs = make_safe_list(installed, exclude=set(
+ pkg.name for pkg in dangerous_pkgs))
+
if use_cache:
- repolist = _get_repo_list()
- _download_pkgdb(repolist, pkgdb, cache_dir)
+ repolist = _get_repo_list() if repolist in (None, []) else repolist
+ _download_dangerous(repolist, dangerous_pkgs, cache_dir)
#print "Backing up database information"
- write_pkgdb(pkgdb, cache_dir)
- return pkgdb
+ write_pkgdb(safe_pkgs, dangerous_pkgs, cache_dir)
+ return (safe_pkgs, dangerous_pkgs)