aboutsummaryrefslogtreecommitdiff
blob: 914672f3aae068dd9a0eddbae203c3061e5f4a8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#! /usr/bin/python
#
# Copyright(c) 2009 Gentoo Foundation
# Licensed under the GNU General Public License, v2
#
# Copyright: 2005-2007 Brian Harring <ferringb@gmail.com>
# License: GPL2/BSD
#
# $Header$

"""Gentoo version comparison object from pkgcore.ebuild.atom_restricts."""

# =======
# Imports
# =======

from portage.versions import vercmp

from gentoolkit import errors
from gentoolkit.cpv import CPV

# =======
# Classes
# =======

class VersionMatch(object):
	"""Gentoo version comparison object from pkgcore.ebuild.atom_restricts.

	Any overriding of this class *must* maintain numerical order of
	self.vals, see intersect for reason why. vals also must be a tuple.
	"""
	_convert_op2int = {(-1,):"<", (-1, 0): "<=", (0,):"=",
		(0, 1):">=", (1,):">"}

	_convert_int2op = dict([(v, k) for k, v in _convert_op2int.items()])

	def __init__(self, cpv, op='='):
		"""Initialize a VersionMatch instance.

		@type cpv: L{gentoolkit.cpv.CPV}
		@param cpv: cpv object
		@type op: str
		@keyword op: operator
		"""

		if not isinstance(cpv, (CPV, self.__class__)):
			err = "cpv must be a gentoolkit.cpv.CPV "
			err += "or gentoolkit.versionmatch.VersionMatch instance"
			raise ValueError(err)
		self.cpv = cpv
		self.operator = op
		self.version = cpv.version
		self.revision = cpv.revision
		self.fullversion = cpv.fullversion

		if self.operator != "~" and self.operator not in self._convert_int2op:
			raise errors.GentoolkitInvalidVersion(
				"invalid operator '%s'" % self.operator)

		if self.operator == "~":
			if not self.version:
				raise errors.GentoolkitInvalidVersion(
					"for ~ op, ver must be specified")
			self.droprevision = True
			self.values = (0,)
		else:
			self.droprevision = False
			self.values = self._convert_int2op[self.operator]

	def match(self, other):
		"""See whether a passed in VersionMatch or CPV instance matches self.

		Example usage:
			>>> from gentoolkit.versionmatch import VersionMatch
			>>> from gentoolkit.cpv import CPV
			>>> VersionMatch(CPV('foo/bar-1.5'), op='>').match(
			... VersionMatch(CPV('foo/bar-2.0')))
			True

		@type other: gentoolkit.versionmatch.VersionMatch OR
		   gentoolkit.cpv.CPV
		@param other: version to compare with self's version
		@rtype: bool
		"""

		if self.droprevision:
			ver1, ver2 = self.version, other.version
		else:
			ver1, ver2 = self.fullversion, other.fullversion

		return vercmp(ver2, ver1) in self.values

	def __str__(self):
		operator = self._convert_op2int[self.values]

		if self.droprevision or not self.revision:
			return "ver %s %s" % (operator, self.version)
		return "ver-rev %s %s-%s" % (
			operator, self.version, self.revision
		)

	def __repr__(self):
		return "<%s %r>" % (self.__class__.__name__, str(self))

	@staticmethod
	def _convert_ops(inst):
		if inst.droprevision:
			return inst.values
		return tuple(sorted(set((-1, 0, 1)).difference(inst.values)))

	def __eq__(self, other):
		if self is other:
			return True
		if isinstance(other, self.__class__):
			if (self.droprevision != other.droprevision or
				self.version != other.version or
				self.revision != other.revision):
				return False
			return self._convert_ops(self) == self._convert_ops(other)

		return False

	def __ne__(self, other):
		return not self == other

	def __hash__(self):
		return hash((
			self.droprevision,
			self.version,
			self.revision,
			self.values
		))

# vim: set ts=4 sw=4 tw=79: