diff options
author | Chris Larson <clarson@kergoth.com> | 2009-07-19 10:05:52 -0700 |
---|---|---|
committer | Richard Purdie <rpurdie@linux.intel.com> | 2010-03-22 14:54:42 +0000 |
commit | f8c6db95d7734e3f4fc7eaf82eda6d59721b3fbb (patch) | |
tree | 18e1882916586b69460252a3465cce9ccdbbbb04 /bitbake | |
parent | b7d175a18a0fab65ff4022e15c68e079296c8e82 (diff) | |
download | poky-f8c6db95d7734e3f4fc7eaf82eda6d59721b3fbb.tar.gz |
Move most utility functions from bb into bb.utils.
(Bitbake rev: ff720ec59b30671c951dbf3b96df10ef56b8b505)
Signed-off-by: Chris Larson <clarson@kergoth.com>
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'bitbake')
-rw-r--r-- | bitbake/lib/bb/__init__.py | 914 | ||||
-rw-r--r-- | bitbake/lib/bb/utils.py | 759 |
2 files changed, 764 insertions, 909 deletions
diff --git a/bitbake/lib/bb/__init__.py b/bitbake/lib/bb/__init__.py index 84116f4f6a..92749d56f2 100644 --- a/bitbake/lib/bb/__init__.py +++ b/bitbake/lib/bb/__init__.py | |||
@@ -66,11 +66,7 @@ __all__ = [ | |||
66 | "providers", | 66 | "providers", |
67 | ] | 67 | ] |
68 | 68 | ||
69 | whitespace = '\t\n\x0b\x0c\r ' | ||
70 | lowercase = 'abcdefghijklmnopqrstuvwxyz' | ||
71 | |||
72 | import sys, os, types, re, string, bb | 69 | import sys, os, types, re, string, bb |
73 | from bb import msg | ||
74 | 70 | ||
75 | #projectdir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) | 71 | #projectdir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))) |
76 | projectdir = os.getcwd() | 72 | projectdir = os.getcwd() |
@@ -109,914 +105,14 @@ def fatal(*args): | |||
109 | bb.msg.fatal(None, ''.join(args)) | 105 | bb.msg.fatal(None, ''.join(args)) |
110 | 106 | ||
111 | 107 | ||
112 | ####################################################################### | ||
113 | ####################################################################### | ||
114 | # | ||
115 | # SECTION: File | ||
116 | # | ||
117 | # PURPOSE: Basic file and directory tree related functions | ||
118 | # | ||
119 | ####################################################################### | ||
120 | ####################################################################### | ||
121 | |||
122 | def mkdirhier(dir): | ||
123 | """Create a directory like 'mkdir -p', but does not complain if | ||
124 | directory already exists like os.makedirs | ||
125 | """ | ||
126 | |||
127 | debug(3, "mkdirhier(%s)" % dir) | ||
128 | try: | ||
129 | os.makedirs(dir) | ||
130 | debug(2, "created " + dir) | ||
131 | except OSError, e: | ||
132 | if e.errno != 17: raise e | ||
133 | |||
134 | |||
135 | ####################################################################### | ||
136 | |||
137 | import stat | ||
138 | |||
139 | def movefile(src,dest,newmtime=None,sstat=None): | ||
140 | """Moves a file from src to dest, preserving all permissions and | ||
141 | attributes; mtime will be preserved even when moving across | ||
142 | filesystems. Returns true on success and false on failure. Move is | ||
143 | atomic. | ||
144 | """ | ||
145 | |||
146 | #print "movefile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")" | ||
147 | try: | ||
148 | if not sstat: | ||
149 | sstat=os.lstat(src) | ||
150 | except Exception, e: | ||
151 | print "movefile: Stating source file failed...", e | ||
152 | return None | ||
153 | |||
154 | destexists=1 | ||
155 | try: | ||
156 | dstat=os.lstat(dest) | ||
157 | except: | ||
158 | dstat=os.lstat(os.path.dirname(dest)) | ||
159 | destexists=0 | ||
160 | |||
161 | if destexists: | ||
162 | if stat.S_ISLNK(dstat[stat.ST_MODE]): | ||
163 | try: | ||
164 | os.unlink(dest) | ||
165 | destexists=0 | ||
166 | except Exception, e: | ||
167 | pass | ||
168 | |||
169 | if stat.S_ISLNK(sstat[stat.ST_MODE]): | ||
170 | try: | ||
171 | target=os.readlink(src) | ||
172 | if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): | ||
173 | os.unlink(dest) | ||
174 | os.symlink(target,dest) | ||
175 | #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) | ||
176 | os.unlink(src) | ||
177 | return os.lstat(dest) | ||
178 | except Exception, e: | ||
179 | print "movefile: failed to properly create symlink:", dest, "->", target, e | ||
180 | return None | ||
181 | |||
182 | renamefailed=1 | ||
183 | if sstat[stat.ST_DEV]==dstat[stat.ST_DEV]: | ||
184 | try: | ||
185 | ret=os.rename(src,dest) | ||
186 | renamefailed=0 | ||
187 | except Exception, e: | ||
188 | import errno | ||
189 | if e[0]!=errno.EXDEV: | ||
190 | # Some random error. | ||
191 | print "movefile: Failed to move", src, "to", dest, e | ||
192 | return None | ||
193 | # Invalid cross-device-link 'bind' mounted or actually Cross-Device | ||
194 | |||
195 | if renamefailed: | ||
196 | didcopy=0 | ||
197 | if stat.S_ISREG(sstat[stat.ST_MODE]): | ||
198 | try: # For safety copy then move it over. | ||
199 | shutil.copyfile(src,dest+"#new") | ||
200 | os.rename(dest+"#new",dest) | ||
201 | didcopy=1 | ||
202 | except Exception, e: | ||
203 | print 'movefile: copy', src, '->', dest, 'failed.', e | ||
204 | return None | ||
205 | else: | ||
206 | #we don't yet handle special, so we need to fall back to /bin/mv | ||
207 | a=getstatusoutput("/bin/mv -f "+"'"+src+"' '"+dest+"'") | ||
208 | if a[0]!=0: | ||
209 | print "movefile: Failed to move special file:" + src + "' to '" + dest + "'", a | ||
210 | return None # failure | ||
211 | try: | ||
212 | if didcopy: | ||
213 | missingos.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) | ||
214 | os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown | ||
215 | os.unlink(src) | ||
216 | except Exception, e: | ||
217 | print "movefile: Failed to chown/chmod/unlink", dest, e | ||
218 | return None | ||
219 | |||
220 | if newmtime: | ||
221 | os.utime(dest,(newmtime,newmtime)) | ||
222 | else: | ||
223 | os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME])) | ||
224 | newmtime=sstat[stat.ST_MTIME] | ||
225 | return newmtime | ||
226 | |||
227 | def copyfile(src,dest,newmtime=None,sstat=None): | ||
228 | """ | ||
229 | Copies a file from src to dest, preserving all permissions and | ||
230 | attributes; mtime will be preserved even when moving across | ||
231 | filesystems. Returns true on success and false on failure. | ||
232 | """ | ||
233 | import os, stat, shutil | ||
234 | |||
235 | #print "copyfile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")" | ||
236 | try: | ||
237 | if not sstat: | ||
238 | sstat=os.lstat(src) | ||
239 | except Exception, e: | ||
240 | print "copyfile: Stating source file failed...", e | ||
241 | return False | ||
242 | |||
243 | destexists=1 | ||
244 | try: | ||
245 | dstat=os.lstat(dest) | ||
246 | except: | ||
247 | dstat=os.lstat(os.path.dirname(dest)) | ||
248 | destexists=0 | ||
249 | |||
250 | if destexists: | ||
251 | if stat.S_ISLNK(dstat[stat.ST_MODE]): | ||
252 | try: | ||
253 | os.unlink(dest) | ||
254 | destexists=0 | ||
255 | except Exception, e: | ||
256 | pass | ||
257 | |||
258 | if stat.S_ISLNK(sstat[stat.ST_MODE]): | ||
259 | try: | ||
260 | target=os.readlink(src) | ||
261 | if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): | ||
262 | os.unlink(dest) | ||
263 | os.symlink(target,dest) | ||
264 | #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) | ||
265 | return os.lstat(dest) | ||
266 | except Exception, e: | ||
267 | print "copyfile: failed to properly create symlink:", dest, "->", target, e | ||
268 | return False | ||
269 | |||
270 | if stat.S_ISREG(sstat[stat.ST_MODE]): | ||
271 | try: # For safety copy then move it over. | ||
272 | shutil.copyfile(src,dest+"#new") | ||
273 | os.rename(dest+"#new",dest) | ||
274 | except Exception, e: | ||
275 | print 'copyfile: copy', src, '->', dest, 'failed.', e | ||
276 | return False | ||
277 | else: | ||
278 | #we don't yet handle special, so we need to fall back to /bin/mv | ||
279 | a=getstatusoutput("/bin/cp -f "+"'"+src+"' '"+dest+"'") | ||
280 | if a[0]!=0: | ||
281 | print "copyfile: Failed to copy special file:" + src + "' to '" + dest + "'", a | ||
282 | return False # failure | ||
283 | try: | ||
284 | os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) | ||
285 | os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown | ||
286 | except Exception, e: | ||
287 | print "copyfile: Failed to chown/chmod/unlink", dest, e | ||
288 | return False | ||
289 | |||
290 | if newmtime: | ||
291 | os.utime(dest,(newmtime,newmtime)) | ||
292 | else: | ||
293 | os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME])) | ||
294 | newmtime=sstat[stat.ST_MTIME] | ||
295 | return newmtime | ||
296 | |||
297 | ####################################################################### | ||
298 | |||
299 | def which(path, item, direction = 0): | ||
300 | """ | ||
301 | Locate a file in a PATH | ||
302 | """ | ||
303 | |||
304 | paths = (path or "").split(':') | ||
305 | if direction != 0: | ||
306 | paths.reverse() | ||
307 | |||
308 | for p in (path or "").split(':'): | ||
309 | next = os.path.join(p, item) | ||
310 | if os.path.exists(next): | ||
311 | return next | ||
312 | |||
313 | return "" | ||
314 | |||
315 | ####################################################################### | ||
316 | |||
317 | |||
318 | |||
319 | |||
320 | ####################################################################### | ||
321 | ####################################################################### | ||
322 | # | ||
323 | # SECTION: Dependency | ||
324 | # | ||
325 | # PURPOSE: Compare build & run dependencies | ||
326 | # | ||
327 | ####################################################################### | ||
328 | ####################################################################### | ||
329 | |||
330 | def tokenize(mystring): | ||
331 | """Breaks a string like 'foo? (bar) oni? (blah (blah))' into (possibly embedded) lists: | ||
332 | |||
333 | >>> tokenize("x") | ||
334 | ['x'] | ||
335 | >>> tokenize("x y") | ||
336 | ['x', 'y'] | ||
337 | >>> tokenize("(x y)") | ||
338 | [['x', 'y']] | ||
339 | >>> tokenize("(x y) b c") | ||
340 | [['x', 'y'], 'b', 'c'] | ||
341 | >>> tokenize("foo? (bar) oni? (blah (blah))") | ||
342 | ['foo?', ['bar'], 'oni?', ['blah', ['blah']]] | ||
343 | >>> tokenize("sys-apps/linux-headers nls? (sys-devel/gettext)") | ||
344 | ['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']] | ||
345 | """ | ||
346 | |||
347 | newtokens = [] | ||
348 | curlist = newtokens | ||
349 | prevlists = [] | ||
350 | level = 0 | ||
351 | accum = "" | ||
352 | for x in mystring: | ||
353 | if x=="(": | ||
354 | if accum: | ||
355 | curlist.append(accum) | ||
356 | accum="" | ||
357 | prevlists.append(curlist) | ||
358 | curlist=[] | ||
359 | level=level+1 | ||
360 | elif x==")": | ||
361 | if accum: | ||
362 | curlist.append(accum) | ||
363 | accum="" | ||
364 | if level==0: | ||
365 | print "!!! tokenizer: Unmatched left parenthesis in:\n'"+mystring+"'" | ||
366 | return None | ||
367 | newlist=curlist | ||
368 | curlist=prevlists.pop() | ||
369 | curlist.append(newlist) | ||
370 | level=level-1 | ||
371 | elif x in whitespace: | ||
372 | if accum: | ||
373 | curlist.append(accum) | ||
374 | accum="" | ||
375 | else: | ||
376 | accum=accum+x | ||
377 | if accum: | ||
378 | curlist.append(accum) | ||
379 | if (level!=0): | ||
380 | print "!!! tokenizer: Exiting with unterminated parenthesis in:\n'"+mystring+"'" | ||
381 | return None | ||
382 | return newtokens | ||
383 | |||
384 | |||
385 | ####################################################################### | ||
386 | |||
387 | def evaluate(tokens,mydefines,allon=0): | ||
388 | """Removes tokens based on whether conditional definitions exist or not. | ||
389 | Recognizes ! | ||
390 | |||
391 | >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {}) | ||
392 | ['sys-apps/linux-headers'] | ||
393 | |||
394 | Negate the flag: | ||
395 | |||
396 | >>> evaluate(['sys-apps/linux-headers', '!nls?', ['sys-devel/gettext']], {}) | ||
397 | ['sys-apps/linux-headers', ['sys-devel/gettext']] | ||
398 | |||
399 | Define 'nls': | ||
400 | |||
401 | >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {"nls":1}) | ||
402 | ['sys-apps/linux-headers', ['sys-devel/gettext']] | ||
403 | |||
404 | Turn allon on: | ||
405 | |||
406 | >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {}, True) | ||
407 | ['sys-apps/linux-headers', ['sys-devel/gettext']] | ||
408 | """ | ||
409 | |||
410 | if tokens == None: | ||
411 | return None | ||
412 | mytokens = tokens + [] # this copies the list | ||
413 | pos = 0 | ||
414 | while pos < len(mytokens): | ||
415 | if type(mytokens[pos]) == types.ListType: | ||
416 | evaluate(mytokens[pos], mydefines) | ||
417 | if not len(mytokens[pos]): | ||
418 | del mytokens[pos] | ||
419 | continue | ||
420 | elif mytokens[pos][-1] == "?": | ||
421 | cur = mytokens[pos][:-1] | ||
422 | del mytokens[pos] | ||
423 | if allon: | ||
424 | if cur[0] == "!": | ||
425 | del mytokens[pos] | ||
426 | else: | ||
427 | if cur[0] == "!": | ||
428 | if (cur[1:] in mydefines) and (pos < len(mytokens)): | ||
429 | del mytokens[pos] | ||
430 | continue | ||
431 | elif (cur not in mydefines) and (pos < len(mytokens)): | ||
432 | del mytokens[pos] | ||
433 | continue | ||
434 | pos = pos + 1 | ||
435 | return mytokens | ||
436 | |||
437 | |||
438 | ####################################################################### | ||
439 | |||
440 | def flatten(mytokens): | ||
441 | """Converts nested arrays into a flat arrays: | ||
442 | |||
443 | >>> flatten([1,[2,3]]) | ||
444 | [1, 2, 3] | ||
445 | >>> flatten(['sys-apps/linux-headers', ['sys-devel/gettext']]) | ||
446 | ['sys-apps/linux-headers', 'sys-devel/gettext'] | ||
447 | """ | ||
448 | |||
449 | newlist=[] | ||
450 | for x in mytokens: | ||
451 | if type(x)==types.ListType: | ||
452 | newlist.extend(flatten(x)) | ||
453 | else: | ||
454 | newlist.append(x) | ||
455 | return newlist | ||
456 | |||
457 | |||
458 | ####################################################################### | ||
459 | |||
460 | _package_weights_ = {"pre":-2,"p":0,"alpha":-4,"beta":-3,"rc":-1} # dicts are unordered | ||
461 | _package_ends_ = ["pre", "p", "alpha", "beta", "rc", "cvs", "bk", "HEAD" ] # so we need ordered list | ||
462 | |||
463 | def relparse(myver): | ||
464 | """Parses the last elements of a version number into a triplet, that can | ||
465 | later be compared: | ||
466 | |||
467 | >>> relparse('1.2_pre3') | ||
468 | [1.2, -2, 3.0] | ||
469 | >>> relparse('1.2b') | ||
470 | [1.2, 98, 0] | ||
471 | >>> relparse('1.2') | ||
472 | [1.2, 0, 0] | ||
473 | """ | ||
474 | |||
475 | number = 0 | ||
476 | p1 = 0 | ||
477 | p2 = 0 | ||
478 | mynewver = myver.split('_') | ||
479 | if len(mynewver)==2: | ||
480 | # an _package_weights_ | ||
481 | number = float(mynewver[0]) | ||
482 | match = 0 | ||
483 | for x in _package_ends_: | ||
484 | elen = len(x) | ||
485 | if mynewver[1][:elen] == x: | ||
486 | match = 1 | ||
487 | p1 = _package_weights_[x] | ||
488 | try: | ||
489 | p2 = float(mynewver[1][elen:]) | ||
490 | except: | ||
491 | p2 = 0 | ||
492 | break | ||
493 | if not match: | ||
494 | # normal number or number with letter at end | ||
495 | divider = len(myver)-1 | ||
496 | if myver[divider:] not in "1234567890": | ||
497 | # letter at end | ||
498 | p1 = ord(myver[divider:]) | ||
499 | number = float(myver[0:divider]) | ||
500 | else: | ||
501 | number = float(myver) | ||
502 | else: | ||
503 | # normal number or number with letter at end | ||
504 | divider = len(myver)-1 | ||
505 | if myver[divider:] not in "1234567890": | ||
506 | #letter at end | ||
507 | p1 = ord(myver[divider:]) | ||
508 | number = float(myver[0:divider]) | ||
509 | else: | ||
510 | number = float(myver) | ||
511 | return [number,p1,p2] | ||
512 | |||
513 | |||
514 | ####################################################################### | ||
515 | |||
516 | __ververify_cache__ = {} | ||
517 | |||
518 | def ververify(myorigval,silent=1): | ||
519 | """Returns 1 if given a valid version string, els 0. Valid versions are in the format | ||
520 | |||
521 | <v1>.<v2>...<vx>[a-z,_{_package_weights_}[vy]] | ||
522 | |||
523 | >>> ververify('2.4.20') | ||
524 | 1 | ||
525 | >>> ververify('2.4..20') # two dots | ||
526 | 0 | ||
527 | >>> ververify('2.x.20') # 'x' is not numeric | ||
528 | 0 | ||
529 | >>> ververify('2.4.20a') | ||
530 | 1 | ||
531 | >>> ververify('2.4.20cvs') # only one trailing letter | ||
532 | 0 | ||
533 | >>> ververify('1a') | ||
534 | 1 | ||
535 | >>> ververify('test_a') # no version at all | ||
536 | 0 | ||
537 | >>> ververify('2.4.20_beta1') | ||
538 | 1 | ||
539 | >>> ververify('2.4.20_beta') | ||
540 | 1 | ||
541 | >>> ververify('2.4.20_wrongext') # _wrongext is no valid trailer | ||
542 | 0 | ||
543 | """ | ||
544 | |||
545 | # Lookup the cache first | ||
546 | try: | ||
547 | return __ververify_cache__[myorigval] | ||
548 | except KeyError: | ||
549 | pass | ||
550 | |||
551 | if len(myorigval) == 0: | ||
552 | if not silent: | ||
553 | error("package version is empty") | ||
554 | __ververify_cache__[myorigval] = 0 | ||
555 | return 0 | ||
556 | myval = myorigval.split('.') | ||
557 | if len(myval)==0: | ||
558 | if not silent: | ||
559 | error("package name has empty version string") | ||
560 | __ververify_cache__[myorigval] = 0 | ||
561 | return 0 | ||
562 | # all but the last version must be a numeric | ||
563 | for x in myval[:-1]: | ||
564 | if not len(x): | ||
565 | if not silent: | ||
566 | error("package version has two points in a row") | ||
567 | __ververify_cache__[myorigval] = 0 | ||
568 | return 0 | ||
569 | try: | ||
570 | foo = int(x) | ||
571 | except: | ||
572 | if not silent: | ||
573 | error("package version contains non-numeric '"+x+"'") | ||
574 | __ververify_cache__[myorigval] = 0 | ||
575 | return 0 | ||
576 | if not len(myval[-1]): | ||
577 | if not silent: | ||
578 | error("package version has trailing dot") | ||
579 | __ververify_cache__[myorigval] = 0 | ||
580 | return 0 | ||
581 | try: | ||
582 | foo = int(myval[-1]) | ||
583 | __ververify_cache__[myorigval] = 1 | ||
584 | return 1 | ||
585 | except: | ||
586 | pass | ||
587 | |||
588 | # ok, our last component is not a plain number or blank, let's continue | ||
589 | if myval[-1][-1] in lowercase: | ||
590 | try: | ||
591 | foo = int(myval[-1][:-1]) | ||
592 | return 1 | ||
593 | __ververify_cache__[myorigval] = 1 | ||
594 | # 1a, 2.0b, etc. | ||
595 | except: | ||
596 | pass | ||
597 | # ok, maybe we have a 1_alpha or 1_beta2; let's see | ||
598 | ep=string.split(myval[-1],"_") | ||
599 | if len(ep)!= 2: | ||
600 | if not silent: | ||
601 | error("package version has more than one letter at then end") | ||
602 | __ververify_cache__[myorigval] = 0 | ||
603 | return 0 | ||
604 | try: | ||
605 | foo = string.atoi(ep[0]) | ||
606 | except: | ||
607 | # this needs to be numeric, i.e. the "1" in "1_alpha" | ||
608 | if not silent: | ||
609 | error("package version must have numeric part before the '_'") | ||
610 | __ververify_cache__[myorigval] = 0 | ||
611 | return 0 | ||
612 | |||
613 | for mye in _package_ends_: | ||
614 | if ep[1][0:len(mye)] == mye: | ||
615 | if len(mye) == len(ep[1]): | ||
616 | # no trailing numeric is ok | ||
617 | __ververify_cache__[myorigval] = 1 | ||
618 | return 1 | ||
619 | else: | ||
620 | try: | ||
621 | foo = string.atoi(ep[1][len(mye):]) | ||
622 | __ververify_cache__[myorigval] = 1 | ||
623 | return 1 | ||
624 | except: | ||
625 | # if no _package_weights_ work, *then* we return 0 | ||
626 | pass | ||
627 | if not silent: | ||
628 | error("package version extension after '_' is invalid") | ||
629 | __ververify_cache__[myorigval] = 0 | ||
630 | return 0 | ||
631 | |||
632 | |||
633 | def isjustname(mypkg): | ||
634 | myparts = string.split(mypkg,'-') | ||
635 | for x in myparts: | ||
636 | if ververify(x): | ||
637 | return 0 | ||
638 | return 1 | ||
639 | |||
640 | |||
641 | _isspecific_cache_={} | ||
642 | |||
643 | def isspecific(mypkg): | ||
644 | "now supports packages with no category" | ||
645 | try: | ||
646 | return __isspecific_cache__[mypkg] | ||
647 | except: | ||
648 | pass | ||
649 | |||
650 | mysplit = string.split(mypkg,"/") | ||
651 | if not isjustname(mysplit[-1]): | ||
652 | __isspecific_cache__[mypkg] = 1 | ||
653 | return 1 | ||
654 | __isspecific_cache__[mypkg] = 0 | ||
655 | return 0 | ||
656 | |||
657 | |||
658 | ####################################################################### | ||
659 | |||
660 | __pkgsplit_cache__={} | ||
661 | |||
662 | def pkgsplit(mypkg, silent=1): | ||
663 | |||
664 | """This function can be used as a package verification function. If | ||
665 | it is a valid name, pkgsplit will return a list containing: | ||
666 | [pkgname, pkgversion(norev), pkgrev ]. | ||
667 | |||
668 | >>> pkgsplit('') | ||
669 | >>> pkgsplit('x') | ||
670 | >>> pkgsplit('x-') | ||
671 | >>> pkgsplit('-1') | ||
672 | >>> pkgsplit('glibc-1.2-8.9-r7') | ||
673 | >>> pkgsplit('glibc-2.2.5-r7') | ||
674 | ['glibc', '2.2.5', 'r7'] | ||
675 | >>> pkgsplit('foo-1.2-1') | ||
676 | >>> pkgsplit('Mesa-3.0') | ||
677 | ['Mesa', '3.0', 'r0'] | ||
678 | """ | ||
679 | |||
680 | try: | ||
681 | return __pkgsplit_cache__[mypkg] | ||
682 | except KeyError: | ||
683 | pass | ||
684 | |||
685 | myparts = string.split(mypkg,'-') | ||
686 | if len(myparts) < 2: | ||
687 | if not silent: | ||
688 | error("package name without name or version part") | ||
689 | __pkgsplit_cache__[mypkg] = None | ||
690 | return None | ||
691 | for x in myparts: | ||
692 | if len(x) == 0: | ||
693 | if not silent: | ||
694 | error("package name with empty name or version part") | ||
695 | __pkgsplit_cache__[mypkg] = None | ||
696 | return None | ||
697 | # verify rev | ||
698 | revok = 0 | ||
699 | myrev = myparts[-1] | ||
700 | ververify(myrev, silent) | ||
701 | if len(myrev) and myrev[0] == "r": | ||
702 | try: | ||
703 | string.atoi(myrev[1:]) | ||
704 | revok = 1 | ||
705 | except: | ||
706 | pass | ||
707 | if revok: | ||
708 | if ververify(myparts[-2]): | ||
709 | if len(myparts) == 2: | ||
710 | __pkgsplit_cache__[mypkg] = None | ||
711 | return None | ||
712 | else: | ||
713 | for x in myparts[:-2]: | ||
714 | if ververify(x): | ||
715 | __pkgsplit_cache__[mypkg]=None | ||
716 | return None | ||
717 | # names can't have versiony looking parts | ||
718 | myval=[string.join(myparts[:-2],"-"),myparts[-2],myparts[-1]] | ||
719 | __pkgsplit_cache__[mypkg]=myval | ||
720 | return myval | ||
721 | else: | ||
722 | __pkgsplit_cache__[mypkg] = None | ||
723 | return None | ||
724 | |||
725 | elif ververify(myparts[-1],silent): | ||
726 | if len(myparts)==1: | ||
727 | if not silent: | ||
728 | print "!!! Name error in",mypkg+": missing name part." | ||
729 | __pkgsplit_cache__[mypkg]=None | ||
730 | return None | ||
731 | else: | ||
732 | for x in myparts[:-1]: | ||
733 | if ververify(x): | ||
734 | if not silent: error("package name has multiple version parts") | ||
735 | __pkgsplit_cache__[mypkg] = None | ||
736 | return None | ||
737 | myval = [string.join(myparts[:-1],"-"), myparts[-1],"r0"] | ||
738 | __pkgsplit_cache__[mypkg] = myval | ||
739 | return myval | ||
740 | else: | ||
741 | __pkgsplit_cache__[mypkg] = None | ||
742 | return None | ||
743 | |||
744 | |||
745 | ####################################################################### | ||
746 | |||
747 | __catpkgsplit_cache__ = {} | ||
748 | |||
749 | def catpkgsplit(mydata,silent=1): | ||
750 | """returns [cat, pkgname, version, rev ] | ||
751 | |||
752 | >>> catpkgsplit('sys-libs/glibc-1.2-r7') | ||
753 | ['sys-libs', 'glibc', '1.2', 'r7'] | ||
754 | >>> catpkgsplit('glibc-1.2-r7') | ||
755 | [None, 'glibc', '1.2', 'r7'] | ||
756 | """ | ||
757 | |||
758 | try: | ||
759 | return __catpkgsplit_cache__[mydata] | ||
760 | except KeyError: | ||
761 | pass | ||
762 | |||
763 | cat = os.path.basename(os.path.dirname(mydata)) | ||
764 | mydata = os.path.join(cat, os.path.basename(mydata)) | ||
765 | if mydata[-3:] == '.bb': | ||
766 | mydata = mydata[:-3] | ||
767 | |||
768 | mysplit = mydata.split("/") | ||
769 | p_split = None | ||
770 | splitlen = len(mysplit) | ||
771 | if splitlen == 1: | ||
772 | retval = [None] | ||
773 | p_split = pkgsplit(mydata,silent) | ||
774 | else: | ||
775 | retval = [mysplit[splitlen - 2]] | ||
776 | p_split = pkgsplit(mysplit[splitlen - 1],silent) | ||
777 | if not p_split: | ||
778 | __catpkgsplit_cache__[mydata] = None | ||
779 | return None | ||
780 | retval.extend(p_split) | ||
781 | __catpkgsplit_cache__[mydata] = retval | ||
782 | return retval | ||
783 | |||
784 | |||
785 | ####################################################################### | ||
786 | |||
787 | __vercmp_cache__ = {} | ||
788 | |||
789 | def vercmp(val1,val2): | ||
790 | """This takes two version strings and returns an integer to tell you whether | ||
791 | the versions are the same, val1>val2 or val2>val1. | ||
792 | |||
793 | >>> vercmp('1', '2') | ||
794 | -1.0 | ||
795 | >>> vercmp('2', '1') | ||
796 | 1.0 | ||
797 | >>> vercmp('1', '1.0') | ||
798 | 0 | ||
799 | >>> vercmp('1', '1.1') | ||
800 | -1.0 | ||
801 | >>> vercmp('1.1', '1_p2') | ||
802 | 1.0 | ||
803 | """ | ||
804 | |||
805 | # quick short-circuit | ||
806 | if val1 == val2: | ||
807 | return 0 | ||
808 | valkey = val1+" "+val2 | ||
809 | |||
810 | # cache lookup | ||
811 | try: | ||
812 | return __vercmp_cache__[valkey] | ||
813 | try: | ||
814 | return - __vercmp_cache__[val2+" "+val1] | ||
815 | except KeyError: | ||
816 | pass | ||
817 | except KeyError: | ||
818 | pass | ||
819 | |||
820 | # consider 1_p2 vc 1.1 | ||
821 | # after expansion will become (1_p2,0) vc (1,1) | ||
822 | # then 1_p2 is compared with 1 before 0 is compared with 1 | ||
823 | # to solve the bug we need to convert it to (1,0_p2) | ||
824 | # by splitting _prepart part and adding it back _after_expansion | ||
825 | |||
826 | val1_prepart = val2_prepart = '' | ||
827 | if val1.count('_'): | ||
828 | val1, val1_prepart = val1.split('_', 1) | ||
829 | if val2.count('_'): | ||
830 | val2, val2_prepart = val2.split('_', 1) | ||
831 | |||
832 | # replace '-' by '.' | ||
833 | # FIXME: Is it needed? can val1/2 contain '-'? | ||
834 | |||
835 | val1 = string.split(val1,'-') | ||
836 | if len(val1) == 2: | ||
837 | val1[0] = val1[0] +"."+ val1[1] | ||
838 | val2 = string.split(val2,'-') | ||
839 | if len(val2) == 2: | ||
840 | val2[0] = val2[0] +"."+ val2[1] | ||
841 | |||
842 | val1 = string.split(val1[0],'.') | ||
843 | val2 = string.split(val2[0],'.') | ||
844 | |||
845 | # add back decimal point so that .03 does not become "3" ! | ||
846 | for x in range(1,len(val1)): | ||
847 | if val1[x][0] == '0' : | ||
848 | val1[x] = '.' + val1[x] | ||
849 | for x in range(1,len(val2)): | ||
850 | if val2[x][0] == '0' : | ||
851 | val2[x] = '.' + val2[x] | ||
852 | |||
853 | # extend varion numbers | ||
854 | if len(val2) < len(val1): | ||
855 | val2.extend(["0"]*(len(val1)-len(val2))) | ||
856 | elif len(val1) < len(val2): | ||
857 | val1.extend(["0"]*(len(val2)-len(val1))) | ||
858 | |||
859 | # add back _prepart tails | ||
860 | if val1_prepart: | ||
861 | val1[-1] += '_' + val1_prepart | ||
862 | if val2_prepart: | ||
863 | val2[-1] += '_' + val2_prepart | ||
864 | # The above code will extend version numbers out so they | ||
865 | # have the same number of digits. | ||
866 | for x in range(0,len(val1)): | ||
867 | cmp1 = relparse(val1[x]) | ||
868 | cmp2 = relparse(val2[x]) | ||
869 | for y in range(0,3): | ||
870 | myret = cmp1[y] - cmp2[y] | ||
871 | if myret != 0: | ||
872 | __vercmp_cache__[valkey] = myret | ||
873 | return myret | ||
874 | __vercmp_cache__[valkey] = 0 | ||
875 | return 0 | ||
876 | |||
877 | |||
878 | ####################################################################### | ||
879 | |||
880 | def pkgcmp(pkg1,pkg2): | ||
881 | """ Compares two packages, which should have been split via | ||
882 | pkgsplit(). if the return value val is less than zero, then pkg2 is | ||
883 | newer than pkg1, zero if equal and positive if older. | ||
884 | |||
885 | >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r7']) | ||
886 | 0 | ||
887 | >>> pkgcmp(['glibc', '2.2.5', 'r4'], ['glibc', '2.2.5', 'r7']) | ||
888 | -1 | ||
889 | >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r2']) | ||
890 | 1 | ||
891 | """ | ||
892 | |||
893 | mycmp = vercmp(pkg1[1],pkg2[1]) | ||
894 | if mycmp > 0: | ||
895 | return 1 | ||
896 | if mycmp < 0: | ||
897 | return -1 | ||
898 | r1=string.atoi(pkg1[2][1:]) | ||
899 | r2=string.atoi(pkg2[2][1:]) | ||
900 | if r1 > r2: | ||
901 | return 1 | ||
902 | if r2 > r1: | ||
903 | return -1 | ||
904 | return 0 | ||
905 | |||
906 | |||
907 | ####################################################################### | ||
908 | |||
909 | def dep_parenreduce(mysplit, mypos=0): | ||
910 | """Accepts a list of strings, and converts '(' and ')' surrounded items to sub-lists: | ||
911 | |||
912 | >>> dep_parenreduce(['']) | ||
913 | [''] | ||
914 | >>> dep_parenreduce(['1', '2', '3']) | ||
915 | ['1', '2', '3'] | ||
916 | >>> dep_parenreduce(['1', '(', '2', '3', ')', '4']) | ||
917 | ['1', ['2', '3'], '4'] | ||
918 | """ | ||
919 | |||
920 | while mypos < len(mysplit): | ||
921 | if mysplit[mypos] == "(": | ||
922 | firstpos = mypos | ||
923 | mypos = mypos + 1 | ||
924 | while mypos < len(mysplit): | ||
925 | if mysplit[mypos] == ")": | ||
926 | mysplit[firstpos:mypos+1] = [mysplit[firstpos+1:mypos]] | ||
927 | mypos = firstpos | ||
928 | break | ||
929 | elif mysplit[mypos] == "(": | ||
930 | # recurse | ||
931 | mysplit = dep_parenreduce(mysplit,mypos) | ||
932 | mypos = mypos + 1 | ||
933 | mypos = mypos + 1 | ||
934 | return mysplit | ||
935 | |||
936 | |||
937 | def dep_opconvert(mysplit, myuse): | ||
938 | "Does dependency operator conversion" | ||
939 | |||
940 | mypos = 0 | ||
941 | newsplit = [] | ||
942 | while mypos < len(mysplit): | ||
943 | if type(mysplit[mypos]) == types.ListType: | ||
944 | newsplit.append(dep_opconvert(mysplit[mypos],myuse)) | ||
945 | mypos += 1 | ||
946 | elif mysplit[mypos] == ")": | ||
947 | # mismatched paren, error | ||
948 | return None | ||
949 | elif mysplit[mypos]=="||": | ||
950 | if ((mypos+1)>=len(mysplit)) or (type(mysplit[mypos+1])!=types.ListType): | ||
951 | # || must be followed by paren'd list | ||
952 | return None | ||
953 | try: | ||
954 | mynew = dep_opconvert(mysplit[mypos+1],myuse) | ||
955 | except Exception, e: | ||
956 | error("unable to satisfy OR dependancy: " + string.join(mysplit," || ")) | ||
957 | raise e | ||
958 | mynew[0:0] = ["||"] | ||
959 | newsplit.append(mynew) | ||
960 | mypos += 2 | ||
961 | elif mysplit[mypos][-1] == "?": | ||
962 | # use clause, i.e "gnome? ( foo bar )" | ||
963 | # this is a quick and dirty hack so that repoman can enable all USE vars: | ||
964 | if (len(myuse) == 1) and (myuse[0] == "*"): | ||
965 | # enable it even if it's ! (for repoman) but kill it if it's | ||
966 | # an arch variable that isn't for this arch. XXX Sparc64? | ||
967 | if (mysplit[mypos][:-1] not in settings.usemask) or \ | ||
968 | (mysplit[mypos][:-1]==settings["ARCH"]): | ||
969 | enabled=1 | ||
970 | else: | ||
971 | enabled=0 | ||
972 | else: | ||
973 | if mysplit[mypos][0] == "!": | ||
974 | myusevar = mysplit[mypos][1:-1] | ||
975 | enabled = not myusevar in myuse | ||
976 | #if myusevar in myuse: | ||
977 | # enabled = 0 | ||
978 | #else: | ||
979 | # enabled = 1 | ||
980 | else: | ||
981 | myusevar=mysplit[mypos][:-1] | ||
982 | enabled = myusevar in myuse | ||
983 | #if myusevar in myuse: | ||
984 | # enabled=1 | ||
985 | #else: | ||
986 | # enabled=0 | ||
987 | if (mypos +2 < len(mysplit)) and (mysplit[mypos+2] == ":"): | ||
988 | # colon mode | ||
989 | if enabled: | ||
990 | # choose the first option | ||
991 | if type(mysplit[mypos+1]) == types.ListType: | ||
992 | newsplit.append(dep_opconvert(mysplit[mypos+1],myuse)) | ||
993 | else: | ||
994 | newsplit.append(mysplit[mypos+1]) | ||
995 | else: | ||
996 | # choose the alternate option | ||
997 | if type(mysplit[mypos+1]) == types.ListType: | ||
998 | newsplit.append(dep_opconvert(mysplit[mypos+3],myuse)) | ||
999 | else: | ||
1000 | newsplit.append(mysplit[mypos+3]) | ||
1001 | mypos += 4 | ||
1002 | else: | ||
1003 | # normal use mode | ||
1004 | if enabled: | ||
1005 | if type(mysplit[mypos+1]) == types.ListType: | ||
1006 | newsplit.append(dep_opconvert(mysplit[mypos+1],myuse)) | ||
1007 | else: | ||
1008 | newsplit.append(mysplit[mypos+1]) | ||
1009 | # otherwise, continue | ||
1010 | mypos += 2 | ||
1011 | else: | ||
1012 | # normal item | ||
1013 | newsplit.append(mysplit[mypos]) | ||
1014 | mypos += 1 | ||
1015 | return newsplit | ||
1016 | |||
1017 | # For compatibility | 108 | # For compatibility |
1018 | from bb.fetch import MalformedUrl, encodeurl, decodeurl | 109 | from bb.fetch import MalformedUrl, encodeurl, decodeurl |
1019 | from bb.data import VarExpandError | 110 | from bb.data import VarExpandError |
111 | from bb.utils import mkdirhier, movefile, copyfile, which | ||
112 | from bb.utils import tokenize, evaluate, flatten | ||
113 | from bb.utils import vercmp, pkgcmp, relparse, ververify | ||
114 | from bb.utils import pkgsplit, catpkgsplit, isjustname, isspecific | ||
115 | from bb.utils import dep_parenreduce, dep_opconvert | ||
1020 | 116 | ||
1021 | if __name__ == "__main__": | 117 | if __name__ == "__main__": |
1022 | import doctest, bb | 118 | import doctest, bb |
diff --git a/bitbake/lib/bb/utils.py b/bitbake/lib/bb/utils.py index 3b7ea2e83c..9776c48245 100644 --- a/bitbake/lib/bb/utils.py +++ b/bitbake/lib/bb/utils.py | |||
@@ -429,3 +429,762 @@ def prune_suffix(var, suffixes, d): | |||
429 | if var.endswith(suffix): | 429 | if var.endswith(suffix): |
430 | return var.replace(suffix, "") | 430 | return var.replace(suffix, "") |
431 | return var | 431 | return var |
432 | |||
433 | def mkdirhier(dir): | ||
434 | """Create a directory like 'mkdir -p', but does not complain if | ||
435 | directory already exists like os.makedirs | ||
436 | """ | ||
437 | |||
438 | debug(3, "mkdirhier(%s)" % dir) | ||
439 | try: | ||
440 | os.makedirs(dir) | ||
441 | debug(2, "created " + dir) | ||
442 | except OSError, e: | ||
443 | if e.errno != 17: raise e | ||
444 | |||
445 | import stat | ||
446 | |||
447 | def movefile(src,dest,newmtime=None,sstat=None): | ||
448 | """Moves a file from src to dest, preserving all permissions and | ||
449 | attributes; mtime will be preserved even when moving across | ||
450 | filesystems. Returns true on success and false on failure. Move is | ||
451 | atomic. | ||
452 | """ | ||
453 | |||
454 | #print "movefile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")" | ||
455 | try: | ||
456 | if not sstat: | ||
457 | sstat=os.lstat(src) | ||
458 | except Exception, e: | ||
459 | print "movefile: Stating source file failed...", e | ||
460 | return None | ||
461 | |||
462 | destexists=1 | ||
463 | try: | ||
464 | dstat=os.lstat(dest) | ||
465 | except: | ||
466 | dstat=os.lstat(os.path.dirname(dest)) | ||
467 | destexists=0 | ||
468 | |||
469 | if destexists: | ||
470 | if stat.S_ISLNK(dstat[stat.ST_MODE]): | ||
471 | try: | ||
472 | os.unlink(dest) | ||
473 | destexists=0 | ||
474 | except Exception, e: | ||
475 | pass | ||
476 | |||
477 | if stat.S_ISLNK(sstat[stat.ST_MODE]): | ||
478 | try: | ||
479 | target=os.readlink(src) | ||
480 | if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): | ||
481 | os.unlink(dest) | ||
482 | os.symlink(target,dest) | ||
483 | #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) | ||
484 | os.unlink(src) | ||
485 | return os.lstat(dest) | ||
486 | except Exception, e: | ||
487 | print "movefile: failed to properly create symlink:", dest, "->", target, e | ||
488 | return None | ||
489 | |||
490 | renamefailed=1 | ||
491 | if sstat[stat.ST_DEV]==dstat[stat.ST_DEV]: | ||
492 | try: | ||
493 | ret=os.rename(src,dest) | ||
494 | renamefailed=0 | ||
495 | except Exception, e: | ||
496 | import errno | ||
497 | if e[0]!=errno.EXDEV: | ||
498 | # Some random error. | ||
499 | print "movefile: Failed to move", src, "to", dest, e | ||
500 | return None | ||
501 | # Invalid cross-device-link 'bind' mounted or actually Cross-Device | ||
502 | |||
503 | if renamefailed: | ||
504 | didcopy=0 | ||
505 | if stat.S_ISREG(sstat[stat.ST_MODE]): | ||
506 | try: # For safety copy then move it over. | ||
507 | shutil.copyfile(src,dest+"#new") | ||
508 | os.rename(dest+"#new",dest) | ||
509 | didcopy=1 | ||
510 | except Exception, e: | ||
511 | print 'movefile: copy', src, '->', dest, 'failed.', e | ||
512 | return None | ||
513 | else: | ||
514 | #we don't yet handle special, so we need to fall back to /bin/mv | ||
515 | a=getstatusoutput("/bin/mv -f "+"'"+src+"' '"+dest+"'") | ||
516 | if a[0]!=0: | ||
517 | print "movefile: Failed to move special file:" + src + "' to '" + dest + "'", a | ||
518 | return None # failure | ||
519 | try: | ||
520 | if didcopy: | ||
521 | missingos.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) | ||
522 | os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown | ||
523 | os.unlink(src) | ||
524 | except Exception, e: | ||
525 | print "movefile: Failed to chown/chmod/unlink", dest, e | ||
526 | return None | ||
527 | |||
528 | if newmtime: | ||
529 | os.utime(dest,(newmtime,newmtime)) | ||
530 | else: | ||
531 | os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME])) | ||
532 | newmtime=sstat[stat.ST_MTIME] | ||
533 | return newmtime | ||
534 | |||
535 | def copyfile(src,dest,newmtime=None,sstat=None): | ||
536 | """ | ||
537 | Copies a file from src to dest, preserving all permissions and | ||
538 | attributes; mtime will be preserved even when moving across | ||
539 | filesystems. Returns true on success and false on failure. | ||
540 | """ | ||
541 | import os, stat, shutil | ||
542 | |||
543 | #print "copyfile("+src+","+dest+","+str(newmtime)+","+str(sstat)+")" | ||
544 | try: | ||
545 | if not sstat: | ||
546 | sstat=os.lstat(src) | ||
547 | except Exception, e: | ||
548 | print "copyfile: Stating source file failed...", e | ||
549 | return False | ||
550 | |||
551 | destexists=1 | ||
552 | try: | ||
553 | dstat=os.lstat(dest) | ||
554 | except: | ||
555 | dstat=os.lstat(os.path.dirname(dest)) | ||
556 | destexists=0 | ||
557 | |||
558 | if destexists: | ||
559 | if stat.S_ISLNK(dstat[stat.ST_MODE]): | ||
560 | try: | ||
561 | os.unlink(dest) | ||
562 | destexists=0 | ||
563 | except Exception, e: | ||
564 | pass | ||
565 | |||
566 | if stat.S_ISLNK(sstat[stat.ST_MODE]): | ||
567 | try: | ||
568 | target=os.readlink(src) | ||
569 | if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): | ||
570 | os.unlink(dest) | ||
571 | os.symlink(target,dest) | ||
572 | #os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) | ||
573 | return os.lstat(dest) | ||
574 | except Exception, e: | ||
575 | print "copyfile: failed to properly create symlink:", dest, "->", target, e | ||
576 | return False | ||
577 | |||
578 | if stat.S_ISREG(sstat[stat.ST_MODE]): | ||
579 | try: # For safety copy then move it over. | ||
580 | shutil.copyfile(src,dest+"#new") | ||
581 | os.rename(dest+"#new",dest) | ||
582 | except Exception, e: | ||
583 | print 'copyfile: copy', src, '->', dest, 'failed.', e | ||
584 | return False | ||
585 | else: | ||
586 | #we don't yet handle special, so we need to fall back to /bin/mv | ||
587 | a=getstatusoutput("/bin/cp -f "+"'"+src+"' '"+dest+"'") | ||
588 | if a[0]!=0: | ||
589 | print "copyfile: Failed to copy special file:" + src + "' to '" + dest + "'", a | ||
590 | return False # failure | ||
591 | try: | ||
592 | os.lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) | ||
593 | os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown | ||
594 | except Exception, e: | ||
595 | print "copyfile: Failed to chown/chmod/unlink", dest, e | ||
596 | return False | ||
597 | |||
598 | if newmtime: | ||
599 | os.utime(dest,(newmtime,newmtime)) | ||
600 | else: | ||
601 | os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME])) | ||
602 | newmtime=sstat[stat.ST_MTIME] | ||
603 | return newmtime | ||
604 | |||
605 | def which(path, item, direction = 0): | ||
606 | """ | ||
607 | Locate a file in a PATH | ||
608 | """ | ||
609 | |||
610 | paths = (path or "").split(':') | ||
611 | if direction != 0: | ||
612 | paths.reverse() | ||
613 | |||
614 | for p in (path or "").split(':'): | ||
615 | next = os.path.join(p, item) | ||
616 | if os.path.exists(next): | ||
617 | return next | ||
618 | |||
619 | return "" | ||
620 | |||
621 | whitespace = '\t\n\x0b\x0c\r ' | ||
622 | lowercase = 'abcdefghijklmnopqrstuvwxyz' | ||
623 | |||
624 | def tokenize(mystring): | ||
625 | """Breaks a string like 'foo? (bar) oni? (blah (blah))' into (possibly embedded) lists: | ||
626 | |||
627 | >>> tokenize("x") | ||
628 | ['x'] | ||
629 | >>> tokenize("x y") | ||
630 | ['x', 'y'] | ||
631 | >>> tokenize("(x y)") | ||
632 | [['x', 'y']] | ||
633 | >>> tokenize("(x y) b c") | ||
634 | [['x', 'y'], 'b', 'c'] | ||
635 | >>> tokenize("foo? (bar) oni? (blah (blah))") | ||
636 | ['foo?', ['bar'], 'oni?', ['blah', ['blah']]] | ||
637 | >>> tokenize("sys-apps/linux-headers nls? (sys-devel/gettext)") | ||
638 | ['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']] | ||
639 | """ | ||
640 | |||
641 | newtokens = [] | ||
642 | curlist = newtokens | ||
643 | prevlists = [] | ||
644 | level = 0 | ||
645 | accum = "" | ||
646 | for x in mystring: | ||
647 | if x=="(": | ||
648 | if accum: | ||
649 | curlist.append(accum) | ||
650 | accum="" | ||
651 | prevlists.append(curlist) | ||
652 | curlist=[] | ||
653 | level=level+1 | ||
654 | elif x==")": | ||
655 | if accum: | ||
656 | curlist.append(accum) | ||
657 | accum="" | ||
658 | if level==0: | ||
659 | print "!!! tokenizer: Unmatched left parenthesis in:\n'"+mystring+"'" | ||
660 | return None | ||
661 | newlist=curlist | ||
662 | curlist=prevlists.pop() | ||
663 | curlist.append(newlist) | ||
664 | level=level-1 | ||
665 | elif x in whitespace: | ||
666 | if accum: | ||
667 | curlist.append(accum) | ||
668 | accum="" | ||
669 | else: | ||
670 | accum=accum+x | ||
671 | if accum: | ||
672 | curlist.append(accum) | ||
673 | if (level!=0): | ||
674 | print "!!! tokenizer: Exiting with unterminated parenthesis in:\n'"+mystring+"'" | ||
675 | return None | ||
676 | return newtokens | ||
677 | |||
678 | def evaluate(tokens,mydefines,allon=0): | ||
679 | """Removes tokens based on whether conditional definitions exist or not. | ||
680 | Recognizes ! | ||
681 | |||
682 | >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {}) | ||
683 | ['sys-apps/linux-headers'] | ||
684 | |||
685 | Negate the flag: | ||
686 | |||
687 | >>> evaluate(['sys-apps/linux-headers', '!nls?', ['sys-devel/gettext']], {}) | ||
688 | ['sys-apps/linux-headers', ['sys-devel/gettext']] | ||
689 | |||
690 | Define 'nls': | ||
691 | |||
692 | >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {"nls":1}) | ||
693 | ['sys-apps/linux-headers', ['sys-devel/gettext']] | ||
694 | |||
695 | Turn allon on: | ||
696 | |||
697 | >>> evaluate(['sys-apps/linux-headers', 'nls?', ['sys-devel/gettext']], {}, True) | ||
698 | ['sys-apps/linux-headers', ['sys-devel/gettext']] | ||
699 | """ | ||
700 | |||
701 | if tokens == None: | ||
702 | return None | ||
703 | mytokens = tokens + [] # this copies the list | ||
704 | pos = 0 | ||
705 | while pos < len(mytokens): | ||
706 | if type(mytokens[pos]) == types.ListType: | ||
707 | evaluate(mytokens[pos], mydefines) | ||
708 | if not len(mytokens[pos]): | ||
709 | del mytokens[pos] | ||
710 | continue | ||
711 | elif mytokens[pos][-1] == "?": | ||
712 | cur = mytokens[pos][:-1] | ||
713 | del mytokens[pos] | ||
714 | if allon: | ||
715 | if cur[0] == "!": | ||
716 | del mytokens[pos] | ||
717 | else: | ||
718 | if cur[0] == "!": | ||
719 | if (cur[1:] in mydefines) and (pos < len(mytokens)): | ||
720 | del mytokens[pos] | ||
721 | continue | ||
722 | elif (cur not in mydefines) and (pos < len(mytokens)): | ||
723 | del mytokens[pos] | ||
724 | continue | ||
725 | pos = pos + 1 | ||
726 | return mytokens | ||
727 | |||
728 | def flatten(mytokens): | ||
729 | """Converts nested arrays into a flat arrays: | ||
730 | |||
731 | >>> flatten([1,[2,3]]) | ||
732 | [1, 2, 3] | ||
733 | >>> flatten(['sys-apps/linux-headers', ['sys-devel/gettext']]) | ||
734 | ['sys-apps/linux-headers', 'sys-devel/gettext'] | ||
735 | """ | ||
736 | |||
737 | newlist=[] | ||
738 | for x in mytokens: | ||
739 | if type(x)==types.ListType: | ||
740 | newlist.extend(flatten(x)) | ||
741 | else: | ||
742 | newlist.append(x) | ||
743 | return newlist | ||
744 | |||
745 | _package_weights_ = {"pre":-2,"p":0,"alpha":-4,"beta":-3,"rc":-1} # dicts are unordered | ||
746 | _package_ends_ = ["pre", "p", "alpha", "beta", "rc", "cvs", "bk", "HEAD" ] # so we need ordered list | ||
747 | |||
748 | def relparse(myver): | ||
749 | """Parses the last elements of a version number into a triplet, that can | ||
750 | later be compared: | ||
751 | |||
752 | >>> relparse('1.2_pre3') | ||
753 | [1.2, -2, 3.0] | ||
754 | >>> relparse('1.2b') | ||
755 | [1.2, 98, 0] | ||
756 | >>> relparse('1.2') | ||
757 | [1.2, 0, 0] | ||
758 | """ | ||
759 | |||
760 | number = 0 | ||
761 | p1 = 0 | ||
762 | p2 = 0 | ||
763 | mynewver = myver.split('_') | ||
764 | if len(mynewver)==2: | ||
765 | # an _package_weights_ | ||
766 | number = float(mynewver[0]) | ||
767 | match = 0 | ||
768 | for x in _package_ends_: | ||
769 | elen = len(x) | ||
770 | if mynewver[1][:elen] == x: | ||
771 | match = 1 | ||
772 | p1 = _package_weights_[x] | ||
773 | try: | ||
774 | p2 = float(mynewver[1][elen:]) | ||
775 | except: | ||
776 | p2 = 0 | ||
777 | break | ||
778 | if not match: | ||
779 | # normal number or number with letter at end | ||
780 | divider = len(myver)-1 | ||
781 | if myver[divider:] not in "1234567890": | ||
782 | # letter at end | ||
783 | p1 = ord(myver[divider:]) | ||
784 | number = float(myver[0:divider]) | ||
785 | else: | ||
786 | number = float(myver) | ||
787 | else: | ||
788 | # normal number or number with letter at end | ||
789 | divider = len(myver)-1 | ||
790 | if myver[divider:] not in "1234567890": | ||
791 | #letter at end | ||
792 | p1 = ord(myver[divider:]) | ||
793 | number = float(myver[0:divider]) | ||
794 | else: | ||
795 | number = float(myver) | ||
796 | return [number,p1,p2] | ||
797 | |||
798 | __ververify_cache__ = {} | ||
799 | |||
800 | def ververify(myorigval,silent=1): | ||
801 | """Returns 1 if given a valid version string, els 0. Valid versions are in the format | ||
802 | |||
803 | <v1>.<v2>...<vx>[a-z,_{_package_weights_}[vy]] | ||
804 | |||
805 | >>> ververify('2.4.20') | ||
806 | 1 | ||
807 | >>> ververify('2.4..20') # two dots | ||
808 | 0 | ||
809 | >>> ververify('2.x.20') # 'x' is not numeric | ||
810 | 0 | ||
811 | >>> ververify('2.4.20a') | ||
812 | 1 | ||
813 | >>> ververify('2.4.20cvs') # only one trailing letter | ||
814 | 0 | ||
815 | >>> ververify('1a') | ||
816 | 1 | ||
817 | >>> ververify('test_a') # no version at all | ||
818 | 0 | ||
819 | >>> ververify('2.4.20_beta1') | ||
820 | 1 | ||
821 | >>> ververify('2.4.20_beta') | ||
822 | 1 | ||
823 | >>> ververify('2.4.20_wrongext') # _wrongext is no valid trailer | ||
824 | 0 | ||
825 | """ | ||
826 | |||
827 | # Lookup the cache first | ||
828 | try: | ||
829 | return __ververify_cache__[myorigval] | ||
830 | except KeyError: | ||
831 | pass | ||
832 | |||
833 | if len(myorigval) == 0: | ||
834 | if not silent: | ||
835 | error("package version is empty") | ||
836 | __ververify_cache__[myorigval] = 0 | ||
837 | return 0 | ||
838 | myval = myorigval.split('.') | ||
839 | if len(myval)==0: | ||
840 | if not silent: | ||
841 | error("package name has empty version string") | ||
842 | __ververify_cache__[myorigval] = 0 | ||
843 | return 0 | ||
844 | # all but the last version must be a numeric | ||
845 | for x in myval[:-1]: | ||
846 | if not len(x): | ||
847 | if not silent: | ||
848 | error("package version has two points in a row") | ||
849 | __ververify_cache__[myorigval] = 0 | ||
850 | return 0 | ||
851 | try: | ||
852 | foo = int(x) | ||
853 | except: | ||
854 | if not silent: | ||
855 | error("package version contains non-numeric '"+x+"'") | ||
856 | __ververify_cache__[myorigval] = 0 | ||
857 | return 0 | ||
858 | if not len(myval[-1]): | ||
859 | if not silent: | ||
860 | error("package version has trailing dot") | ||
861 | __ververify_cache__[myorigval] = 0 | ||
862 | return 0 | ||
863 | try: | ||
864 | foo = int(myval[-1]) | ||
865 | __ververify_cache__[myorigval] = 1 | ||
866 | return 1 | ||
867 | except: | ||
868 | pass | ||
869 | |||
870 | # ok, our last component is not a plain number or blank, let's continue | ||
871 | if myval[-1][-1] in lowercase: | ||
872 | try: | ||
873 | foo = int(myval[-1][:-1]) | ||
874 | return 1 | ||
875 | __ververify_cache__[myorigval] = 1 | ||
876 | # 1a, 2.0b, etc. | ||
877 | except: | ||
878 | pass | ||
879 | # ok, maybe we have a 1_alpha or 1_beta2; let's see | ||
880 | ep=string.split(myval[-1],"_") | ||
881 | if len(ep)!= 2: | ||
882 | if not silent: | ||
883 | error("package version has more than one letter at then end") | ||
884 | __ververify_cache__[myorigval] = 0 | ||
885 | return 0 | ||
886 | try: | ||
887 | foo = string.atoi(ep[0]) | ||
888 | except: | ||
889 | # this needs to be numeric, i.e. the "1" in "1_alpha" | ||
890 | if not silent: | ||
891 | error("package version must have numeric part before the '_'") | ||
892 | __ververify_cache__[myorigval] = 0 | ||
893 | return 0 | ||
894 | |||
895 | for mye in _package_ends_: | ||
896 | if ep[1][0:len(mye)] == mye: | ||
897 | if len(mye) == len(ep[1]): | ||
898 | # no trailing numeric is ok | ||
899 | __ververify_cache__[myorigval] = 1 | ||
900 | return 1 | ||
901 | else: | ||
902 | try: | ||
903 | foo = string.atoi(ep[1][len(mye):]) | ||
904 | __ververify_cache__[myorigval] = 1 | ||
905 | return 1 | ||
906 | except: | ||
907 | # if no _package_weights_ work, *then* we return 0 | ||
908 | pass | ||
909 | if not silent: | ||
910 | error("package version extension after '_' is invalid") | ||
911 | __ververify_cache__[myorigval] = 0 | ||
912 | return 0 | ||
913 | |||
914 | def isjustname(mypkg): | ||
915 | myparts = string.split(mypkg,'-') | ||
916 | for x in myparts: | ||
917 | if ververify(x): | ||
918 | return 0 | ||
919 | return 1 | ||
920 | |||
921 | _isspecific_cache_={} | ||
922 | |||
923 | def isspecific(mypkg): | ||
924 | "now supports packages with no category" | ||
925 | try: | ||
926 | return __isspecific_cache__[mypkg] | ||
927 | except: | ||
928 | pass | ||
929 | |||
930 | mysplit = string.split(mypkg,"/") | ||
931 | if not isjustname(mysplit[-1]): | ||
932 | __isspecific_cache__[mypkg] = 1 | ||
933 | return 1 | ||
934 | __isspecific_cache__[mypkg] = 0 | ||
935 | return 0 | ||
936 | |||
937 | __pkgsplit_cache__={} | ||
938 | |||
939 | def pkgsplit(mypkg, silent=1): | ||
940 | |||
941 | """This function can be used as a package verification function. If | ||
942 | it is a valid name, pkgsplit will return a list containing: | ||
943 | [pkgname, pkgversion(norev), pkgrev ]. | ||
944 | |||
945 | >>> pkgsplit('') | ||
946 | >>> pkgsplit('x') | ||
947 | >>> pkgsplit('x-') | ||
948 | >>> pkgsplit('-1') | ||
949 | >>> pkgsplit('glibc-1.2-8.9-r7') | ||
950 | >>> pkgsplit('glibc-2.2.5-r7') | ||
951 | ['glibc', '2.2.5', 'r7'] | ||
952 | >>> pkgsplit('foo-1.2-1') | ||
953 | >>> pkgsplit('Mesa-3.0') | ||
954 | ['Mesa', '3.0', 'r0'] | ||
955 | """ | ||
956 | |||
957 | try: | ||
958 | return __pkgsplit_cache__[mypkg] | ||
959 | except KeyError: | ||
960 | pass | ||
961 | |||
962 | myparts = string.split(mypkg,'-') | ||
963 | if len(myparts) < 2: | ||
964 | if not silent: | ||
965 | error("package name without name or version part") | ||
966 | __pkgsplit_cache__[mypkg] = None | ||
967 | return None | ||
968 | for x in myparts: | ||
969 | if len(x) == 0: | ||
970 | if not silent: | ||
971 | error("package name with empty name or version part") | ||
972 | __pkgsplit_cache__[mypkg] = None | ||
973 | return None | ||
974 | # verify rev | ||
975 | revok = 0 | ||
976 | myrev = myparts[-1] | ||
977 | ververify(myrev, silent) | ||
978 | if len(myrev) and myrev[0] == "r": | ||
979 | try: | ||
980 | string.atoi(myrev[1:]) | ||
981 | revok = 1 | ||
982 | except: | ||
983 | pass | ||
984 | if revok: | ||
985 | if ververify(myparts[-2]): | ||
986 | if len(myparts) == 2: | ||
987 | __pkgsplit_cache__[mypkg] = None | ||
988 | return None | ||
989 | else: | ||
990 | for x in myparts[:-2]: | ||
991 | if ververify(x): | ||
992 | __pkgsplit_cache__[mypkg]=None | ||
993 | return None | ||
994 | # names can't have versiony looking parts | ||
995 | myval=[string.join(myparts[:-2],"-"),myparts[-2],myparts[-1]] | ||
996 | __pkgsplit_cache__[mypkg]=myval | ||
997 | return myval | ||
998 | else: | ||
999 | __pkgsplit_cache__[mypkg] = None | ||
1000 | return None | ||
1001 | |||
1002 | elif ververify(myparts[-1],silent): | ||
1003 | if len(myparts)==1: | ||
1004 | if not silent: | ||
1005 | print "!!! Name error in",mypkg+": missing name part." | ||
1006 | __pkgsplit_cache__[mypkg]=None | ||
1007 | return None | ||
1008 | else: | ||
1009 | for x in myparts[:-1]: | ||
1010 | if ververify(x): | ||
1011 | if not silent: error("package name has multiple version parts") | ||
1012 | __pkgsplit_cache__[mypkg] = None | ||
1013 | return None | ||
1014 | myval = [string.join(myparts[:-1],"-"), myparts[-1],"r0"] | ||
1015 | __pkgsplit_cache__[mypkg] = myval | ||
1016 | return myval | ||
1017 | else: | ||
1018 | __pkgsplit_cache__[mypkg] = None | ||
1019 | return None | ||
1020 | |||
1021 | __catpkgsplit_cache__ = {} | ||
1022 | |||
1023 | def catpkgsplit(mydata,silent=1): | ||
1024 | """returns [cat, pkgname, version, rev ] | ||
1025 | |||
1026 | >>> catpkgsplit('sys-libs/glibc-1.2-r7') | ||
1027 | ['sys-libs', 'glibc', '1.2', 'r7'] | ||
1028 | >>> catpkgsplit('glibc-1.2-r7') | ||
1029 | [None, 'glibc', '1.2', 'r7'] | ||
1030 | """ | ||
1031 | |||
1032 | try: | ||
1033 | return __catpkgsplit_cache__[mydata] | ||
1034 | except KeyError: | ||
1035 | pass | ||
1036 | |||
1037 | cat = os.path.basename(os.path.dirname(mydata)) | ||
1038 | mydata = os.path.join(cat, os.path.basename(mydata)) | ||
1039 | if mydata[-3:] == '.bb': | ||
1040 | mydata = mydata[:-3] | ||
1041 | |||
1042 | mysplit = mydata.split("/") | ||
1043 | p_split = None | ||
1044 | splitlen = len(mysplit) | ||
1045 | if splitlen == 1: | ||
1046 | retval = [None] | ||
1047 | p_split = pkgsplit(mydata,silent) | ||
1048 | else: | ||
1049 | retval = [mysplit[splitlen - 2]] | ||
1050 | p_split = pkgsplit(mysplit[splitlen - 1],silent) | ||
1051 | if not p_split: | ||
1052 | __catpkgsplit_cache__[mydata] = None | ||
1053 | return None | ||
1054 | retval.extend(p_split) | ||
1055 | __catpkgsplit_cache__[mydata] = retval | ||
1056 | return retval | ||
1057 | |||
1058 | def pkgcmp(pkg1,pkg2): | ||
1059 | """ Compares two packages, which should have been split via | ||
1060 | pkgsplit(). if the return value val is less than zero, then pkg2 is | ||
1061 | newer than pkg1, zero if equal and positive if older. | ||
1062 | |||
1063 | >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r7']) | ||
1064 | 0 | ||
1065 | >>> pkgcmp(['glibc', '2.2.5', 'r4'], ['glibc', '2.2.5', 'r7']) | ||
1066 | -1 | ||
1067 | >>> pkgcmp(['glibc', '2.2.5', 'r7'], ['glibc', '2.2.5', 'r2']) | ||
1068 | 1 | ||
1069 | """ | ||
1070 | |||
1071 | mycmp = vercmp(pkg1[1],pkg2[1]) | ||
1072 | if mycmp > 0: | ||
1073 | return 1 | ||
1074 | if mycmp < 0: | ||
1075 | return -1 | ||
1076 | r1=string.atoi(pkg1[2][1:]) | ||
1077 | r2=string.atoi(pkg2[2][1:]) | ||
1078 | if r1 > r2: | ||
1079 | return 1 | ||
1080 | if r2 > r1: | ||
1081 | return -1 | ||
1082 | return 0 | ||
1083 | |||
1084 | def dep_parenreduce(mysplit, mypos=0): | ||
1085 | """Accepts a list of strings, and converts '(' and ')' surrounded items to sub-lists: | ||
1086 | |||
1087 | >>> dep_parenreduce(['']) | ||
1088 | [''] | ||
1089 | >>> dep_parenreduce(['1', '2', '3']) | ||
1090 | ['1', '2', '3'] | ||
1091 | >>> dep_parenreduce(['1', '(', '2', '3', ')', '4']) | ||
1092 | ['1', ['2', '3'], '4'] | ||
1093 | """ | ||
1094 | |||
1095 | while mypos < len(mysplit): | ||
1096 | if mysplit[mypos] == "(": | ||
1097 | firstpos = mypos | ||
1098 | mypos = mypos + 1 | ||
1099 | while mypos < len(mysplit): | ||
1100 | if mysplit[mypos] == ")": | ||
1101 | mysplit[firstpos:mypos+1] = [mysplit[firstpos+1:mypos]] | ||
1102 | mypos = firstpos | ||
1103 | break | ||
1104 | elif mysplit[mypos] == "(": | ||
1105 | # recurse | ||
1106 | mysplit = dep_parenreduce(mysplit,mypos) | ||
1107 | mypos = mypos + 1 | ||
1108 | mypos = mypos + 1 | ||
1109 | return mysplit | ||
1110 | |||
1111 | def dep_opconvert(mysplit, myuse): | ||
1112 | "Does dependency operator conversion" | ||
1113 | |||
1114 | mypos = 0 | ||
1115 | newsplit = [] | ||
1116 | while mypos < len(mysplit): | ||
1117 | if type(mysplit[mypos]) == types.ListType: | ||
1118 | newsplit.append(dep_opconvert(mysplit[mypos],myuse)) | ||
1119 | mypos += 1 | ||
1120 | elif mysplit[mypos] == ")": | ||
1121 | # mismatched paren, error | ||
1122 | return None | ||
1123 | elif mysplit[mypos]=="||": | ||
1124 | if ((mypos+1)>=len(mysplit)) or (type(mysplit[mypos+1])!=types.ListType): | ||
1125 | # || must be followed by paren'd list | ||
1126 | return None | ||
1127 | try: | ||
1128 | mynew = dep_opconvert(mysplit[mypos+1],myuse) | ||
1129 | except Exception, e: | ||
1130 | error("unable to satisfy OR dependancy: " + string.join(mysplit," || ")) | ||
1131 | raise e | ||
1132 | mynew[0:0] = ["||"] | ||
1133 | newsplit.append(mynew) | ||
1134 | mypos += 2 | ||
1135 | elif mysplit[mypos][-1] == "?": | ||
1136 | # use clause, i.e "gnome? ( foo bar )" | ||
1137 | # this is a quick and dirty hack so that repoman can enable all USE vars: | ||
1138 | if (len(myuse) == 1) and (myuse[0] == "*"): | ||
1139 | # enable it even if it's ! (for repoman) but kill it if it's | ||
1140 | # an arch variable that isn't for this arch. XXX Sparc64? | ||
1141 | if (mysplit[mypos][:-1] not in settings.usemask) or \ | ||
1142 | (mysplit[mypos][:-1]==settings["ARCH"]): | ||
1143 | enabled=1 | ||
1144 | else: | ||
1145 | enabled=0 | ||
1146 | else: | ||
1147 | if mysplit[mypos][0] == "!": | ||
1148 | myusevar = mysplit[mypos][1:-1] | ||
1149 | enabled = not myusevar in myuse | ||
1150 | #if myusevar in myuse: | ||
1151 | # enabled = 0 | ||
1152 | #else: | ||
1153 | # enabled = 1 | ||
1154 | else: | ||
1155 | myusevar=mysplit[mypos][:-1] | ||
1156 | enabled = myusevar in myuse | ||
1157 | #if myusevar in myuse: | ||
1158 | # enabled=1 | ||
1159 | #else: | ||
1160 | # enabled=0 | ||
1161 | if (mypos +2 < len(mysplit)) and (mysplit[mypos+2] == ":"): | ||
1162 | # colon mode | ||
1163 | if enabled: | ||
1164 | # choose the first option | ||
1165 | if type(mysplit[mypos+1]) == types.ListType: | ||
1166 | newsplit.append(dep_opconvert(mysplit[mypos+1],myuse)) | ||
1167 | else: | ||
1168 | newsplit.append(mysplit[mypos+1]) | ||
1169 | else: | ||
1170 | # choose the alternate option | ||
1171 | if type(mysplit[mypos+1]) == types.ListType: | ||
1172 | newsplit.append(dep_opconvert(mysplit[mypos+3],myuse)) | ||
1173 | else: | ||
1174 | newsplit.append(mysplit[mypos+3]) | ||
1175 | mypos += 4 | ||
1176 | else: | ||
1177 | # normal use mode | ||
1178 | if enabled: | ||
1179 | if type(mysplit[mypos+1]) == types.ListType: | ||
1180 | newsplit.append(dep_opconvert(mysplit[mypos+1],myuse)) | ||
1181 | else: | ||
1182 | newsplit.append(mysplit[mypos+1]) | ||
1183 | # otherwise, continue | ||
1184 | mypos += 2 | ||
1185 | else: | ||
1186 | # normal item | ||
1187 | newsplit.append(mysplit[mypos]) | ||
1188 | mypos += 1 | ||
1189 | return newsplit | ||
1190 | |||