def restrictions(self): # ordering here matters; against 24702 ebuilds for # a non matchable atom with package as the first restriction # 10 loops, best of 3: 206 msec per loop # with category as the first(the obvious ordering) # 10 loops, best of 3: 209 msec per loop # why? because category is more likely to collide; # at the time of this profiling, there were 151 categories. # over 11k packages however. r = [restricts.PackageDep(self.package), restricts.CategoryDep(self.category)] if self.repo_id is not None: r.insert(0, restricts.RepositoryDep(self.repo_id)) if self.fullver is not None: if self.op == '=*': r.append(packages.PackageRestriction( "fullver", values.StrGlobMatch(self.fullver))) else: r.append(restricts.VersionMatch( self.op, self.version, self.revision, negate=self.negate_vers)) if self.slot is not None: r.append(restricts.SlotDep(self.slot)) if self.subslot is not None: r.append(restricts.SubSlotDep(self.subslot)) if self.use is not None: r.extend(restricts._parse_nontransitive_use(self.use)) return tuple(r)
def generate_restrict_from_range(self, node, negate=False): op = str(node.get("range").strip()) slot = str(node.get("slot", "").strip()) try: restrict = self.op_translate[op.lstrip("r")] except KeyError: raise ValueError(f'unknown operator: {op!r}') if node.text is None: raise ValueError(f"{op!r} node missing version") base = str(node.text.strip()) glob = base.endswith("*") if glob: base = base[:-1] base = cpv.VersionedCPV(f"cat/pkg-{base}") if glob: if op != "eq": raise ValueError(f"glob cannot be used with {op} ops") return packages.PackageRestriction( "fullver", values.StrGlobMatch(base.fullver)) restrictions = [] if op.startswith("r"): if not base.revision: if op == "rlt": # rlt -r0 can never match # this is a non-range. raise ValueError( "range %s version %s is a guaranteed empty set" % (op, str(node.text.strip()))) elif op == "rle": # rle -r0 -> = -r0 return atom_restricts.VersionMatch("=", base.version, negate=negate) elif op == "rge": # rge -r0 -> ~ return atom_restricts.VersionMatch("~", base.version, negate=negate) # rgt -r0 passes through to regular ~ + > restrictions.append(atom_restricts.VersionMatch("~", base.version)) restrictions.append( atom_restricts.VersionMatch(restrict, base.version, rev=base.revision), ) if slot: restrictions.append(atom_restricts.SlotDep(slot)) return packages.AndRestriction(*restrictions, negate=negate)
def parse_match(text): """generate appropriate restriction for text Parsing basically breaks it down into chunks split by /, with each chunk allowing for prefix/postfix globbing- note that a postfixed glob on package token is treated as package attribute matching, not as necessarily a version match. If only one chunk is found, it's treated as a package chunk. Finally, it supports a nonstandard variation of atom syntax where the category can be dropped. Examples: - `*`: match all - `dev-*/*`: category must start with 'dev-' - `dev-*`: package must start with 'dev-' - `*-apps/portage*`: category must end in '-apps', package must start with 'portage' - `>=portage-2.1`: atom syntax, package 'portage', version greater then or equal to '2.1' - dev-qt/*:5: all Qt 5 libs - boost:0/1.60: all packages named boost with a slot/subslot of 0/1.60.0 :param text: string to attempt to parse :type text: string :return: :obj:`pkgcore.restrictions.packages` derivative """ # Ensure the text var is a string if we're under py3k. if not is_py3k: text = text.encode('ascii') orig_text = text = text.strip() if "!" in text: raise ParseError( "'!' or any form of blockers make no sense in this usage: '%s'" % (text, )) restrictions = [] if '::' in text: text, repo_id = text.rsplit('::', 1) restrictions.append(restricts.RepositoryDep(repo_id)) if ':' in text: text, slot = text.rsplit(':', 1) slot, _sep, subslot = slot.partition('/') if slot: restrictions.append(restricts.SlotDep(slot)) if subslot: restrictions.append(restricts.SubSlotDep(subslot)) tsplit = text.rsplit("/", 1) if len(tsplit) == 1: ops, text = collect_ops(text) if not ops: if "*" in text: r = convert_glob(text) if r is None: restrictions.append(packages.AlwaysTrue) else: restrictions.append( packages.PackageRestriction("package", r)) if len(restrictions) == 1: return restrictions[0] return packages.AndRestriction(*restrictions) elif text.startswith("*"): raise ParseError( "cannot do prefix glob matches with version ops: %s" % (orig_text, )) # ok... fake category. whee. try: r = list( collect_package_restrictions(atom.atom( "%scategory/%s" % (ops, text)).restrictions, attrs=("category", ), invert=True)) except errors.MalformedAtom as e: e.atom = orig_text raise_from(ParseError(str(e))) if not restrictions and len(r) == 1: return r[0] restrictions.extend(r) return packages.AndRestriction(*restrictions) elif text[0] in "=<>~" or "*" not in text: try: return atom.atom(orig_text) except errors.MalformedAtom as e: raise_from(ParseError(str(e))) r = map(convert_glob, tsplit) if not r[0] and not r[1]: restrictions.append(packages.AlwaysTrue) elif not r[0]: restrictions.append(packages.PackageRestriction("package", r[1])) elif not r[1]: restrictions.append(packages.PackageRestriction("category", r[0])) else: restrictions.extend(( packages.PackageRestriction("category", r[0]), packages.PackageRestriction("package", r[1]), )) if len(restrictions) == 1: return restrictions[0] return packages.AndRestriction(*restrictions)