def test_parsing(self): # check for gentoo bug 263787 self.process_pkg(False, 'app-text', 'foo-123-bar') self.process_ver(False, 'app-text', 'foo-123-bar', '2.0017a_p', '-r5') with pytest.raises(cpv.InvalidCPV): cpv.UnversionedCPV('app-text/foo-123') for cat_ret, cats in [[False, self.good_cats], [True, self.bad_cats]]: for cat in cats: for pkg_ret, pkgs in [[False, self.good_pkgs], [True, self.bad_pkgs]]: for pkg in pkgs: self.process_pkg(cat_ret or pkg_ret, cat, pkg) for cp in self.good_cp: cat, pkg = cp.rsplit("/", 1) for rev_ret, revs in [[False, self.good_revs], [True, self.bad_revs]]: for rev in revs: for ver_ret, vers in [[False, self.good_vers], [True, self.bad_vers]]: for ver in vers: self.process_ver(ver_ret or rev_ret, cat, pkg, ver, rev) for x in (10, 18, 19, 36, 100): assert cpv.CPV("da", "ba", f"1-r0{'0' * x}").revision == 0 assert \ int(cpv.CPV("da", "ba", f"1-r1{'0' * x}1").revision) == int(f"1{'0' * x}1")
def test_r0_revisions(self): # single '0' obj = cpv.CPV("dev-util/diffball-1.0-r0", versioned=True) assert obj.cpvstr == "dev-util/diffball-1.0" assert str(obj) == "dev-util/diffball-1.0" assert obj.fullver == "1.0-r0" assert obj.revision == 0 # multiple '0' obj = cpv.CPV("dev-util/diffball-1.0-r000", versioned=True) assert obj.cpvstr == "dev-util/diffball-1.0" assert str(obj) == "dev-util/diffball-1.0" assert obj.fullver == "1.0-r000" assert obj.revision == 0 # single '0' prefix obj = cpv.CPV("dev-util/diffball-1.0-r01", versioned=True) assert obj.cpvstr == "dev-util/diffball-1.0-r1" assert str(obj) == "dev-util/diffball-1.0-r1" assert obj.fullver == "1.0-r01" assert obj.revision == 1 # multiple '0' prefixes obj = cpv.CPV("dev-util/diffball-1.0-r0001", versioned=True) assert obj.cpvstr == "dev-util/diffball-1.0-r1" assert str(obj) == "dev-util/diffball-1.0-r1" assert obj.fullver == "1.0-r0001" assert obj.revision == 1
def parse_pv(repo, text): """Return a CPV instance from either a cpv or a pv string. If a pv is passed it needs to match a single cpv in repo. """ try: return cpv.CPV.versioned(text) except errors.InvalidCPV: restrict = parse_match('=%s' % (text, )) result = None for match in repo.itermatch(restrict): if result is not None: raise ParseError('multiple matches for %s (%s, %s)' % (text, result.cpvstr, match.cpvstr)) result = match if result is None: raise ParseError('no matches for %s' % (text, )) return cpv.CPV(result.category, result.package, result.version)
def native_init(self, atom, negate_vers=False, eapi=-1): """ :param atom: string, see gentoo ebuild atom syntax :keyword negate_vers: boolean controlling whether the version should be inverted for restriction matching :keyword eapi: string/int controlling what eapi to enforce for this atom """ sf = object.__setattr__ orig_atom = atom override_kls = False use_start = atom.find("[") slot_start = atom.find(":") if use_start != -1: # use dep use_end = atom.find("]", use_start) if use_end == -1: raise errors.MalformedAtom(orig_atom, "use restriction isn't completed") elif use_end != len(atom) - 1: raise errors.MalformedAtom(orig_atom, "trailing garbage after use dep") sf(self, "use", tuple(sorted(atom[use_start + 1:use_end].split(',')))) for x in self.use: # stripped purely for validation reasons try: if x[-1] in "=?": override_kls = True x = x[:-1] if x[0] == '!': x = x[1:] if x[0] == '-': raise errors.MalformedAtom( orig_atom, "malformed use flag: %s" % x) elif x[0] == '-': x = x[1:] if x[-1] == ')' and eapi not in (0, 1, 2, 3): # use defaults. if x[-3:] in ("(+)", "(-)"): x = x[:-3] if not x: raise errors.MalformedAtom(orig_atom, 'empty use dep detected') elif x[0] not in alphanum: raise errors.MalformedAtom( orig_atom, "invalid first char spotted in use dep '%s' (must be alphanumeric)" % x) if not valid_use_chars.issuperset(x): raise errors.MalformedAtom( orig_atom, "invalid char spotted in use dep '%s'" % x) except IndexError: raise errors.MalformedAtom(orig_atom, 'empty use dep detected') if override_kls: sf(self, '__class__', self._transitive_use_atom) atom = atom[0:use_start] + atom[use_end + 1:] else: sf(self, "use", None) if slot_start != -1: i2 = atom.find("::", slot_start) if i2 != -1: repo_id = atom[i2 + 2:] if not repo_id: raise errors.MalformedAtom(orig_atom, "repo_id must not be empty") elif repo_id[0] in '-': raise errors.MalformedAtom( orig_atom, "invalid first char of repo_id '%s' (must not begin with a hyphen)" % repo_id) elif not valid_repo_chars.issuperset(repo_id): raise errors.MalformedAtom( orig_atom, "repo_id may contain only [a-Z0-9_-/], found %r" % (repo_id, )) atom = atom[:i2] sf(self, "repo_id", repo_id) else: sf(self, "repo_id", None) # slot dep. slot = atom[slot_start + 1:] slot_operator = subslot = None if not slot: # if the slot char came in only due to repo_id, force slots to None if i2 == -1: raise errors.MalformedAtom( orig_atom, "Empty slot targets aren't allowed") slot = None else: slots = (slot, ) if eapi not in (0, 1, 2, 3, 4): if slot[0:1] in ("*", "="): if len(slot) > 1: raise errors.MalformedAtom( orig_atom, "Slot operators '*' and '=' do not take slot targets" ) slot_operator = slot slot, slots = None, () else: if slot.endswith('='): slot_operator = '=' slot = slot[:-1] slots = slot.split('/', 1) elif eapi == 0: raise errors.MalformedAtom( orig_atom, "slot dependencies aren't allowed in EAPI 0") for chunk in slots: if not chunk: raise errors.MalformedAtom( orig_atom, "Empty slot targets aren't allowed") if chunk[0] in '-.': raise errors.MalformedAtom( orig_atom, "Slot targets must not start with a hypen or dot: %r" % chunk) elif not valid_slot_chars.issuperset(chunk): raise errors.MalformedAtom( orig_atom, "Invalid character(s) in slot target: %s" % ', '.join( map( repr, sorted( set(chunk).difference(valid_slot_chars))))) if len(slots) == 2: slot, subslot = slots sf(self, "slot_operator", slot_operator) sf(self, "slot", slot) sf(self, "subslot", subslot) atom = atom[:slot_start] else: sf(self, "slot_operator", None) sf(self, "slot", None) sf(self, "subslot", None) sf(self, "repo_id", None) sf(self, "blocks", atom[0] == "!") if self.blocks: atom = atom[1:] # hackish/slow, but lstrip doesn't take a 'prune this many' arg # open to alternatives if eapi not in (0, 1) and atom.startswith("!"): atom = atom[1:] sf(self, "blocks_strongly", True) else: sf(self, "blocks_strongly", False) else: sf(self, "blocks_strongly", False) if atom[0] in ('<', '>'): if atom[1] == '=': sf(self, 'op', atom[:2]) atom = atom[2:] else: sf(self, 'op', atom[0]) atom = atom[1:] elif atom[0] == '=': if atom[-1] == '*': sf(self, 'op', '=*') atom = atom[1:-1] else: atom = atom[1:] sf(self, 'op', '=') elif atom[0] == '~': sf(self, 'op', '~') atom = atom[1:] else: sf(self, 'op', '') sf(self, 'cpvstr', atom) if eapi == 0: for x in ('use', 'slot'): if getattr(self, x) is not None: raise errors.MalformedAtom( orig_atom, "%s atoms aren't supported for EAPI 0" % x) elif eapi == 1: if self.use is not None: raise errors.MalformedAtom( orig_atom, "use atoms aren't supported for EAPI < 2") if eapi != -1: if self.repo_id is not None: raise errors.MalformedAtom( orig_atom, "repo_id atoms aren't supported for EAPI %i" % eapi) if use_start != -1 and slot_start != -1 and use_start < slot_start: raise errors.MalformedAtom(orig_atom, "slot restriction must proceed use") try: c = cpv.CPV(self.cpvstr, versioned=bool(self.op)) except errors.InvalidCPV as e: raise_from(errors.MalformedAtom(orig_atom)) sf(self, "key", c.key) sf(self, "package", c.package) sf(self, "category", c.category) sf(self, "version", c.version) sf(self, "fullver", c.fullver) sf(self, "revision", c.revision) if self.op: if self.version is None: raise errors.MalformedAtom(orig_atom, "operator requires a version") elif self.op == '~' and self.revision: raise errors.MalformedAtom( orig_atom, "~ revision operater cannot be combined with a revision") elif self.version is not None: raise errors.MalformedAtom(orig_atom, 'versioned atom requires an operator') sf(self, "_hash", hash(orig_atom)) sf(self, "negate_vers", negate_vers)
def test_init(self): cpv.CPV("dev-util", "diffball", "0.7.1") cpv.CPV("dev-util", "diffball") cpv.CPV("dev-util/diffball-0.7.1", versioned=True) with pytest.raises(TypeError): cpv.VersionedCPV("dev-util", "diffball", None)
def make_inst(self, cat, pkg, fullver=""): if self.testing_secondary_args: return cpv.CPV(cat, pkg, fullver, versioned=bool(fullver)) if fullver: return cpv.VersionedCPV(f"{cat}/{pkg}-{fullver}") return cpv.UnversionedCPV(f"{cat}/{pkg}")