diff options
Diffstat (limited to 'pym/gentoolkit/cpv.py')
-rw-r--r-- | pym/gentoolkit/cpv.py | 150 |
1 files changed, 115 insertions, 35 deletions
diff --git a/pym/gentoolkit/cpv.py b/pym/gentoolkit/cpv.py index 9f2c303..663afea 100644 --- a/pym/gentoolkit/cpv.py +++ b/pym/gentoolkit/cpv.py @@ -1,6 +1,8 @@ #!/usr/bin/python # -# Copyright(c) 2009, Gentoo Foundation +# Copyright(c) 2005 Jason Stubbs <jstubbs@gentoo.org> +# Copyright(c) 2005-2006 Brian Harring <ferringb@gmail.com> +# Copyright(c) 2009-2010 Gentoo Foundation # # Licensed under the GNU General Public License, v2 # @@ -18,11 +20,22 @@ __all__ = ( # Imports # ======= +import re + from portage.versions import catpkgsplit, vercmp, pkgcmp from gentoolkit import errors # ======= +# Globals +# ======= + +isvalid_version_re = re.compile("^(?:cvs\\.)?(?:\\d+)(?:\\.\\d+)*[a-z]?" + "(?:_(p(?:re)?|beta|alpha|rc)\\d*)*$") +isvalid_cat_re = re.compile("^(?:[a-zA-Z0-9][-a-zA-Z0-9+._]*(?:/(?!$))?)+$") +_pkg_re = re.compile("^[a-zA-Z0-9+_]+$") + +# ======= # Classes # ======= @@ -43,25 +56,63 @@ class CPV(object): True """ - def __init__(self, cpv): + def __init__(self, cpv, validate=False): self.cpv = cpv - - values = split_cpv(cpv) - self.category = values[0] - self.name = values[1] - self.version = values[2] - self.revision = values[3] - del values - - if not self.name: + self._category = None + self._name = None + self._version = None + self._revision = None + self._cp = None + self._fullversion = None + + self.validate = validate + if validate and not self.name: raise errors.GentoolkitInvalidCPV(cpv) - sep = '/' if self.category else '' - self.cp = sep.join((self.category, self.name)) - - sep = '-' if self.revision else '' - self.fullversion = sep.join((self.version, self.revision)) - del sep + @property + def category(self): + if self._category is None: + self._set_cpv_chunks() + return self._category + + @property + def name(self): + if self._name is None: + self._set_cpv_chunks() + return self._name + + @property + def version(self): + if self._version is None: + self._set_cpv_chunks() + return self._version + + @property + def revision(self): + if self._revision is None: + self._set_cpv_chunks() + return self._revision + + @property + def cp(self): + if self._cp is None: + sep = '/' if self.category else '' + self._cp = sep.join((self.category, self.name)) + return self._cp + + @property + def fullversion(self): + if self._fullversion is None: + sep = '-' if self.revision else '' + self._fullversion = sep.join((self.version, self.revision)) + return self._fullversion + + def _set_cpv_chunks(self): + chunks = split_cpv(self.cpv, validate=self.validate) + self._category = chunks[0] + self._name = chunks[1] + self._version = chunks[2] + self._revision = chunks[3] def __eq__(self, other): if not isinstance(other, self.__class__): @@ -142,34 +193,63 @@ def compare_strs(pkg1, pkg2): return pkgcmp(pkg1[1:], pkg2[1:]) -def split_cpv(cpv): +def split_cpv(cpv, validate=True): """Split a cpv into category, name, version and revision. - Inlined from helpers because of circular imports. + Modified from pkgcore.ebuild.cpv - @todo: this function is slow and accepts some crazy things for cpv @type cpv: str - @param cpv: pkg, cat/pkg, pkg-ver, cat/pkg-ver, atom or regex + @param cpv: pkg, cat/pkg, pkg-ver, cat/pkg-ver @rtype: tuple @return: (category, pkg_name, version, revision) Each tuple element is a string or empty string (""). """ - result = catpkgsplit(cpv) + category = name = version = revision = '' + + try: + category, pkgver = cpv.rsplit("/", 1) + except ValueError: + pkgver = cpv + if validate and category and not isvalid_cat_re.match(category): + raise errors.GentoolkitInvalidCPV(cpv) + pkg_chunks = pkgver.split("-") + lpkg_chunks = len(pkg_chunks) + if lpkg_chunks == 1: + return (category, pkg_chunks[0], version, revision) + if isvalid_rev(pkg_chunks[-1]): + if lpkg_chunks < 3: + # needs at least ('pkg', 'ver', 'rev') + raise errors.GentoolkitInvalidCPV(cpv) + rev = pkg_chunks.pop(-1) + if rev: + revision = rev + + if validate and not isvalid_version_re.match(pkg_chunks[-1]): + raise errors.GentoolkitInvalidCPV(cpv) + version = pkg_chunks.pop(-1) + + if not isvalid_pkg_name(pkg_chunks): + raise errors.GentoolkitInvalidCPV(cpv) + name = '-'.join(pkg_chunks) + + return (category, name, version, revision) + + +def isvalid_pkg_name(chunks): + if not chunks[0]: + # this means a leading - + return False + mf = _pkg_re.match + if not all(not s or mf(s) for s in chunks): + return False + if chunks[-1].isdigit() or not chunks[-1]: + # not allowed. + return False + return True - if result: - result = list(result) - if result[0] == 'null': - result[0] = '' - if result[3] == 'r0': - result[3] = '' - else: - result = cpv.split("/") - if len(result) == 1: - result = ['', cpv, '', ''] - else: - result = result + ['', ''] - return tuple(result) +def isvalid_rev(s): + return s and s[0] == 'r' and s[1:].isdigit() # vim: set ts=4 sw=4 tw=79: |