Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/util.py @ 2177:6886bc0b77af
merge with crew.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Tue, 02 May 2006 14:37:55 -0700 |
parents | d821918e3bee 9b42304d9896 |
children | fb28ce04b349 |
comparison
equal
deleted
inserted
replaced
2174:3044a3fdae76 | 2177:6886bc0b77af |
---|---|
407 | 407 |
408 def rename(src, dst): | 408 def rename(src, dst): |
409 """forcibly rename a file""" | 409 """forcibly rename a file""" |
410 try: | 410 try: |
411 os.rename(src, dst) | 411 os.rename(src, dst) |
412 except: | 412 except OSError, err: |
413 os.unlink(dst) | 413 # on windows, rename to existing file is not allowed, so we |
414 # must delete destination first. but if file is open, unlink | |
415 # schedules it for delete but does not delete it. rename | |
416 # happens immediately even for open files, so we create | |
417 # temporary file, delete it, rename destination to that name, | |
418 # then delete that. then rename is safe to do. | |
419 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.') | |
420 os.close(fd) | |
421 os.unlink(temp) | |
422 os.rename(dst, temp) | |
423 os.unlink(temp) | |
414 os.rename(src, dst) | 424 os.rename(src, dst) |
415 | 425 |
416 def unlink(f): | 426 def unlink(f): |
417 """unlink and remove the directory if it is empty""" | 427 """unlink and remove the directory if it is empty""" |
418 os.unlink(f) | 428 os.unlink(f) |
450 parts = os.path.normcase(path).split(os.sep) | 460 parts = os.path.normcase(path).split(os.sep) |
451 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '') | 461 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '') |
452 or os.pardir in parts): | 462 or os.pardir in parts): |
453 raise Abort(_("path contains illegal component: %s\n") % path) | 463 raise Abort(_("path contains illegal component: %s\n") % path) |
454 | 464 |
465 def _makelock_file(info, pathname): | |
466 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL) | |
467 os.write(ld, info) | |
468 os.close(ld) | |
469 | |
470 def _readlock_file(pathname): | |
471 return posixfile(pathname).read() | |
472 | |
473 def nlinks(pathname): | |
474 """Return number of hardlinks for the given file.""" | |
475 return os.stat(pathname).st_nlink | |
476 | |
477 if hasattr(os, 'link'): | |
478 os_link = os.link | |
479 else: | |
480 def os_link(src, dst): | |
481 raise OSError(0, _("Hardlinks not supported")) | |
482 | |
483 def fstat(fp): | |
484 '''stat file object that may not have fileno method.''' | |
485 try: | |
486 return os.fstat(fp.fileno()) | |
487 except AttributeError: | |
488 return os.stat(fp.name) | |
489 | |
490 posixfile = file | |
491 | |
492 # Platform specific variants | |
493 if os.name == 'nt': | |
494 demandload(globals(), "msvcrt") | |
495 nulldev = 'NUL:' | |
496 | |
497 class winstdout: | |
498 '''stdout on windows misbehaves if sent through a pipe''' | |
499 | |
500 def __init__(self, fp): | |
501 self.fp = fp | |
502 | |
503 def __getattr__(self, key): | |
504 return getattr(self.fp, key) | |
505 | |
506 def close(self): | |
507 try: | |
508 self.fp.close() | |
509 except: pass | |
510 | |
511 def write(self, s): | |
512 try: | |
513 return self.fp.write(s) | |
514 except IOError, inst: | |
515 if inst.errno != 0: raise | |
516 self.close() | |
517 raise IOError(errno.EPIPE, 'Broken pipe') | |
518 | |
519 sys.stdout = winstdout(sys.stdout) | |
520 | |
521 def system_rcpath(): | |
522 try: | |
523 return system_rcpath_win32() | |
524 except: | |
525 return [r'c:\mercurial\mercurial.ini'] | |
526 | |
527 def os_rcpath(): | |
528 '''return default os-specific hgrc search path''' | |
529 return system_rcpath() + [os.path.join(os.path.expanduser('~'), | |
530 'mercurial.ini')] | |
531 | |
532 def parse_patch_output(output_line): | |
533 """parses the output produced by patch and returns the file name""" | |
534 pf = output_line[14:] | |
535 if pf[0] == '`': | |
536 pf = pf[1:-1] # Remove the quotes | |
537 return pf | |
538 | |
539 def testpid(pid): | |
540 '''return False if pid dead, True if running or not known''' | |
541 return True | |
542 | |
543 def is_exec(f, last): | |
544 return last | |
545 | |
546 def set_exec(f, mode): | |
547 pass | |
548 | |
549 def set_binary(fd): | |
550 msvcrt.setmode(fd.fileno(), os.O_BINARY) | |
551 | |
552 def pconvert(path): | |
553 return path.replace("\\", "/") | |
554 | |
555 def localpath(path): | |
556 return path.replace('/', '\\') | |
557 | |
558 def normpath(path): | |
559 return pconvert(os.path.normpath(path)) | |
560 | |
561 makelock = _makelock_file | |
562 readlock = _readlock_file | |
563 | |
564 def explain_exit(code): | |
565 return _("exited with status %d") % code, code | |
566 | |
567 try: | |
568 # override functions with win32 versions if possible | |
569 from util_win32 import * | |
570 except ImportError: | |
571 pass | |
572 | |
573 else: | |
574 nulldev = '/dev/null' | |
575 | |
576 def rcfiles(path): | |
577 rcs = [os.path.join(path, 'hgrc')] | |
578 rcdir = os.path.join(path, 'hgrc.d') | |
579 try: | |
580 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir) | |
581 if f.endswith(".rc")]) | |
582 except OSError, inst: pass | |
583 return rcs | |
584 | |
585 def os_rcpath(): | |
586 '''return default os-specific hgrc search path''' | |
587 path = [] | |
588 if len(sys.argv) > 0: | |
589 path.extend(rcfiles(os.path.dirname(sys.argv[0]) + | |
590 '/../etc/mercurial')) | |
591 path.extend(rcfiles('/etc/mercurial')) | |
592 path.append(os.path.expanduser('~/.hgrc')) | |
593 path = [os.path.normpath(f) for f in path] | |
594 return path | |
595 | |
596 def parse_patch_output(output_line): | |
597 """parses the output produced by patch and returns the file name""" | |
598 pf = output_line[14:] | |
599 if pf.startswith("'") and pf.endswith("'") and pf.find(" ") >= 0: | |
600 pf = pf[1:-1] # Remove the quotes | |
601 return pf | |
602 | |
603 def is_exec(f, last): | |
604 """check whether a file is executable""" | |
605 return (os.stat(f).st_mode & 0100 != 0) | |
606 | |
607 def set_exec(f, mode): | |
608 s = os.stat(f).st_mode | |
609 if (s & 0100 != 0) == mode: | |
610 return | |
611 if mode: | |
612 # Turn on +x for every +r bit when making a file executable | |
613 # and obey umask. | |
614 umask = os.umask(0) | |
615 os.umask(umask) | |
616 os.chmod(f, s | (s & 0444) >> 2 & ~umask) | |
617 else: | |
618 os.chmod(f, s & 0666) | |
619 | |
620 def set_binary(fd): | |
621 pass | |
622 | |
623 def pconvert(path): | |
624 return path | |
625 | |
626 def localpath(path): | |
627 return path | |
628 | |
629 normpath = os.path.normpath | |
630 | |
631 def makelock(info, pathname): | |
632 try: | |
633 os.symlink(info, pathname) | |
634 except OSError, why: | |
635 if why.errno == errno.EEXIST: | |
636 raise | |
637 else: | |
638 _makelock_file(info, pathname) | |
639 | |
640 def readlock(pathname): | |
641 try: | |
642 return os.readlink(pathname) | |
643 except OSError, why: | |
644 if why.errno == errno.EINVAL: | |
645 return _readlock_file(pathname) | |
646 else: | |
647 raise | |
648 | |
649 def testpid(pid): | |
650 '''return False if pid dead, True if running or not sure''' | |
651 try: | |
652 os.kill(pid, 0) | |
653 return True | |
654 except OSError, inst: | |
655 return inst.errno != errno.ESRCH | |
656 | |
657 def explain_exit(code): | |
658 """return a 2-tuple (desc, code) describing a process's status""" | |
659 if os.WIFEXITED(code): | |
660 val = os.WEXITSTATUS(code) | |
661 return _("exited with status %d") % val, val | |
662 elif os.WIFSIGNALED(code): | |
663 val = os.WTERMSIG(code) | |
664 return _("killed by signal %d") % val, val | |
665 elif os.WIFSTOPPED(code): | |
666 val = os.WSTOPSIG(code) | |
667 return _("stopped by signal %d") % val, val | |
668 raise ValueError(_("invalid exit code")) | |
669 | |
455 def opener(base, audit=True): | 670 def opener(base, audit=True): |
456 """ | 671 """ |
457 return a function that opens files relative to base | 672 return a function that opens files relative to base |
458 | 673 |
459 this function is used to hide the details of COW semantics and | 674 this function is used to hide the details of COW semantics and |
462 p = base | 677 p = base |
463 audit_p = audit | 678 audit_p = audit |
464 | 679 |
465 def mktempcopy(name): | 680 def mktempcopy(name): |
466 d, fn = os.path.split(name) | 681 d, fn = os.path.split(name) |
467 fd, temp = tempfile.mkstemp(prefix=".%s-" % fn, dir=d) | 682 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) |
468 fp = os.fdopen(fd, "wb") | 683 os.close(fd) |
684 fp = posixfile(temp, "wb") | |
469 try: | 685 try: |
470 fp.write(file(name, "rb").read()) | 686 fp.write(posixfile(name, "rb").read()) |
471 except: | 687 except: |
472 try: os.unlink(temp) | 688 try: os.unlink(temp) |
473 except: pass | 689 except: pass |
474 raise | 690 raise |
475 fp.close() | 691 fp.close() |
476 st = os.lstat(name) | 692 st = os.lstat(name) |
477 os.chmod(temp, st.st_mode) | 693 os.chmod(temp, st.st_mode) |
478 return temp | 694 return temp |
479 | 695 |
480 class atomictempfile(file): | 696 class atomictempfile(posixfile): |
481 """the file will only be copied when rename is called""" | 697 """the file will only be copied when rename is called""" |
482 def __init__(self, name, mode): | 698 def __init__(self, name, mode): |
483 self.__name = name | 699 self.__name = name |
484 self.temp = mktempcopy(name) | 700 self.temp = mktempcopy(name) |
485 file.__init__(self, self.temp, mode) | 701 posixfile.__init__(self, self.temp, mode) |
486 def rename(self): | 702 def rename(self): |
487 if not self.closed: | 703 if not self.closed: |
488 file.close(self) | 704 posixfile.close(self) |
489 rename(self.temp, self.__name) | 705 rename(self.temp, self.__name) |
490 def __del__(self): | 706 def __del__(self): |
491 if not self.closed: | 707 if not self.closed: |
492 try: | 708 try: |
493 os.unlink(self.temp) | 709 os.unlink(self.temp) |
494 except: pass | 710 except: pass |
495 file.close(self) | 711 posixfile.close(self) |
496 | 712 |
497 class atomicfile(atomictempfile): | 713 class atomicfile(atomictempfile): |
498 """the file will only be copied on close""" | 714 """the file will only be copied on close""" |
499 def __init__(self, name, mode): | 715 def __init__(self, name, mode): |
500 atomictempfile.__init__(self, name, mode) | 716 atomictempfile.__init__(self, name, mode) |
523 return atomicfile(f, mode) | 739 return atomicfile(f, mode) |
524 elif atomictemp: | 740 elif atomictemp: |
525 return atomictempfile(f, mode) | 741 return atomictempfile(f, mode) |
526 if nlink > 1: | 742 if nlink > 1: |
527 rename(mktempcopy(f), f) | 743 rename(mktempcopy(f), f) |
528 return file(f, mode) | 744 return posixfile(f, mode) |
529 | 745 |
530 return o | 746 return o |
531 | |
532 def _makelock_file(info, pathname): | |
533 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL) | |
534 os.write(ld, info) | |
535 os.close(ld) | |
536 | |
537 def _readlock_file(pathname): | |
538 return file(pathname).read() | |
539 | |
540 def nlinks(pathname): | |
541 """Return number of hardlinks for the given file.""" | |
542 return os.stat(pathname).st_nlink | |
543 | |
544 if hasattr(os, 'link'): | |
545 os_link = os.link | |
546 else: | |
547 def os_link(src, dst): | |
548 raise OSError(0, _("Hardlinks not supported")) | |
549 | |
550 # Platform specific variants | |
551 if os.name == 'nt': | |
552 demandload(globals(), "msvcrt") | |
553 nulldev = 'NUL:' | |
554 | |
555 class winstdout: | |
556 '''stdout on windows misbehaves if sent through a pipe''' | |
557 | |
558 def __init__(self, fp): | |
559 self.fp = fp | |
560 | |
561 def __getattr__(self, key): | |
562 return getattr(self.fp, key) | |
563 | |
564 def close(self): | |
565 try: | |
566 self.fp.close() | |
567 except: pass | |
568 | |
569 def write(self, s): | |
570 try: | |
571 return self.fp.write(s) | |
572 except IOError, inst: | |
573 if inst.errno != 0: raise | |
574 self.close() | |
575 raise IOError(errno.EPIPE, 'Broken pipe') | |
576 | |
577 sys.stdout = winstdout(sys.stdout) | |
578 | |
579 def system_rcpath(): | |
580 try: | |
581 return system_rcpath_win32() | |
582 except: | |
583 return [r'c:\mercurial\mercurial.ini'] | |
584 | |
585 def os_rcpath(): | |
586 '''return default os-specific hgrc search path''' | |
587 return system_rcpath() + [os.path.join(os.path.expanduser('~'), | |
588 'mercurial.ini')] | |
589 | |
590 def parse_patch_output(output_line): | |
591 """parses the output produced by patch and returns the file name""" | |
592 pf = output_line[14:] | |
593 if pf[0] == '`': | |
594 pf = pf[1:-1] # Remove the quotes | |
595 return pf | |
596 | |
597 def testpid(pid): | |
598 '''return False if pid dead, True if running or not known''' | |
599 return True | |
600 | |
601 def is_exec(f, last): | |
602 return last | |
603 | |
604 def set_exec(f, mode): | |
605 pass | |
606 | |
607 def set_binary(fd): | |
608 msvcrt.setmode(fd.fileno(), os.O_BINARY) | |
609 | |
610 def pconvert(path): | |
611 return path.replace("\\", "/") | |
612 | |
613 def localpath(path): | |
614 return path.replace('/', '\\') | |
615 | |
616 def normpath(path): | |
617 return pconvert(os.path.normpath(path)) | |
618 | |
619 makelock = _makelock_file | |
620 readlock = _readlock_file | |
621 | |
622 def explain_exit(code): | |
623 return _("exited with status %d") % code, code | |
624 | |
625 try: | |
626 # override functions with win32 versions if possible | |
627 from util_win32 import * | |
628 except ImportError: | |
629 pass | |
630 | |
631 else: | |
632 nulldev = '/dev/null' | |
633 | |
634 def rcfiles(path): | |
635 rcs = [os.path.join(path, 'hgrc')] | |
636 rcdir = os.path.join(path, 'hgrc.d') | |
637 try: | |
638 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir) | |
639 if f.endswith(".rc")]) | |
640 except OSError, inst: pass | |
641 return rcs | |
642 | |
643 def os_rcpath(): | |
644 '''return default os-specific hgrc search path''' | |
645 path = [] | |
646 if len(sys.argv) > 0: | |
647 path.extend(rcfiles(os.path.dirname(sys.argv[0]) + | |
648 '/../etc/mercurial')) | |
649 path.extend(rcfiles('/etc/mercurial')) | |
650 path.append(os.path.expanduser('~/.hgrc')) | |
651 path = [os.path.normpath(f) for f in path] | |
652 return path | |
653 | |
654 def parse_patch_output(output_line): | |
655 """parses the output produced by patch and returns the file name""" | |
656 pf = output_line[14:] | |
657 if pf.startswith("'") and pf.endswith("'") and pf.find(" ") >= 0: | |
658 pf = pf[1:-1] # Remove the quotes | |
659 return pf | |
660 | |
661 def is_exec(f, last): | |
662 """check whether a file is executable""" | |
663 return (os.stat(f).st_mode & 0100 != 0) | |
664 | |
665 def set_exec(f, mode): | |
666 s = os.stat(f).st_mode | |
667 if (s & 0100 != 0) == mode: | |
668 return | |
669 if mode: | |
670 # Turn on +x for every +r bit when making a file executable | |
671 # and obey umask. | |
672 umask = os.umask(0) | |
673 os.umask(umask) | |
674 os.chmod(f, s | (s & 0444) >> 2 & ~umask) | |
675 else: | |
676 os.chmod(f, s & 0666) | |
677 | |
678 def set_binary(fd): | |
679 pass | |
680 | |
681 def pconvert(path): | |
682 return path | |
683 | |
684 def localpath(path): | |
685 return path | |
686 | |
687 normpath = os.path.normpath | |
688 | |
689 def makelock(info, pathname): | |
690 try: | |
691 os.symlink(info, pathname) | |
692 except OSError, why: | |
693 if why.errno == errno.EEXIST: | |
694 raise | |
695 else: | |
696 _makelock_file(info, pathname) | |
697 | |
698 def readlock(pathname): | |
699 try: | |
700 return os.readlink(pathname) | |
701 except OSError, why: | |
702 if why.errno == errno.EINVAL: | |
703 return _readlock_file(pathname) | |
704 else: | |
705 raise | |
706 | |
707 def testpid(pid): | |
708 '''return False if pid dead, True if running or not sure''' | |
709 try: | |
710 os.kill(pid, 0) | |
711 return True | |
712 except OSError, inst: | |
713 return inst.errno != errno.ESRCH | |
714 | |
715 def explain_exit(code): | |
716 """return a 2-tuple (desc, code) describing a process's status""" | |
717 if os.WIFEXITED(code): | |
718 val = os.WEXITSTATUS(code) | |
719 return _("exited with status %d") % val, val | |
720 elif os.WIFSIGNALED(code): | |
721 val = os.WTERMSIG(code) | |
722 return _("killed by signal %d") % val, val | |
723 elif os.WIFSTOPPED(code): | |
724 val = os.WSTOPSIG(code) | |
725 return _("stopped by signal %d") % val, val | |
726 raise ValueError(_("invalid exit code")) | |
727 | 747 |
728 class chunkbuffer(object): | 748 class chunkbuffer(object): |
729 """Allow arbitrary sized chunks of data to be efficiently read from an | 749 """Allow arbitrary sized chunks of data to be efficiently read from an |
730 iterator over chunks of arbitrary size.""" | 750 iterator over chunks of arbitrary size.""" |
731 | 751 |