--- a/mercurial/vfs.py Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/vfs.py Sun Oct 06 09:45:02 2019 -0400
@@ -22,23 +22,26 @@
util,
)
+
def _avoidambig(path, oldstat):
"""Avoid file stat ambiguity forcibly
This function causes copying ``path`` file, if it is owned by
another (see issue5418 and issue5584 for detail).
"""
+
def checkandavoid():
newstat = util.filestat.frompath(path)
# return whether file stat ambiguity is (already) avoided
- return (not newstat.isambig(oldstat) or
- newstat.avoidambig(path, oldstat))
+ return not newstat.isambig(oldstat) or newstat.avoidambig(path, oldstat)
+
if not checkandavoid():
# simply copy to change owner of path to get privilege to
# advance mtime (see issue5418)
util.rename(util.mktempcopy(path), path)
checkandavoid()
+
class abstractvfs(object):
"""Abstract base class; cannot be instantiated"""
@@ -173,8 +176,9 @@
return os.mkdir(self.join(path))
def mkstemp(self, suffix='', prefix='tmp', dir=None):
- fd, name = pycompat.mkstemp(suffix=suffix, prefix=prefix,
- dir=self.join(dir))
+ fd, name = pycompat.mkstemp(
+ suffix=suffix, prefix=prefix, dir=self.join(dir)
+ )
dname, fname = util.split(name)
if dir:
return fd, os.path.join(dir, fname)
@@ -227,6 +231,7 @@
If ``forcibly``, this tries to remove READ-ONLY files, too.
"""
if forcibly:
+
def onerror(function, path, excinfo):
if function is not os.remove:
raise
@@ -236,10 +241,12 @@
raise
os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
os.remove(path)
+
else:
onerror = None
- return shutil.rmtree(self.join(path),
- ignore_errors=ignore_errors, onerror=onerror)
+ return shutil.rmtree(
+ self.join(path), ignore_errors=ignore_errors, onerror=onerror
+ )
def setflags(self, path, l, x):
return util.setflags(self.join(path), l, x)
@@ -255,8 +262,9 @@
util.tryunlink(self.join(path))
def unlinkpath(self, path=None, ignoremissing=False, rmdir=True):
- return util.unlinkpath(self.join(path), ignoremissing=ignoremissing,
- rmdir=rmdir)
+ return util.unlinkpath(
+ self.join(path), ignoremissing=ignoremissing, rmdir=rmdir
+ )
def utime(self, path=None, t=None):
return os.utime(self.join(path), t)
@@ -294,7 +302,8 @@
vfs = getattr(self, 'vfs', self)
if getattr(vfs, '_backgroundfilecloser', None):
raise error.Abort(
- _('can only have 1 active background file closer'))
+ _('can only have 1 active background file closer')
+ )
with backgroundfilecloser(ui, expectedcount=expectedcount) as bfc:
try:
@@ -303,6 +312,7 @@
finally:
vfs._backgroundfilecloser = None
+
class vfs(abstractvfs):
'''Operate files relative to a base directory
@@ -313,8 +323,15 @@
(b) the base directory is managed by hg and considered sort-of append-only.
See pathutil.pathauditor() for details.
'''
- def __init__(self, base, audit=True, cacheaudited=False, expandpath=False,
- realpath=False):
+
+ def __init__(
+ self,
+ base,
+ audit=True,
+ cacheaudited=False,
+ expandpath=False,
+ realpath=False,
+ ):
if expandpath:
base = util.expandpath(base)
if realpath:
@@ -324,7 +341,7 @@
if audit:
self.audit = pathutil.pathauditor(self.base, cached=cacheaudited)
else:
- self.audit = (lambda path, mode=None: True)
+ self.audit = lambda path, mode=None: True
self.createmode = None
self._trustnlink = None
self.options = {}
@@ -351,9 +368,17 @@
raise error.Abort("%s: %r" % (r, path))
self.audit(path, mode=mode)
- def __call__(self, path, mode="r", atomictemp=False, notindexed=False,
- backgroundclose=False, checkambig=False, auditpath=True,
- makeparentdirs=True):
+ def __call__(
+ self,
+ path,
+ mode="r",
+ atomictemp=False,
+ notindexed=False,
+ backgroundclose=False,
+ checkambig=False,
+ auditpath=True,
+ makeparentdirs=True,
+ ):
'''Open ``path`` file, which is relative to vfs root.
By default, parent directories are created as needed. Newly created
@@ -389,7 +414,7 @@
f = self.join(path)
if "b" not in mode:
- mode += "b" # for that other OS
+ mode += "b" # for that other OS
nlink = -1
if mode not in ('r', 'rb'):
@@ -400,8 +425,9 @@
if atomictemp:
if makeparentdirs:
util.makedirs(dirname, self.createmode, notindexed)
- return util.atomictempfile(f, mode, self.createmode,
- checkambig=checkambig)
+ return util.atomictempfile(
+ f, mode, self.createmode, checkambig=checkambig
+ )
try:
if 'w' in mode:
util.unlink(f)
@@ -412,7 +438,7 @@
with util.posixfile(f):
nlink = util.nlinks(f)
if nlink < 1:
- nlink = 2 # force mktempcopy (issue1922)
+ nlink = 2 # force mktempcopy (issue1922)
except (OSError, IOError) as e:
if e.errno != errno.ENOENT:
raise
@@ -430,16 +456,25 @@
if checkambig:
if mode in ('r', 'rb'):
- raise error.Abort(_('implementation error: mode %s is not'
- ' valid for checkambig=True') % mode)
+ raise error.Abort(
+ _(
+ 'implementation error: mode %s is not'
+ ' valid for checkambig=True'
+ )
+ % mode
+ )
fp = checkambigatclosing(fp)
- if (backgroundclose and
- isinstance(threading.currentThread(), threading._MainThread)):
+ if backgroundclose and isinstance(
+ threading.currentThread(), threading._MainThread
+ ):
if not self._backgroundfilecloser:
- raise error.Abort(_('backgroundclose can only be used when a '
- 'backgroundclosing context manager is active')
- )
+ raise error.Abort(
+ _(
+ 'backgroundclose can only be used when a '
+ 'backgroundclosing context manager is active'
+ )
+ )
fp = delayclosedfile(fp, self._backgroundfilecloser)
@@ -456,9 +491,12 @@
try:
os.symlink(src, linkname)
except OSError as err:
- raise OSError(err.errno, _('could not symlink to %r: %s') %
- (src, encoding.strtolocal(err.strerror)),
- linkname)
+ raise OSError(
+ err.errno,
+ _('could not symlink to %r: %s')
+ % (src, encoding.strtolocal(err.strerror)),
+ linkname,
+ )
else:
self.write(dst, src)
@@ -468,8 +506,10 @@
else:
return self.base
+
opener = vfs
+
class proxyvfs(abstractvfs):
def __init__(self, vfs):
self.vfs = vfs
@@ -485,6 +525,7 @@
def options(self, value):
self.vfs.options = value
+
class filtervfs(proxyvfs, abstractvfs):
'''Wrapper vfs for filtering filenames with a function.'''
@@ -501,8 +542,10 @@
else:
return self.vfs.join(path)
+
filteropener = filtervfs
+
class readonlyvfs(proxyvfs):
'''Wrapper vfs preventing any writing.'''
@@ -517,11 +560,13 @@
def join(self, path, *insidef):
return self.vfs.join(path, *insidef)
+
class closewrapbase(object):
"""Base class of wrapper, which hooks closing
Do not instantiate outside of the vfs layer.
"""
+
def __init__(self, fh):
object.__setattr__(self, r'_origfh', fh)
@@ -544,11 +589,13 @@
def close(self):
raise NotImplementedError('attempted instantiating ' + str(type(self)))
+
class delayclosedfile(closewrapbase):
"""Proxy for a file object whose close is delayed.
Do not instantiate outside of the vfs layer.
"""
+
def __init__(self, fh, closer):
super(delayclosedfile, self).__init__(fh)
object.__setattr__(self, r'_closer', closer)
@@ -559,8 +606,10 @@
def close(self):
self._closer.close(self._origfh)
+
class backgroundfilecloser(object):
"""Coordinates background closing of file handles on multiple threads."""
+
def __init__(self, ui, expectedcount=-1):
self._running = False
self._entered = False
@@ -587,8 +636,9 @@
maxqueue = ui.configint('worker', 'backgroundclosemaxqueue')
threadcount = ui.configint('worker', 'backgroundclosethreadcount')
- ui.debug('starting %d threads for background file closing\n' %
- threadcount)
+ ui.debug(
+ 'starting %d threads for background file closing\n' % threadcount
+ )
self._queue = pycompat.queue.Queue(maxsize=maxqueue)
self._running = True
@@ -629,8 +679,9 @@
def close(self, fh):
"""Schedule a file for closing."""
if not self._entered:
- raise error.Abort(_('can only call close() when context manager '
- 'active'))
+ raise error.Abort(
+ _('can only call close() when context manager ' 'active')
+ )
# If a background thread encountered an exception, raise now so we fail
# fast. Otherwise we may potentially go on for minutes until the error
@@ -647,6 +698,7 @@
self._queue.put(fh, block=True, timeout=None)
+
class checkambigatclosing(closewrapbase):
"""Proxy for a file object, to avoid ambiguity of file stat
@@ -657,6 +709,7 @@
Do not instantiate outside of the vfs layer.
"""
+
def __init__(self, fh):
super(checkambigatclosing, self).__init__(fh)
object.__setattr__(self, r'_oldstat', util.filestat.frompath(fh.name))