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