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 _validate_args(parser, namespace): namespace.pkg_dir = False if not namespace.targets: if namespace.selected_repo: # use repo restriction since no targets specified restriction = restricts.RepositoryDep( namespace.selected_repo.repo_id) token = namespace.selected_repo.repo_id else: # Use a path restriction if we're in a repo, obviously it'll work # faster if we're in an invididual ebuild dir but we're not that # restrictive. try: restriction = namespace.repo.path_restrict(namespace.cwd) token = namespace.cwd except (AttributeError, ValueError): parser.error( 'missing target argument and not in a supported repo') # determine if we're grabbing the keywords for a single pkg in cwd namespace.pkg_dir = any( isinstance(x, restricts.PackageDep) for x in reversed(restriction.restrictions)) namespace.targets = [(token, restriction)]
def path_restrict(self, path): """Return a restriction from a given path in a repo. :param path: full or partial path to an ebuild :return: a package restriction matching the given path if possible :raises ValueError: if the repo doesn't contain the given path, the path relates to a file that isn't an ebuild, or the ebuild isn't in the proper directory layout """ if path not in self: raise ValueError( f"{self.repo_id!r} repo doesn't contain: {path!r}") if not path.startswith(os.sep) and os.path.exists( pjoin(self.location, path)): path_chunks = path.split(os.path.sep) else: path = os.path.realpath(os.path.abspath(path)) relpath = path[len(os.path.realpath(self.location)):].strip('/') path_chunks = relpath.split(os.path.sep) if os.path.isfile(path): if not path.endswith('.ebuild'): raise ValueError(f"file is not an ebuild: {path!r}") elif len(path_chunks) != 3: # ebuild isn't in a category/PN directory raise ValueError( f"ebuild not in the correct directory layout: {path!r}") restrictions = [] # add restrictions until path components run out try: restrictions.append(restricts.RepositoryDep(self.repo_id)) if path_chunks[0] in self.categories: restrictions.append(restricts.CategoryDep(path_chunks[0])) restrictions.append(restricts.PackageDep(path_chunks[1])) base = cpv.VersionedCPV( f"{path_chunks[0]}/{os.path.splitext(path_chunks[2])[0]}") restrictions.append( restricts.VersionMatch('=', base.version, rev=base.revision)) except IndexError: pass return packages.AndRestriction(*restrictions)
def _validate_args(parser, namespace): namespace.pkg_dir = False # disable colors when not using the native output format if namespace.format != 'showkw': namespace.color = False if namespace.color: # default colors to use for keyword types _COLORS = { '+': '\u001b[32m', '~': '\u001b[33m', '-': '\u001b[31m', '*': '\u001b[31m', 'o': '\u001b[30;1m', 'reset': '\u001b[0m', } else: _COLORS = None namespace.colormap = partial(_colormap, _COLORS) if not namespace.targets: if namespace.selected_repo: # use repo restriction since no targets specified restriction = restricts.RepositoryDep(namespace.selected_repo.repo_id) token = namespace.selected_repo.repo_id else: # Use a path restriction if we're in a repo, obviously it'll work # faster if we're in an invididual ebuild dir but we're not that # restrictive. try: restriction = namespace.repo.path_restrict(namespace.cwd) token = namespace.cwd except (AttributeError, ValueError): parser.error('missing target argument and not in a supported repo') # determine if we're grabbing the keywords for a single pkg in cwd namespace.pkg_dir = any( isinstance(x, restricts.PackageDep) for x in reversed(restriction.restrictions)) namespace.targets = [(token, restriction)]
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)