def test_force(self): # TODO we could do with both more tests and a more powerful # force_* implementation. This just tests if the function # takes the right number of arguments. # TODO test negate handling succeeds = values.GetAttrRestriction('test', values.AlwaysTrue) fails = values.GetAttrRestriction('test', values.AlwaysFalse) class Dummy: test = True dummy = Dummy() class FakePackage: """XXX this is vastly too minimal.""" value = dummy pkg = FakePackage() args = [pkg, 'value', dummy] self.assertForceTrue(succeeds, args) self.assertNotForceFalse(succeeds, args) self.assertNotForceTrue(fails, args) self.assertForceFalse(fails, args)
def parse_maintainer_name(value): """ Case insensitive Regex match on the name bit of metadata.xml's maintainer data. """ return packages.PackageRestriction( 'maintainers', values.AnyMatch( values.GetAttrRestriction( 'name', values.StrRegex(value.lower(), case_sensitive=False))))
def parse_ownsre(value): """Value is a regexp matched against the string form of an fs object. This means the object kind is prepended to the path the regexp has to match. """ return packages.PackageRestriction( 'contents', values.AnyMatch( values.GetAttrRestriction('location', values.StrRegex(value))))
class RequiredUseCheck(Check): """REQUIRED_USE validity checks.""" # only run the check for EAPI 4 and above _source = (sources.RestrictionRepoSource, ( packages.PackageRestriction('eapi', values.GetAttrRestriction( 'options.has_required_use', values.FunctionRestriction(bool))),)) required_addons = (addons.UseAddon, addons.ProfileAddon) known_results = frozenset([InvalidRequiredUse, RequiredUseDefaults, UnstatedIuse]) def __init__(self, *args, use_addon, profile_addon): super().__init__(*args) self.iuse_filter = use_addon.get_filter('required_use') self.profiles = profile_addon def feed(self, pkg): # check REQUIRED_USE for invalid nodes _nodes, unstated = self.iuse_filter((str,), pkg, pkg.required_use) yield from unstated # check both stable/unstable profiles for stable KEYWORDS and only # unstable profiles for unstable KEYWORDS keywords = [] for keyword in pkg.sorted_keywords: if keyword[0] != '~': keywords.append(keyword) keywords.append('~' + keyword.lstrip('~')) # check USE defaults (pkg IUSE defaults + profile USE) against # REQUIRED_USE for all profiles matching a pkg's KEYWORDS failures = defaultdict(list) for keyword in keywords: for profile in sorted(self.profiles.get(keyword, ()), key=attrgetter('name')): # skip packages masked by the profile if profile.visible(pkg): src = FakeConfigurable(pkg, profile) for node in pkg.required_use.evaluate_depset(src.use): if not node.match(src.use): failures[node].append((src.use, profile.key, profile.name)) if self.options.verbosity > 0: # report all failures with profile info in verbose mode for node, profile_info in failures.items(): for use, keyword, profile in profile_info: yield RequiredUseDefaults( str(node), sorted(use), keyword, profile, pkg=pkg) else: # only report one failure per REQUIRED_USE node in regular mode for node, profile_info in failures.items(): num_profiles = len(profile_info) _use, _keyword, profile = profile_info[0] yield RequiredUseDefaults( str(node), profile=profile, num_profiles=num_profiles, pkg=pkg)
class MissingSlotDepCheck(Check): """Check for missing slot dependencies.""" # only run the check for EAPI 5 and above _source = (sources.RestrictionRepoSource, ( packages.PackageRestriction('eapi', values.GetAttrRestriction( 'options.sub_slotting', values.FunctionRestriction(bool))),)) required_addons = (addons.UseAddon,) known_results = frozenset([MissingSlotDep]) def __init__(self, *args, use_addon): super().__init__(*args) self.iuse_filter = use_addon.get_filter() def feed(self, pkg): rdepend, _ = self.iuse_filter((atom_cls,), pkg, pkg.rdepend) depend, _ = self.iuse_filter((atom_cls,), pkg, pkg.depend) # skip deps that are blockers or have explicit slots/slot operators for dep in (x for x in set(rdepend).intersection(depend) if not (x.blocks or x.slot is not None or x.slot_operator is not None)): dep_slots = {x.slot for x in pkg.repo.itermatch(dep.no_usedeps)} if len(dep_slots) > 1: yield MissingSlotDep(str(dep), sorted(dep_slots), pkg=pkg)
def parse_owns(value): return packages.PackageRestriction( 'contents', values.AnyMatch( values.GetAttrRestriction('location', values.StrExactMatch(value))))