1 import itertools, os.path, re, utils
21 _re = re.compile(_rules, re.X)
24 __slot__ = 'distribution', 'source', 'version'
26 def __init__(self, distribution, source, version):
27 self.distribution, self.source, self.version = distribution, source, version
29 def __init__(self, dir = '', version = None):
32 f = file(os.path.join(dir, "debian/changelog"))
37 match = self._re.match(line)
41 v = version(match.group('version'))
45 v = Version(match.group('version'))
46 self.append(self.Entry(match.group('distribution'), match.group('source'), v))
48 class Version(object):
49 _version_rules = ur"""
66 _version_re = re.compile(_version_rules, re.X)
68 def __init__(self, version):
69 match = self._version_re.match(version)
71 raise RuntimeError, "Invalid debian version"
73 if match.group("epoch") is not None:
74 self.epoch = int(match.group("epoch"))
75 self.upstream = match.group("upstream")
76 self.revision = match.group("revision")
83 if self.epoch is not None:
84 return "%d:%s" % (self.epoch, self.complete_noepoch)
85 return self.complete_noepoch
88 def complete_noepoch(self):
89 if self.revision is not None:
90 return "%s-%s" % (self.upstream, self.revision)
95 from warnings import warn
96 warn("debian argument was replaced by revision", DeprecationWarning, stacklevel = 2)
99 class VersionLinux(Version):
100 _version_linux_rules = ur"""
123 (?P<revision_experimental>
133 _version_linux_re = re.compile(_version_linux_rules, re.X)
135 def __init__(self, version):
136 super(VersionLinux, self).__init__(version)
137 match = self._version_linux_re.match(version)
139 raise RuntimeError, "Invalid debian linux version"
140 d = match.groupdict()
141 self.linux_major = d['major']
142 self.linux_modifier = d['modifier']
143 self.linux_version = d['version']
144 if d['modifier'] is not None:
145 self.linux_upstream = '-'.join((d['version'], d['modifier']))
147 self.linux_upstream = d['version']
148 self.linux_dfsg = d['dfsg']
149 self.linux_revision_experimental = match.group('revision_experimental') and True
150 self.linux_revision_other = match.group('revision_other') and True
152 class PackageFieldList(list):
153 def __init__(self, value = None):
157 return ' '.join(self)
159 def _extend(self, value):
160 if value is not None:
161 self.extend([j.strip() for j in re.split('\s', value.strip())])
163 def extend(self, value):
164 if isinstance(value, str):
167 super(PackageFieldList, self).extend(value)
169 class PackageDescription(object):
170 __slots__ = "short", "long"
172 def __init__(self, value = None):
175 if value is not None:
176 short, long = value.split("\n", 1)
178 self.append_short(short)
181 wrap = utils.TextWrapper(width = 74, fix_sentence_endings = True).wrap
182 short = ', '.join(self.short)
185 long_pars.append(wrap(i))
186 long = '\n .\n '.join(['\n '.join(i) for i in long_pars])
187 return short + '\n ' + long
189 def append(self, str):
192 self.long.extend(str.split("\n.\n"))
194 def append_short(self, str):
195 for i in [i.strip() for i in str.split(",")]:
199 def extend(self, desc):
200 if isinstance(desc, PackageDescription):
201 self.short.extend(desc.short)
202 self.long.extend(desc.long)
206 class PackageRelation(list):
207 def __init__(self, value=None, override_arches=None):
209 self.extend(value, override_arches)
212 return ', '.join([str(i) for i in self])
214 def _search_value(self, value):
216 if i._search_value(value):
220 def append(self, value, override_arches=None):
221 if isinstance(value, basestring):
222 value = PackageRelationGroup(value, override_arches)
223 elif not isinstance(value, PackageRelationGroup):
224 raise ValueError, "got %s" % type(value)
225 j = self._search_value(value)
227 j._update_arches(value)
229 super(PackageRelation, self).append(value)
231 def extend(self, value, override_arches=None):
232 if isinstance(value, basestring):
233 value = [j.strip() for j in re.split(',', value.strip())]
234 elif not isinstance(value, (list, tuple)):
235 raise ValueError, "got %s" % type(value)
237 self.append(i, override_arches)
239 class PackageRelationGroup(list):
240 def __init__(self, value=None, override_arches=None):
242 self.extend(value, override_arches)
245 return ' | '.join([str(i) for i in self])
247 def _search_value(self, value):
248 for i, j in itertools.izip(self, value):
249 if i.name != j.name or i.version != j.version:
253 def _update_arches(self, value):
254 for i, j in itertools.izip(self, value):
256 for arch in j.arches:
257 if arch not in i.arches:
258 i.arches.append(arch)
260 def append(self, value, override_arches=None):
261 if isinstance(value, basestring):
262 value = PackageRelationEntry(value, override_arches)
263 elif not isinstance(value, PackageRelationEntry):
265 super(PackageRelationGroup, self).append(value)
267 def extend(self, value, override_arches=None):
268 if isinstance(value, basestring):
269 value = [j.strip() for j in re.split('\|', value.strip())]
270 elif not isinstance(value, (list, tuple)):
273 self.append(i, override_arches)
275 class PackageRelationEntry(object):
276 __slots__ = "name", "operator", "version", "arches"
278 _re = re.compile(r'^(\S+)(?: \((<<|<=|=|!=|>=|>>)\s*([^)]+)\))?(?: \[([^]]+)\])?$')
280 class _operator(object):
281 OP_LT = 1; OP_LE = 2; OP_EQ = 3; OP_NE = 4; OP_GE = 5; OP_GT = 6
282 operators = { '<<': OP_LT, '<=': OP_LE, '=': OP_EQ, '!=': OP_NE, '>=': OP_GE, '>>': OP_GT }
283 operators_neg = { OP_LT: OP_GE, OP_LE: OP_GT, OP_EQ: OP_NE, OP_NE: OP_EQ, OP_GE: OP_LT, OP_GT: OP_LE }
284 operators_text = dict([(b, a) for a, b in operators.iteritems()])
288 def __init__(self, value):
289 self._op = self.operators[value]
292 return self.__class__(self.operators_text[self.operators_neg[self._op]])
295 return self.operators_text[self._op]
297 def __init__(self, value=None, override_arches=None):
298 if not isinstance(value, basestring):
304 self.arches = list(override_arches)
308 if self.operator is not None and self.version is not None:
309 ret.extend([' (', str(self.operator), ' ', self.version, ')'])
311 ret.extend([' [', ' '.join(self.arches), ']'])
314 def parse(self, value):
315 match = self._re.match(value)
317 raise RuntimeError, "Can't parse dependency %s" % value
318 match = match.groups()
320 if match[1] is not None:
321 self.operator = self._operator(match[1])
324 self.version = match[2]
325 if match[3] is not None:
326 self.arches = re.split('\s+', match[3])
331 _fields = utils.SortedDict((
334 ('Architecture', PackageFieldList),
339 ('Standards-Version', str),
340 ('Build-Depends', PackageRelation),
341 ('Build-Depends-Indep', PackageRelation),
342 ('Provides', PackageRelation),
343 ('Pre-Depends', PackageRelation),
344 ('Depends', PackageRelation),
345 ('Recommends', PackageRelation),
346 ('Suggests', PackageRelation),
347 ('Replaces', PackageRelation),
348 ('Conflicts', PackageRelation),
349 ('Description', PackageDescription),
352 def __setitem__(self, key, value):
354 cls = self._fields[key]
355 if not isinstance(value, cls):
357 except KeyError: pass
358 super(Package, self).__setitem__(key, value)
361 keys = set(self.keys())
362 for i in self._fields.iterkeys():
370 for i in self.iterkeys():
373 def itervalues(self):
374 for i in self.iterkeys():