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/lib/bb/utils.py | |
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/lib/bb/utils.py')
-rw-r--r-- | bitbake/lib/bb/utils.py | 759 |
1 files changed, 759 insertions, 0 deletions
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 | |||