aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pym/gentoolkit/cpv.py')
-rw-r--r--pym/gentoolkit/cpv.py150
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: