mercurial/util.py
changeset 2177 6886bc0b77af
parent 2165 d821918e3bee
parent 2176 9b42304d9896
child 2193 fb28ce04b349
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