Skip to content

Commit

Permalink
RubyCompatCheck: new check for new USE_RUBY compatible values
Browse files Browse the repository at this point in the history
Resolves: #304
Signed-off-by: Arthur Zamarin <[email protected]>
  • Loading branch information
arthurzam committed Jun 30, 2023
1 parent c41771d commit 839a1f4
Show file tree
Hide file tree
Showing 13 changed files with 302 additions and 0 deletions.
109 changes: 109 additions & 0 deletions src/pkgcheck/checks/ruby.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
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_"


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}"


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))

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

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
}

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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"__class__": "RubyCompatUpdate", "category": "RubyCompatCheck", "package": "RubyCompatUpdate", "version": "0", "updates": ["ruby31", "ruby32"]}
{"__class__": "RubyCompatUpdate", "category": "RubyCompatCheck", "package": "RubyCompatUpdate", "version": "1", "updates": ["ruby32"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
EAPI=7

USE_RUBY="ruby27 ruby30"
inherit ruby-ng

DESCRIPTION="Ebuild with potential USE_RUBY updates"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
LICENSE="BSD"
SLOT="0"

RDEPEND="
stub/stub2
"

ruby_add_rdepend "
stub/ruby-dep
"
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
EAPI=7

USE_RUBY="ruby27 ruby30 ruby31"
inherit ruby-ng

DESCRIPTION="Ebuild with potential USE_RUBY updates"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
LICENSE="BSD"
SLOT="0"

RDEPEND="
stub/stub2
"

ruby_add_depend "
stub/ruby-dep
"
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
EAPI=7

USE_RUBY="ruby27 ruby30"
inherit ruby-ng

DESCRIPTION="Ebuild without potential USE_RUBY updates"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
LICENSE="BSD"
SLOT="0"

RDEPEND="
stub/stub2
"

ruby_add_rdepend "
stub/ruby-dep-old
"
6 changes: 6 additions & 0 deletions testdata/repos/python/dev-lang/ruby/ruby-2.7.ebuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
EAPI=7

DESCRIPTION="Stub ebuild for ruby interpreter"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
LICENSE="BSD"
SLOT="2.7"
6 changes: 6 additions & 0 deletions testdata/repos/python/dev-lang/ruby/ruby-3.0.ebuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
EAPI=7

DESCRIPTION="Stub ebuild for ruby interpreter"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
LICENSE="BSD"
SLOT="3.0"
6 changes: 6 additions & 0 deletions testdata/repos/python/dev-lang/ruby/ruby-3.1.ebuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
EAPI=7

DESCRIPTION="Stub ebuild for ruby interpreter"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
LICENSE="BSD"
SLOT="3.1"
6 changes: 6 additions & 0 deletions testdata/repos/python/dev-lang/ruby/ruby-3.2.ebuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
EAPI=7

DESCRIPTION="Stub ebuild for ruby interpreter"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
LICENSE="BSD"
SLOT="3.2"
83 changes: 83 additions & 0 deletions testdata/repos/python/eclass/ruby-ng.eclass
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
_ruby_implementation_depend() {
local rubypn= rubyslot=

case $1 in
ruby27) rubypn="dev-lang/ruby" rubyslot=":2.7" ;;
ruby30) rubypn="dev-lang/ruby" rubyslot=":3.0" ;;
ruby31) rubypn="dev-lang/ruby" rubyslot=":3.1" ;;
ruby32) rubypn="dev-lang/ruby" rubyslot=":3.2" ;;
*) die "$1: unknown Ruby implementation"
esac

echo "$2${rubypn}$3${rubyslot}"
}

_ruby_implementations_depend() {
local depend _ruby_implementation
for _ruby_implementation in "${_RUBY_GET_ALL_IMPLS[@]}"; do
depend="${depend}${depend+ }ruby_targets_${_ruby_implementation}? ( $(_ruby_implementation_depend $_ruby_implementation) )"
done
DEPEND="${depend}"
IUSE="${_RUBY_GET_ALL_IMPLS[*]/#/ruby_targets_}"
REQUIRED_USE="|| ( ${IUSE} )"
}

_ruby_atoms_samelib_generic() {
local shopt_save=$(shopt -p -o noglob)
echo "RUBYTARGET? ("
for token in $*; do
case "$token" in
"||" | "(" | ")" | *"?")
echo "${token}" ;;
*])
echo "${token%[*}[RUBYTARGET(-),${token/*[}" ;;
*)
echo "${token}[RUBYTARGET(-)]" ;;
esac
done
echo ")"
${shopt_save}
}

_ruby_atoms_samelib() {
local atoms=$(_ruby_atoms_samelib_generic "$*")
for _ruby_implementation in "${_RUBY_GET_ALL_IMPLS[@]}"; do
echo "${atoms//RUBYTARGET/ruby_targets_${_ruby_implementation}}"
done
}

_ruby_get_all_impls() {
_RUBY_GET_ALL_IMPLS=()

local i found_valid_impl
for i in ${USE_RUBY}; do
case ${i} in
# removed implementations
ruby19|ruby2[0-7]|jruby)
;;
*)
found_valid_impl=1
_RUBY_GET_ALL_IMPLS+=( ${i} )
;;
esac
done

if [[ -z ${found_valid_impl} ]] ; then
die "No supported implementation in USE_RUBY."
fi
}

ruby_add_depend() {
DEPEND+=" $(_ruby_atoms_samelib "$1")"
}

ruby_add_bdepend() {
BDEPEND+=" $(_ruby_atoms_samelib "$1")"
}

ruby_add_rdepend() {
RDEPEND+=" $(_ruby_atoms_samelib "$1")"
}

_ruby_get_all_impls
_ruby_implementations_depend
5 changes: 5 additions & 0 deletions testdata/repos/python/profiles/desc/ruby_targets.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# available RUBY_TARGETS USE_EXPAND flags
ruby27 - Build with MRI Ruby 2.7.x
ruby30 - Build with MRI Ruby 3.0.x
ruby31 - Build with MRI Ruby 3.1.x
ruby32 - Build with MRI Ruby 3.2.x
14 changes: 14 additions & 0 deletions testdata/repos/python/stub/ruby-dep-old/ruby-dep-old-0.ebuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
EAPI=7

USE_RUBY="ruby27 ruby30"

inherit ruby-ng

DESCRIPTION="Stub ebuild with old USE_RUBY support"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
LICENSE="BSD"
SLOT="0"

RDEPEND="
stub/stub2
"
14 changes: 14 additions & 0 deletions testdata/repos/python/stub/ruby-dep/ruby-dep-0.ebuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
EAPI=7

USE_RUBY="ruby27 ruby30 ruby31 ruby32"

inherit ruby-ng

DESCRIPTION="Stub ebuild with complete USE_RUBY support"
HOMEPAGE="https://github.com/pkgcore/pkgcheck"
LICENSE="BSD"
SLOT="0"

RDEPEND="
stub/stub1
"

0 comments on commit 839a1f4

Please sign in to comment.