| 1 |
import re
|
| 2 |
|
| 3 |
from copy import *
|
| 4 |
|
| 5 |
|
| 6 |
pkg_regexp = re.compile("^[a-zA-Z0-9]([-_+a-zA-Z0-9]*[+a-zA-Z0-9])?$")
|
| 7 |
ver_regexp = re.compile("^(cvs\\.)?(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d*)*)(-r(\\d+))?$")
|
| 8 |
suffix_regexp = re.compile("^(alpha|beta|rc|pre|p)(\\d*)$")
|
| 9 |
suffix_value = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1}
|
| 10 |
|
| 11 |
class CPV(object):
|
| 12 |
|
| 13 |
"""
|
| 14 |
Attributes
|
| 15 |
|
| 16 |
str category
|
| 17 |
str package
|
| 18 |
str key (cat/pkg)
|
| 19 |
str version
|
| 20 |
int revision
|
| 21 |
|
| 22 |
Methods
|
| 23 |
|
| 24 |
int __hash__()
|
| 25 |
str __repr__()
|
| 26 |
int __cmp__(CPV)
|
| 27 |
"""
|
| 28 |
|
| 29 |
def __init__(self, cpvstr):
|
| 30 |
if not isinstance(cpvstr, str):
|
| 31 |
raise ValueError(cpvstr)
|
| 32 |
self.__dict__["cpvstr"] = cpvstr
|
| 33 |
self.__dict__["hash"] = hash(cpvstr)
|
| 34 |
|
| 35 |
def __hash__(self):
|
| 36 |
return self.hash
|
| 37 |
|
| 38 |
def __repr__(self):
|
| 39 |
return self.cpvstr
|
| 40 |
|
| 41 |
def __setattr__(self, name, value):
|
| 42 |
raise Exception()
|
| 43 |
|
| 44 |
def __getattr__(self, name):
|
| 45 |
|
| 46 |
if name == "category":
|
| 47 |
myparts = self.cpvstr.split("/")
|
| 48 |
if len(myparts) >= 2:
|
| 49 |
if not pkg_regexp.match(myparts[0]):
|
| 50 |
raise ValueError(self.cpvstr)
|
| 51 |
self.__dict__["category"] = myparts[0]
|
| 52 |
else:
|
| 53 |
self.__dict__["category"] = None
|
| 54 |
return self.category
|
| 55 |
|
| 56 |
if name == "package":
|
| 57 |
if self.category:
|
| 58 |
myparts = self.cpvstr[len(self.category)+1:].split("-")
|
| 59 |
else:
|
| 60 |
myparts = self.cpvstr.split("-")
|
| 61 |
if ver_regexp.match(myparts[0]):
|
| 62 |
raise ValueError(self.cpvstr)
|
| 63 |
pos = 1
|
| 64 |
while pos < len(myparts) and not ver_regexp.match(myparts[pos]):
|
| 65 |
pos += 1
|
| 66 |
pkgname = "-".join(myparts[:pos])
|
| 67 |
if not pkg_regexp.match(pkgname):
|
| 68 |
raise ValueError(self.cpvstr)
|
| 69 |
self.__dict__["package"] = pkgname
|
| 70 |
return self.package
|
| 71 |
|
| 72 |
if name == "key":
|
| 73 |
if self.category:
|
| 74 |
self.__dict__["key"] = self.category +"/"+ self.package
|
| 75 |
else:
|
| 76 |
self.__dict__["key"] = self.package
|
| 77 |
return self.key
|
| 78 |
|
| 79 |
if name == "version" or name == "revision":
|
| 80 |
if self.category:
|
| 81 |
myparts = self.cpvstr[len(self.category+self.package)+2:].split("-")
|
| 82 |
else:
|
| 83 |
myparts = self.cpvstr[len(self.package)+1:].split("-")
|
| 84 |
|
| 85 |
if not myparts[0]:
|
| 86 |
self.__dict__["version"] = None
|
| 87 |
self.__dict__["revision"] = None
|
| 88 |
|
| 89 |
else:
|
| 90 |
if myparts[-1][0] == "r" and myparts[-1][1:].isdigit():
|
| 91 |
self.__dict__["revision"] = int(myparts[-1][1:])
|
| 92 |
myparts = myparts[:-1]
|
| 93 |
else:
|
| 94 |
self.__dict__["revision"] = 0
|
| 95 |
|
| 96 |
for x in myparts:
|
| 97 |
if not ver_regexp.match(x):
|
| 98 |
raise ValueError(self.mycpv)
|
| 99 |
|
| 100 |
self.__dict__["version"] = "-".join(myparts)
|
| 101 |
|
| 102 |
if name == "version":
|
| 103 |
return self.version
|
| 104 |
else:
|
| 105 |
return self.revision
|
| 106 |
|
| 107 |
raise AttributeError(name)
|
| 108 |
|
| 109 |
def __cmp__(self, other):
|
| 110 |
|
| 111 |
if self.cpvstr == other.cpvstr:
|
| 112 |
return 0
|
| 113 |
|
| 114 |
if self.category and other.category and self.category != other.category:
|
| 115 |
return cmp(self.category, other.category)
|
| 116 |
|
| 117 |
if self.package and other.package and self.package != other.package:
|
| 118 |
return cmp(self.package, other.package)
|
| 119 |
|
| 120 |
if self.version != other.version:
|
| 121 |
|
| 122 |
if self.version is None:
|
| 123 |
raise ValueError(self)
|
| 124 |
|
| 125 |
if other.version is None:
|
| 126 |
raise ValueError(other)
|
| 127 |
|
| 128 |
match1 = ver_regexp.match(self.version)
|
| 129 |
match2 = ver_regexp.match(other.version)
|
| 130 |
|
| 131 |
# shortcut for cvs ebuilds (new style)
|
| 132 |
if match1.group(1) and not match2.group(1):
|
| 133 |
return 1
|
| 134 |
elif match2.group(1) and not match1.group(1):
|
| 135 |
return -1
|
| 136 |
|
| 137 |
# building lists of the version parts before the suffix
|
| 138 |
# first part is simple
|
| 139 |
list1 = [int(match1.group(2))]
|
| 140 |
list2 = [int(match2.group(2))]
|
| 141 |
|
| 142 |
# this part would greatly benefit from a fixed-length version pattern
|
| 143 |
if len(match1.group(3)) or len(match2.group(3)):
|
| 144 |
vlist1 = match1.group(3)[1:].split(".")
|
| 145 |
vlist2 = match2.group(3)[1:].split(".")
|
| 146 |
for i in range(0, max(len(vlist1), len(vlist2))):
|
| 147 |
if len(vlist1) <= i or len(vlist1[i]) == 0:
|
| 148 |
list1.append(0)
|
| 149 |
list2.append(int(vlist2[i]))
|
| 150 |
elif len(vlist2) <= i or len(vlist2[i]) == 0:
|
| 151 |
list1.append(int(vlist1[i]))
|
| 152 |
list2.append(0)
|
| 153 |
# Let's make life easy and use integers unless we're forced to use floats
|
| 154 |
elif (vlist1[i][0] != "0" and vlist2[i][0] != "0"):
|
| 155 |
list1.append(int(vlist1[i]))
|
| 156 |
list2.append(int(vlist2[i]))
|
| 157 |
# now we have to use floats so 1.02 compares correctly against 1.1
|
| 158 |
else:
|
| 159 |
list1.append(float("0."+vlist1[i]))
|
| 160 |
list2.append(float("0."+vlist2[i]))
|
| 161 |
|
| 162 |
# and now the final letter
|
| 163 |
if len(match1.group(5)):
|
| 164 |
list1.append(ord(match1.group(5)))
|
| 165 |
if len(match2.group(5)):
|
| 166 |
list2.append(ord(match2.group(5)))
|
| 167 |
|
| 168 |
for i in range(0, max(len(list1), len(list2))):
|
| 169 |
if len(list1) <= i:
|
| 170 |
return -1
|
| 171 |
elif len(list2) <= i:
|
| 172 |
return 1
|
| 173 |
elif list1[i] != list2[i]:
|
| 174 |
return list1[i] - list2[i]
|
| 175 |
|
| 176 |
# main version is equal, so now compare the _suffix part
|
| 177 |
list1 = match1.group(6).split("_")[1:]
|
| 178 |
list2 = match2.group(6).split("_")[1:]
|
| 179 |
|
| 180 |
for i in range(0, max(len(list1), len(list2))):
|
| 181 |
if len(list1) <= i:
|
| 182 |
s1 = ("p","0")
|
| 183 |
else:
|
| 184 |
s1 = suffix_regexp.match(list1[i]).groups()
|
| 185 |
if len(list2) <= i:
|
| 186 |
s2 = ("p","0")
|
| 187 |
else:
|
| 188 |
s2 = suffix_regexp.match(list2[i]).groups()
|
| 189 |
if s1[0] != s2[0]:
|
| 190 |
return suffix_value[s1[0]] - suffix_value[s2[0]]
|
| 191 |
if s1[1] != s2[1]:
|
| 192 |
# it's possible that the s(1|2)[1] == ''
|
| 193 |
# in such a case, fudge it.
|
| 194 |
try: r1 = int(s1[1])
|
| 195 |
except ValueError: r1 = 0
|
| 196 |
try: r2 = int(s2[1])
|
| 197 |
except ValueError: r2 = 0
|
| 198 |
return r1 - r2
|
| 199 |
|
| 200 |
return cmp(self.revision, other.revision)
|
| 201 |
|
| 202 |
|
| 203 |
class Atom(object):
|
| 204 |
|
| 205 |
"""
|
| 206 |
Attributes
|
| 207 |
|
| 208 |
bool blocks
|
| 209 |
str operator
|
| 210 |
bool glob_match
|
| 211 |
CPV cpv
|
| 212 |
|
| 213 |
Methods
|
| 214 |
int __hash__()
|
| 215 |
str __str__()
|
| 216 |
str __repr__()
|
| 217 |
bool match(CPV)
|
| 218 |
"""
|
| 219 |
|
| 220 |
def __init__(self, atomstr):
|
| 221 |
if not isinstance(atomstr, str):
|
| 222 |
raise ValueError(atomstr)
|
| 223 |
self.__dict__["atomstr"] = atomstr
|
| 224 |
self.__dict__["hash"] = hash(atomstr)
|
| 225 |
|
| 226 |
def __hash__(self):
|
| 227 |
return self.hash
|
| 228 |
|
| 229 |
def __str__(self):
|
| 230 |
return self.atomstr
|
| 231 |
|
| 232 |
def __repr__(self):
|
| 233 |
return "Atom('" + self.atomstr + "')"
|
| 234 |
|
| 235 |
def __setattr__(self, name, value):
|
| 236 |
raise Exception()
|
| 237 |
|
| 238 |
def __eq__(self, other):
|
| 239 |
if isinstance(other, Atom):
|
| 240 |
return hash(self) == other.hash
|
| 241 |
return False
|
| 242 |
|
| 243 |
def __copy__(self):
|
| 244 |
return self
|
| 245 |
|
| 246 |
def __getattr__(self, name):
|
| 247 |
|
| 248 |
if "operator" not in self.__dict__:
|
| 249 |
|
| 250 |
myatom = self.atomstr
|
| 251 |
|
| 252 |
if myatom[0] == "!":
|
| 253 |
self.__dict__["blocks"] = True
|
| 254 |
myatom = myatom[1:]
|
| 255 |
else:
|
| 256 |
self.__dict__["blocks"] = False
|
| 257 |
|
| 258 |
if myatom[0:2] in ["<=", ">="]:
|
| 259 |
self.__dict__["operator"] = myatom[0:2]
|
| 260 |
myatom = myatom[2:]
|
| 261 |
elif myatom[0] in ["<", ">", "=", "~"]:
|
| 262 |
self.__dict__["operator"] = myatom[0]
|
| 263 |
myatom = myatom[1:]
|
| 264 |
else:
|
| 265 |
self.__dict__["operator"] = None
|
| 266 |
|
| 267 |
if myatom[-1] == "*":
|
| 268 |
self.__dict__["glob_match"] = True
|
| 269 |
myatom = myatom[:-1]
|
| 270 |
else:
|
| 271 |
self.__dict__["glob_match"] = False
|
| 272 |
|
| 273 |
self.__dict__["cpv"] = CPV(myatom)
|
| 274 |
|
| 275 |
if self.operator != "=" and self.glob_match:
|
| 276 |
raise ValueError(self.atomstr)
|
| 277 |
|
| 278 |
if self.operator and not self.cpv.version:
|
| 279 |
raise ValueError(self.atomstr)
|
| 280 |
|
| 281 |
if not self.operator and self.cpv.version:
|
| 282 |
raise ValueError(self.atomstr)
|
| 283 |
|
| 284 |
if self.operator == "~" and self.cpv.revision:
|
| 285 |
raise ValueError(self.atomstr)
|
| 286 |
|
| 287 |
if self.glob_match and self.cpv.revision:
|
| 288 |
raise ValueError(self.atomstr)
|
| 289 |
|
| 290 |
if not self.__dict__.has_key(name):
|
| 291 |
return self.cpv.__getattr__(name)
|
| 292 |
|
| 293 |
return self.__dict__[name]
|
| 294 |
|
| 295 |
def match(self, cpv):
|
| 296 |
|
| 297 |
if self.cpv.category and cpv.category and self.cpv.category != cpv.category:
|
| 298 |
return False
|
| 299 |
|
| 300 |
if self.cpv.package and cpv.package and self.cpv.package != cpv.package:
|
| 301 |
return False
|
| 302 |
|
| 303 |
if not self.operator:
|
| 304 |
return True
|
| 305 |
|
| 306 |
if self.operator == "=":
|
| 307 |
if self.glob_match and cpv.version.startswith(self.cpv.version):
|
| 308 |
return True
|
| 309 |
if self.cpv.version != cpv.version:
|
| 310 |
return False
|
| 311 |
if self.cpv.revision != cpv.revision:
|
| 312 |
return False
|
| 313 |
return True
|
| 314 |
|
| 315 |
if self.operator == "~" and self.cpv.version == cpv.version:
|
| 316 |
return True
|
| 317 |
|
| 318 |
diff = cmp(self.cpv, cpv)
|
| 319 |
|
| 320 |
if not diff:
|
| 321 |
if self.operator == "<=" or self.operator == ">=":
|
| 322 |
return True
|
| 323 |
else:
|
| 324 |
return False
|
| 325 |
|
| 326 |
if diff > 0:
|
| 327 |
if self.operator[0] == "<":
|
| 328 |
return True
|
| 329 |
else:
|
| 330 |
return False
|
| 331 |
|
| 332 |
#if diff < 0:
|
| 333 |
if self.operator[0] == ">":
|
| 334 |
return True
|
| 335 |
#else:
|
| 336 |
return False
|
| 337 |
|
| 338 |
def with_key(self, key):
|
| 339 |
return Atom(self.atomstr.replace(self.cpv.key, key))
|
| 340 |
|
| 341 |
def intersects(self, atom):
|
| 342 |
if self == atom:
|
| 343 |
return True
|
| 344 |
if self.cpv.key != atom.cpv.key:
|
| 345 |
return False
|
| 346 |
if self.blocks != atom.blocks:
|
| 347 |
return False
|
| 348 |
if not self.operator or not atom.operator:
|
| 349 |
return True
|
| 350 |
if self.cpv == other.cpv:
|
| 351 |
if self.operator == atom.operator:
|
| 352 |
return True
|
| 353 |
if self.operator == "<":
|
| 354 |
return (atom.operator[0] == "<")
|
| 355 |
if self.operator == ">":
|
| 356 |
return (other.operator[0] == ">" or other.operator == "~")
|
| 357 |
if self.operator == "=":
|
| 358 |
return (other.operator != "<" and other.operator != ">")
|
| 359 |
if self.operator == "~" or self.operator == ">=":
|
| 360 |
return (other.operator != "<")
|
| 361 |
return (other.operator != ">")
|
| 362 |
elif self.cpv.version == other.cpv.version:
|
| 363 |
if self.cpv > other.cpv:
|
| 364 |
if self.operator == "=" and other.operator == "~":
|
| 365 |
return True
|
| 366 |
elif self.operator == "~" and other.operator == "=":
|
| 367 |
return True
|
| 368 |
if self.operator in ["=","~"] and other.operator in ["=","~"]:
|
| 369 |
return False
|
| 370 |
if self.cpv > other.cpv:
|
| 371 |
if self.operator in ["<","<="]:
|
| 372 |
return True
|
| 373 |
if other.operator in [">",">="]:
|
| 374 |
return True
|
| 375 |
return False
|
| 376 |
if self.operator in [">",">="]:
|
| 377 |
return True
|
| 378 |
if other.operator in ["<","<="]:
|
| 379 |
return True
|
| 380 |
return False
|
| 381 |
|
| 382 |
def encapsulates(self, atom):
|
| 383 |
if not self.intersects(atom):
|
| 384 |
return False
|
| 385 |
|
| 386 |
if self.operator and not atom.operator:
|
| 387 |
return False
|
| 388 |
if not self.operator:
|
| 389 |
return True
|
| 390 |
|
| 391 |
if self.cpv == atom.cpv:
|
| 392 |
if self.operator == other.operator:
|
| 393 |
return True
|
| 394 |
if other.operator == "=":
|
| 395 |
return True
|
| 396 |
if self.operator == "<=" and other.operator == "<":
|
| 397 |
return True
|
| 398 |
if self.operator == ">=" and other.operator == ">":
|
| 399 |
return True
|
| 400 |
return False
|
| 401 |
elif self.cpv.version == other.cpv.version:
|
| 402 |
if self.cpv < other.cpv and self.operator == "~":
|
| 403 |
return true
|
| 404 |
if self.cpv > other.cpv:
|
| 405 |
if self.operator in ["<","<="] and other.operator not in [">",">="]:
|
| 406 |
return True
|
| 407 |
return False
|
| 408 |
if self.operator in [">",">="] and other.operator not in ["<","<="]:
|
| 409 |
return True
|
| 410 |
return False
|
| 411 |
|
| 412 |
|
| 413 |
|
| 414 |
|
| 415 |
|
| 416 |
class UseCondition(object):
|
| 417 |
|
| 418 |
_use_regex = re.compile("^!?[\\w-]+\?$")
|
| 419 |
|
| 420 |
def can_parse(cls, condition_str):
|
| 421 |
return (cls._use_regex.match(condition_str) is not None)
|
| 422 |
can_parse = classmethod(can_parse)
|
| 423 |
|
| 424 |
def __init__(self, condition_str):
|
| 425 |
condition_str = condition_str[:-1]
|
| 426 |
self.__dict__["_hash"] = hash(condition_str)
|
| 427 |
self.__dict__["negated"] = (condition_str[0] == "!")
|
| 428 |
if self.negated:
|
| 429 |
self.__dict__["flag"] = condition_str[1:]
|
| 430 |
else:
|
| 431 |
self.__dict__["flag"] = condition_str
|
| 432 |
|
| 433 |
def __setattr__(self, name, value):
|
| 434 |
raise TypeError("UseCondition has only read-only attributes (assign to "+name+")")
|
| 435 |
|
| 436 |
def __hash__(self):
|
| 437 |
return self._hash
|
| 438 |
|
| 439 |
def __eq__(self, other):
|
| 440 |
return (isinstance(other, UseCondition) and self._hash == other._hash)
|
| 441 |
|
| 442 |
def __copy__(self):
|
| 443 |
return self
|
| 444 |
|
| 445 |
def conflicts_with(self, other):
|
| 446 |
return (self.flag == other.flag and self.negated != other.negated)
|
| 447 |
|
| 448 |
|
| 449 |
class ParseError(Exception):
|
| 450 |
pass
|
| 451 |
|
| 452 |
|
| 453 |
class DependSpec(object):
|
| 454 |
|
| 455 |
def __init__(self, dependstr="", element_class=str):
|
| 456 |
dependstr = " ( ".join(dependstr.split("("))
|
| 457 |
dependstr = " ) ".join(dependstr.split(")"))
|
| 458 |
dependstr = " ".join(dependstr.split())
|
| 459 |
self.__dict__["_origstr"] = dependstr
|
| 460 |
self.__dict__["_str"] = None
|
| 461 |
self.__dict__["_element_class"] = element_class
|
| 462 |
self.__dict__["_needs_brackets"] = True
|
| 463 |
self.__dict__["_specials"] = []
|
| 464 |
self.__dict__["condition"] = None
|
| 465 |
|
| 466 |
def __copy__(self):
|
| 467 |
dependspec = self.__class__()
|
| 468 |
dependspec.__dict__["_element_class"] = self._element_class
|
| 469 |
dependspec.__dict__["_specials"] = self._specials[:]
|
| 470 |
dependspec.__dict__["condition"] = copy(self.condition)
|
| 471 |
dependspec.__dict__["_needs_brackets"] = self._needs_brackets
|
| 472 |
self._parsed
|
| 473 |
dependspec.__dict__["_elements"] = self._elements[:]
|
| 474 |
dependspec.__dict__["_parsed"] = True
|
| 475 |
return dependspec
|
| 476 |
|
| 477 |
def __setattr__(self, name, value):
|
| 478 |
raise TypeError("DependSpec has only read-only attributes (assign to "+name+")")
|
| 479 |
|
| 480 |
def __str__(self):
|
| 481 |
if self._str is not None:
|
| 482 |
return self._str
|
| 483 |
self._parsed
|
| 484 |
mystr = []
|
| 485 |
for element in self._elements:
|
| 486 |
x = str(element)
|
| 487 |
if x:
|
| 488 |
if isinstance(element, DependSpec) and element._needs_brackets:
|
| 489 |
x = "( "+x+" )"
|
| 490 |
mystr.append(x)
|
| 491 |
mystr = " ".join(mystr)
|
| 492 |
if self.condition:
|
| 493 |
mystr = str(self.condition)+" ( "+mystr+" )"
|
| 494 |
self.__dict__["_str"] = mystr
|
| 495 |
return mystr
|
| 496 |
|
| 497 |
def _needs_brackets(self):
|
| 498 |
return True
|
| 499 |
|
| 500 |
def __hash__(self):
|
| 501 |
return hash(str(self))
|
| 502 |
|
| 503 |
def __eq__(self, other):
|
| 504 |
return (isinstance(other, DependSpec) and str(self) == str(other))
|
| 505 |
|
| 506 |
def __getattr__(self, name):
|
| 507 |
if "_parsed" not in self.__dict__:
|
| 508 |
self._parse()
|
| 509 |
return self.__dict__[name]
|
| 510 |
|
| 511 |
def __getitem__(self, idx):
|
| 512 |
self._parsed
|
| 513 |
return self._elements[idx]
|
| 514 |
|
| 515 |
def __len__(self):
|
| 516 |
self._parsed
|
| 517 |
return len(self._elements)
|
| 518 |
|
| 519 |
def _parse(self):
|
| 520 |
dependstr = self._origstr
|
| 521 |
if dependstr.count("(") != dependstr.count(")"):
|
| 522 |
raise ParseError(dependstr)
|
| 523 |
self.__dict__["_elements"] = []
|
| 524 |
specials_found = []
|
| 525 |
condition = None
|
| 526 |
strlen = len(dependstr)
|
| 527 |
pos = 0
|
| 528 |
while pos != strlen:
|
| 529 |
if dependstr[pos] == " ":
|
| 530 |
pos += 1
|
| 531 |
continue
|
| 532 |
if dependstr[pos] == ")":
|
| 533 |
raise ParseError(dependstr)
|
| 534 |
if dependstr[pos] == "(":
|
| 535 |
pos += 1
|
| 536 |
bracket_count = 1
|
| 537 |
nextpos = pos
|
| 538 |
while bracket_count:
|
| 539 |
nextpos_d = {}
|
| 540 |
nextpos_d[dependstr.find("(", nextpos)] = True
|
| 541 |
nextpos_d[dependstr.find(")", nextpos)] = True
|
| 542 |
if -1 in nextpos_d:
|
| 543 |
del nextpos_d[-1]
|
| 544 |
nextpos = min(nextpos_d.keys())
|
| 545 |
if dependstr[nextpos] == "(":
|
| 546 |
bracket_count += 1
|
| 547 |
else:
|
| 548 |
bracket_count -= 1
|
| 549 |
nextpos += 1
|
| 550 |
element = self.__class__(dependstr[pos:nextpos-1])
|
| 551 |
element.__dict__["_element_class"] = self._element_class
|
| 552 |
if condition:
|
| 553 |
element.__dict__["condition"] = condition
|
| 554 |
condition = None
|
| 555 |
pos = nextpos
|
| 556 |
self._elements.append(element)
|
| 557 |
continue
|
| 558 |
nextpos_d = {strlen:True}
|
| 559 |
nextpos_d[dependstr.find(" ", pos)] = True
|
| 560 |
nextpos_d[dependstr.find("(", pos)] = True
|
| 561 |
nextpos_d[dependstr.find(")", pos)] = True
|
| 562 |
if -1 in nextpos_d:
|
| 563 |
del nextpos_d[-1]
|
| 564 |
nextpos = min(nextpos_d.keys())
|
| 565 |
element = dependstr[pos:nextpos]
|
| 566 |
if element in self._specials:
|
| 567 |
specials_found += [(element, len(self._elements))]
|
| 568 |
elif UseCondition.can_parse(element):
|
| 569 |
if condition:
|
| 570 |
raise ParseError(dependstr)
|
| 571 |
condition = UseCondition(element)
|
| 572 |
else:
|
| 573 |
if condition:
|
| 574 |
raise ParseError(dependstr)
|
| 575 |
self._elements.append(self._element_class(element))
|
| 576 |
pos = nextpos
|
| 577 |
if condition:
|
| 578 |
raise ParseError(dependstr)
|
| 579 |
for special in specials_found:
|
| 580 |
if special[1] == len(self._elements):
|
| 581 |
raise ParseError(dependstr)
|
| 582 |
try:
|
| 583 |
self._do_special(special[0], special[1])
|
| 584 |
except ParseError:
|
| 585 |
raise ParseError(dependstr)
|
| 586 |
self.__dict__["_parsed"] = True
|
| 587 |
|
| 588 |
def all_conditions(self):
|
| 589 |
cond_d = {}
|
| 590 |
if self.condition:
|
| 591 |
cond_d[self.condition] = True
|
| 592 |
yield self.condition
|
| 593 |
|
| 594 |
self._parsed
|
| 595 |
for element in self._elements:
|
| 596 |
if isinstance(element, DependSpec):
|
| 597 |
for cond in element.all_conditions():
|
| 598 |
if cond not in cond_d:
|
| 599 |
cond_d[cond] = True
|
| 600 |
yield cond
|
| 601 |
|
| 602 |
def with_only_conditions(self, conditions):
|
| 603 |
if self.condition and self.condition not in conditions:
|
| 604 |
return self.__class__()
|
| 605 |
self._parsed
|
| 606 |
dependspec = copy(self)
|
| 607 |
dependspec.__dict__["condition"] = None
|
| 608 |
for idx in range(len(dependspec._elements)):
|
| 609 |
if isinstance(dependspec._elements[idx], DependSpec):
|
| 610 |
dependspec._elements[idx] = dependspec._elements[idx].with_only_conditions(conditions)
|
| 611 |
return dependspec
|
| 612 |
|
| 613 |
def _can_combine_with(self, other):
|
| 614 |
return self.condition == other.condition
|
| 615 |
|
| 616 |
def compacted(self):
|
| 617 |
elements = []
|
| 618 |
element_d = {}
|
| 619 |
self._parsed
|
| 620 |
for element in self._elements:
|
| 621 |
if element in element_d:
|
| 622 |
continue
|
| 623 |
if isinstance(element, DependSpec):
|
| 624 |
element = element.compacted()
|
| 625 |
if not len(element._elements):
|
| 626 |
continue
|
| 627 |
if self._can_combine_with(element):
|
| 628 |
for element in element._elements:
|
| 629 |
if element in element_d:
|
| 630 |
continue
|
| 631 |
elements.append(element)
|
| 632 |
element_d[element] = True
|
| 633 |
else:
|
| 634 |
elements.append(element)
|
| 635 |
element_d[element] = True
|
| 636 |
else:
|
| 637 |
elements.append(element)
|
| 638 |
element_d[element] = True
|
| 639 |
if not elements:
|
| 640 |
return self.__class__()
|
| 641 |
dependspec = copy(self)
|
| 642 |
dependspec.__dict__["_elements"] = elements
|
| 643 |
return dependspec
|
| 644 |
|
| 645 |
|
| 646 |
class AtomDependSpec(DependSpec):
|
| 647 |
|
| 648 |
def create_from(atoms, preferential=False):
|
| 649 |
dependstr = []
|
| 650 |
for atom in atoms:
|
| 651 |
dependstr.append(str(atom))
|
| 652 |
dependstr = " ".join(dependstr)
|
| 653 |
if preferential:
|
| 654 |
dependstr = "|| ( "+dependstr+" )"
|
| 655 |
return AtomDependSpec(dependstr)
|
| 656 |
create_from = staticmethod(create_from)
|
| 657 |
|
| 658 |
def __init__(self, dependstr=""):
|
| 659 |
super(self.__class__, self).__init__(dependstr, element_class=Atom)
|
| 660 |
self.__dict__["preferential"] = False
|
| 661 |
self.__dict__["_specials"] = ["||"]
|
| 662 |
|
| 663 |
def __copy__(self):
|
| 664 |
atomdependspec = super(self.__class__, self).__copy__()
|
| 665 |
atomdependspec.__dict__["preferential"] = self.preferential
|
| 666 |
return atomdependspec
|
| 667 |
|
| 668 |
def __str__(self):
|
| 669 |
if self._str is not None:
|
| 670 |
return self._str
|
| 671 |
mystr = super(self.__class__, self).__str__()
|
| 672 |
if self.preferential:
|
| 673 |
mystr = "|| ( "+mystr+" )"
|
| 674 |
self.__dict__["_str"] = mystr
|
| 675 |
return mystr
|
| 676 |
|
| 677 |
def _do_special(self, special, idx):
|
| 678 |
if not isinstance(self._elements[idx], AtomDependSpec) or self._elements[idx].preferential:
|
| 679 |
raise ParseError()
|
| 680 |
self._elements[idx].__dict__["preferential"] = True
|
| 681 |
self._elements[idx].__dict__["_needs_brackets"] = False
|
| 682 |
|
| 683 |
def _can_combine_with(self, other):
|
| 684 |
if self.preferential != other.preferential:
|
| 685 |
return False
|
| 686 |
return super(self.__class__, self)._can_combine_with(other)
|
| 687 |
|
| 688 |
def compacted(self):
|
| 689 |
atomdependspec = super(self.__class__, self).compacted()
|
| 690 |
if atomdependspec.preferential and len(atomdependspec._elements) <= 1:
|
| 691 |
atomdependspec.__dict__["preferential"] = False
|
| 692 |
atomdependspec.__dict__["_needs_brackets"] = True
|
| 693 |
atomdependspec = atomdependspec.compacted()
|
| 694 |
return atomdependspec
|
| 695 |
|
| 696 |
def with_keys_transformed(self, key_map):
|
| 697 |
atomdependspec = copy(self)
|
| 698 |
atomdependspec._parsed
|
| 699 |
for x in range(len(atomdependspec._elements)):
|
| 700 |
if isinstance(atomdependspec._elements[x], AtomDependSpec):
|
| 701 |
atomdependspec._elements[x] = atomdependspec._elements[x].with_keys_transformed()
|
| 702 |
elif atomdependspec._elements[x].key in key_map:
|
| 703 |
elements = []
|
| 704 |
for newkey in key_map[atomdependspec._elements[x].key]:
|
| 705 |
elements.append(atomdependspec._elements[x].with_key(newkey))
|
| 706 |
atomdependspec._elements[x] = AtomDependSpec.create_from(elements, preferential=True)
|
| 707 |
atomdependspec.__dict__["_str"] = None
|
| 708 |
return atomdependspec
|
| 709 |
|
| 710 |
def combinations(self):
|
| 711 |
if not self._elements:
|
| 712 |
return []
|
| 713 |
|
| 714 |
if self.condition:
|
| 715 |
raise NotImplementedError()
|
| 716 |
|
| 717 |
combinations = []
|
| 718 |
|
| 719 |
if self.preferential:
|
| 720 |
for element in self._elements:
|
| 721 |
if isinstance(element, AtomDependSpec):
|
| 722 |
combinations += element.combinations()
|
| 723 |
else:
|
| 724 |
combinations += [[element]]
|
| 725 |
else:
|
| 726 |
singles = []
|
| 727 |
others = []
|
| 728 |
for element in self._elements:
|
| 729 |
if isinstance(element, AtomDependSpec):
|
| 730 |
others += [element.combinations()]
|
| 731 |
else:
|
| 732 |
singles += [element]
|
| 733 |
if others:
|
| 734 |
indexes = []
|
| 735 |
endindex = len(others)
|
| 736 |
for x in range(endindex):
|
| 737 |
indexes.append(0)
|
| 738 |
index = 0
|
| 739 |
while index != endindex:
|
| 740 |
if indexes[index] >= len(others[index]):
|
| 741 |
index += 1
|
| 742 |
if index == endindex:
|
| 743 |
continue
|
| 744 |
for x in range(index):
|
| 745 |
indexes[x] = 0
|
| 746 |
indexes[index] += 1
|
| 747 |
continue
|
| 748 |
else:
|
| 749 |
index = 0
|
| 750 |
newcomb = singles[:]
|
| 751 |
for x in range(endindex):
|
| 752 |
if others[x]:
|
| 753 |
newcomb.extend(others[x][indexes[x]])
|
| 754 |
combinations.append(newcomb)
|
| 755 |
indexes[index] += 1
|
| 756 |
else:
|
| 757 |
combinations = [singles]
|
| 758 |
return combinations
|