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