diff options
Diffstat (limited to 'src/software/openlmi/software/yumdb/process.py')
-rw-r--r-- | src/software/openlmi/software/yumdb/process.py | 178 |
1 files changed, 118 insertions, 60 deletions
diff --git a/src/software/openlmi/software/yumdb/process.py b/src/software/openlmi/software/yumdb/process.py index faa0711..96c471e 100644 --- a/src/software/openlmi/software/yumdb/process.py +++ b/src/software/openlmi/software/yumdb/process.py @@ -75,44 +75,96 @@ def _get_package_filter_function(filters): filters = dict((k, value) for k, value in filters.items() if value is not None) + match = None if "nevra" in filters: - def _cmp_nevra(pkg): - """@return True if pkg matches nevra filter""" - value = '%s-%s:%s-%s.%s' % ( - pkg.name, - "0" if not pkg.epoch or pkg.epoch == "(none)" - else pkg.epoch, - pkg.version, pkg.release, pkg.arch) - return value == filters["nevra"] - return _cmp_nevra - + match = util.RE_NEVRA.match(filters["nevra"]) elif "envra" in filters: - def _cmp_envra(pkg): - """@return True if pkg matches envra filter""" - value = '%s:%s-%s-%s.%s' % ( - "0" if not pkg.epoch or pkg.epoch == "(none)" - else pkg.epoch, - pkg.name, - pkg.version, pkg.release, pkg.arch) - return value == filters["envra"] - return _cmp_envra - - else: - if "evra" in filters: - for prop_name in ("epoch", "version", "release", "epoch"): - filters.pop(prop_name, None) - filter_list = [] - # properties are sorted by their filtering ability - # (the most unprobable property, that can match, comes first) - for prop_name in ("evra", "name", "version", "epoch", - "release", "arch"): - if not prop_name in filters: - continue - filter_list.append((prop_name, filters.pop(prop_name))) - def _cmp_props(pkg): - """@return True if pkg matches properies filter""" - return all(getattr(pkg, p) == v for p, v in filter_list) - return _cmp_props + match = util.RE_ENVRA.match(filters["envra"]) + if match is not None: + for attr in ("name", "epoch", "version", "release", "arch"): + match_attr = attr + if attr in {'version', 'release'}: + match_attr = attr[:3] + filters[attr] = match.group(match_attr) + filters.pop('nevra', None) + filters.pop('envra', None) + elif "evra" in filters: + for prop_name in ("epoch", "version", "release", "epoch"): + filters.pop(prop_name, None) + filter_list = [] + # properties are sorted by their filtering ability + # (the most unprobable property, that can match, comes first) + for prop_name in ("evra", "name", "version", "epoch", + "release", "repoid", "arch"): + if not prop_name in filters: + continue + filter_list.append((prop_name, filters.pop(prop_name))) + def _cmp_props(pkg): + """@return True if pkg matches properies filter""" + return all(getattr(pkg, p) == v for p, v in filter_list) + return _cmp_props + +class RepoFilterSetter(object): + """ + A context manager, that will set a repository filter lasting + as long as the object itself. + """ + def __init__(self, yum_base, include_repos=None, exclude_repos=None): + if not isinstance(yum_base, yum.YumBase): + raise TypeError("yum_base must be a YumBase instance") + self._yum_base = yum_base + self._include = include_repos + self._exclude = exclude_repos + # after __enter__ this will be dictionary containing ( + # repoid, enabled) pairs + self._prev_states = None + + def __enter__(self): + self._prev_states = { r.id: r.enabled + for r in self._yum_base.repos.repos.values()} + if isinstance(self._exclude, (list, tuple, set)): + exclude = ",".join(self._exclude) + else: + exclude = self._exclude + # set of repositories, that were affected + repos = set() + if exclude: + repos.update(self._yum_base.repos.disableRepo(exclude)) + _logger().info('disabling repositories: [%s]', ", ".join(repos)) + if isinstance(self._include, (list, tuple, set)): + include = ",".join(self._include) + else: + include = self._include + if include: + affected = self._yum_base.repos.enableRepo(include) + _logger().info('enabling repositories: [%s]', ", ".join(affected)) + repos.update(affected) + for repoid, prev_enabled in self._prev_states.items(): + if ( repoid not in repos + or ( bool(prev_enabled) + is bool(self._yum_base.repos.getRepo(repoid).enabled))): + # keep only manipulated repositories + del self._prev_states[repoid] + if len(self._prev_states): + for repoid in (r for r, v in self._prev_states.items() if v): + self._yum_base.pkgSack.sacks.pop(repoid, None) + self._yum_base.repos.populateSack() + return self + + def __exit__(self, exc_type, exc_value, exc_tb): + # restore previous repository states + if len(self._prev_states): + _logger().info('restoring repositories: [%s]', + ", ".join(self._prev_states.keys())) + for repoid, enabled in self._prev_states.items(): + repo = self._yum_base.repos.getRepo(repoid) + if enabled: + repo.enable() + else: + repo.disable() + for repoid in (r for r, v in self._prev_states.items() if not v): + self._yum_base.pkgSack.sacks.pop(repoid, None) + self._yum_base.repos.populateSack() # ***************************************************************************** # Decorators @@ -204,7 +256,7 @@ class YumWorker(Process): yum_args=None, yum_kwargs=None, logging_config=None): - Process.__init__(self) + Process.__init__(self, name="YumWorker") self._queue_in = queue_in self._queue_out = queue_out self._session_level = 0 @@ -304,7 +356,7 @@ class YumWorker(Process): for orig in packages: pkg = packageinfo.make_package_from_db(orig) if cache_packages is True: - self._pkg_cache[pkg.pkgid] = orig + self._pkg_cache[pkg.objid] = orig res.append(pkg) return res @@ -336,15 +388,15 @@ class YumWorker(Process): if not isinstance(pkg, packageinfo.PackageInfo): raise TypeError("pkg must be instance of PackageInfo") _logger().debug("looking up yum package %s with id=%d", - pkg, pkg.pkgid) + pkg, pkg.objid) try: - result = self._pkg_cache[pkg.pkgid] + result = self._pkg_cache[pkg.objid] _logger().debug("lookup successful") except KeyError: _logger().warn("lookup of package %s with id=%d failed, trying" - " to query database", pkg, pkg.pkgid) + " to query database", pkg, pkg.objid) result = self._handle_filter_packages( - 'installed' if pkg.installed else 'avail_reinst', + 'installed' if pkg.installed else 'available', allow_duplicates=False, sort=False, transform=False, @@ -363,8 +415,10 @@ class YumWorker(Process): last modification times. """ if self._yum_base is not None: - self._yum_base.repos.close() + for repoid in self._yum_base.repos.repos.keys(): + self._yum_base.repos.delete(repoid) del self._yum_base.repos + del self._yum_base.pkgSack self._repodir_mtimes.clear() @_trace_function @@ -388,16 +442,17 @@ class YumWorker(Process): for repo in self._yum_base.repos.repos.values(): filename = repo.repofile if ( not os.path.exists(filename) - or os.stat(filename).st_mtime > repo.repo_config_age): - _logger().info('config file of repository "%s"' - ' changed', repo.id) + or ( int(os.stat(filename).st_mtime) + > repo.repo_config_age)): + _logger().info('config file of repository "%s" changed', + repo.id) dirty = True break if dirty is True: _logger().info("repository cache is dirty, cleaning up ...") self._clear_repository_cache() - if dirty is True or not self._repodir_mtimes: self._yum_base.getReposFromConfig() + if dirty is True or not self._repodir_mtimes: self._update_repodir_mtimes() @_trace_function @@ -478,14 +533,14 @@ class YumWorker(Process): Handler for session end job. """ _logger().info("ending session level %d", self._session_level) - self._session_level -= 1 + self._session_level = max(self._session_level - 1, 0) if self._session_level == 0: self._unlock_database() self._session_ended = True @_needs_database def _handle_get_package_list(self, kind, allow_duplicates, sort, - transform=True): + include_repos=None, exclude_repos=None, transform=True): """ Handler for listing packages job. @param transform says, whether to return just a package abstractions @@ -500,10 +555,11 @@ class YumWorker(Process): what = 'all' else: what = kind - _logger().debug("calling YumBase.doPackageLists(%s, showdups=%s)", - what, allow_duplicates) - pkglist = self._yum_base.doPackageLists(what, showdups=allow_duplicates) - _logger().debug("YumBase.doPackageLists() finished") + with RepoFilterSetter(self._yum_base, include_repos, exclude_repos): + _logger().debug("calling YumBase.doPackageLists(%s, showdups=%s)", + what, allow_duplicates) + pkglist = self._yum_base.doPackageLists(what, + showdups=allow_duplicates) if kind == 'all': result = pkglist.available + pkglist.installed elif kind == 'available': @@ -519,12 +575,14 @@ class YumWorker(Process): @_needs_database def _handle_filter_packages(self, kind, allow_duplicates, sort, + include_repos=None, exclude_repos=None, transform=True, **filters): """ Handler for filtering packages job. @return [pkg1, pkg2, ...] """ pkglist = self._handle_get_package_list(kind, allow_duplicates, False, + include_repos=include_repos, exclude_repos=exclude_repos, transform=False) matches = _get_package_filter_function(filters) result = [p for p in pkglist if matches(p)] @@ -644,24 +702,24 @@ class YumWorker(Process): @return list of yumdb.Repository instances -- filtered """ filters = dict((k, v) for k, v in filters.items() if v is not None) - if 'name' in filters: + if 'repoid' in filters: self._check_repository_configs() try: repo = repository.make_repository_from_db( - self._yum_base.repos.getRepo(filters["name"])) + self._yum_base.repos.getRepo(filters["repoid"])) if ( (kind == "enabled" and not repo.enabled) or (kind == "disabled" and repo.enabled)): _logger().warn( 'no such repository with id="%s"matching filters', - filters['name']) + filters['repoid']) return [] _logger().debug( "exactly one repository matching filters found") return [repo] except (KeyError, yum.Errors.RepoError): _logger().warn('repository with id="%s" could not be found', - filters['name']) - raise errors.RepositoryNotFound(filters['name']) + filters['repoid']) + raise errors.RepositoryNotFound(filters['repoid']) repos = self._handle_get_repository_list(kind, transform=False) result = [] for repo in repos: @@ -681,9 +739,9 @@ class YumWorker(Process): @return previous enabled state """ try: - repo = self._yum_base.repos.getRepo(repo.name) + repo = self._yum_base.repos.getRepo(repo.repoid) except (KeyError, yum.Errors.RepoError): - raise errors.RepositoryNotFound(repo.name) + raise errors.RepositoryNotFound(repo.repoid) res = repo.enabled try: if enable ^ res: |