Source code for pkgcheck.checks.ruby
import itertools
from pkgcore.ebuild.atom import atom
from snakeoil.sequences import iflatten_instance
from snakeoil.strings import pluralism
from .. import results
from . import Check
IUSE_PREFIX = "ruby_targets_"
[docs]
class RubyCompatUpdate(results.VersionResult, results.Info):
"""``USE_RUBY`` can be updated to support newer ruby version(s)."""
def __init__(self, updates, **kwargs):
super().__init__(**kwargs)
self.updates = tuple(updates)
@property
def desc(self):
s = pluralism(self.updates)
updates = ", ".join(self.updates)
return f"USE_RUBY update{s} available: {updates}"
[docs]
class RubyCompatCheck(Check):
"""Check ruby ebuilds for possible ``USE_RUBY`` updates.
Supports ebuilds inheriting ``ruby-ng``.
"""
known_results = frozenset({RubyCompatUpdate})
whitelist_categories = frozenset({"virtual"})
def __init__(self, *args):
super().__init__(*args)
repo = self.options.target_repo
# sorter for ruby targets leveraging USE_EXPAND flag ordering from repo
self.sorter = repo.use_expand_sorter("ruby_targets")
# determine available USE_RUBY use flags
targets = []
for target, _desc in repo.use_expand_desc.get(IUSE_PREFIX[:-1], ()):
if target[len(IUSE_PREFIX) :].startswith("ruby"):
targets.append(target[len(IUSE_PREFIX) :])
self.multi_targets = tuple(sorted(targets, key=self.sorter))
[docs]
def ruby_deps(self, deps, prefix):
for dep in (x for x in deps if x.use):
for x in dep.use:
if x.startswith(("-", "!")):
continue
if x.startswith(prefix):
yield dep.no_usedeps
break
[docs]
def deps(self, pkg):
"""Set of dependencies for a given package's attributes."""
return {
p
for attr in (x.lower() for x in pkg.eapi.dep_keys)
for p in iflatten_instance(getattr(pkg, attr), atom)
if not p.blocks
}
[docs]
def feed(self, pkg):
if pkg.category in self.whitelist_categories or "ruby-ng" not in pkg.inherited:
return
deps = self.deps(pkg)
try:
# determine the latest supported ruby version
latest_target = sorted(
(
f"ruby{x.slot.replace('.', '')}"
for x in deps
if x.key == "dev-lang/ruby" and x.slot is not None
),
key=self.sorter,
)[-1]
except IndexError:
return
# determine ruby impls to target
targets = set(
itertools.takewhile(lambda x: x != latest_target, reversed(self.multi_targets))
)
if targets:
try:
# determine if deps support missing ruby targets
for dep in self.ruby_deps(deps, IUSE_PREFIX):
# TODO: use query caching for repo matching?
latest = sorted(self.options.search_repo.match(dep))[-1]
targets.intersection_update(
f"ruby{x.rsplit('ruby', 1)[-1]}"
for x in latest.iuse_stripped
if x.startswith(IUSE_PREFIX)
)
if not targets:
return
except IndexError:
return
yield RubyCompatUpdate(sorted(targets, key=self.sorter), pkg=pkg)