@@ -8,16 +8,17 @@
# GNU General Public License version 2 or any later version.
"""Mercurial utility functions and platform specific implementations.
This contains helper routines that are independent of the SCM core and
hide platform-specific details from the core.
"""
+import platform as pyplatform
import i18n
_ = i18n._
import error, osutil, encoding, parsers
import errno, shutil, sys, tempfile, traceback
import re as remod
import os, time, datetime, calendar, textwrap, signal, collections
import stat
import imp, socket, urllib
@@ -54,17 +55,16 @@ normcase = platform.normcase
normcasespec = platform.normcasespec
normcasefallback = platform.normcasefallback
openhardlinks = platform.openhardlinks
oslink = platform.oslink
parsepatchoutput = platform.parsepatchoutput
pconvert = platform.pconvert
poll = platform.poll
popen = platform.popen
-posixfile = platform.posixfile
quotecommand = platform.quotecommand
readpipe = platform.readpipe
rename = platform.rename
removedirs = platform.removedirs
samedevice = platform.samedevice
samefile = platform.samefile
samestat = platform.samestat
setbinary = platform.setbinary
@@ -801,16 +801,98 @@ def checksignature(func):
return func(*args, **kwargs)
except TypeError:
if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
raise error.SignatureError
raise
return check
+class mixedfilemodewrapper(object):
+ """Wraps a file handle when it is opened in read/write mode.
+
+ fopen() and fdopen() on Windows have a specific-to-Windows requirement
+ that files opened with mode r+, w+, or a+ make a call to a file positioning
+ function when switching between reads and writes. Without this extra call,
+ Python will raise a not very intuitive "IOError: [Errno 0] Error."
+
+ Solaris appears to suffer from a similar issue, although it will lose
+ its file seek position instead of raising an error. See issue4943.
+ This issue appears to be fixed in Python 3 on Solaris.
+
+ This class wraps posixfile instances when the file is opened in read/write
+ mode and automatically adds checks or inserts appropriate file positioning
+ calls when necessary.
+ """
+ OPNONE = 0
+ OPREAD = 1
+ OPWRITE = 2
+
+ def __init__(self, fp):
+ object.__setattr__(self, '_fp', fp)
+ object.__setattr__(self, '_lastop', 0)
+
+ def __getattr__(self, name):
+ return getattr(self._fp, name)
+
+ def __setattr__(self, name, value):
+ return self._fp.__setattr__(name, value)
+
+ def _noopseek(self):
+ self._fp.seek(0, os.SEEK_CUR)
+
+ def seek(self, *args, **kwargs):
+ object.__setattr__(self, '_lastop', self.OPNONE)
+ return self._fp.seek(*args, **kwargs)
+
+ def write(self, d):
+ if self._lastop == self.OPREAD:
+ self._noopseek()
+
+ object.__setattr__(self, '_lastop', self.OPWRITE)
+ return self._fp.write(d)
+
+ def writelines(self, *args, **kwargs):
+ if self._lastop == self.OPREAD:
+ self._noopeseek()
+
+ object.__setattr__(self, '_lastop', self.OPWRITE)
+ return self._fp.writelines(*args, **kwargs)
+
+ def read(self, *args, **kwargs):
+ if self._lastop == self.OPWRITE:
+ self._noopseek()
+
+ object.__setattr__(self, '_lastop', self.OPREAD)
+ return self._fp.read(*args, **kwargs)
+
+ def readline(self, *args, **kwargs):
+ if self._lastop == self.OPWRITE:
+ self._noopseek()
+
+ object.__setattr__(self, '_lastop', self.OPREAD)
+ return self._fp.readline(*args, **kwargs)
+
+ def readlines(self, *args, **kwargs):
+ if self._lastop == self.OPWRITE:
+ self._noopseek()
+
+ object.__setattr__(self, '_lastop', self.OPREAD)
+ return self._fp.readlines(*args, **kwargs)
+
+if os.name == 'nt' or pyplatform.system() == 'SunOS':
+ def posixfile(name, mode='r', buffering=-1):
+ fp = platform.posixfile(name, mode, buffering)
+
+ if '+' in mode:
+ return mixedfilemodewrapper(fp)
+ return fp
+else:
+ posixfile = platform.posixfile
+
def copyfile(src, dest, hardlink=False):
"copy a file, preserving mode and atime/mtime"
if os.path.lexists(dest):
unlink(dest)
# hardlinks are problematic on CIFS, quietly ignore this flag
# until we find a way to work around it cleanly (issue4546)
if False and hardlink:
try:
@@ -22,97 +22,26 @@ setsignalhandler = win32.setsignalhandle
spawndetached = win32.spawndetached
split = os.path.split
termwidth = win32.termwidth
testpid = win32.testpid
unlink = win32.unlink
umask = 0o022
-class mixedfilemodewrapper(object):
- """Wraps a file handle when it is opened in read/write mode.
-
- fopen() and fdopen() on Windows have a specific-to-Windows requirement
- that files opened with mode r+, w+, or a+ make a call to a file positioning
- function when switching between reads and writes. Without this extra call,
- Python will raise a not very intuitive "IOError: [Errno 0] Error."
-
- This class wraps posixfile instances when the file is opened in read/write
- mode and automatically adds checks or inserts appropriate file positioning
- calls when necessary.
- """
- OPNONE = 0
- OPREAD = 1
- OPWRITE = 2
-
- def __init__(self, fp):
- object.__setattr__(self, '_fp', fp)
- object.__setattr__(self, '_lastop', 0)
-
- def __getattr__(self, name):
- return getattr(self._fp, name)
-
- def __setattr__(self, name, value):
- return self._fp.__setattr__(name, value)
-
- def _noopseek(self):
- self._fp.seek(0, os.SEEK_CUR)
-
- def seek(self, *args, **kwargs):
- object.__setattr__(self, '_lastop', self.OPNONE)
- return self._fp.seek(*args, **kwargs)
-
- def write(self, d):
- if self._lastop == self.OPREAD:
- self._noopseek()
-
- object.__setattr__(self, '_lastop', self.OPWRITE)
- return self._fp.write(d)
-
- def writelines(self, *args, **kwargs):
- if self._lastop == self.OPREAD:
- self._noopeseek()
-
- object.__setattr__(self, '_lastop', self.OPWRITE)
- return self._fp.writelines(*args, **kwargs)
-
- def read(self, *args, **kwargs):
- if self._lastop == self.OPWRITE:
- self._noopseek()
-
- object.__setattr__(self, '_lastop', self.OPREAD)
- return self._fp.read(*args, **kwargs)
-
- def readline(self, *args, **kwargs):
- if self._lastop == self.OPWRITE:
- self._noopseek()
-
- object.__setattr__(self, '_lastop', self.OPREAD)
- return self._fp.readline(*args, **kwargs)
-
- def readlines(self, *args, **kwargs):
- if self._lastop == self.OPWRITE:
- self._noopseek()
-
- object.__setattr__(self, '_lastop', self.OPREAD)
- return self._fp.readlines(*args, **kwargs)
-
def posixfile(name, mode='r', buffering=-1):
'''Open a file with even more POSIX-like semantics'''
try:
fp = osutil.posixfile(name, mode, buffering) # may raise WindowsError
# The position when opening in append mode is implementation defined, so
# make it consistent with other platforms, which position at EOF.
if 'a' in mode:
fp.seek(0, os.SEEK_END)
- if '+' in mode:
- return mixedfilemodewrapper(fp)
-
return fp
except WindowsError as err:
# convert to a friendlier exception
raise IOError(err.errno, '%s: %s' % (name, err.strerror))
class winstdout(object):
'''stdout on windows misbehaves if sent through a pipe'''