mercurial/util.py
changeset 43076 2372284d9457
parent 42782 e94c8f584ee2
child 43077 687b865b95ad
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
    32 import sys
    32 import sys
    33 import time
    33 import time
    34 import traceback
    34 import traceback
    35 import warnings
    35 import warnings
    36 
    36 
    37 from .thirdparty import (
    37 from .thirdparty import attr
    38     attr,
       
    39 )
       
    40 from hgdemandimport import tracing
    38 from hgdemandimport import tracing
    41 from . import (
    39 from . import (
    42     encoding,
    40     encoding,
    43     error,
    41     error,
    44     i18n,
    42     i18n,
   140 
   138 
   141 # Python compatibility
   139 # Python compatibility
   142 
   140 
   143 _notset = object()
   141 _notset = object()
   144 
   142 
       
   143 
   145 def bitsfrom(container):
   144 def bitsfrom(container):
   146     bits = 0
   145     bits = 0
   147     for bit in container:
   146     for bit in container:
   148         bits |= bit
   147         bits |= bit
   149     return bits
   148     return bits
       
   149 
   150 
   150 
   151 # python 2.6 still have deprecation warning enabled by default. We do not want
   151 # python 2.6 still have deprecation warning enabled by default. We do not want
   152 # to display anything to standard user so detect if we are running test and
   152 # to display anything to standard user so detect if we are running test and
   153 # only use python deprecation warning in this case.
   153 # only use python deprecation warning in this case.
   154 _dowarn = bool(encoding.environ.get('HGEMITWARNINGS'))
   154 _dowarn = bool(encoding.environ.get('HGEMITWARNINGS'))
   162     warnings.filterwarnings(r'default', r'', DeprecationWarning, r'mercurial')
   162     warnings.filterwarnings(r'default', r'', DeprecationWarning, r'mercurial')
   163     warnings.filterwarnings(r'default', r'', DeprecationWarning, r'hgext')
   163     warnings.filterwarnings(r'default', r'', DeprecationWarning, r'hgext')
   164     warnings.filterwarnings(r'default', r'', DeprecationWarning, r'hgext3rd')
   164     warnings.filterwarnings(r'default', r'', DeprecationWarning, r'hgext3rd')
   165 if _dowarn and pycompat.ispy3:
   165 if _dowarn and pycompat.ispy3:
   166     # silence warning emitted by passing user string to re.sub()
   166     # silence warning emitted by passing user string to re.sub()
   167     warnings.filterwarnings(r'ignore', r'bad escape', DeprecationWarning,
   167     warnings.filterwarnings(
   168                             r'mercurial')
   168         r'ignore', r'bad escape', DeprecationWarning, r'mercurial'
   169     warnings.filterwarnings(r'ignore', r'invalid escape sequence',
   169     )
   170                             DeprecationWarning, r'mercurial')
   170     warnings.filterwarnings(
       
   171         r'ignore', r'invalid escape sequence', DeprecationWarning, r'mercurial'
       
   172     )
   171     # TODO: reinvent imp.is_frozen()
   173     # TODO: reinvent imp.is_frozen()
   172     warnings.filterwarnings(r'ignore', r'the imp module is deprecated',
   174     warnings.filterwarnings(
   173                             DeprecationWarning, r'mercurial')
   175         r'ignore',
       
   176         r'the imp module is deprecated',
       
   177         DeprecationWarning,
       
   178         r'mercurial',
       
   179     )
       
   180 
   174 
   181 
   175 def nouideprecwarn(msg, version, stacklevel=1):
   182 def nouideprecwarn(msg, version, stacklevel=1):
   176     """Issue an python native deprecation warning
   183     """Issue an python native deprecation warning
   177 
   184 
   178     This is a noop outside of tests, use 'ui.deprecwarn' when possible.
   185     This is a noop outside of tests, use 'ui.deprecwarn' when possible.
   179     """
   186     """
   180     if _dowarn:
   187     if _dowarn:
   181         msg += ("\n(compatibility will be dropped after Mercurial-%s,"
   188         msg += (
   182                 " update your code.)") % version
   189             "\n(compatibility will be dropped after Mercurial-%s,"
       
   190             " update your code.)"
       
   191         ) % version
   183         warnings.warn(pycompat.sysstr(msg), DeprecationWarning, stacklevel + 1)
   192         warnings.warn(pycompat.sysstr(msg), DeprecationWarning, stacklevel + 1)
       
   193 
   184 
   194 
   185 DIGESTS = {
   195 DIGESTS = {
   186     'md5': hashlib.md5,
   196     'md5': hashlib.md5,
   187     'sha1': hashlib.sha1,
   197     'sha1': hashlib.sha1,
   188     'sha512': hashlib.sha512,
   198     'sha512': hashlib.sha512,
   190 # List of digest types from strongest to weakest
   200 # List of digest types from strongest to weakest
   191 DIGESTS_BY_STRENGTH = ['sha512', 'sha1', 'md5']
   201 DIGESTS_BY_STRENGTH = ['sha512', 'sha1', 'md5']
   192 
   202 
   193 for k in DIGESTS_BY_STRENGTH:
   203 for k in DIGESTS_BY_STRENGTH:
   194     assert k in DIGESTS
   204     assert k in DIGESTS
       
   205 
   195 
   206 
   196 class digester(object):
   207 class digester(object):
   197     """helper to compute digests.
   208     """helper to compute digests.
   198 
   209 
   199     This helper can be used to compute one or more digests given their name.
   210     This helper can be used to compute one or more digests given their name.
   238         for k in DIGESTS_BY_STRENGTH:
   249         for k in DIGESTS_BY_STRENGTH:
   239             if k in supported:
   250             if k in supported:
   240                 return k
   251                 return k
   241         return None
   252         return None
   242 
   253 
       
   254 
   243 class digestchecker(object):
   255 class digestchecker(object):
   244     """file handle wrapper that additionally checks content against a given
   256     """file handle wrapper that additionally checks content against a given
   245     size and digests.
   257     size and digests.
   246 
   258 
   247         d = digestchecker(fh, size, {'md5': '...'})
   259         d = digestchecker(fh, size, {'md5': '...'})
   262         self._got += len(content)
   274         self._got += len(content)
   263         return content
   275         return content
   264 
   276 
   265     def validate(self):
   277     def validate(self):
   266         if self._size != self._got:
   278         if self._size != self._got:
   267             raise error.Abort(_('size mismatch: expected %d, got %d') %
   279             raise error.Abort(
   268                               (self._size, self._got))
   280                 _('size mismatch: expected %d, got %d')
       
   281                 % (self._size, self._got)
       
   282             )
   269         for k, v in self._digests.items():
   283         for k, v in self._digests.items():
   270             if v != self._digester[k]:
   284             if v != self._digester[k]:
   271                 # i18n: first parameter is a digest name
   285                 # i18n: first parameter is a digest name
   272                 raise error.Abort(_('%s mismatch: expected %s, got %s') %
   286                 raise error.Abort(
   273                                   (k, v, self._digester[k]))
   287                     _('%s mismatch: expected %s, got %s')
       
   288                     % (k, v, self._digester[k])
       
   289                 )
       
   290 
   274 
   291 
   275 try:
   292 try:
   276     buffer = buffer
   293     buffer = buffer
   277 except NameError:
   294 except NameError:
       
   295 
   278     def buffer(sliceable, offset=0, length=None):
   296     def buffer(sliceable, offset=0, length=None):
   279         if length is not None:
   297         if length is not None:
   280             return memoryview(sliceable)[offset:offset + length]
   298             return memoryview(sliceable)[offset : offset + length]
   281         return memoryview(sliceable)[offset:]
   299         return memoryview(sliceable)[offset:]
   282 
   300 
       
   301 
   283 _chunksize = 4096
   302 _chunksize = 4096
       
   303 
   284 
   304 
   285 class bufferedinputpipe(object):
   305 class bufferedinputpipe(object):
   286     """a manually buffered input pipe
   306     """a manually buffered input pipe
   287 
   307 
   288     Python will not let us use buffered IO and lazy reading with 'polling' at
   308     Python will not let us use buffered IO and lazy reading with 'polling' at
   294     empty from the output (allowing collaboration of the buffer with polling).
   314     empty from the output (allowing collaboration of the buffer with polling).
   295 
   315 
   296     This class lives in the 'util' module because it makes use of the 'os'
   316     This class lives in the 'util' module because it makes use of the 'os'
   297     module from the python stdlib.
   317     module from the python stdlib.
   298     """
   318     """
       
   319 
   299     def __new__(cls, fh):
   320     def __new__(cls, fh):
   300         # If we receive a fileobjectproxy, we need to use a variation of this
   321         # If we receive a fileobjectproxy, we need to use a variation of this
   301         # class that notifies observers about activity.
   322         # class that notifies observers about activity.
   302         if isinstance(fh, fileobjectproxy):
   323         if isinstance(fh, fileobjectproxy):
   303             cls = observedbufferedinputpipe
   324             cls = observedbufferedinputpipe
   350         while (not self._eof) and lfi < 0:
   371         while (not self._eof) and lfi < 0:
   351             self._fillbuffer()
   372             self._fillbuffer()
   352             if self._buffer:
   373             if self._buffer:
   353                 lfi = self._buffer[-1].find('\n')
   374                 lfi = self._buffer[-1].find('\n')
   354         size = lfi + 1
   375         size = lfi + 1
   355         if lfi < 0: # end of file
   376         if lfi < 0:  # end of file
   356             size = self._lenbuf
   377             size = self._lenbuf
   357         elif len(self._buffer) > 1:
   378         elif len(self._buffer) > 1:
   358             # we need to take previous chunks into account
   379             # we need to take previous chunks into account
   359             size += self._lenbuf - len(self._buffer[-1])
   380             size += self._lenbuf - len(self._buffer[-1])
   360         return self._frombuffer(size)
   381         return self._frombuffer(size)
   368         buf = self._buffer[0]
   389         buf = self._buffer[0]
   369         if len(self._buffer) > 1:
   390         if len(self._buffer) > 1:
   370             buf = ''.join(self._buffer)
   391             buf = ''.join(self._buffer)
   371 
   392 
   372         data = buf[:size]
   393         data = buf[:size]
   373         buf = buf[len(data):]
   394         buf = buf[len(data) :]
   374         if buf:
   395         if buf:
   375             self._buffer = [buf]
   396             self._buffer = [buf]
   376             self._lenbuf = len(buf)
   397             self._lenbuf = len(buf)
   377         else:
   398         else:
   378             self._buffer = []
   399             self._buffer = []
   387         else:
   408         else:
   388             self._lenbuf += len(data)
   409             self._lenbuf += len(data)
   389             self._buffer.append(data)
   410             self._buffer.append(data)
   390 
   411 
   391         return data
   412         return data
       
   413 
   392 
   414 
   393 def mmapread(fp):
   415 def mmapread(fp):
   394     try:
   416     try:
   395         fd = getattr(fp, 'fileno', lambda: fp)()
   417         fd = getattr(fp, 'fileno', lambda: fp)()
   396         return mmap.mmap(fd, 0, access=mmap.ACCESS_READ)
   418         return mmap.mmap(fd, 0, access=mmap.ACCESS_READ)
   399         # if the file is empty, and if so, return an empty buffer.
   421         # if the file is empty, and if so, return an empty buffer.
   400         if os.fstat(fd).st_size == 0:
   422         if os.fstat(fd).st_size == 0:
   401             return ''
   423             return ''
   402         raise
   424         raise
   403 
   425 
       
   426 
   404 class fileobjectproxy(object):
   427 class fileobjectproxy(object):
   405     """A proxy around file objects that tells a watcher when events occur.
   428     """A proxy around file objects that tells a watcher when events occur.
   406 
   429 
   407     This type is intended to only be used for testing purposes. Think hard
   430     This type is intended to only be used for testing purposes. Think hard
   408     before using it in important code.
   431     before using it in important code.
   409     """
   432     """
       
   433 
   410     __slots__ = (
   434     __slots__ = (
   411         r'_orig',
   435         r'_orig',
   412         r'_observer',
   436         r'_observer',
   413     )
   437     )
   414 
   438 
   417         object.__setattr__(self, r'_observer', observer)
   441         object.__setattr__(self, r'_observer', observer)
   418 
   442 
   419     def __getattribute__(self, name):
   443     def __getattribute__(self, name):
   420         ours = {
   444         ours = {
   421             r'_observer',
   445             r'_observer',
   422 
       
   423             # IOBase
   446             # IOBase
   424             r'close',
   447             r'close',
   425             # closed if a property
   448             # closed if a property
   426             r'fileno',
   449             r'fileno',
   427             r'flush',
   450             r'flush',
   483 
   506 
   484         return res
   507         return res
   485 
   508 
   486     def close(self, *args, **kwargs):
   509     def close(self, *args, **kwargs):
   487         return object.__getattribute__(self, r'_observedcall')(
   510         return object.__getattribute__(self, r'_observedcall')(
   488             r'close', *args, **kwargs)
   511             r'close', *args, **kwargs
       
   512         )
   489 
   513 
   490     def fileno(self, *args, **kwargs):
   514     def fileno(self, *args, **kwargs):
   491         return object.__getattribute__(self, r'_observedcall')(
   515         return object.__getattribute__(self, r'_observedcall')(
   492             r'fileno', *args, **kwargs)
   516             r'fileno', *args, **kwargs
       
   517         )
   493 
   518 
   494     def flush(self, *args, **kwargs):
   519     def flush(self, *args, **kwargs):
   495         return object.__getattribute__(self, r'_observedcall')(
   520         return object.__getattribute__(self, r'_observedcall')(
   496             r'flush', *args, **kwargs)
   521             r'flush', *args, **kwargs
       
   522         )
   497 
   523 
   498     def isatty(self, *args, **kwargs):
   524     def isatty(self, *args, **kwargs):
   499         return object.__getattribute__(self, r'_observedcall')(
   525         return object.__getattribute__(self, r'_observedcall')(
   500             r'isatty', *args, **kwargs)
   526             r'isatty', *args, **kwargs
       
   527         )
   501 
   528 
   502     def readable(self, *args, **kwargs):
   529     def readable(self, *args, **kwargs):
   503         return object.__getattribute__(self, r'_observedcall')(
   530         return object.__getattribute__(self, r'_observedcall')(
   504             r'readable', *args, **kwargs)
   531             r'readable', *args, **kwargs
       
   532         )
   505 
   533 
   506     def readline(self, *args, **kwargs):
   534     def readline(self, *args, **kwargs):
   507         return object.__getattribute__(self, r'_observedcall')(
   535         return object.__getattribute__(self, r'_observedcall')(
   508             r'readline', *args, **kwargs)
   536             r'readline', *args, **kwargs
       
   537         )
   509 
   538 
   510     def readlines(self, *args, **kwargs):
   539     def readlines(self, *args, **kwargs):
   511         return object.__getattribute__(self, r'_observedcall')(
   540         return object.__getattribute__(self, r'_observedcall')(
   512             r'readlines', *args, **kwargs)
   541             r'readlines', *args, **kwargs
       
   542         )
   513 
   543 
   514     def seek(self, *args, **kwargs):
   544     def seek(self, *args, **kwargs):
   515         return object.__getattribute__(self, r'_observedcall')(
   545         return object.__getattribute__(self, r'_observedcall')(
   516             r'seek', *args, **kwargs)
   546             r'seek', *args, **kwargs
       
   547         )
   517 
   548 
   518     def seekable(self, *args, **kwargs):
   549     def seekable(self, *args, **kwargs):
   519         return object.__getattribute__(self, r'_observedcall')(
   550         return object.__getattribute__(self, r'_observedcall')(
   520             r'seekable', *args, **kwargs)
   551             r'seekable', *args, **kwargs
       
   552         )
   521 
   553 
   522     def tell(self, *args, **kwargs):
   554     def tell(self, *args, **kwargs):
   523         return object.__getattribute__(self, r'_observedcall')(
   555         return object.__getattribute__(self, r'_observedcall')(
   524             r'tell', *args, **kwargs)
   556             r'tell', *args, **kwargs
       
   557         )
   525 
   558 
   526     def truncate(self, *args, **kwargs):
   559     def truncate(self, *args, **kwargs):
   527         return object.__getattribute__(self, r'_observedcall')(
   560         return object.__getattribute__(self, r'_observedcall')(
   528             r'truncate', *args, **kwargs)
   561             r'truncate', *args, **kwargs
       
   562         )
   529 
   563 
   530     def writable(self, *args, **kwargs):
   564     def writable(self, *args, **kwargs):
   531         return object.__getattribute__(self, r'_observedcall')(
   565         return object.__getattribute__(self, r'_observedcall')(
   532             r'writable', *args, **kwargs)
   566             r'writable', *args, **kwargs
       
   567         )
   533 
   568 
   534     def writelines(self, *args, **kwargs):
   569     def writelines(self, *args, **kwargs):
   535         return object.__getattribute__(self, r'_observedcall')(
   570         return object.__getattribute__(self, r'_observedcall')(
   536             r'writelines', *args, **kwargs)
   571             r'writelines', *args, **kwargs
       
   572         )
   537 
   573 
   538     def read(self, *args, **kwargs):
   574     def read(self, *args, **kwargs):
   539         return object.__getattribute__(self, r'_observedcall')(
   575         return object.__getattribute__(self, r'_observedcall')(
   540             r'read', *args, **kwargs)
   576             r'read', *args, **kwargs
       
   577         )
   541 
   578 
   542     def readall(self, *args, **kwargs):
   579     def readall(self, *args, **kwargs):
   543         return object.__getattribute__(self, r'_observedcall')(
   580         return object.__getattribute__(self, r'_observedcall')(
   544             r'readall', *args, **kwargs)
   581             r'readall', *args, **kwargs
       
   582         )
   545 
   583 
   546     def readinto(self, *args, **kwargs):
   584     def readinto(self, *args, **kwargs):
   547         return object.__getattribute__(self, r'_observedcall')(
   585         return object.__getattribute__(self, r'_observedcall')(
   548             r'readinto', *args, **kwargs)
   586             r'readinto', *args, **kwargs
       
   587         )
   549 
   588 
   550     def write(self, *args, **kwargs):
   589     def write(self, *args, **kwargs):
   551         return object.__getattribute__(self, r'_observedcall')(
   590         return object.__getattribute__(self, r'_observedcall')(
   552             r'write', *args, **kwargs)
   591             r'write', *args, **kwargs
       
   592         )
   553 
   593 
   554     def detach(self, *args, **kwargs):
   594     def detach(self, *args, **kwargs):
   555         return object.__getattribute__(self, r'_observedcall')(
   595         return object.__getattribute__(self, r'_observedcall')(
   556             r'detach', *args, **kwargs)
   596             r'detach', *args, **kwargs
       
   597         )
   557 
   598 
   558     def read1(self, *args, **kwargs):
   599     def read1(self, *args, **kwargs):
   559         return object.__getattribute__(self, r'_observedcall')(
   600         return object.__getattribute__(self, r'_observedcall')(
   560             r'read1', *args, **kwargs)
   601             r'read1', *args, **kwargs
       
   602         )
       
   603 
   561 
   604 
   562 class observedbufferedinputpipe(bufferedinputpipe):
   605 class observedbufferedinputpipe(bufferedinputpipe):
   563     """A variation of bufferedinputpipe that is aware of fileobjectproxy.
   606     """A variation of bufferedinputpipe that is aware of fileobjectproxy.
   564 
   607 
   565     ``bufferedinputpipe`` makes low-level calls to ``os.read()`` that
   608     ``bufferedinputpipe`` makes low-level calls to ``os.read()`` that
   568 
   611 
   569     This variation of ``bufferedinputpipe`` can notify observers about
   612     This variation of ``bufferedinputpipe`` can notify observers about
   570     ``os.read()`` events. It also re-publishes other events, such as
   613     ``os.read()`` events. It also re-publishes other events, such as
   571     ``read()`` and ``readline()``.
   614     ``read()`` and ``readline()``.
   572     """
   615     """
       
   616 
   573     def _fillbuffer(self):
   617     def _fillbuffer(self):
   574         res = super(observedbufferedinputpipe, self)._fillbuffer()
   618         res = super(observedbufferedinputpipe, self)._fillbuffer()
   575 
   619 
   576         fn = getattr(self._input._observer, r'osread', None)
   620         fn = getattr(self._input._observer, r'osread', None)
   577         if fn:
   621         if fn:
   596         fn = getattr(self._input._observer, r'bufferedreadline', None)
   640         fn = getattr(self._input._observer, r'bufferedreadline', None)
   597         if fn:
   641         if fn:
   598             fn(res)
   642             fn(res)
   599 
   643 
   600         return res
   644         return res
       
   645 
   601 
   646 
   602 PROXIED_SOCKET_METHODS = {
   647 PROXIED_SOCKET_METHODS = {
   603     r'makefile',
   648     r'makefile',
   604     r'recv',
   649     r'recv',
   605     r'recvfrom',
   650     r'recvfrom',
   612     r'settimeout',
   657     r'settimeout',
   613     r'gettimeout',
   658     r'gettimeout',
   614     r'setsockopt',
   659     r'setsockopt',
   615 }
   660 }
   616 
   661 
       
   662 
   617 class socketproxy(object):
   663 class socketproxy(object):
   618     """A proxy around a socket that tells a watcher when events occur.
   664     """A proxy around a socket that tells a watcher when events occur.
   619 
   665 
   620     This is like ``fileobjectproxy`` except for sockets.
   666     This is like ``fileobjectproxy`` except for sockets.
   621 
   667 
   622     This type is intended to only be used for testing purposes. Think hard
   668     This type is intended to only be used for testing purposes. Think hard
   623     before using it in important code.
   669     before using it in important code.
   624     """
   670     """
       
   671 
   625     __slots__ = (
   672     __slots__ = (
   626         r'_orig',
   673         r'_orig',
   627         r'_observer',
   674         r'_observer',
   628     )
   675     )
   629 
   676 
   662 
   709 
   663         return res
   710         return res
   664 
   711 
   665     def makefile(self, *args, **kwargs):
   712     def makefile(self, *args, **kwargs):
   666         res = object.__getattribute__(self, r'_observedcall')(
   713         res = object.__getattribute__(self, r'_observedcall')(
   667             r'makefile', *args, **kwargs)
   714             r'makefile', *args, **kwargs
       
   715         )
   668 
   716 
   669         # The file object may be used for I/O. So we turn it into a
   717         # The file object may be used for I/O. So we turn it into a
   670         # proxy using our observer.
   718         # proxy using our observer.
   671         observer = object.__getattribute__(self, r'_observer')
   719         observer = object.__getattribute__(self, r'_observer')
   672         return makeloggingfileobject(observer.fh, res, observer.name,
   720         return makeloggingfileobject(
   673                                      reads=observer.reads,
   721             observer.fh,
   674                                      writes=observer.writes,
   722             res,
   675                                      logdata=observer.logdata,
   723             observer.name,
   676                                      logdataapis=observer.logdataapis)
   724             reads=observer.reads,
       
   725             writes=observer.writes,
       
   726             logdata=observer.logdata,
       
   727             logdataapis=observer.logdataapis,
       
   728         )
   677 
   729 
   678     def recv(self, *args, **kwargs):
   730     def recv(self, *args, **kwargs):
   679         return object.__getattribute__(self, r'_observedcall')(
   731         return object.__getattribute__(self, r'_observedcall')(
   680             r'recv', *args, **kwargs)
   732             r'recv', *args, **kwargs
       
   733         )
   681 
   734 
   682     def recvfrom(self, *args, **kwargs):
   735     def recvfrom(self, *args, **kwargs):
   683         return object.__getattribute__(self, r'_observedcall')(
   736         return object.__getattribute__(self, r'_observedcall')(
   684             r'recvfrom', *args, **kwargs)
   737             r'recvfrom', *args, **kwargs
       
   738         )
   685 
   739 
   686     def recvfrom_into(self, *args, **kwargs):
   740     def recvfrom_into(self, *args, **kwargs):
   687         return object.__getattribute__(self, r'_observedcall')(
   741         return object.__getattribute__(self, r'_observedcall')(
   688             r'recvfrom_into', *args, **kwargs)
   742             r'recvfrom_into', *args, **kwargs
       
   743         )
   689 
   744 
   690     def recv_into(self, *args, **kwargs):
   745     def recv_into(self, *args, **kwargs):
   691         return object.__getattribute__(self, r'_observedcall')(
   746         return object.__getattribute__(self, r'_observedcall')(
   692             r'recv_info', *args, **kwargs)
   747             r'recv_info', *args, **kwargs
       
   748         )
   693 
   749 
   694     def send(self, *args, **kwargs):
   750     def send(self, *args, **kwargs):
   695         return object.__getattribute__(self, r'_observedcall')(
   751         return object.__getattribute__(self, r'_observedcall')(
   696             r'send', *args, **kwargs)
   752             r'send', *args, **kwargs
       
   753         )
   697 
   754 
   698     def sendall(self, *args, **kwargs):
   755     def sendall(self, *args, **kwargs):
   699         return object.__getattribute__(self, r'_observedcall')(
   756         return object.__getattribute__(self, r'_observedcall')(
   700             r'sendall', *args, **kwargs)
   757             r'sendall', *args, **kwargs
       
   758         )
   701 
   759 
   702     def sendto(self, *args, **kwargs):
   760     def sendto(self, *args, **kwargs):
   703         return object.__getattribute__(self, r'_observedcall')(
   761         return object.__getattribute__(self, r'_observedcall')(
   704             r'sendto', *args, **kwargs)
   762             r'sendto', *args, **kwargs
       
   763         )
   705 
   764 
   706     def setblocking(self, *args, **kwargs):
   765     def setblocking(self, *args, **kwargs):
   707         return object.__getattribute__(self, r'_observedcall')(
   766         return object.__getattribute__(self, r'_observedcall')(
   708             r'setblocking', *args, **kwargs)
   767             r'setblocking', *args, **kwargs
       
   768         )
   709 
   769 
   710     def settimeout(self, *args, **kwargs):
   770     def settimeout(self, *args, **kwargs):
   711         return object.__getattribute__(self, r'_observedcall')(
   771         return object.__getattribute__(self, r'_observedcall')(
   712             r'settimeout', *args, **kwargs)
   772             r'settimeout', *args, **kwargs
       
   773         )
   713 
   774 
   714     def gettimeout(self, *args, **kwargs):
   775     def gettimeout(self, *args, **kwargs):
   715         return object.__getattribute__(self, r'_observedcall')(
   776         return object.__getattribute__(self, r'_observedcall')(
   716             r'gettimeout', *args, **kwargs)
   777             r'gettimeout', *args, **kwargs
       
   778         )
   717 
   779 
   718     def setsockopt(self, *args, **kwargs):
   780     def setsockopt(self, *args, **kwargs):
   719         return object.__getattribute__(self, r'_observedcall')(
   781         return object.__getattribute__(self, r'_observedcall')(
   720             r'setsockopt', *args, **kwargs)
   782             r'setsockopt', *args, **kwargs
       
   783         )
       
   784 
   721 
   785 
   722 class baseproxyobserver(object):
   786 class baseproxyobserver(object):
   723     def _writedata(self, data):
   787     def _writedata(self, data):
   724         if not self.logdata:
   788         if not self.logdata:
   725             if self.logdataapis:
   789             if self.logdataapis:
   730         # Simple case writes all data on a single line.
   794         # Simple case writes all data on a single line.
   731         if b'\n' not in data:
   795         if b'\n' not in data:
   732             if self.logdataapis:
   796             if self.logdataapis:
   733                 self.fh.write(': %s\n' % stringutil.escapestr(data))
   797                 self.fh.write(': %s\n' % stringutil.escapestr(data))
   734             else:
   798             else:
   735                 self.fh.write('%s>     %s\n'
   799                 self.fh.write(
   736                               % (self.name, stringutil.escapestr(data)))
   800                     '%s>     %s\n' % (self.name, stringutil.escapestr(data))
       
   801                 )
   737             self.fh.flush()
   802             self.fh.flush()
   738             return
   803             return
   739 
   804 
   740         # Data with newlines is written to multiple lines.
   805         # Data with newlines is written to multiple lines.
   741         if self.logdataapis:
   806         if self.logdataapis:
   742             self.fh.write(':\n')
   807             self.fh.write(':\n')
   743 
   808 
   744         lines = data.splitlines(True)
   809         lines = data.splitlines(True)
   745         for line in lines:
   810         for line in lines:
   746             self.fh.write('%s>     %s\n'
   811             self.fh.write(
   747                           % (self.name, stringutil.escapestr(line)))
   812                 '%s>     %s\n' % (self.name, stringutil.escapestr(line))
       
   813             )
   748         self.fh.flush()
   814         self.fh.flush()
       
   815 
   749 
   816 
   750 class fileobjectobserver(baseproxyobserver):
   817 class fileobjectobserver(baseproxyobserver):
   751     """Logs file object activity."""
   818     """Logs file object activity."""
   752     def __init__(self, fh, name, reads=True, writes=True, logdata=False,
   819 
   753                  logdataapis=True):
   820     def __init__(
       
   821         self, fh, name, reads=True, writes=True, logdata=False, logdataapis=True
       
   822     ):
   754         self.fh = fh
   823         self.fh = fh
   755         self.name = name
   824         self.name = name
   756         self.logdata = logdata
   825         self.logdata = logdata
   757         self.logdataapis = logdataapis
   826         self.logdataapis = logdataapis
   758         self.reads = reads
   827         self.reads = reads
   789     def readinto(self, res, dest):
   858     def readinto(self, res, dest):
   790         if not self.reads:
   859         if not self.reads:
   791             return
   860             return
   792 
   861 
   793         if self.logdataapis:
   862         if self.logdataapis:
   794             self.fh.write('%s> readinto(%d) -> %r' % (self.name, len(dest),
   863             self.fh.write(
   795                                                       res))
   864                 '%s> readinto(%d) -> %r' % (self.name, len(dest), res)
       
   865             )
   796 
   866 
   797         data = dest[0:res] if res is not None else b''
   867         data = dest[0:res] if res is not None else b''
   798 
   868 
   799         # _writedata() uses "in" operator and is confused by memoryview because
   869         # _writedata() uses "in" operator and is confused by memoryview because
   800         # characters are ints on Python 3.
   870         # characters are ints on Python 3.
   827     def bufferedread(self, res, size):
   897     def bufferedread(self, res, size):
   828         if not self.reads:
   898         if not self.reads:
   829             return
   899             return
   830 
   900 
   831         if self.logdataapis:
   901         if self.logdataapis:
   832             self.fh.write('%s> bufferedread(%d) -> %d' % (
   902             self.fh.write(
   833                 self.name, size, len(res)))
   903                 '%s> bufferedread(%d) -> %d' % (self.name, size, len(res))
       
   904             )
   834 
   905 
   835         self._writedata(res)
   906         self._writedata(res)
   836 
   907 
   837     def bufferedreadline(self, res):
   908     def bufferedreadline(self, res):
   838         if not self.reads:
   909         if not self.reads:
   839             return
   910             return
   840 
   911 
   841         if self.logdataapis:
   912         if self.logdataapis:
   842             self.fh.write('%s> bufferedreadline() -> %d' % (
   913             self.fh.write(
   843                 self.name, len(res)))
   914                 '%s> bufferedreadline() -> %d' % (self.name, len(res))
       
   915             )
   844 
   916 
   845         self._writedata(res)
   917         self._writedata(res)
   846 
   918 
   847 def makeloggingfileobject(logh, fh, name, reads=True, writes=True,
   919 
   848                           logdata=False, logdataapis=True):
   920 def makeloggingfileobject(
       
   921     logh, fh, name, reads=True, writes=True, logdata=False, logdataapis=True
       
   922 ):
   849     """Turn a file object into a logging file object."""
   923     """Turn a file object into a logging file object."""
   850 
   924 
   851     observer = fileobjectobserver(logh, name, reads=reads, writes=writes,
   925     observer = fileobjectobserver(
   852                                   logdata=logdata, logdataapis=logdataapis)
   926         logh,
       
   927         name,
       
   928         reads=reads,
       
   929         writes=writes,
       
   930         logdata=logdata,
       
   931         logdataapis=logdataapis,
       
   932     )
   853     return fileobjectproxy(fh, observer)
   933     return fileobjectproxy(fh, observer)
       
   934 
   854 
   935 
   855 class socketobserver(baseproxyobserver):
   936 class socketobserver(baseproxyobserver):
   856     """Logs socket activity."""
   937     """Logs socket activity."""
   857     def __init__(self, fh, name, reads=True, writes=True, states=True,
   938 
   858                  logdata=False, logdataapis=True):
   939     def __init__(
       
   940         self,
       
   941         fh,
       
   942         name,
       
   943         reads=True,
       
   944         writes=True,
       
   945         states=True,
       
   946         logdata=False,
       
   947         logdataapis=True,
       
   948     ):
   859         self.fh = fh
   949         self.fh = fh
   860         self.name = name
   950         self.name = name
   861         self.reads = reads
   951         self.reads = reads
   862         self.writes = writes
   952         self.writes = writes
   863         self.states = states
   953         self.states = states
   866 
   956 
   867     def makefile(self, res, mode=None, bufsize=None):
   957     def makefile(self, res, mode=None, bufsize=None):
   868         if not self.states:
   958         if not self.states:
   869             return
   959             return
   870 
   960 
   871         self.fh.write('%s> makefile(%r, %r)\n' % (
   961         self.fh.write('%s> makefile(%r, %r)\n' % (self.name, mode, bufsize))
   872             self.name, mode, bufsize))
       
   873 
   962 
   874     def recv(self, res, size, flags=0):
   963     def recv(self, res, size, flags=0):
   875         if not self.reads:
   964         if not self.reads:
   876             return
   965             return
   877 
   966 
   878         if self.logdataapis:
   967         if self.logdataapis:
   879             self.fh.write('%s> recv(%d, %d) -> %d' % (
   968             self.fh.write(
   880                 self.name, size, flags, len(res)))
   969                 '%s> recv(%d, %d) -> %d' % (self.name, size, flags, len(res))
       
   970             )
   881         self._writedata(res)
   971         self._writedata(res)
   882 
   972 
   883     def recvfrom(self, res, size, flags=0):
   973     def recvfrom(self, res, size, flags=0):
   884         if not self.reads:
   974         if not self.reads:
   885             return
   975             return
   886 
   976 
   887         if self.logdataapis:
   977         if self.logdataapis:
   888             self.fh.write('%s> recvfrom(%d, %d) -> %d' % (
   978             self.fh.write(
   889                 self.name, size, flags, len(res[0])))
   979                 '%s> recvfrom(%d, %d) -> %d'
       
   980                 % (self.name, size, flags, len(res[0]))
       
   981             )
   890 
   982 
   891         self._writedata(res[0])
   983         self._writedata(res[0])
   892 
   984 
   893     def recvfrom_into(self, res, buf, size, flags=0):
   985     def recvfrom_into(self, res, buf, size, flags=0):
   894         if not self.reads:
   986         if not self.reads:
   895             return
   987             return
   896 
   988 
   897         if self.logdataapis:
   989         if self.logdataapis:
   898             self.fh.write('%s> recvfrom_into(%d, %d) -> %d' % (
   990             self.fh.write(
   899                 self.name, size, flags, res[0]))
   991                 '%s> recvfrom_into(%d, %d) -> %d'
   900 
   992                 % (self.name, size, flags, res[0])
   901         self._writedata(buf[0:res[0]])
   993             )
       
   994 
       
   995         self._writedata(buf[0 : res[0]])
   902 
   996 
   903     def recv_into(self, res, buf, size=0, flags=0):
   997     def recv_into(self, res, buf, size=0, flags=0):
   904         if not self.reads:
   998         if not self.reads:
   905             return
   999             return
   906 
  1000 
   907         if self.logdataapis:
  1001         if self.logdataapis:
   908             self.fh.write('%s> recv_into(%d, %d) -> %d' % (
  1002             self.fh.write(
   909                 self.name, size, flags, res))
  1003                 '%s> recv_into(%d, %d) -> %d' % (self.name, size, flags, res)
       
  1004             )
   910 
  1005 
   911         self._writedata(buf[0:res])
  1006         self._writedata(buf[0:res])
   912 
  1007 
   913     def send(self, res, data, flags=0):
  1008     def send(self, res, data, flags=0):
   914         if not self.writes:
  1009         if not self.writes:
   915             return
  1010             return
   916 
  1011 
   917         self.fh.write('%s> send(%d, %d) -> %d' % (
  1012         self.fh.write(
   918             self.name, len(data), flags, len(res)))
  1013             '%s> send(%d, %d) -> %d' % (self.name, len(data), flags, len(res))
       
  1014         )
   919         self._writedata(data)
  1015         self._writedata(data)
   920 
  1016 
   921     def sendall(self, res, data, flags=0):
  1017     def sendall(self, res, data, flags=0):
   922         if not self.writes:
  1018         if not self.writes:
   923             return
  1019             return
   924 
  1020 
   925         if self.logdataapis:
  1021         if self.logdataapis:
   926             # Returns None on success. So don't bother reporting return value.
  1022             # Returns None on success. So don't bother reporting return value.
   927             self.fh.write('%s> sendall(%d, %d)' % (
  1023             self.fh.write('%s> sendall(%d, %d)' % (self.name, len(data), flags))
   928                 self.name, len(data), flags))
       
   929 
  1024 
   930         self._writedata(data)
  1025         self._writedata(data)
   931 
  1026 
   932     def sendto(self, res, data, flagsoraddress, address=None):
  1027     def sendto(self, res, data, flagsoraddress, address=None):
   933         if not self.writes:
  1028         if not self.writes:
   937             flags = flagsoraddress
  1032             flags = flagsoraddress
   938         else:
  1033         else:
   939             flags = 0
  1034             flags = 0
   940 
  1035 
   941         if self.logdataapis:
  1036         if self.logdataapis:
   942             self.fh.write('%s> sendto(%d, %d, %r) -> %d' % (
  1037             self.fh.write(
   943                 self.name, len(data), flags, address, res))
  1038                 '%s> sendto(%d, %d, %r) -> %d'
       
  1039                 % (self.name, len(data), flags, address, res)
       
  1040             )
   944 
  1041 
   945         self._writedata(data)
  1042         self._writedata(data)
   946 
  1043 
   947     def setblocking(self, res, flag):
  1044     def setblocking(self, res, flag):
   948         if not self.states:
  1045         if not self.states:
   964 
  1061 
   965     def setsockopt(self, res, level, optname, value):
  1062     def setsockopt(self, res, level, optname, value):
   966         if not self.states:
  1063         if not self.states:
   967             return
  1064             return
   968 
  1065 
   969         self.fh.write('%s> setsockopt(%r, %r, %r) -> %r\n' % (
  1066         self.fh.write(
   970             self.name, level, optname, value, res))
  1067             '%s> setsockopt(%r, %r, %r) -> %r\n'
   971 
  1068             % (self.name, level, optname, value, res)
   972 def makeloggingsocket(logh, fh, name, reads=True, writes=True, states=True,
  1069         )
   973                       logdata=False, logdataapis=True):
  1070 
       
  1071 
       
  1072 def makeloggingsocket(
       
  1073     logh,
       
  1074     fh,
       
  1075     name,
       
  1076     reads=True,
       
  1077     writes=True,
       
  1078     states=True,
       
  1079     logdata=False,
       
  1080     logdataapis=True,
       
  1081 ):
   974     """Turn a socket into a logging socket."""
  1082     """Turn a socket into a logging socket."""
   975 
  1083 
   976     observer = socketobserver(logh, name, reads=reads, writes=writes,
  1084     observer = socketobserver(
   977                               states=states, logdata=logdata,
  1085         logh,
   978                               logdataapis=logdataapis)
  1086         name,
       
  1087         reads=reads,
       
  1088         writes=writes,
       
  1089         states=states,
       
  1090         logdata=logdata,
       
  1091         logdataapis=logdataapis,
       
  1092     )
   979     return socketproxy(fh, observer)
  1093     return socketproxy(fh, observer)
       
  1094 
   980 
  1095 
   981 def version():
  1096 def version():
   982     """Return version information if available."""
  1097     """Return version information if available."""
   983     try:
  1098     try:
   984         from . import __version__
  1099         from . import __version__
       
  1100 
   985         return __version__.version
  1101         return __version__.version
   986     except ImportError:
  1102     except ImportError:
   987         return 'unknown'
  1103         return 'unknown'
       
  1104 
   988 
  1105 
   989 def versiontuple(v=None, n=4):
  1106 def versiontuple(v=None, n=4):
   990     """Parses a Mercurial version string into an N-tuple.
  1107     """Parses a Mercurial version string into an N-tuple.
   991 
  1108 
   992     The version string to be parsed is specified with the ``v`` argument.
  1109     The version string to be parsed is specified with the ``v`` argument.
  1066     if n == 3:
  1183     if n == 3:
  1067         return (vints[0], vints[1], vints[2])
  1184         return (vints[0], vints[1], vints[2])
  1068     if n == 4:
  1185     if n == 4:
  1069         return (vints[0], vints[1], vints[2], extra)
  1186         return (vints[0], vints[1], vints[2], extra)
  1070 
  1187 
       
  1188 
  1071 def cachefunc(func):
  1189 def cachefunc(func):
  1072     '''cache the result of function calls'''
  1190     '''cache the result of function calls'''
  1073     # XXX doesn't handle keywords args
  1191     # XXX doesn't handle keywords args
  1074     if func.__code__.co_argcount == 0:
  1192     if func.__code__.co_argcount == 0:
  1075         cache = []
  1193         cache = []
       
  1194 
  1076         def f():
  1195         def f():
  1077             if len(cache) == 0:
  1196             if len(cache) == 0:
  1078                 cache.append(func())
  1197                 cache.append(func())
  1079             return cache[0]
  1198             return cache[0]
       
  1199 
  1080         return f
  1200         return f
  1081     cache = {}
  1201     cache = {}
  1082     if func.__code__.co_argcount == 1:
  1202     if func.__code__.co_argcount == 1:
  1083         # we gain a small amount of time because
  1203         # we gain a small amount of time because
  1084         # we don't need to pack/unpack the list
  1204         # we don't need to pack/unpack the list
  1085         def f(arg):
  1205         def f(arg):
  1086             if arg not in cache:
  1206             if arg not in cache:
  1087                 cache[arg] = func(arg)
  1207                 cache[arg] = func(arg)
  1088             return cache[arg]
  1208             return cache[arg]
       
  1209 
  1089     else:
  1210     else:
       
  1211 
  1090         def f(*args):
  1212         def f(*args):
  1091             if args not in cache:
  1213             if args not in cache:
  1092                 cache[args] = func(*args)
  1214                 cache[args] = func(*args)
  1093             return cache[args]
  1215             return cache[args]
  1094 
  1216 
  1095     return f
  1217     return f
       
  1218 
  1096 
  1219 
  1097 class cow(object):
  1220 class cow(object):
  1098     """helper class to make copy-on-write easier
  1221     """helper class to make copy-on-write easier
  1099 
  1222 
  1100     Call preparewrite before doing any writes.
  1223     Call preparewrite before doing any writes.
  1109 
  1232 
  1110     def copy(self):
  1233     def copy(self):
  1111         """always do a cheap copy"""
  1234         """always do a cheap copy"""
  1112         self._copied = getattr(self, '_copied', 0) + 1
  1235         self._copied = getattr(self, '_copied', 0) + 1
  1113         return self
  1236         return self
       
  1237 
  1114 
  1238 
  1115 class sortdict(collections.OrderedDict):
  1239 class sortdict(collections.OrderedDict):
  1116     '''a simple sorted dictionary
  1240     '''a simple sorted dictionary
  1117 
  1241 
  1118     >>> d1 = sortdict([(b'a', 0), (b'b', 1)])
  1242     >>> d1 = sortdict([(b'a', 0), (b'b', 1)])
  1134         def update(self, src):
  1258         def update(self, src):
  1135             if isinstance(src, dict):
  1259             if isinstance(src, dict):
  1136                 src = src.iteritems()
  1260                 src = src.iteritems()
  1137             for k, v in src:
  1261             for k, v in src:
  1138                 self[k] = v
  1262                 self[k] = v
       
  1263 
  1139 
  1264 
  1140 class cowdict(cow, dict):
  1265 class cowdict(cow, dict):
  1141     """copy-on-write dict
  1266     """copy-on-write dict
  1142 
  1267 
  1143     Be sure to call d = d.preparewrite() before writing to d.
  1268     Be sure to call d = d.preparewrite() before writing to d.
  1161     False
  1286     False
  1162     >>> b is b.preparewrite()
  1287     >>> b is b.preparewrite()
  1163     True
  1288     True
  1164     """
  1289     """
  1165 
  1290 
       
  1291 
  1166 class cowsortdict(cow, sortdict):
  1292 class cowsortdict(cow, sortdict):
  1167     """copy-on-write sortdict
  1293     """copy-on-write sortdict
  1168 
  1294 
  1169     Be sure to call d = d.preparewrite() before writing to d.
  1295     Be sure to call d = d.preparewrite() before writing to d.
  1170     """
  1296     """
  1171 
  1297 
       
  1298 
  1172 class transactional(object):
  1299 class transactional(object):
  1173     """Base class for making a transactional type into a context manager."""
  1300     """Base class for making a transactional type into a context manager."""
       
  1301 
  1174     __metaclass__ = abc.ABCMeta
  1302     __metaclass__ = abc.ABCMeta
  1175 
  1303 
  1176     @abc.abstractmethod
  1304     @abc.abstractmethod
  1177     def close(self):
  1305     def close(self):
  1178         """Successfully closes the transaction."""
  1306         """Successfully closes the transaction."""
  1191         try:
  1319         try:
  1192             if exc_type is None:
  1320             if exc_type is None:
  1193                 self.close()
  1321                 self.close()
  1194         finally:
  1322         finally:
  1195             self.release()
  1323             self.release()
       
  1324 
  1196 
  1325 
  1197 @contextlib.contextmanager
  1326 @contextlib.contextmanager
  1198 def acceptintervention(tr=None):
  1327 def acceptintervention(tr=None):
  1199     """A context manager that closes the transaction on InterventionRequired
  1328     """A context manager that closes the transaction on InterventionRequired
  1200 
  1329 
  1210         tr.close()
  1339         tr.close()
  1211         raise
  1340         raise
  1212     finally:
  1341     finally:
  1213         tr.release()
  1342         tr.release()
  1214 
  1343 
       
  1344 
  1215 @contextlib.contextmanager
  1345 @contextlib.contextmanager
  1216 def nullcontextmanager():
  1346 def nullcontextmanager():
  1217     yield
  1347     yield
  1218 
  1348 
       
  1349 
  1219 class _lrucachenode(object):
  1350 class _lrucachenode(object):
  1220     """A node in a doubly linked list.
  1351     """A node in a doubly linked list.
  1221 
  1352 
  1222     Holds a reference to nodes on either side as well as a key-value
  1353     Holds a reference to nodes on either side as well as a key-value
  1223     pair for the dictionary entry.
  1354     pair for the dictionary entry.
  1224     """
  1355     """
       
  1356 
  1225     __slots__ = (r'next', r'prev', r'key', r'value', r'cost')
  1357     __slots__ = (r'next', r'prev', r'key', r'value', r'cost')
  1226 
  1358 
  1227     def __init__(self):
  1359     def __init__(self):
  1228         self.next = None
  1360         self.next = None
  1229         self.prev = None
  1361         self.prev = None
  1235     def markempty(self):
  1367     def markempty(self):
  1236         """Mark the node as emptied."""
  1368         """Mark the node as emptied."""
  1237         self.key = _notset
  1369         self.key = _notset
  1238         self.value = None
  1370         self.value = None
  1239         self.cost = 0
  1371         self.cost = 0
       
  1372 
  1240 
  1373 
  1241 class lrucachedict(object):
  1374 class lrucachedict(object):
  1242     """Dict that caches most recent accesses and sets.
  1375     """Dict that caches most recent accesses and sets.
  1243 
  1376 
  1244     The dict consists of an actual backing dict - indexed by original
  1377     The dict consists of an actual backing dict - indexed by original
  1258     cause the total cost of the cache to go beyond the maximum cost limit,
  1391     cause the total cost of the cache to go beyond the maximum cost limit,
  1259     nodes will be evicted to make room for the new code. This can be used
  1392     nodes will be evicted to make room for the new code. This can be used
  1260     to e.g. set a max memory limit and associate an estimated bytes size
  1393     to e.g. set a max memory limit and associate an estimated bytes size
  1261     cost to each item in the cache. By default, no maximum cost is enforced.
  1394     cost to each item in the cache. By default, no maximum cost is enforced.
  1262     """
  1395     """
       
  1396 
  1263     def __init__(self, max, maxcost=0):
  1397     def __init__(self, max, maxcost=0):
  1264         self._cache = {}
  1398         self._cache = {}
  1265 
  1399 
  1266         self._head = head = _lrucachenode()
  1400         self._head = head = _lrucachenode()
  1267         head.prev = head
  1401         head.prev = head
  1528             del self._cache[n.key]
  1662             del self._cache[n.key]
  1529             self.totalcost -= n.cost
  1663             self.totalcost -= n.cost
  1530             n.markempty()
  1664             n.markempty()
  1531             n = n.prev
  1665             n = n.prev
  1532 
  1666 
       
  1667 
  1533 def lrucachefunc(func):
  1668 def lrucachefunc(func):
  1534     '''cache most recent results of function calls'''
  1669     '''cache most recent results of function calls'''
  1535     cache = {}
  1670     cache = {}
  1536     order = collections.deque()
  1671     order = collections.deque()
  1537     if func.__code__.co_argcount == 1:
  1672     if func.__code__.co_argcount == 1:
       
  1673 
  1538         def f(arg):
  1674         def f(arg):
  1539             if arg not in cache:
  1675             if arg not in cache:
  1540                 if len(cache) > 20:
  1676                 if len(cache) > 20:
  1541                     del cache[order.popleft()]
  1677                     del cache[order.popleft()]
  1542                 cache[arg] = func(arg)
  1678                 cache[arg] = func(arg)
  1543             else:
  1679             else:
  1544                 order.remove(arg)
  1680                 order.remove(arg)
  1545             order.append(arg)
  1681             order.append(arg)
  1546             return cache[arg]
  1682             return cache[arg]
       
  1683 
  1547     else:
  1684     else:
       
  1685 
  1548         def f(*args):
  1686         def f(*args):
  1549             if args not in cache:
  1687             if args not in cache:
  1550                 if len(cache) > 20:
  1688                 if len(cache) > 20:
  1551                     del cache[order.popleft()]
  1689                     del cache[order.popleft()]
  1552                 cache[args] = func(*args)
  1690                 cache[args] = func(*args)
  1555             order.append(args)
  1693             order.append(args)
  1556             return cache[args]
  1694             return cache[args]
  1557 
  1695 
  1558     return f
  1696     return f
  1559 
  1697 
       
  1698 
  1560 class propertycache(object):
  1699 class propertycache(object):
  1561     def __init__(self, func):
  1700     def __init__(self, func):
  1562         self.func = func
  1701         self.func = func
  1563         self.name = func.__name__
  1702         self.name = func.__name__
       
  1703 
  1564     def __get__(self, obj, type=None):
  1704     def __get__(self, obj, type=None):
  1565         result = self.func(obj)
  1705         result = self.func(obj)
  1566         self.cachevalue(obj, result)
  1706         self.cachevalue(obj, result)
  1567         return result
  1707         return result
  1568 
  1708 
  1569     def cachevalue(self, obj, value):
  1709     def cachevalue(self, obj, value):
  1570         # __dict__ assignment required to bypass __setattr__ (eg: repoview)
  1710         # __dict__ assignment required to bypass __setattr__ (eg: repoview)
  1571         obj.__dict__[self.name] = value
  1711         obj.__dict__[self.name] = value
       
  1712 
  1572 
  1713 
  1573 def clearcachedproperty(obj, prop):
  1714 def clearcachedproperty(obj, prop):
  1574     '''clear a cached property value, if one has been set'''
  1715     '''clear a cached property value, if one has been set'''
  1575     prop = pycompat.sysstr(prop)
  1716     prop = pycompat.sysstr(prop)
  1576     if prop in obj.__dict__:
  1717     if prop in obj.__dict__:
  1577         del obj.__dict__[prop]
  1718         del obj.__dict__[prop]
  1578 
  1719 
       
  1720 
  1579 def increasingchunks(source, min=1024, max=65536):
  1721 def increasingchunks(source, min=1024, max=65536):
  1580     '''return no less than min bytes per chunk while data remains,
  1722     '''return no less than min bytes per chunk while data remains,
  1581     doubling min after each chunk until it reaches max'''
  1723     doubling min after each chunk until it reaches max'''
       
  1724 
  1582     def log2(x):
  1725     def log2(x):
  1583         if not x:
  1726         if not x:
  1584             return 0
  1727             return 0
  1585         i = 0
  1728         i = 0
  1586         while x:
  1729         while x:
  1605             blen = 0
  1748             blen = 0
  1606             buf = []
  1749             buf = []
  1607     if buf:
  1750     if buf:
  1608         yield ''.join(buf)
  1751         yield ''.join(buf)
  1609 
  1752 
       
  1753 
  1610 def always(fn):
  1754 def always(fn):
  1611     return True
  1755     return True
  1612 
  1756 
       
  1757 
  1613 def never(fn):
  1758 def never(fn):
  1614     return False
  1759     return False
       
  1760 
  1615 
  1761 
  1616 def nogc(func):
  1762 def nogc(func):
  1617     """disable garbage collector
  1763     """disable garbage collector
  1618 
  1764 
  1619     Python's garbage collector triggers a GC each time a certain number of
  1765     Python's garbage collector triggers a GC each time a certain number of
  1624     containers.
  1770     containers.
  1625 
  1771 
  1626     This garbage collector issue have been fixed in 2.7. But it still affect
  1772     This garbage collector issue have been fixed in 2.7. But it still affect
  1627     CPython's performance.
  1773     CPython's performance.
  1628     """
  1774     """
       
  1775 
  1629     def wrapper(*args, **kwargs):
  1776     def wrapper(*args, **kwargs):
  1630         gcenabled = gc.isenabled()
  1777         gcenabled = gc.isenabled()
  1631         gc.disable()
  1778         gc.disable()
  1632         try:
  1779         try:
  1633             return func(*args, **kwargs)
  1780             return func(*args, **kwargs)
  1634         finally:
  1781         finally:
  1635             if gcenabled:
  1782             if gcenabled:
  1636                 gc.enable()
  1783                 gc.enable()
       
  1784 
  1637     return wrapper
  1785     return wrapper
       
  1786 
  1638 
  1787 
  1639 if pycompat.ispypy:
  1788 if pycompat.ispypy:
  1640     # PyPy runs slower with gc disabled
  1789     # PyPy runs slower with gc disabled
  1641     nogc = lambda x: x
  1790     nogc = lambda x: x
       
  1791 
  1642 
  1792 
  1643 def pathto(root, n1, n2):
  1793 def pathto(root, n1, n2):
  1644     '''return the relative path from one place to another.
  1794     '''return the relative path from one place to another.
  1645     root should use os.sep to separate directories
  1795     root should use os.sep to separate directories
  1646     n1 should use os.sep to separate directories
  1796     n1 should use os.sep to separate directories
  1664         a.pop()
  1814         a.pop()
  1665         b.pop()
  1815         b.pop()
  1666     b.reverse()
  1816     b.reverse()
  1667     return pycompat.ossep.join((['..'] * len(a)) + b) or '.'
  1817     return pycompat.ossep.join((['..'] * len(a)) + b) or '.'
  1668 
  1818 
       
  1819 
  1669 # the location of data files matching the source code
  1820 # the location of data files matching the source code
  1670 if procutil.mainfrozen() and getattr(sys, 'frozen', None) != 'macosx_app':
  1821 if procutil.mainfrozen() and getattr(sys, 'frozen', None) != 'macosx_app':
  1671     # executable version (py2exe) doesn't support __file__
  1822     # executable version (py2exe) doesn't support __file__
  1672     datapath = os.path.dirname(pycompat.sysexecutable)
  1823     datapath = os.path.dirname(pycompat.sysexecutable)
  1673 else:
  1824 else:
  1674     datapath = os.path.dirname(pycompat.fsencode(__file__))
  1825     datapath = os.path.dirname(pycompat.fsencode(__file__))
  1675 
  1826 
  1676 i18n.setdatapath(datapath)
  1827 i18n.setdatapath(datapath)
  1677 
  1828 
       
  1829 
  1678 def checksignature(func):
  1830 def checksignature(func):
  1679     '''wrap a function with code to check for calling errors'''
  1831     '''wrap a function with code to check for calling errors'''
       
  1832 
  1680     def check(*args, **kwargs):
  1833     def check(*args, **kwargs):
  1681         try:
  1834         try:
  1682             return func(*args, **kwargs)
  1835             return func(*args, **kwargs)
  1683         except TypeError:
  1836         except TypeError:
  1684             if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
  1837             if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
  1685                 raise error.SignatureError
  1838                 raise error.SignatureError
  1686             raise
  1839             raise
  1687 
  1840 
  1688     return check
  1841     return check
       
  1842 
  1689 
  1843 
  1690 # a whilelist of known filesystems where hardlink works reliably
  1844 # a whilelist of known filesystems where hardlink works reliably
  1691 _hardlinkfswhitelist = {
  1845 _hardlinkfswhitelist = {
  1692     'apfs',
  1846     'apfs',
  1693     'btrfs',
  1847     'btrfs',
  1701     'tmpfs',
  1855     'tmpfs',
  1702     'ufs',
  1856     'ufs',
  1703     'xfs',
  1857     'xfs',
  1704     'zfs',
  1858     'zfs',
  1705 }
  1859 }
       
  1860 
  1706 
  1861 
  1707 def copyfile(src, dest, hardlink=False, copystat=False, checkambig=False):
  1862 def copyfile(src, dest, hardlink=False, copystat=False, checkambig=False):
  1708     '''copy a file, preserving mode and optionally other stat info like
  1863     '''copy a file, preserving mode and optionally other stat info like
  1709     atime/mtime
  1864     atime/mtime
  1710 
  1865 
  1732     if hardlink:
  1887     if hardlink:
  1733         try:
  1888         try:
  1734             oslink(src, dest)
  1889             oslink(src, dest)
  1735             return
  1890             return
  1736         except (IOError, OSError):
  1891         except (IOError, OSError):
  1737             pass # fall back to normal copy
  1892             pass  # fall back to normal copy
  1738     if os.path.islink(src):
  1893     if os.path.islink(src):
  1739         os.symlink(os.readlink(src), dest)
  1894         os.symlink(os.readlink(src), dest)
  1740         # copytime is ignored for symlinks, but in general copytime isn't needed
  1895         # copytime is ignored for symlinks, but in general copytime isn't needed
  1741         # for them anyway
  1896         # for them anyway
  1742     else:
  1897     else:
  1750                 if oldstat and oldstat.stat:
  1905                 if oldstat and oldstat.stat:
  1751                     newstat = filestat.frompath(dest)
  1906                     newstat = filestat.frompath(dest)
  1752                     if newstat.isambig(oldstat):
  1907                     if newstat.isambig(oldstat):
  1753                         # stat of copied file is ambiguous to original one
  1908                         # stat of copied file is ambiguous to original one
  1754                         advanced = (
  1909                         advanced = (
  1755                             oldstat.stat[stat.ST_MTIME] + 1) & 0x7fffffff
  1910                             oldstat.stat[stat.ST_MTIME] + 1
       
  1911                         ) & 0x7FFFFFFF
  1756                         os.utime(dest, (advanced, advanced))
  1912                         os.utime(dest, (advanced, advanced))
  1757         except shutil.Error as inst:
  1913         except shutil.Error as inst:
  1758             raise error.Abort(str(inst))
  1914             raise error.Abort(str(inst))
  1759 
  1915 
       
  1916 
  1760 def copyfiles(src, dst, hardlink=None, progress=None):
  1917 def copyfiles(src, dst, hardlink=None, progress=None):
  1761     """Copy a directory tree using hardlinks if possible."""
  1918     """Copy a directory tree using hardlinks if possible."""
  1762     num = 0
  1919     num = 0
  1763 
  1920 
  1764     def settopic():
  1921     def settopic():
  1765         if progress:
  1922         if progress:
  1766             progress.topic = _('linking') if hardlink else _('copying')
  1923             progress.topic = _('linking') if hardlink else _('copying')
  1767 
  1924 
  1768     if os.path.isdir(src):
  1925     if os.path.isdir(src):
  1769         if hardlink is None:
  1926         if hardlink is None:
  1770             hardlink = (os.stat(src).st_dev ==
  1927             hardlink = (
  1771                         os.stat(os.path.dirname(dst)).st_dev)
  1928                 os.stat(src).st_dev == os.stat(os.path.dirname(dst)).st_dev
       
  1929             )
  1772         settopic()
  1930         settopic()
  1773         os.mkdir(dst)
  1931         os.mkdir(dst)
  1774         for name, kind in listdir(src):
  1932         for name, kind in listdir(src):
  1775             srcname = os.path.join(src, name)
  1933             srcname = os.path.join(src, name)
  1776             dstname = os.path.join(dst, name)
  1934             dstname = os.path.join(dst, name)
  1777             hardlink, n = copyfiles(srcname, dstname, hardlink, progress)
  1935             hardlink, n = copyfiles(srcname, dstname, hardlink, progress)
  1778             num += n
  1936             num += n
  1779     else:
  1937     else:
  1780         if hardlink is None:
  1938         if hardlink is None:
  1781             hardlink = (os.stat(os.path.dirname(src)).st_dev ==
  1939             hardlink = (
  1782                         os.stat(os.path.dirname(dst)).st_dev)
  1940                 os.stat(os.path.dirname(src)).st_dev
       
  1941                 == os.stat(os.path.dirname(dst)).st_dev
       
  1942             )
  1783         settopic()
  1943         settopic()
  1784 
  1944 
  1785         if hardlink:
  1945         if hardlink:
  1786             try:
  1946             try:
  1787                 oslink(src, dst)
  1947                 oslink(src, dst)
  1794         if progress:
  1954         if progress:
  1795             progress.increment()
  1955             progress.increment()
  1796 
  1956 
  1797     return hardlink, num
  1957     return hardlink, num
  1798 
  1958 
       
  1959 
  1799 _winreservednames = {
  1960 _winreservednames = {
  1800     'con', 'prn', 'aux', 'nul',
  1961     'con',
  1801     'com1', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9',
  1962     'prn',
  1802     'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9',
  1963     'aux',
       
  1964     'nul',
       
  1965     'com1',
       
  1966     'com2',
       
  1967     'com3',
       
  1968     'com4',
       
  1969     'com5',
       
  1970     'com6',
       
  1971     'com7',
       
  1972     'com8',
       
  1973     'com9',
       
  1974     'lpt1',
       
  1975     'lpt2',
       
  1976     'lpt3',
       
  1977     'lpt4',
       
  1978     'lpt5',
       
  1979     'lpt6',
       
  1980     'lpt7',
       
  1981     'lpt8',
       
  1982     'lpt9',
  1803 }
  1983 }
  1804 _winreservedchars = ':*?"<>|'
  1984 _winreservedchars = ':*?"<>|'
       
  1985 
       
  1986 
  1805 def checkwinfilename(path):
  1987 def checkwinfilename(path):
  1806     r'''Check that the base-relative path is a valid filename on Windows.
  1988     r'''Check that the base-relative path is a valid filename on Windows.
  1807     Returns None if the path is ok, or a UI string describing the problem.
  1989     Returns None if the path is ok, or a UI string describing the problem.
  1808 
  1990 
  1809     >>> checkwinfilename(b"just/a/normal/path")
  1991     >>> checkwinfilename(b"just/a/normal/path")
  1833     for n in path.replace('\\', '/').split('/'):
  2015     for n in path.replace('\\', '/').split('/'):
  1834         if not n:
  2016         if not n:
  1835             continue
  2017             continue
  1836         for c in _filenamebytestr(n):
  2018         for c in _filenamebytestr(n):
  1837             if c in _winreservedchars:
  2019             if c in _winreservedchars:
  1838                 return _("filename contains '%s', which is reserved "
  2020                 return (
  1839                          "on Windows") % c
  2021                     _("filename contains '%s', which is reserved " "on Windows")
       
  2022                     % c
       
  2023                 )
  1840             if ord(c) <= 31:
  2024             if ord(c) <= 31:
  1841                 return _("filename contains '%s', which is invalid "
  2025                 return _(
  1842                          "on Windows") % stringutil.escapestr(c)
  2026                     "filename contains '%s', which is invalid " "on Windows"
       
  2027                 ) % stringutil.escapestr(c)
  1843         base = n.split('.')[0]
  2028         base = n.split('.')[0]
  1844         if base and base.lower() in _winreservednames:
  2029         if base and base.lower() in _winreservednames:
  1845             return _("filename contains '%s', which is reserved "
  2030             return (
  1846                      "on Windows") % base
  2031                 _("filename contains '%s', which is reserved " "on Windows")
       
  2032                 % base
       
  2033             )
  1847         t = n[-1:]
  2034         t = n[-1:]
  1848         if t in '. ' and n not in '..':
  2035         if t in '. ' and n not in '..':
  1849             return _("filename ends with '%s', which is not allowed "
  2036             return (
  1850                      "on Windows") % t
  2037                 _("filename ends with '%s', which is not allowed " "on Windows")
       
  2038                 % t
       
  2039             )
       
  2040 
  1851 
  2041 
  1852 if pycompat.iswindows:
  2042 if pycompat.iswindows:
  1853     checkosfilename = checkwinfilename
  2043     checkosfilename = checkwinfilename
  1854     timer = time.clock
  2044     timer = time.clock
  1855 else:
  2045 else:
  1856     checkosfilename = platform.checkosfilename
  2046     checkosfilename = platform.checkosfilename
  1857     timer = time.time
  2047     timer = time.time
  1858 
  2048 
  1859 if safehasattr(time, "perf_counter"):
  2049 if safehasattr(time, "perf_counter"):
  1860     timer = time.perf_counter
  2050     timer = time.perf_counter
       
  2051 
  1861 
  2052 
  1862 def makelock(info, pathname):
  2053 def makelock(info, pathname):
  1863     """Create a lock file atomically if possible
  2054     """Create a lock file atomically if possible
  1864 
  2055 
  1865     This may leave a stale lock file if symlink isn't supported and signal
  2056     This may leave a stale lock file if symlink isn't supported and signal
  1868     try:
  2059     try:
  1869         return os.symlink(info, pathname)
  2060         return os.symlink(info, pathname)
  1870     except OSError as why:
  2061     except OSError as why:
  1871         if why.errno == errno.EEXIST:
  2062         if why.errno == errno.EEXIST:
  1872             raise
  2063             raise
  1873     except AttributeError: # no symlink in os
  2064     except AttributeError:  # no symlink in os
  1874         pass
  2065         pass
  1875 
  2066 
  1876     flags = os.O_CREAT | os.O_WRONLY | os.O_EXCL | getattr(os, 'O_BINARY', 0)
  2067     flags = os.O_CREAT | os.O_WRONLY | os.O_EXCL | getattr(os, 'O_BINARY', 0)
  1877     ld = os.open(pathname, flags)
  2068     ld = os.open(pathname, flags)
  1878     os.write(ld, info)
  2069     os.write(ld, info)
  1879     os.close(ld)
  2070     os.close(ld)
       
  2071 
  1880 
  2072 
  1881 def readlock(pathname):
  2073 def readlock(pathname):
  1882     try:
  2074     try:
  1883         return readlink(pathname)
  2075         return readlink(pathname)
  1884     except OSError as why:
  2076     except OSError as why:
  1885         if why.errno not in (errno.EINVAL, errno.ENOSYS):
  2077         if why.errno not in (errno.EINVAL, errno.ENOSYS):
  1886             raise
  2078             raise
  1887     except AttributeError: # no symlink in os
  2079     except AttributeError:  # no symlink in os
  1888         pass
  2080         pass
  1889     with posixfile(pathname, 'rb') as fp:
  2081     with posixfile(pathname, 'rb') as fp:
  1890         return fp.read()
  2082         return fp.read()
       
  2083 
  1891 
  2084 
  1892 def fstat(fp):
  2085 def fstat(fp):
  1893     '''stat file object that may not have fileno method.'''
  2086     '''stat file object that may not have fileno method.'''
  1894     try:
  2087     try:
  1895         return os.fstat(fp.fileno())
  2088         return os.fstat(fp.fileno())
  1896     except AttributeError:
  2089     except AttributeError:
  1897         return os.stat(fp.name)
  2090         return os.stat(fp.name)
  1898 
  2091 
       
  2092 
  1899 # File system features
  2093 # File system features
       
  2094 
  1900 
  2095 
  1901 def fscasesensitive(path):
  2096 def fscasesensitive(path):
  1902     """
  2097     """
  1903     Return true if the given path is on a case-sensitive filesystem
  2098     Return true if the given path is on a case-sensitive filesystem
  1904 
  2099 
  1909     d, b = os.path.split(path)
  2104     d, b = os.path.split(path)
  1910     b2 = b.upper()
  2105     b2 = b.upper()
  1911     if b == b2:
  2106     if b == b2:
  1912         b2 = b.lower()
  2107         b2 = b.lower()
  1913         if b == b2:
  2108         if b == b2:
  1914             return True # no evidence against case sensitivity
  2109             return True  # no evidence against case sensitivity
  1915     p2 = os.path.join(d, b2)
  2110     p2 = os.path.join(d, b2)
  1916     try:
  2111     try:
  1917         s2 = os.lstat(p2)
  2112         s2 = os.lstat(p2)
  1918         if s2 == s1:
  2113         if s2 == s1:
  1919             return False
  2114             return False
  1920         return True
  2115         return True
  1921     except OSError:
  2116     except OSError:
  1922         return True
  2117         return True
  1923 
  2118 
       
  2119 
  1924 try:
  2120 try:
  1925     import re2
  2121     import re2
       
  2122 
  1926     _re2 = None
  2123     _re2 = None
  1927 except ImportError:
  2124 except ImportError:
  1928     _re2 = False
  2125     _re2 = False
       
  2126 
  1929 
  2127 
  1930 class _re(object):
  2128 class _re(object):
  1931     def _checkre2(self):
  2129     def _checkre2(self):
  1932         global _re2
  2130         global _re2
  1933         try:
  2131         try:
  1968         if _re2:
  2166         if _re2:
  1969             return re2.escape
  2167             return re2.escape
  1970         else:
  2168         else:
  1971             return remod.escape
  2169             return remod.escape
  1972 
  2170 
       
  2171 
  1973 re = _re()
  2172 re = _re()
  1974 
  2173 
  1975 _fspathcache = {}
  2174 _fspathcache = {}
       
  2175 
       
  2176 
  1976 def fspath(name, root):
  2177 def fspath(name, root):
  1977     '''Get name in the case stored in the filesystem
  2178     '''Get name in the case stored in the filesystem
  1978 
  2179 
  1979     The name should be relative to root, and be normcase-ed for efficiency.
  2180     The name should be relative to root, and be normcase-ed for efficiency.
  1980 
  2181 
  1981     Note that this function is unnecessary, and should not be
  2182     Note that this function is unnecessary, and should not be
  1982     called, for case-sensitive filesystems (simply because it's expensive).
  2183     called, for case-sensitive filesystems (simply because it's expensive).
  1983 
  2184 
  1984     The root should be normcase-ed, too.
  2185     The root should be normcase-ed, too.
  1985     '''
  2186     '''
       
  2187 
  1986     def _makefspathcacheentry(dir):
  2188     def _makefspathcacheentry(dir):
  1987         return dict((normcase(n), n) for n in os.listdir(dir))
  2189         return dict((normcase(n), n) for n in os.listdir(dir))
  1988 
  2190 
  1989     seps = pycompat.ossep
  2191     seps = pycompat.ossep
  1990     if pycompat.osaltsep:
  2192     if pycompat.osaltsep:
  1991         seps = seps + pycompat.osaltsep
  2193         seps = seps + pycompat.osaltsep
  1992     # Protect backslashes. This gets silly very quickly.
  2194     # Protect backslashes. This gets silly very quickly.
  1993     seps.replace('\\','\\\\')
  2195     seps.replace('\\', '\\\\')
  1994     pattern = remod.compile(br'([^%s]+)|([%s]+)' % (seps, seps))
  2196     pattern = remod.compile(br'([^%s]+)|([%s]+)' % (seps, seps))
  1995     dir = os.path.normpath(root)
  2197     dir = os.path.normpath(root)
  1996     result = []
  2198     result = []
  1997     for part, sep in pattern.findall(name):
  2199     for part, sep in pattern.findall(name):
  1998         if sep:
  2200         if sep:
  2013         result.append(found or part)
  2215         result.append(found or part)
  2014         dir = os.path.join(dir, part)
  2216         dir = os.path.join(dir, part)
  2015 
  2217 
  2016     return ''.join(result)
  2218     return ''.join(result)
  2017 
  2219 
       
  2220 
  2018 def checknlink(testfile):
  2221 def checknlink(testfile):
  2019     '''check whether hardlink count reporting works properly'''
  2222     '''check whether hardlink count reporting works properly'''
  2020 
  2223 
  2021     # testfile may be open, so we need a separate file for checking to
  2224     # testfile may be open, so we need a separate file for checking to
  2022     # work around issue2543 (or testfile may get lost on Samba shares)
  2225     # work around issue2543 (or testfile may get lost on Samba shares)
  2023     f1, f2, fp = None, None, None
  2226     f1, f2, fp = None, None, None
  2024     try:
  2227     try:
  2025         fd, f1 = pycompat.mkstemp(prefix='.%s-' % os.path.basename(testfile),
  2228         fd, f1 = pycompat.mkstemp(
  2026                                   suffix='1~', dir=os.path.dirname(testfile))
  2229             prefix='.%s-' % os.path.basename(testfile),
       
  2230             suffix='1~',
       
  2231             dir=os.path.dirname(testfile),
       
  2232         )
  2027         os.close(fd)
  2233         os.close(fd)
  2028         f2 = '%s2~' % f1[:-2]
  2234         f2 = '%s2~' % f1[:-2]
  2029 
  2235 
  2030         oslink(f1, f2)
  2236         oslink(f1, f2)
  2031         # nlinks() may behave differently for files on Windows shares if
  2237         # nlinks() may behave differently for files on Windows shares if
  2042                 if f is not None:
  2248                 if f is not None:
  2043                     os.unlink(f)
  2249                     os.unlink(f)
  2044             except OSError:
  2250             except OSError:
  2045                 pass
  2251                 pass
  2046 
  2252 
       
  2253 
  2047 def endswithsep(path):
  2254 def endswithsep(path):
  2048     '''Check path ends with os.sep or os.altsep.'''
  2255     '''Check path ends with os.sep or os.altsep.'''
  2049     return (path.endswith(pycompat.ossep)
  2256     return (
  2050             or pycompat.osaltsep and path.endswith(pycompat.osaltsep))
  2257         path.endswith(pycompat.ossep)
       
  2258         or pycompat.osaltsep
       
  2259         and path.endswith(pycompat.osaltsep)
       
  2260     )
       
  2261 
  2051 
  2262 
  2052 def splitpath(path):
  2263 def splitpath(path):
  2053     '''Split path by os.sep.
  2264     '''Split path by os.sep.
  2054     Note that this function does not use os.altsep because this is
  2265     Note that this function does not use os.altsep because this is
  2055     an alternative of simple "xxx.split(os.sep)".
  2266     an alternative of simple "xxx.split(os.sep)".
  2056     It is recommended to use os.path.normpath() before using this
  2267     It is recommended to use os.path.normpath() before using this
  2057     function if need.'''
  2268     function if need.'''
  2058     return path.split(pycompat.ossep)
  2269     return path.split(pycompat.ossep)
       
  2270 
  2059 
  2271 
  2060 def mktempcopy(name, emptyok=False, createmode=None, enforcewritable=False):
  2272 def mktempcopy(name, emptyok=False, createmode=None, enforcewritable=False):
  2061     """Create a temporary file with the same contents from name
  2273     """Create a temporary file with the same contents from name
  2062 
  2274 
  2063     The permission bits are copied from the original file.
  2275     The permission bits are copied from the original file.
  2089         ofp = posixfile(temp, "wb")
  2301         ofp = posixfile(temp, "wb")
  2090         for chunk in filechunkiter(ifp):
  2302         for chunk in filechunkiter(ifp):
  2091             ofp.write(chunk)
  2303             ofp.write(chunk)
  2092         ifp.close()
  2304         ifp.close()
  2093         ofp.close()
  2305         ofp.close()
  2094     except: # re-raises
  2306     except:  # re-raises
  2095         try:
  2307         try:
  2096             os.unlink(temp)
  2308             os.unlink(temp)
  2097         except OSError:
  2309         except OSError:
  2098             pass
  2310             pass
  2099         raise
  2311         raise
  2100     return temp
  2312     return temp
  2101 
  2313 
       
  2314 
  2102 class filestat(object):
  2315 class filestat(object):
  2103     """help to exactly detect change of a file
  2316     """help to exactly detect change of a file
  2104 
  2317 
  2105     'stat' attribute is result of 'os.stat()' if specified 'path'
  2318     'stat' attribute is result of 'os.stat()' if specified 'path'
  2106     exists. Otherwise, it is None. This can avoid preparative
  2319     exists. Otherwise, it is None. This can avoid preparative
  2107     'exists()' examination on client side of this class.
  2320     'exists()' examination on client side of this class.
  2108     """
  2321     """
       
  2322 
  2109     def __init__(self, stat):
  2323     def __init__(self, stat):
  2110         self.stat = stat
  2324         self.stat = stat
  2111 
  2325 
  2112     @classmethod
  2326     @classmethod
  2113     def frompath(cls, path):
  2327     def frompath(cls, path):
  2129     def __eq__(self, old):
  2343     def __eq__(self, old):
  2130         try:
  2344         try:
  2131             # if ambiguity between stat of new and old file is
  2345             # if ambiguity between stat of new and old file is
  2132             # avoided, comparison of size, ctime and mtime is enough
  2346             # avoided, comparison of size, ctime and mtime is enough
  2133             # to exactly detect change of a file regardless of platform
  2347             # to exactly detect change of a file regardless of platform
  2134             return (self.stat.st_size == old.stat.st_size and
  2348             return (
  2135                     self.stat[stat.ST_CTIME] == old.stat[stat.ST_CTIME] and
  2349                 self.stat.st_size == old.stat.st_size
  2136                     self.stat[stat.ST_MTIME] == old.stat[stat.ST_MTIME])
  2350                 and self.stat[stat.ST_CTIME] == old.stat[stat.ST_CTIME]
       
  2351                 and self.stat[stat.ST_MTIME] == old.stat[stat.ST_MTIME]
       
  2352             )
  2137         except AttributeError:
  2353         except AttributeError:
  2138             pass
  2354             pass
  2139         try:
  2355         try:
  2140             return self.stat is None and old.stat is None
  2356             return self.stat is None and old.stat is None
  2141         except AttributeError:
  2357         except AttributeError:
  2170 
  2386 
  2171         Advancing mtime "if isambig(oldstat)" ensures "S[n-1].mtime !=
  2387         Advancing mtime "if isambig(oldstat)" ensures "S[n-1].mtime !=
  2172         S[n].mtime", even if size of a file isn't changed.
  2388         S[n].mtime", even if size of a file isn't changed.
  2173         """
  2389         """
  2174         try:
  2390         try:
  2175             return (self.stat[stat.ST_CTIME] == old.stat[stat.ST_CTIME])
  2391             return self.stat[stat.ST_CTIME] == old.stat[stat.ST_CTIME]
  2176         except AttributeError:
  2392         except AttributeError:
  2177             return False
  2393             return False
  2178 
  2394 
  2179     def avoidambig(self, path, old):
  2395     def avoidambig(self, path, old):
  2180         """Change file stat of specified path to avoid ambiguity
  2396         """Change file stat of specified path to avoid ambiguity
  2185         appropriate privileges for 'path'. This returns False in this
  2401         appropriate privileges for 'path'. This returns False in this
  2186         case.
  2402         case.
  2187 
  2403 
  2188         Otherwise, this returns True, as "ambiguity is avoided".
  2404         Otherwise, this returns True, as "ambiguity is avoided".
  2189         """
  2405         """
  2190         advanced = (old.stat[stat.ST_MTIME] + 1) & 0x7fffffff
  2406         advanced = (old.stat[stat.ST_MTIME] + 1) & 0x7FFFFFFF
  2191         try:
  2407         try:
  2192             os.utime(path, (advanced, advanced))
  2408             os.utime(path, (advanced, advanced))
  2193         except OSError as inst:
  2409         except OSError as inst:
  2194             if inst.errno == errno.EPERM:
  2410             if inst.errno == errno.EPERM:
  2195                 # utime() on the file created by another user causes EPERM,
  2411                 # utime() on the file created by another user causes EPERM,
  2199         return True
  2415         return True
  2200 
  2416 
  2201     def __ne__(self, other):
  2417     def __ne__(self, other):
  2202         return not self == other
  2418         return not self == other
  2203 
  2419 
       
  2420 
  2204 class atomictempfile(object):
  2421 class atomictempfile(object):
  2205     '''writable file object that atomically updates a file
  2422     '''writable file object that atomically updates a file
  2206 
  2423 
  2207     All writes will go to a temporary copy of the original file. Call
  2424     All writes will go to a temporary copy of the original file. Call
  2208     close() when you are done writing, and atomictempfile will rename
  2425     close() when you are done writing, and atomictempfile will rename
  2212 
  2429 
  2213     checkambig argument of constructor is used with filestat, and is
  2430     checkambig argument of constructor is used with filestat, and is
  2214     useful only if target file is guarded by any lock (e.g. repo.lock
  2431     useful only if target file is guarded by any lock (e.g. repo.lock
  2215     or repo.wlock).
  2432     or repo.wlock).
  2216     '''
  2433     '''
       
  2434 
  2217     def __init__(self, name, mode='w+b', createmode=None, checkambig=False):
  2435     def __init__(self, name, mode='w+b', createmode=None, checkambig=False):
  2218         self.__name = name      # permanent name
  2436         self.__name = name  # permanent name
  2219         self._tempname = mktempcopy(name, emptyok=('w' in mode),
  2437         self._tempname = mktempcopy(
  2220                                     createmode=createmode,
  2438             name,
  2221                                     enforcewritable=('w' in mode))
  2439             emptyok=('w' in mode),
       
  2440             createmode=createmode,
       
  2441             enforcewritable=('w' in mode),
       
  2442         )
  2222 
  2443 
  2223         self._fp = posixfile(self._tempname, mode)
  2444         self._fp = posixfile(self._tempname, mode)
  2224         self._checkambig = checkambig
  2445         self._checkambig = checkambig
  2225 
  2446 
  2226         # delegated methods
  2447         # delegated methods
  2238             if oldstat and oldstat.stat:
  2459             if oldstat and oldstat.stat:
  2239                 rename(self._tempname, filename)
  2460                 rename(self._tempname, filename)
  2240                 newstat = filestat.frompath(filename)
  2461                 newstat = filestat.frompath(filename)
  2241                 if newstat.isambig(oldstat):
  2462                 if newstat.isambig(oldstat):
  2242                     # stat of changed file is ambiguous to original one
  2463                     # stat of changed file is ambiguous to original one
  2243                     advanced = (oldstat.stat[stat.ST_MTIME] + 1) & 0x7fffffff
  2464                     advanced = (oldstat.stat[stat.ST_MTIME] + 1) & 0x7FFFFFFF
  2244                     os.utime(filename, (advanced, advanced))
  2465                     os.utime(filename, (advanced, advanced))
  2245             else:
  2466             else:
  2246                 rename(self._tempname, filename)
  2467                 rename(self._tempname, filename)
  2247 
  2468 
  2248     def discard(self):
  2469     def discard(self):
  2252             except OSError:
  2473             except OSError:
  2253                 pass
  2474                 pass
  2254             self._fp.close()
  2475             self._fp.close()
  2255 
  2476 
  2256     def __del__(self):
  2477     def __del__(self):
  2257         if safehasattr(self, '_fp'): # constructor actually did something
  2478         if safehasattr(self, '_fp'):  # constructor actually did something
  2258             self.discard()
  2479             self.discard()
  2259 
  2480 
  2260     def __enter__(self):
  2481     def __enter__(self):
  2261         return self
  2482         return self
  2262 
  2483 
  2263     def __exit__(self, exctype, excvalue, traceback):
  2484     def __exit__(self, exctype, excvalue, traceback):
  2264         if exctype is not None:
  2485         if exctype is not None:
  2265             self.discard()
  2486             self.discard()
  2266         else:
  2487         else:
  2267             self.close()
  2488             self.close()
       
  2489 
  2268 
  2490 
  2269 def unlinkpath(f, ignoremissing=False, rmdir=True):
  2491 def unlinkpath(f, ignoremissing=False, rmdir=True):
  2270     """unlink and remove the directory if it is empty"""
  2492     """unlink and remove the directory if it is empty"""
  2271     if ignoremissing:
  2493     if ignoremissing:
  2272         tryunlink(f)
  2494         tryunlink(f)
  2277         try:
  2499         try:
  2278             removedirs(os.path.dirname(f))
  2500             removedirs(os.path.dirname(f))
  2279         except OSError:
  2501         except OSError:
  2280             pass
  2502             pass
  2281 
  2503 
       
  2504 
  2282 def tryunlink(f):
  2505 def tryunlink(f):
  2283     """Attempt to remove a file, ignoring ENOENT errors."""
  2506     """Attempt to remove a file, ignoring ENOENT errors."""
  2284     try:
  2507     try:
  2285         unlink(f)
  2508         unlink(f)
  2286     except OSError as e:
  2509     except OSError as e:
  2287         if e.errno != errno.ENOENT:
  2510         if e.errno != errno.ENOENT:
  2288             raise
  2511             raise
       
  2512 
  2289 
  2513 
  2290 def makedirs(name, mode=None, notindexed=False):
  2514 def makedirs(name, mode=None, notindexed=False):
  2291     """recursive directory creation with parent mode inheritance
  2515     """recursive directory creation with parent mode inheritance
  2292 
  2516 
  2293     Newly created directories are marked as "not to be indexed by
  2517     Newly created directories are marked as "not to be indexed by
  2313                 return
  2537                 return
  2314             raise
  2538             raise
  2315     if mode is not None:
  2539     if mode is not None:
  2316         os.chmod(name, mode)
  2540         os.chmod(name, mode)
  2317 
  2541 
       
  2542 
  2318 def readfile(path):
  2543 def readfile(path):
  2319     with open(path, 'rb') as fp:
  2544     with open(path, 'rb') as fp:
  2320         return fp.read()
  2545         return fp.read()
  2321 
  2546 
       
  2547 
  2322 def writefile(path, text):
  2548 def writefile(path, text):
  2323     with open(path, 'wb') as fp:
  2549     with open(path, 'wb') as fp:
  2324         fp.write(text)
  2550         fp.write(text)
  2325 
  2551 
       
  2552 
  2326 def appendfile(path, text):
  2553 def appendfile(path, text):
  2327     with open(path, 'ab') as fp:
  2554     with open(path, 'ab') as fp:
  2328         fp.write(text)
  2555         fp.write(text)
  2329 
  2556 
       
  2557 
  2330 class chunkbuffer(object):
  2558 class chunkbuffer(object):
  2331     """Allow arbitrary sized chunks of data to be efficiently read from an
  2559     """Allow arbitrary sized chunks of data to be efficiently read from an
  2332     iterator over chunks of arbitrary size."""
  2560     iterator over chunks of arbitrary size."""
  2333 
  2561 
  2334     def __init__(self, in_iter):
  2562     def __init__(self, in_iter):
  2335         """in_iter is the iterator that's iterating over the input chunks."""
  2563         """in_iter is the iterator that's iterating over the input chunks."""
       
  2564 
  2336         def splitbig(chunks):
  2565         def splitbig(chunks):
  2337             for chunk in chunks:
  2566             for chunk in chunks:
  2338                 if len(chunk) > 2**20:
  2567                 if len(chunk) > 2 ** 20:
  2339                     pos = 0
  2568                     pos = 0
  2340                     while pos < len(chunk):
  2569                     while pos < len(chunk):
  2341                         end = pos + 2 ** 18
  2570                         end = pos + 2 ** 18
  2342                         yield chunk[pos:end]
  2571                         yield chunk[pos:end]
  2343                         pos = end
  2572                         pos = end
  2344                 else:
  2573                 else:
  2345                     yield chunk
  2574                     yield chunk
       
  2575 
  2346         self.iter = splitbig(in_iter)
  2576         self.iter = splitbig(in_iter)
  2347         self._queue = collections.deque()
  2577         self._queue = collections.deque()
  2348         self._chunkoffset = 0
  2578         self._chunkoffset = 0
  2349 
  2579 
  2350     def read(self, l=None):
  2580     def read(self, l=None):
  2359         buf = []
  2589         buf = []
  2360         queue = self._queue
  2590         queue = self._queue
  2361         while left > 0:
  2591         while left > 0:
  2362             # refill the queue
  2592             # refill the queue
  2363             if not queue:
  2593             if not queue:
  2364                 target = 2**18
  2594                 target = 2 ** 18
  2365                 for chunk in self.iter:
  2595                 for chunk in self.iter:
  2366                     queue.append(chunk)
  2596                     queue.append(chunk)
  2367                     target -= len(chunk)
  2597                     target -= len(chunk)
  2368                     if target <= 0:
  2598                     if target <= 0:
  2369                         break
  2599                         break
  2399                 buf.append(chunk[offset:])
  2629                 buf.append(chunk[offset:])
  2400                 self._chunkoffset = 0
  2630                 self._chunkoffset = 0
  2401 
  2631 
  2402             # Partial chunk needed.
  2632             # Partial chunk needed.
  2403             else:
  2633             else:
  2404                 buf.append(chunk[offset:offset + left])
  2634                 buf.append(chunk[offset : offset + left])
  2405                 self._chunkoffset += left
  2635                 self._chunkoffset += left
  2406                 left -= chunkremaining
  2636                 left -= chunkremaining
  2407 
  2637 
  2408         return ''.join(buf)
  2638         return ''.join(buf)
       
  2639 
  2409 
  2640 
  2410 def filechunkiter(f, size=131072, limit=None):
  2641 def filechunkiter(f, size=131072, limit=None):
  2411     """Create a generator that produces the data in the file size
  2642     """Create a generator that produces the data in the file size
  2412     (default 131072) bytes at a time, up to optional limit (default is
  2643     (default 131072) bytes at a time, up to optional limit (default is
  2413     to read all data).  Chunks may be less than size bytes if the
  2644     to read all data).  Chunks may be less than size bytes if the
  2426             break
  2657             break
  2427         if limit:
  2658         if limit:
  2428             limit -= len(s)
  2659             limit -= len(s)
  2429         yield s
  2660         yield s
  2430 
  2661 
       
  2662 
  2431 class cappedreader(object):
  2663 class cappedreader(object):
  2432     """A file object proxy that allows reading up to N bytes.
  2664     """A file object proxy that allows reading up to N bytes.
  2433 
  2665 
  2434     Given a source file object, instances of this type allow reading up to
  2666     Given a source file object, instances of this type allow reading up to
  2435     N bytes from that source file object. Attempts to read past the allowed
  2667     N bytes from that source file object. Attempts to read past the allowed
  2437 
  2669 
  2438     It is assumed that I/O is not performed on the original file object
  2670     It is assumed that I/O is not performed on the original file object
  2439     in addition to I/O that is performed by this instance. If there is,
  2671     in addition to I/O that is performed by this instance. If there is,
  2440     state tracking will get out of sync and unexpected results will ensue.
  2672     state tracking will get out of sync and unexpected results will ensue.
  2441     """
  2673     """
       
  2674 
  2442     def __init__(self, fh, limit):
  2675     def __init__(self, fh, limit):
  2443         """Allow reading up to <limit> bytes from <fh>."""
  2676         """Allow reading up to <limit> bytes from <fh>."""
  2444         self._fh = fh
  2677         self._fh = fh
  2445         self._left = limit
  2678         self._left = limit
  2446 
  2679 
  2460     def readinto(self, b):
  2693     def readinto(self, b):
  2461         res = self.read(len(b))
  2694         res = self.read(len(b))
  2462         if res is None:
  2695         if res is None:
  2463             return None
  2696             return None
  2464 
  2697 
  2465         b[0:len(res)] = res
  2698         b[0 : len(res)] = res
  2466         return len(res)
  2699         return len(res)
       
  2700 
  2467 
  2701 
  2468 def unitcountfn(*unittable):
  2702 def unitcountfn(*unittable):
  2469     '''return a function that renders a readable count of some quantity'''
  2703     '''return a function that renders a readable count of some quantity'''
  2470 
  2704 
  2471     def go(count):
  2705     def go(count):
  2473             if abs(count) >= divisor * multiplier:
  2707             if abs(count) >= divisor * multiplier:
  2474                 return format % (count / float(divisor))
  2708                 return format % (count / float(divisor))
  2475         return unittable[-1][2] % count
  2709         return unittable[-1][2] % count
  2476 
  2710 
  2477     return go
  2711     return go
       
  2712 
  2478 
  2713 
  2479 def processlinerange(fromline, toline):
  2714 def processlinerange(fromline, toline):
  2480     """Check that linerange <fromline>:<toline> makes sense and return a
  2715     """Check that linerange <fromline>:<toline> makes sense and return a
  2481     0-based range.
  2716     0-based range.
  2482 
  2717 
  2495         raise error.ParseError(_("line range must be positive"))
  2730         raise error.ParseError(_("line range must be positive"))
  2496     if fromline < 1:
  2731     if fromline < 1:
  2497         raise error.ParseError(_("fromline must be strictly positive"))
  2732         raise error.ParseError(_("fromline must be strictly positive"))
  2498     return fromline - 1, toline
  2733     return fromline - 1, toline
  2499 
  2734 
       
  2735 
  2500 bytecount = unitcountfn(
  2736 bytecount = unitcountfn(
  2501     (100, 1 << 30, _('%.0f GB')),
  2737     (100, 1 << 30, _('%.0f GB')),
  2502     (10, 1 << 30, _('%.1f GB')),
  2738     (10, 1 << 30, _('%.1f GB')),
  2503     (1, 1 << 30, _('%.2f GB')),
  2739     (1, 1 << 30, _('%.2f GB')),
  2504     (100, 1 << 20, _('%.0f MB')),
  2740     (100, 1 << 20, _('%.0f MB')),
  2506     (1, 1 << 20, _('%.2f MB')),
  2742     (1, 1 << 20, _('%.2f MB')),
  2507     (100, 1 << 10, _('%.0f KB')),
  2743     (100, 1 << 10, _('%.0f KB')),
  2508     (10, 1 << 10, _('%.1f KB')),
  2744     (10, 1 << 10, _('%.1f KB')),
  2509     (1, 1 << 10, _('%.2f KB')),
  2745     (1, 1 << 10, _('%.2f KB')),
  2510     (1, 1, _('%.0f bytes')),
  2746     (1, 1, _('%.0f bytes')),
  2511     )
  2747 )
       
  2748 
  2512 
  2749 
  2513 class transformingwriter(object):
  2750 class transformingwriter(object):
  2514     """Writable file wrapper to transform data by function"""
  2751     """Writable file wrapper to transform data by function"""
  2515 
  2752 
  2516     def __init__(self, fp, encode):
  2753     def __init__(self, fp, encode):
  2523     def flush(self):
  2760     def flush(self):
  2524         self._fp.flush()
  2761         self._fp.flush()
  2525 
  2762 
  2526     def write(self, data):
  2763     def write(self, data):
  2527         return self._fp.write(self._encode(data))
  2764         return self._fp.write(self._encode(data))
       
  2765 
  2528 
  2766 
  2529 # Matches a single EOL which can either be a CRLF where repeated CR
  2767 # Matches a single EOL which can either be a CRLF where repeated CR
  2530 # are removed or a LF. We do not care about old Macintosh files, so a
  2768 # are removed or a LF. We do not care about old Macintosh files, so a
  2531 # stray CR is an error.
  2769 # stray CR is an error.
  2532 _eolre = remod.compile(br'\r*\n')
  2770 _eolre = remod.compile(br'\r*\n')
  2533 
  2771 
       
  2772 
  2534 def tolf(s):
  2773 def tolf(s):
  2535     return _eolre.sub('\n', s)
  2774     return _eolre.sub('\n', s)
  2536 
  2775 
       
  2776 
  2537 def tocrlf(s):
  2777 def tocrlf(s):
  2538     return _eolre.sub('\r\n', s)
  2778     return _eolre.sub('\r\n', s)
  2539 
  2779 
       
  2780 
  2540 def _crlfwriter(fp):
  2781 def _crlfwriter(fp):
  2541     return transformingwriter(fp, tocrlf)
  2782     return transformingwriter(fp, tocrlf)
       
  2783 
  2542 
  2784 
  2543 if pycompat.oslinesep == '\r\n':
  2785 if pycompat.oslinesep == '\r\n':
  2544     tonativeeol = tocrlf
  2786     tonativeeol = tocrlf
  2545     fromnativeeol = tolf
  2787     fromnativeeol = tolf
  2546     nativeeolwriter = _crlfwriter
  2788     nativeeolwriter = _crlfwriter
  2547 else:
  2789 else:
  2548     tonativeeol = pycompat.identity
  2790     tonativeeol = pycompat.identity
  2549     fromnativeeol = pycompat.identity
  2791     fromnativeeol = pycompat.identity
  2550     nativeeolwriter = pycompat.identity
  2792     nativeeolwriter = pycompat.identity
  2551 
  2793 
  2552 if (pyplatform.python_implementation() == 'CPython' and
  2794 if pyplatform.python_implementation() == 'CPython' and sys.version_info < (
  2553     sys.version_info < (3, 0)):
  2795     3,
       
  2796     0,
       
  2797 ):
  2554     # There is an issue in CPython that some IO methods do not handle EINTR
  2798     # There is an issue in CPython that some IO methods do not handle EINTR
  2555     # correctly. The following table shows what CPython version (and functions)
  2799     # correctly. The following table shows what CPython version (and functions)
  2556     # are affected (buggy: has the EINTR bug, okay: otherwise):
  2800     # are affected (buggy: has the EINTR bug, okay: otherwise):
  2557     #
  2801     #
  2558     #                | < 2.7.4 | 2.7.4 to 2.7.12 | >= 3.0
  2802     #                | < 2.7.4 | 2.7.4 to 2.7.12 | >= 3.0
  2577     # to minimize the performance impact.
  2821     # to minimize the performance impact.
  2578     if sys.version_info >= (2, 7, 4):
  2822     if sys.version_info >= (2, 7, 4):
  2579         # fp.readline deals with EINTR correctly, use it as a workaround.
  2823         # fp.readline deals with EINTR correctly, use it as a workaround.
  2580         def _safeiterfile(fp):
  2824         def _safeiterfile(fp):
  2581             return iter(fp.readline, '')
  2825             return iter(fp.readline, '')
       
  2826 
  2582     else:
  2827     else:
  2583         # fp.read* are broken too, manually deal with EINTR in a stupid way.
  2828         # fp.read* are broken too, manually deal with EINTR in a stupid way.
  2584         # note: this may block longer than necessary because of bufsize.
  2829         # note: this may block longer than necessary because of bufsize.
  2585         def _safeiterfile(fp, bufsize=4096):
  2830         def _safeiterfile(fp, bufsize=4096):
  2586             fd = fp.fileno()
  2831             fd = fp.fileno()
  2614             fastpath = stat.S_ISREG(os.fstat(fp.fileno()).st_mode)
  2859             fastpath = stat.S_ISREG(os.fstat(fp.fileno()).st_mode)
  2615         if fastpath:
  2860         if fastpath:
  2616             return fp
  2861             return fp
  2617         else:
  2862         else:
  2618             return _safeiterfile(fp)
  2863             return _safeiterfile(fp)
       
  2864 
       
  2865 
  2619 else:
  2866 else:
  2620     # PyPy and CPython 3 do not have the EINTR issue thus no workaround needed.
  2867     # PyPy and CPython 3 do not have the EINTR issue thus no workaround needed.
  2621     def iterfile(fp):
  2868     def iterfile(fp):
  2622         return fp
  2869         return fp
  2623 
  2870 
       
  2871 
  2624 def iterlines(iterator):
  2872 def iterlines(iterator):
  2625     for chunk in iterator:
  2873     for chunk in iterator:
  2626         for line in chunk.splitlines():
  2874         for line in chunk.splitlines():
  2627             yield line
  2875             yield line
  2628 
  2876 
       
  2877 
  2629 def expandpath(path):
  2878 def expandpath(path):
  2630     return os.path.expanduser(os.path.expandvars(path))
  2879     return os.path.expanduser(os.path.expandvars(path))
       
  2880 
  2631 
  2881 
  2632 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
  2882 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
  2633     """Return the result of interpolating items in the mapping into string s.
  2883     """Return the result of interpolating items in the mapping into string s.
  2634 
  2884 
  2635     prefix is a single character string, or a two character string with
  2885     prefix is a single character string, or a two character string with
  2652             prefix_char = prefix
  2902             prefix_char = prefix
  2653         mapping[prefix_char] = prefix_char
  2903         mapping[prefix_char] = prefix_char
  2654     r = remod.compile(br'%s(%s)' % (prefix, patterns))
  2904     r = remod.compile(br'%s(%s)' % (prefix, patterns))
  2655     return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
  2905     return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
  2656 
  2906 
       
  2907 
  2657 def getport(port):
  2908 def getport(port):
  2658     """Return the port for a given network service.
  2909     """Return the port for a given network service.
  2659 
  2910 
  2660     If port is an integer, it's returned as is. If it's a string, it's
  2911     If port is an integer, it's returned as is. If it's a string, it's
  2661     looked up using socket.getservbyname(). If there's no matching
  2912     looked up using socket.getservbyname(). If there's no matching
  2667         pass
  2918         pass
  2668 
  2919 
  2669     try:
  2920     try:
  2670         return socket.getservbyname(pycompat.sysstr(port))
  2921         return socket.getservbyname(pycompat.sysstr(port))
  2671     except socket.error:
  2922     except socket.error:
  2672         raise error.Abort(_("no port number associated with service '%s'")
  2923         raise error.Abort(
  2673                           % port)
  2924             _("no port number associated with service '%s'") % port
       
  2925         )
       
  2926 
  2674 
  2927 
  2675 class url(object):
  2928 class url(object):
  2676     r"""Reliable URL parser.
  2929     r"""Reliable URL parser.
  2677 
  2930 
  2678     This parses URLs and provides attributes for the following
  2931     This parses URLs and provides attributes for the following
  2820                     self.user, self.passwd = self.user.split(':', 1)
  3073                     self.user, self.passwd = self.user.split(':', 1)
  2821                 if not self.host:
  3074                 if not self.host:
  2822                     self.host = None
  3075                     self.host = None
  2823 
  3076 
  2824             # Don't split on colons in IPv6 addresses without ports
  3077             # Don't split on colons in IPv6 addresses without ports
  2825             if (self.host and ':' in self.host and
  3078             if (
  2826                 not (self.host.startswith('[') and self.host.endswith(']'))):
  3079                 self.host
       
  3080                 and ':' in self.host
       
  3081                 and not (self.host.startswith('[') and self.host.endswith(']'))
       
  3082             ):
  2827                 self._hostport = self.host
  3083                 self._hostport = self.host
  2828                 self.host, self.port = self.host.rsplit(':', 1)
  3084                 self.host, self.port = self.host.rsplit(':', 1)
  2829                 if not self.host:
  3085                 if not self.host:
  2830                     self.host = None
  3086                     self.host = None
  2831 
  3087 
  2832             if (self.host and self.scheme == 'file' and
  3088             if (
  2833                 self.host not in ('localhost', '127.0.0.1', '[::1]')):
  3089                 self.host
       
  3090                 and self.scheme == 'file'
       
  3091                 and self.host not in ('localhost', '127.0.0.1', '[::1]')
       
  3092             ):
  2834                 raise error.Abort(_('file:// URLs can only refer to localhost'))
  3093                 raise error.Abort(_('file:// URLs can only refer to localhost'))
  2835 
  3094 
  2836         self.path = path
  3095         self.path = path
  2837 
  3096 
  2838         # leave the query string escaped
  3097         # leave the query string escaped
  2839         for a in ('user', 'passwd', 'host', 'port',
  3098         for a in ('user', 'passwd', 'host', 'port', 'path', 'fragment'):
  2840                   'path', 'fragment'):
       
  2841             v = getattr(self, a)
  3099             v = getattr(self, a)
  2842             if v is not None:
  3100             if v is not None:
  2843                 setattr(self, a, urlreq.unquote(v))
  3101                 setattr(self, a, urlreq.unquote(v))
  2844 
  3102 
  2845     @encoding.strmethod
  3103     @encoding.strmethod
  2846     def __repr__(self):
  3104     def __repr__(self):
  2847         attrs = []
  3105         attrs = []
  2848         for a in ('scheme', 'user', 'passwd', 'host', 'port', 'path',
  3106         for a in (
  2849                   'query', 'fragment'):
  3107             'scheme',
       
  3108             'user',
       
  3109             'passwd',
       
  3110             'host',
       
  3111             'port',
       
  3112             'path',
       
  3113             'query',
       
  3114             'fragment',
       
  3115         ):
  2850             v = getattr(self, a)
  3116             v = getattr(self, a)
  2851             if v is not None:
  3117             if v is not None:
  2852                 attrs.append('%s: %r' % (a, pycompat.bytestr(v)))
  3118                 attrs.append('%s: %r' % (a, pycompat.bytestr(v)))
  2853         return '<url %s>' % ', '.join(attrs)
  3119         return '<url %s>' % ', '.join(attrs)
  2854 
  3120 
  2895             return s
  3161             return s
  2896 
  3162 
  2897         s = self.scheme + ':'
  3163         s = self.scheme + ':'
  2898         if self.user or self.passwd or self.host:
  3164         if self.user or self.passwd or self.host:
  2899             s += '//'
  3165             s += '//'
  2900         elif self.scheme and (not self.path or self.path.startswith('/')
  3166         elif self.scheme and (
  2901                               or hasdriveletter(self.path)):
  3167             not self.path
       
  3168             or self.path.startswith('/')
       
  3169             or hasdriveletter(self.path)
       
  3170         ):
  2902             s += '//'
  3171             s += '//'
  2903             if hasdriveletter(self.path):
  3172             if hasdriveletter(self.path):
  2904                 s += '/'
  3173                 s += '/'
  2905         if self.user:
  3174         if self.user:
  2906             s += urlreq.quote(self.user, safe=self._safechars)
  3175             s += urlreq.quote(self.user, safe=self._safechars)
  2942             return (s, None)
  3211             return (s, None)
  2943         # authinfo[1] is passed to urllib2 password manager, and its
  3212         # authinfo[1] is passed to urllib2 password manager, and its
  2944         # URIs must not contain credentials. The host is passed in the
  3213         # URIs must not contain credentials. The host is passed in the
  2945         # URIs list because Python < 2.4.3 uses only that to search for
  3214         # URIs list because Python < 2.4.3 uses only that to search for
  2946         # a password.
  3215         # a password.
  2947         return (s, (None, (s, self.host),
  3216         return (s, (None, (s, self.host), self.user, self.passwd or ''))
  2948                     self.user, self.passwd or ''))
       
  2949 
  3217 
  2950     def isabs(self):
  3218     def isabs(self):
  2951         if self.scheme and self.scheme != 'file':
  3219         if self.scheme and self.scheme != 'file':
  2952             return True # remote URL
  3220             return True  # remote URL
  2953         if hasdriveletter(self.path):
  3221         if hasdriveletter(self.path):
  2954             return True # absolute for our purposes - can't be joined()
  3222             return True  # absolute for our purposes - can't be joined()
  2955         if self.path.startswith(br'\\'):
  3223         if self.path.startswith(br'\\'):
  2956             return True # Windows UNC path
  3224             return True  # Windows UNC path
  2957         if self.path.startswith('/'):
  3225         if self.path.startswith('/'):
  2958             return True # POSIX-style
  3226             return True  # POSIX-style
  2959         return False
  3227         return False
  2960 
  3228 
  2961     def localpath(self):
  3229     def localpath(self):
  2962         if self.scheme == 'file' or self.scheme == 'bundle':
  3230         if self.scheme == 'file' or self.scheme == 'bundle':
  2963             path = self.path or '/'
  3231             path = self.path or '/'
  2964             # For Windows, we need to promote hosts containing drive
  3232             # For Windows, we need to promote hosts containing drive
  2965             # letters to paths with drive letters.
  3233             # letters to paths with drive letters.
  2966             if hasdriveletter(self._hostport):
  3234             if hasdriveletter(self._hostport):
  2967                 path = self._hostport + '/' + self.path
  3235                 path = self._hostport + '/' + self.path
  2968             elif (self.host is not None and self.path
  3236             elif (
  2969                   and not hasdriveletter(path)):
  3237                 self.host is not None and self.path and not hasdriveletter(path)
       
  3238             ):
  2970                 path = '/' + path
  3239                 path = '/' + path
  2971             return path
  3240             return path
  2972         return self._origpath
  3241         return self._origpath
  2973 
  3242 
  2974     def islocal(self):
  3243     def islocal(self):
  2975         '''whether localpath will return something that posixfile can open'''
  3244         '''whether localpath will return something that posixfile can open'''
  2976         return (not self.scheme or self.scheme == 'file'
  3245         return (
  2977                 or self.scheme == 'bundle')
  3246             not self.scheme or self.scheme == 'file' or self.scheme == 'bundle'
       
  3247         )
       
  3248 
  2978 
  3249 
  2979 def hasscheme(path):
  3250 def hasscheme(path):
  2980     return bool(url(path).scheme)
  3251     return bool(url(path).scheme)
  2981 
  3252 
       
  3253 
  2982 def hasdriveletter(path):
  3254 def hasdriveletter(path):
  2983     return path and path[1:2] == ':' and path[0:1].isalpha()
  3255     return path and path[1:2] == ':' and path[0:1].isalpha()
  2984 
  3256 
       
  3257 
  2985 def urllocalpath(path):
  3258 def urllocalpath(path):
  2986     return url(path, parsequery=False, parsefragment=False).localpath()
  3259     return url(path, parsequery=False, parsefragment=False).localpath()
       
  3260 
  2987 
  3261 
  2988 def checksafessh(path):
  3262 def checksafessh(path):
  2989     """check if a path / url is a potentially unsafe ssh exploit (SEC)
  3263     """check if a path / url is a potentially unsafe ssh exploit (SEC)
  2990 
  3264 
  2991     This is a sanity check for ssh urls. ssh will parse the first item as
  3265     This is a sanity check for ssh urls. ssh will parse the first item as
  2995 
  3269 
  2996     Raises an error.Abort when the url is unsafe.
  3270     Raises an error.Abort when the url is unsafe.
  2997     """
  3271     """
  2998     path = urlreq.unquote(path)
  3272     path = urlreq.unquote(path)
  2999     if path.startswith('ssh://-') or path.startswith('svn+ssh://-'):
  3273     if path.startswith('ssh://-') or path.startswith('svn+ssh://-'):
  3000         raise error.Abort(_('potentially unsafe url: %r') %
  3274         raise error.Abort(
  3001                           (pycompat.bytestr(path),))
  3275             _('potentially unsafe url: %r') % (pycompat.bytestr(path),)
       
  3276         )
       
  3277 
  3002 
  3278 
  3003 def hidepassword(u):
  3279 def hidepassword(u):
  3004     '''hide user credential in a url string'''
  3280     '''hide user credential in a url string'''
  3005     u = url(u)
  3281     u = url(u)
  3006     if u.passwd:
  3282     if u.passwd:
  3007         u.passwd = '***'
  3283         u.passwd = '***'
  3008     return bytes(u)
  3284     return bytes(u)
  3009 
  3285 
       
  3286 
  3010 def removeauth(u):
  3287 def removeauth(u):
  3011     '''remove all authentication information from a url string'''
  3288     '''remove all authentication information from a url string'''
  3012     u = url(u)
  3289     u = url(u)
  3013     u.user = u.passwd = None
  3290     u.user = u.passwd = None
  3014     return bytes(u)
  3291     return bytes(u)
       
  3292 
  3015 
  3293 
  3016 timecount = unitcountfn(
  3294 timecount = unitcountfn(
  3017     (1, 1e3, _('%.0f s')),
  3295     (1, 1e3, _('%.0f s')),
  3018     (100, 1, _('%.1f s')),
  3296     (100, 1, _('%.1f s')),
  3019     (10, 1, _('%.2f s')),
  3297     (10, 1, _('%.2f s')),
  3025     (10, 0.000001, _('%.2f us')),
  3303     (10, 0.000001, _('%.2f us')),
  3026     (1, 0.000001, _('%.3f us')),
  3304     (1, 0.000001, _('%.3f us')),
  3027     (100, 0.000000001, _('%.1f ns')),
  3305     (100, 0.000000001, _('%.1f ns')),
  3028     (10, 0.000000001, _('%.2f ns')),
  3306     (10, 0.000000001, _('%.2f ns')),
  3029     (1, 0.000000001, _('%.3f ns')),
  3307     (1, 0.000000001, _('%.3f ns')),
  3030     )
  3308 )
       
  3309 
  3031 
  3310 
  3032 @attr.s
  3311 @attr.s
  3033 class timedcmstats(object):
  3312 class timedcmstats(object):
  3034     """Stats information produced by the timedcm context manager on entering."""
  3313     """Stats information produced by the timedcm context manager on entering."""
  3035 
  3314 
  3044 
  3323 
  3045     def __bytes__(self):
  3324     def __bytes__(self):
  3046         return timecount(self.elapsed) if self.elapsed else '<unknown>'
  3325         return timecount(self.elapsed) if self.elapsed else '<unknown>'
  3047 
  3326 
  3048     __str__ = encoding.strmethod(__bytes__)
  3327     __str__ = encoding.strmethod(__bytes__)
       
  3328 
  3049 
  3329 
  3050 @contextlib.contextmanager
  3330 @contextlib.contextmanager
  3051 def timedcm(whencefmt, *whenceargs):
  3331 def timedcm(whencefmt, *whenceargs):
  3052     """A context manager that produces timing information for a given context.
  3332     """A context manager that produces timing information for a given context.
  3053 
  3333 
  3064             yield timing_stats
  3344             yield timing_stats
  3065     finally:
  3345     finally:
  3066         timing_stats.elapsed = timer() - timing_stats.start
  3346         timing_stats.elapsed = timer() - timing_stats.start
  3067         timedcm._nested -= 1
  3347         timedcm._nested -= 1
  3068 
  3348 
       
  3349 
  3069 timedcm._nested = 0
  3350 timedcm._nested = 0
       
  3351 
  3070 
  3352 
  3071 def timed(func):
  3353 def timed(func):
  3072     '''Report the execution time of a function call to stderr.
  3354     '''Report the execution time of a function call to stderr.
  3073 
  3355 
  3074     During development, use as a decorator when you need to measure
  3356     During development, use as a decorator when you need to measure
  3081 
  3363 
  3082     def wrapper(*args, **kwargs):
  3364     def wrapper(*args, **kwargs):
  3083         with timedcm(pycompat.bytestr(func.__name__)) as time_stats:
  3365         with timedcm(pycompat.bytestr(func.__name__)) as time_stats:
  3084             result = func(*args, **kwargs)
  3366             result = func(*args, **kwargs)
  3085         stderr = procutil.stderr
  3367         stderr = procutil.stderr
  3086         stderr.write('%s%s: %s\n' % (
  3368         stderr.write(
  3087             ' ' * time_stats.level * 2, pycompat.bytestr(func.__name__),
  3369             '%s%s: %s\n'
  3088             time_stats))
  3370             % (
       
  3371                 ' ' * time_stats.level * 2,
       
  3372                 pycompat.bytestr(func.__name__),
       
  3373                 time_stats,
       
  3374             )
       
  3375         )
  3089         return result
  3376         return result
       
  3377 
  3090     return wrapper
  3378     return wrapper
  3091 
  3379 
  3092 _sizeunits = (('m', 2**20), ('k', 2**10), ('g', 2**30),
  3380 
  3093               ('kb', 2**10), ('mb', 2**20), ('gb', 2**30), ('b', 1))
  3381 _sizeunits = (
       
  3382     ('m', 2 ** 20),
       
  3383     ('k', 2 ** 10),
       
  3384     ('g', 2 ** 30),
       
  3385     ('kb', 2 ** 10),
       
  3386     ('mb', 2 ** 20),
       
  3387     ('gb', 2 ** 30),
       
  3388     ('b', 1),
       
  3389 )
       
  3390 
  3094 
  3391 
  3095 def sizetoint(s):
  3392 def sizetoint(s):
  3096     '''Convert a space specifier to a byte count.
  3393     '''Convert a space specifier to a byte count.
  3097 
  3394 
  3098     >>> sizetoint(b'30')
  3395     >>> sizetoint(b'30')
  3104     '''
  3401     '''
  3105     t = s.strip().lower()
  3402     t = s.strip().lower()
  3106     try:
  3403     try:
  3107         for k, u in _sizeunits:
  3404         for k, u in _sizeunits:
  3108             if t.endswith(k):
  3405             if t.endswith(k):
  3109                 return int(float(t[:-len(k)]) * u)
  3406                 return int(float(t[: -len(k)]) * u)
  3110         return int(t)
  3407         return int(t)
  3111     except ValueError:
  3408     except ValueError:
  3112         raise error.ParseError(_("couldn't parse size: %s") % s)
  3409         raise error.ParseError(_("couldn't parse size: %s") % s)
       
  3410 
  3113 
  3411 
  3114 class hooks(object):
  3412 class hooks(object):
  3115     '''A collection of hook functions that can be used to extend a
  3413     '''A collection of hook functions that can be used to extend a
  3116     function's behavior. Hooks are called in lexicographic order,
  3414     function's behavior. Hooks are called in lexicographic order,
  3117     based on the names of their sources.'''
  3415     based on the names of their sources.'''
  3126         self._hooks.sort(key=lambda x: x[0])
  3424         self._hooks.sort(key=lambda x: x[0])
  3127         results = []
  3425         results = []
  3128         for source, hook in self._hooks:
  3426         for source, hook in self._hooks:
  3129             results.append(hook(*args))
  3427             results.append(hook(*args))
  3130         return results
  3428         return results
       
  3429 
  3131 
  3430 
  3132 def getstackframes(skip=0, line=' %-*s in %s\n', fileline='%s:%d', depth=0):
  3431 def getstackframes(skip=0, line=' %-*s in %s\n', fileline='%s:%d', depth=0):
  3133     '''Yields lines for a nicely formatted stacktrace.
  3432     '''Yields lines for a nicely formatted stacktrace.
  3134     Skips the 'skip' last entries, then return the last 'depth' entries.
  3433     Skips the 'skip' last entries, then return the last 'depth' entries.
  3135     Each file+linenumber is formatted according to fileline.
  3434     Each file+linenumber is formatted according to fileline.
  3139       filepath+linenumber,
  3438       filepath+linenumber,
  3140       function
  3439       function
  3141 
  3440 
  3142     Not be used in production code but very convenient while developing.
  3441     Not be used in production code but very convenient while developing.
  3143     '''
  3442     '''
  3144     entries = [(fileline % (pycompat.sysbytes(fn), ln), pycompat.sysbytes(func))
  3443     entries = [
  3145         for fn, ln, func, _text in traceback.extract_stack()[:-skip - 1]
  3444         (fileline % (pycompat.sysbytes(fn), ln), pycompat.sysbytes(func))
  3146         ][-depth:]
  3445         for fn, ln, func, _text in traceback.extract_stack()[: -skip - 1]
       
  3446     ][-depth:]
  3147     if entries:
  3447     if entries:
  3148         fnmax = max(len(entry[0]) for entry in entries)
  3448         fnmax = max(len(entry[0]) for entry in entries)
  3149         for fnln, func in entries:
  3449         for fnln, func in entries:
  3150             if line is None:
  3450             if line is None:
  3151                 yield (fnmax, fnln, func)
  3451                 yield (fnmax, fnln, func)
  3152             else:
  3452             else:
  3153                 yield line % (fnmax, fnln, func)
  3453                 yield line % (fnmax, fnln, func)
  3154 
  3454 
  3155 def debugstacktrace(msg='stacktrace', skip=0,
  3455 
  3156                     f=procutil.stderr, otherf=procutil.stdout, depth=0):
  3456 def debugstacktrace(
       
  3457     msg='stacktrace', skip=0, f=procutil.stderr, otherf=procutil.stdout, depth=0
       
  3458 ):
  3157     '''Writes a message to f (stderr) with a nicely formatted stacktrace.
  3459     '''Writes a message to f (stderr) with a nicely formatted stacktrace.
  3158     Skips the 'skip' entries closest to the call, then show 'depth' entries.
  3460     Skips the 'skip' entries closest to the call, then show 'depth' entries.
  3159     By default it will flush stdout first.
  3461     By default it will flush stdout first.
  3160     It can be used everywhere and intentionally does not require an ui object.
  3462     It can be used everywhere and intentionally does not require an ui object.
  3161     Not be used in production code but very convenient while developing.
  3463     Not be used in production code but very convenient while developing.
  3165     f.write('%s at:\n' % msg.rstrip())
  3467     f.write('%s at:\n' % msg.rstrip())
  3166     for line in getstackframes(skip + 1, depth=depth):
  3468     for line in getstackframes(skip + 1, depth=depth):
  3167         f.write(line)
  3469         f.write(line)
  3168     f.flush()
  3470     f.flush()
  3169 
  3471 
       
  3472 
  3170 class dirs(object):
  3473 class dirs(object):
  3171     '''a multiset of directory names from a dirstate or manifest'''
  3474     '''a multiset of directory names from a dirstate or manifest'''
  3172 
  3475 
  3173     def __init__(self, map, skip=None):
  3476     def __init__(self, map, skip=None):
  3174         self._dirs = {}
  3477         self._dirs = {}
  3176         if isinstance(map, dict) and skip is not None:
  3479         if isinstance(map, dict) and skip is not None:
  3177             for f, s in map.iteritems():
  3480             for f, s in map.iteritems():
  3178                 if s[0] != skip:
  3481                 if s[0] != skip:
  3179                     addpath(f)
  3482                     addpath(f)
  3180         elif skip is not None:
  3483         elif skip is not None:
  3181             raise error.ProgrammingError("skip character is only supported "
  3484             raise error.ProgrammingError(
  3182                                          "with a dict source")
  3485                 "skip character is only supported " "with a dict source"
       
  3486             )
  3183         else:
  3487         else:
  3184             for f in map:
  3488             for f in map:
  3185                 addpath(f)
  3489                 addpath(f)
  3186 
  3490 
  3187     def addpath(self, path):
  3491     def addpath(self, path):
  3204         return iter(self._dirs)
  3508         return iter(self._dirs)
  3205 
  3509 
  3206     def __contains__(self, d):
  3510     def __contains__(self, d):
  3207         return d in self._dirs
  3511         return d in self._dirs
  3208 
  3512 
       
  3513 
  3209 if safehasattr(parsers, 'dirs'):
  3514 if safehasattr(parsers, 'dirs'):
  3210     dirs = parsers.dirs
  3515     dirs = parsers.dirs
  3211 
  3516 
  3212 if rustdirs is not None:
  3517 if rustdirs is not None:
  3213     dirs = rustdirs
  3518     dirs = rustdirs
       
  3519 
  3214 
  3520 
  3215 def finddirs(path):
  3521 def finddirs(path):
  3216     pos = path.rfind('/')
  3522     pos = path.rfind('/')
  3217     while pos != -1:
  3523     while pos != -1:
  3218         yield path[:pos]
  3524         yield path[:pos]
  3220     yield ''
  3526     yield ''
  3221 
  3527 
  3222 
  3528 
  3223 # convenient shortcut
  3529 # convenient shortcut
  3224 dst = debugstacktrace
  3530 dst = debugstacktrace
       
  3531 
  3225 
  3532 
  3226 def safename(f, tag, ctx, others=None):
  3533 def safename(f, tag, ctx, others=None):
  3227     """
  3534     """
  3228     Generate a name that it is safe to rename f to in the given context.
  3535     Generate a name that it is safe to rename f to in the given context.
  3229 
  3536 
  3244     for n in itertools.count(1):
  3551     for n in itertools.count(1):
  3245         fn = '%s~%s~%s' % (f, tag, n)
  3552         fn = '%s~%s~%s' % (f, tag, n)
  3246         if fn not in ctx and fn not in others:
  3553         if fn not in ctx and fn not in others:
  3247             return fn
  3554             return fn
  3248 
  3555 
       
  3556 
  3249 def readexactly(stream, n):
  3557 def readexactly(stream, n):
  3250     '''read n bytes from stream.read and abort if less was available'''
  3558     '''read n bytes from stream.read and abort if less was available'''
  3251     s = stream.read(n)
  3559     s = stream.read(n)
  3252     if len(s) < n:
  3560     if len(s) < n:
  3253         raise error.Abort(_("stream ended unexpectedly"
  3561         raise error.Abort(
  3254                            " (got %d bytes, expected %d)")
  3562             _("stream ended unexpectedly" " (got %d bytes, expected %d)")
  3255                           % (len(s), n))
  3563             % (len(s), n)
       
  3564         )
  3256     return s
  3565     return s
       
  3566 
  3257 
  3567 
  3258 def uvarintencode(value):
  3568 def uvarintencode(value):
  3259     """Encode an unsigned integer value to a varint.
  3569     """Encode an unsigned integer value to a varint.
  3260 
  3570 
  3261     A varint is a variable length integer of 1 or more bytes. Each byte
  3571     A varint is a variable length integer of 1 or more bytes. Each byte
  3277     Traceback (most recent call last):
  3587     Traceback (most recent call last):
  3278         ...
  3588         ...
  3279     ProgrammingError: negative value for uvarint: -1
  3589     ProgrammingError: negative value for uvarint: -1
  3280     """
  3590     """
  3281     if value < 0:
  3591     if value < 0:
  3282         raise error.ProgrammingError('negative value for uvarint: %d'
  3592         raise error.ProgrammingError('negative value for uvarint: %d' % value)
  3283                                      % value)
  3593     bits = value & 0x7F
  3284     bits = value & 0x7f
       
  3285     value >>= 7
  3594     value >>= 7
  3286     bytes = []
  3595     bytes = []
  3287     while value:
  3596     while value:
  3288         bytes.append(pycompat.bytechr(0x80 | bits))
  3597         bytes.append(pycompat.bytechr(0x80 | bits))
  3289         bits = value & 0x7f
  3598         bits = value & 0x7F
  3290         value >>= 7
  3599         value >>= 7
  3291     bytes.append(pycompat.bytechr(bits))
  3600     bytes.append(pycompat.bytechr(bits))
  3292 
  3601 
  3293     return ''.join(bytes)
  3602     return ''.join(bytes)
       
  3603 
  3294 
  3604 
  3295 def uvarintdecodestream(fh):
  3605 def uvarintdecodestream(fh):
  3296     """Decode an unsigned variable length integer from a stream.
  3606     """Decode an unsigned variable length integer from a stream.
  3297 
  3607 
  3298     The passed argument is anything that has a ``.read(N)`` method.
  3608     The passed argument is anything that has a ``.read(N)`` method.
  3318     """
  3628     """
  3319     result = 0
  3629     result = 0
  3320     shift = 0
  3630     shift = 0
  3321     while True:
  3631     while True:
  3322         byte = ord(readexactly(fh, 1))
  3632         byte = ord(readexactly(fh, 1))
  3323         result |= ((byte & 0x7f) << shift)
  3633         result |= (byte & 0x7F) << shift
  3324         if not (byte & 0x80):
  3634         if not (byte & 0x80):
  3325             return result
  3635             return result
  3326         shift += 7
  3636         shift += 7