--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/posix.py Thu Mar 26 13:54:44 2009 -0500
@@ -0,0 +1,222 @@
+"""
+posix.py - Posix utility function implementations for Mercurial
+
+ Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
+
+This software may be used and distributed according to the terms of
+the GNU General Public License version 2, incorporated herein by
+reference.
+"""
+
+from i18n import _
+import os, sys, osutil, errno, stat, getpass
+
+posixfile = file
+nulldev = '/dev/null'
+normpath = os.path.normpath
+samestat = os.path.samestat
+
+umask = os.umask(0)
+os.umask(umask)
+
+def openhardlinks():
+ '''return true if it is safe to hold open file handles to hardlinks'''
+ return True
+
+def rcfiles(path):
+ rcs = [os.path.join(path, 'hgrc')]
+ rcdir = os.path.join(path, 'hgrc.d')
+ try:
+ rcs.extend([os.path.join(rcdir, f)
+ for f, kind in osutil.listdir(rcdir)
+ if f.endswith(".rc")])
+ except OSError:
+ pass
+ return rcs
+
+def system_rcpath():
+ path = []
+ # old mod_python does not set sys.argv
+ if len(getattr(sys, 'argv', [])) > 0:
+ path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
+ '/../etc/mercurial'))
+ path.extend(rcfiles('/etc/mercurial'))
+ return path
+
+def user_rcpath():
+ return [os.path.expanduser('~/.hgrc')]
+
+def parse_patch_output(output_line):
+ """parses the output produced by patch and returns the file name"""
+ pf = output_line[14:]
+ if os.sys.platform == 'OpenVMS':
+ if pf[0] == '`':
+ pf = pf[1:-1] # Remove the quotes
+ else:
+ if pf.startswith("'") and pf.endswith("'") and " " in pf:
+ pf = pf[1:-1] # Remove the quotes
+ return pf
+
+def sshargs(sshcmd, host, user, port):
+ '''Build argument list for ssh'''
+ args = user and ("%s@%s" % (user, host)) or host
+ return port and ("%s -p %s" % (args, port)) or args
+
+def is_exec(f):
+ """check whether a file is executable"""
+ return (os.lstat(f).st_mode & 0100 != 0)
+
+def set_flags(f, l, x):
+ s = os.lstat(f).st_mode
+ if l:
+ if not stat.S_ISLNK(s):
+ # switch file to link
+ data = file(f).read()
+ os.unlink(f)
+ try:
+ os.symlink(data, f)
+ except:
+ # failed to make a link, rewrite file
+ file(f, "w").write(data)
+ # no chmod needed at this point
+ return
+ if stat.S_ISLNK(s):
+ # switch link to file
+ data = os.readlink(f)
+ os.unlink(f)
+ file(f, "w").write(data)
+ s = 0666 & ~umask # avoid restatting for chmod
+
+ sx = s & 0100
+ if x and not sx:
+ # Turn on +x for every +r bit when making a file executable
+ # and obey umask.
+ os.chmod(f, s | (s & 0444) >> 2 & ~umask)
+ elif not x and sx:
+ # Turn off all +x bits
+ os.chmod(f, s & 0666)
+
+def set_binary(fd):
+ pass
+
+def pconvert(path):
+ return path
+
+def localpath(path):
+ return path
+
+def shellquote(s):
+ if os.sys.platform == 'OpenVMS':
+ return '"%s"' % s
+ else:
+ return "'%s'" % s.replace("'", "'\\''")
+
+def quotecommand(cmd):
+ return cmd
+
+def popen(command, mode='r'):
+ return os.popen(command, mode)
+
+def testpid(pid):
+ '''return False if pid dead, True if running or not sure'''
+ if os.sys.platform == 'OpenVMS':
+ return True
+ try:
+ os.kill(pid, 0)
+ return True
+ except OSError, inst:
+ return inst.errno != errno.ESRCH
+
+def explain_exit(code):
+ """return a 2-tuple (desc, code) describing a process's status"""
+ if os.WIFEXITED(code):
+ val = os.WEXITSTATUS(code)
+ return _("exited with status %d") % val, val
+ elif os.WIFSIGNALED(code):
+ val = os.WTERMSIG(code)
+ return _("killed by signal %d") % val, val
+ elif os.WIFSTOPPED(code):
+ val = os.WSTOPSIG(code)
+ return _("stopped by signal %d") % val, val
+ raise ValueError(_("invalid exit code"))
+
+def isowner(fp, st=None):
+ """Return True if the file object f belongs to the current user.
+
+ The return value of a util.fstat(f) may be passed as the st argument.
+ """
+ if st is None:
+ st = fstat(fp)
+ return st.st_uid == os.getuid()
+
+def find_exe(command):
+ '''Find executable for command searching like which does.
+ If command is a basename then PATH is searched for command.
+ PATH isn't searched if command is an absolute or relative path.
+ If command isn't found None is returned.'''
+ if sys.platform == 'OpenVMS':
+ return command
+
+ def findexisting(executable):
+ 'Will return executable if existing file'
+ if os.path.exists(executable):
+ return executable
+ return None
+
+ if os.sep in command:
+ return findexisting(command)
+
+ for path in os.environ.get('PATH', '').split(os.pathsep):
+ executable = findexisting(os.path.join(path, command))
+ if executable is not None:
+ return executable
+ return None
+
+def set_signal_handler():
+ pass
+
+def statfiles(files):
+ 'Stat each file in files and yield stat or None if file does not exist.'
+ lstat = os.lstat
+ for nf in files:
+ try:
+ st = lstat(nf)
+ except OSError, err:
+ if err.errno not in (errno.ENOENT, errno.ENOTDIR):
+ raise
+ st = None
+ yield st
+
+def getuser():
+ '''return name of current user'''
+ return getpass.getuser()
+
+def expand_glob(pats):
+ '''On Windows, expand the implicit globs in a list of patterns'''
+ return list(pats)
+
+def username(uid=None):
+ """Return the name of the user with the given uid.
+
+ If uid is None, return the name of the current user."""
+
+ if uid is None:
+ uid = os.getuid()
+ try:
+ return pwd.getpwuid(uid)[0]
+ except KeyError:
+ return str(uid)
+
+def groupname(gid=None):
+ """Return the name of the group with the given gid.
+
+ If gid is None, return the name of the current group."""
+
+ if gid is None:
+ gid = os.getgid()
+ try:
+ return grp.getgrgid(gid)[0]
+ except KeyError:
+ return str(gid)
+
+
--- a/mercurial/store.py Sat Mar 14 10:46:48 2009 -0400
+++ b/mercurial/store.py Thu Mar 26 13:54:44 2009 -0500
@@ -136,7 +136,7 @@
# files in .hg/ will be created using this mode
mode = os.stat(path).st_mode
# avoid some useless chmods
- if (0777 & ~util._umask) == (0777 & mode):
+ if (0777 & ~util.umask) == (0777 & mode):
mode = None
except OSError:
mode = None
--- a/mercurial/util.py Sat Mar 14 10:46:48 2009 -0400
+++ b/mercurial/util.py Thu Mar 26 13:54:44 2009 -0500
@@ -13,7 +13,7 @@
"""
from i18n import _
-import cStringIO, errno, getpass, re, shutil, sys, tempfile, traceback, error
+import cStringIO, errno, re, shutil, sys, tempfile, traceback, error
import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
import imp, unicodedata
@@ -339,22 +339,6 @@
def always(fn): return True
def never(fn): return False
-def expand_glob(pats):
- '''On Windows, expand the implicit globs in a list of patterns'''
- if os.name != 'nt':
- return list(pats)
- ret = []
- for p in pats:
- kind, name = patkind(p, None)
- if kind is None:
- globbed = glob.glob(name)
- if globbed:
- ret.extend(globbed)
- continue
- # if we couldn't expand the glob, just keep it around
- ret.append(p)
- return ret
-
def patkind(name, default):
"""Split a string into an optional pattern kind prefix and the
actual pattern."""
@@ -858,12 +842,32 @@
# want to add "foo/bar/baz" before checking if there's a "foo/.hg"
self.auditeddir.update(prefixes)
-def _makelock_file(info, pathname):
+if os.name == 'nt':
+ from windows import *
+else:
+ from posix import *
+
+def makelock(info, pathname):
+ try:
+ return os.symlink(info, pathname)
+ except OSError, why:
+ if why.errno == errno.EEXIST:
+ raise
+ except AttributeError: # no symlink in os
+ pass
+
ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
os.write(ld, info)
os.close(ld)
-def _readlock_file(pathname):
+def readlock(pathname):
+ try:
+ return os.readlink(pathname)
+ except OSError, why:
+ if why.errno not in (errno.EINVAL, errno.ENOSYS):
+ raise
+ except AttributeError: # no symlink in os
+ pass
return posixfile(pathname).read()
def nlinks(pathname):
@@ -883,103 +887,6 @@
except AttributeError:
return os.stat(fp.name)
-posixfile = file
-
-def openhardlinks():
- '''return true if it is safe to hold open file handles to hardlinks'''
- return True
-
-def _statfiles(files):
- 'Stat each file in files and yield stat or None if file does not exist.'
- lstat = os.lstat
- for nf in files:
- try:
- st = lstat(nf)
- except OSError, err:
- if err.errno not in (errno.ENOENT, errno.ENOTDIR):
- raise
- st = None
- yield st
-
-def _statfiles_clustered(files):
- '''Stat each file in files and yield stat or None if file does not exist.
- Cluster and cache stat per directory to minimize number of OS stat calls.'''
- ncase = os.path.normcase
- sep = os.sep
- dircache = {} # dirname -> filename -> status | None if file does not exist
- for nf in files:
- nf = ncase(nf)
- pos = nf.rfind(sep)
- if pos == -1:
- dir, base = '.', nf
- else:
- dir, base = nf[:pos+1], nf[pos+1:]
- cache = dircache.get(dir, None)
- if cache is None:
- try:
- dmap = dict([(ncase(n), s)
- for n, k, s in osutil.listdir(dir, True)])
- except OSError, err:
- # handle directory not found in Python version prior to 2.5
- # Python <= 2.4 returns native Windows code 3 in errno
- # Python >= 2.5 returns ENOENT and adds winerror field
- # EINVAL is raised if dir is not a directory.
- if err.errno not in (3, errno.ENOENT, errno.EINVAL,
- errno.ENOTDIR):
- raise
- dmap = {}
- cache = dircache.setdefault(dir, dmap)
- yield cache.get(base, None)
-
-if sys.platform == 'win32':
- statfiles = _statfiles_clustered
-else:
- statfiles = _statfiles
-
-getuser_fallback = None
-
-def getuser():
- '''return name of current user'''
- try:
- return getpass.getuser()
- except ImportError:
- # import of pwd will fail on windows - try fallback
- if getuser_fallback:
- return getuser_fallback()
- # raised if win32api not available
- raise Abort(_('user name not available - set USERNAME '
- 'environment variable'))
-
-def username(uid=None):
- """Return the name of the user with the given uid.
-
- If uid is None, return the name of the current user."""
- try:
- import pwd
- if uid is None:
- uid = os.getuid()
- try:
- return pwd.getpwuid(uid)[0]
- except KeyError:
- return str(uid)
- except ImportError:
- return None
-
-def groupname(gid=None):
- """Return the name of the group with the given gid.
-
- If gid is None, return the name of the current group."""
- try:
- import grp
- if gid is None:
- gid = os.getgid()
- try:
- return grp.getgrgid(gid)[0]
- except KeyError:
- return str(gid)
- except ImportError:
- return None
-
# File system features
def checkcase(path):
@@ -1088,9 +995,6 @@
except (OSError, AttributeError):
return False
-_umask = os.umask(0)
-os.umask(_umask)
-
def needbinarypatch():
"""return True if patches should be applied in binary mode by default."""
return os.name == 'nt'
@@ -1114,379 +1018,6 @@
def lookup_reg(key, name=None, scope=None):
return None
-# Platform specific variants
-if os.name == 'nt':
- import msvcrt
- nulldev = 'NUL:'
-
- class winstdout:
- '''stdout on windows misbehaves if sent through a pipe'''
-
- def __init__(self, fp):
- self.fp = fp
-
- def __getattr__(self, key):
- return getattr(self.fp, key)
-
- def close(self):
- try:
- self.fp.close()
- except: pass
-
- def write(self, s):
- try:
- # This is workaround for "Not enough space" error on
- # writing large size of data to console.
- limit = 16000
- l = len(s)
- start = 0
- while start < l:
- end = start + limit
- self.fp.write(s[start:end])
- start = end
- except IOError, inst:
- if inst.errno != 0: raise
- self.close()
- raise IOError(errno.EPIPE, 'Broken pipe')
-
- def flush(self):
- try:
- return self.fp.flush()
- except IOError, inst:
- if inst.errno != errno.EINVAL: raise
- self.close()
- raise IOError(errno.EPIPE, 'Broken pipe')
-
- sys.stdout = winstdout(sys.stdout)
-
- def _is_win_9x():
- '''return true if run on windows 95, 98 or me.'''
- try:
- return sys.getwindowsversion()[3] == 1
- except AttributeError:
- return 'command' in os.environ.get('comspec', '')
-
- def openhardlinks():
- return not _is_win_9x and "win32api" in locals()
-
- def system_rcpath():
- try:
- return system_rcpath_win32()
- except:
- return [r'c:\mercurial\mercurial.ini']
-
- def user_rcpath():
- '''return os-specific hgrc search path to the user dir'''
- try:
- path = user_rcpath_win32()
- except:
- home = os.path.expanduser('~')
- path = [os.path.join(home, 'mercurial.ini'),
- os.path.join(home, '.hgrc')]
- userprofile = os.environ.get('USERPROFILE')
- if userprofile:
- path.append(os.path.join(userprofile, 'mercurial.ini'))
- path.append(os.path.join(userprofile, '.hgrc'))
- return path
-
- def parse_patch_output(output_line):
- """parses the output produced by patch and returns the file name"""
- pf = output_line[14:]
- if pf[0] == '`':
- pf = pf[1:-1] # Remove the quotes
- return pf
-
- def sshargs(sshcmd, host, user, port):
- '''Build argument list for ssh or Plink'''
- pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
- args = user and ("%s@%s" % (user, host)) or host
- return port and ("%s %s %s" % (args, pflag, port)) or args
-
- def testpid(pid):
- '''return False if pid dead, True if running or not known'''
- return True
-
- def set_flags(f, l, x):
- pass
-
- def set_binary(fd):
- # When run without console, pipes may expose invalid
- # fileno(), usually set to -1.
- if hasattr(fd, 'fileno') and fd.fileno() >= 0:
- msvcrt.setmode(fd.fileno(), os.O_BINARY)
-
- def pconvert(path):
- return '/'.join(splitpath(path))
-
- def localpath(path):
- return path.replace('/', '\\')
-
- def normpath(path):
- return pconvert(os.path.normpath(path))
-
- makelock = _makelock_file
- readlock = _readlock_file
-
- def samestat(s1, s2):
- return False
-
- # A sequence of backslashes is special iff it precedes a double quote:
- # - if there's an even number of backslashes, the double quote is not
- # quoted (i.e. it ends the quoted region)
- # - if there's an odd number of backslashes, the double quote is quoted
- # - in both cases, every pair of backslashes is unquoted into a single
- # backslash
- # (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
- # So, to quote a string, we must surround it in double quotes, double
- # the number of backslashes that preceed double quotes and add another
- # backslash before every double quote (being careful with the double
- # quote we've appended to the end)
- _quotere = None
- def shellquote(s):
- global _quotere
- if _quotere is None:
- _quotere = re.compile(r'(\\*)("|\\$)')
- return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
-
- def quotecommand(cmd):
- """Build a command string suitable for os.popen* calls."""
- # The extra quotes are needed because popen* runs the command
- # through the current COMSPEC. cmd.exe suppress enclosing quotes.
- return '"' + cmd + '"'
-
- def popen(command, mode='r'):
- # Work around "popen spawned process may not write to stdout
- # under windows"
- # http://bugs.python.org/issue1366
- command += " 2> %s" % nulldev
- return os.popen(quotecommand(command), mode)
-
- def explain_exit(code):
- return _("exited with status %d") % code, code
-
- # if you change this stub into a real check, please try to implement the
- # username and groupname functions above, too.
- def isowner(fp, st=None):
- return True
-
- def find_exe(command):
- '''Find executable for command searching like cmd.exe does.
- If command is a basename then PATH is searched for command.
- PATH isn't searched if command is an absolute or relative path.
- An extension from PATHEXT is found and added if not present.
- If command isn't found None is returned.'''
- pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
- pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
- if os.path.splitext(command)[1].lower() in pathexts:
- pathexts = ['']
-
- def findexisting(pathcommand):
- 'Will append extension (if needed) and return existing file'
- for ext in pathexts:
- executable = pathcommand + ext
- if os.path.exists(executable):
- return executable
- return None
-
- if os.sep in command:
- return findexisting(command)
-
- for path in os.environ.get('PATH', '').split(os.pathsep):
- executable = findexisting(os.path.join(path, command))
- if executable is not None:
- return executable
- return None
-
- def set_signal_handler():
- try:
- set_signal_handler_win32()
- except NameError:
- pass
-
- try:
- # override functions with win32 versions if possible
- from util_win32 import *
- if not _is_win_9x():
- posixfile = posixfile_nt
- except ImportError:
- pass
-
-else:
- nulldev = '/dev/null'
-
- def rcfiles(path):
- rcs = [os.path.join(path, 'hgrc')]
- rcdir = os.path.join(path, 'hgrc.d')
- try:
- rcs.extend([os.path.join(rcdir, f)
- for f, kind in osutil.listdir(rcdir)
- if f.endswith(".rc")])
- except OSError:
- pass
- return rcs
-
- def system_rcpath():
- path = []
- # old mod_python does not set sys.argv
- if len(getattr(sys, 'argv', [])) > 0:
- path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
- '/../etc/mercurial'))
- path.extend(rcfiles('/etc/mercurial'))
- return path
-
- def user_rcpath():
- return [os.path.expanduser('~/.hgrc')]
-
- def parse_patch_output(output_line):
- """parses the output produced by patch and returns the file name"""
- pf = output_line[14:]
- if os.sys.platform == 'OpenVMS':
- if pf[0] == '`':
- pf = pf[1:-1] # Remove the quotes
- else:
- if pf.startswith("'") and pf.endswith("'") and " " in pf:
- pf = pf[1:-1] # Remove the quotes
- return pf
-
- def sshargs(sshcmd, host, user, port):
- '''Build argument list for ssh'''
- args = user and ("%s@%s" % (user, host)) or host
- return port and ("%s -p %s" % (args, port)) or args
-
- def is_exec(f):
- """check whether a file is executable"""
- return (os.lstat(f).st_mode & 0100 != 0)
-
- def set_flags(f, l, x):
- s = os.lstat(f).st_mode
- if l:
- if not stat.S_ISLNK(s):
- # switch file to link
- data = file(f).read()
- os.unlink(f)
- try:
- os.symlink(data, f)
- except:
- # failed to make a link, rewrite file
- file(f, "w").write(data)
- # no chmod needed at this point
- return
- if stat.S_ISLNK(s):
- # switch link to file
- data = os.readlink(f)
- os.unlink(f)
- file(f, "w").write(data)
- s = 0666 & ~_umask # avoid restatting for chmod
-
- sx = s & 0100
- if x and not sx:
- # Turn on +x for every +r bit when making a file executable
- # and obey umask.
- os.chmod(f, s | (s & 0444) >> 2 & ~_umask)
- elif not x and sx:
- # Turn off all +x bits
- os.chmod(f, s & 0666)
-
- def set_binary(fd):
- pass
-
- def pconvert(path):
- return path
-
- def localpath(path):
- return path
-
- normpath = os.path.normpath
- samestat = os.path.samestat
-
- def makelock(info, pathname):
- try:
- os.symlink(info, pathname)
- except OSError, why:
- if why.errno == errno.EEXIST:
- raise
- else:
- _makelock_file(info, pathname)
-
- def readlock(pathname):
- try:
- return os.readlink(pathname)
- except OSError, why:
- if why.errno in (errno.EINVAL, errno.ENOSYS):
- return _readlock_file(pathname)
- else:
- raise
-
- def shellquote(s):
- if os.sys.platform == 'OpenVMS':
- return '"%s"' % s
- else:
- return "'%s'" % s.replace("'", "'\\''")
-
- def quotecommand(cmd):
- return cmd
-
- def popen(command, mode='r'):
- return os.popen(command, mode)
-
- def testpid(pid):
- '''return False if pid dead, True if running or not sure'''
- if os.sys.platform == 'OpenVMS':
- return True
- try:
- os.kill(pid, 0)
- return True
- except OSError, inst:
- return inst.errno != errno.ESRCH
-
- def explain_exit(code):
- """return a 2-tuple (desc, code) describing a process's status"""
- if os.WIFEXITED(code):
- val = os.WEXITSTATUS(code)
- return _("exited with status %d") % val, val
- elif os.WIFSIGNALED(code):
- val = os.WTERMSIG(code)
- return _("killed by signal %d") % val, val
- elif os.WIFSTOPPED(code):
- val = os.WSTOPSIG(code)
- return _("stopped by signal %d") % val, val
- raise ValueError(_("invalid exit code"))
-
- def isowner(fp, st=None):
- """Return True if the file object f belongs to the current user.
-
- The return value of a util.fstat(f) may be passed as the st argument.
- """
- if st is None:
- st = fstat(fp)
- return st.st_uid == os.getuid()
-
- def find_exe(command):
- '''Find executable for command searching like which does.
- If command is a basename then PATH is searched for command.
- PATH isn't searched if command is an absolute or relative path.
- If command isn't found None is returned.'''
- if sys.platform == 'OpenVMS':
- return command
-
- def findexisting(executable):
- 'Will return executable if existing file'
- if os.path.exists(executable):
- return executable
- return None
-
- if os.sep in command:
- return findexisting(command)
-
- for path in os.environ.get('PATH', '').split(os.pathsep):
- executable = findexisting(os.path.join(path, command))
- if executable is not None:
- return executable
- return None
-
- def set_signal_handler():
- pass
-
def mktempcopy(name, emptyok=False, createmode=None):
"""Create a temporary file with the same contents from name
@@ -1510,7 +1041,7 @@
raise
st_mode = createmode
if st_mode is None:
- st_mode = ~_umask
+ st_mode = ~umask
st_mode &= 0666
os.chmod(temp, st_mode)
if emptyok:
--- a/mercurial/util_win32.py Sat Mar 14 10:46:48 2009 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,375 +0,0 @@
-# util_win32.py - utility functions that use win32 API
-#
-# Copyright 2005 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 GNU General Public License, incorporated herein by reference.
-
-# Mark Hammond's win32all package allows better functionality on
-# Windows. this module overrides definitions in util.py. if not
-# available, import of this module will fail, and generic code will be
-# used.
-
-import win32api
-
-import errno, os, sys, pywintypes, win32con, win32file, win32process
-import cStringIO, winerror
-import osutil
-import util
-from win32com.shell import shell,shellcon
-
-class WinError(Exception):
- winerror_map = {
- winerror.ERROR_ACCESS_DENIED: errno.EACCES,
- winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES,
- winerror.ERROR_ACCOUNT_RESTRICTION: errno.EACCES,
- winerror.ERROR_ALREADY_ASSIGNED: errno.EBUSY,
- winerror.ERROR_ALREADY_EXISTS: errno.EEXIST,
- winerror.ERROR_ARITHMETIC_OVERFLOW: errno.ERANGE,
- winerror.ERROR_BAD_COMMAND: errno.EIO,
- winerror.ERROR_BAD_DEVICE: errno.ENODEV,
- winerror.ERROR_BAD_DRIVER_LEVEL: errno.ENXIO,
- winerror.ERROR_BAD_EXE_FORMAT: errno.ENOEXEC,
- winerror.ERROR_BAD_FORMAT: errno.ENOEXEC,
- winerror.ERROR_BAD_LENGTH: errno.EINVAL,
- winerror.ERROR_BAD_PATHNAME: errno.ENOENT,
- winerror.ERROR_BAD_PIPE: errno.EPIPE,
- winerror.ERROR_BAD_UNIT: errno.ENODEV,
- winerror.ERROR_BAD_USERNAME: errno.EINVAL,
- winerror.ERROR_BROKEN_PIPE: errno.EPIPE,
- winerror.ERROR_BUFFER_OVERFLOW: errno.ENAMETOOLONG,
- winerror.ERROR_BUSY: errno.EBUSY,
- winerror.ERROR_BUSY_DRIVE: errno.EBUSY,
- winerror.ERROR_CALL_NOT_IMPLEMENTED: errno.ENOSYS,
- winerror.ERROR_CANNOT_MAKE: errno.EACCES,
- winerror.ERROR_CANTOPEN: errno.EIO,
- winerror.ERROR_CANTREAD: errno.EIO,
- winerror.ERROR_CANTWRITE: errno.EIO,
- winerror.ERROR_CRC: errno.EIO,
- winerror.ERROR_CURRENT_DIRECTORY: errno.EACCES,
- winerror.ERROR_DEVICE_IN_USE: errno.EBUSY,
- winerror.ERROR_DEV_NOT_EXIST: errno.ENODEV,
- winerror.ERROR_DIRECTORY: errno.EINVAL,
- winerror.ERROR_DIR_NOT_EMPTY: errno.ENOTEMPTY,
- winerror.ERROR_DISK_CHANGE: errno.EIO,
- winerror.ERROR_DISK_FULL: errno.ENOSPC,
- winerror.ERROR_DRIVE_LOCKED: errno.EBUSY,
- winerror.ERROR_ENVVAR_NOT_FOUND: errno.EINVAL,
- winerror.ERROR_EXE_MARKED_INVALID: errno.ENOEXEC,
- winerror.ERROR_FILENAME_EXCED_RANGE: errno.ENAMETOOLONG,
- winerror.ERROR_FILE_EXISTS: errno.EEXIST,
- winerror.ERROR_FILE_INVALID: errno.ENODEV,
- winerror.ERROR_FILE_NOT_FOUND: errno.ENOENT,
- winerror.ERROR_GEN_FAILURE: errno.EIO,
- winerror.ERROR_HANDLE_DISK_FULL: errno.ENOSPC,
- winerror.ERROR_INSUFFICIENT_BUFFER: errno.ENOMEM,
- winerror.ERROR_INVALID_ACCESS: errno.EACCES,
- winerror.ERROR_INVALID_ADDRESS: errno.EFAULT,
- winerror.ERROR_INVALID_BLOCK: errno.EFAULT,
- winerror.ERROR_INVALID_DATA: errno.EINVAL,
- winerror.ERROR_INVALID_DRIVE: errno.ENODEV,
- winerror.ERROR_INVALID_EXE_SIGNATURE: errno.ENOEXEC,
- winerror.ERROR_INVALID_FLAGS: errno.EINVAL,
- winerror.ERROR_INVALID_FUNCTION: errno.ENOSYS,
- winerror.ERROR_INVALID_HANDLE: errno.EBADF,
- winerror.ERROR_INVALID_LOGON_HOURS: errno.EACCES,
- winerror.ERROR_INVALID_NAME: errno.EINVAL,
- winerror.ERROR_INVALID_OWNER: errno.EINVAL,
- winerror.ERROR_INVALID_PARAMETER: errno.EINVAL,
- winerror.ERROR_INVALID_PASSWORD: errno.EPERM,
- winerror.ERROR_INVALID_PRIMARY_GROUP: errno.EINVAL,
- winerror.ERROR_INVALID_SIGNAL_NUMBER: errno.EINVAL,
- winerror.ERROR_INVALID_TARGET_HANDLE: errno.EIO,
- winerror.ERROR_INVALID_WORKSTATION: errno.EACCES,
- winerror.ERROR_IO_DEVICE: errno.EIO,
- winerror.ERROR_IO_INCOMPLETE: errno.EINTR,
- winerror.ERROR_LOCKED: errno.EBUSY,
- winerror.ERROR_LOCK_VIOLATION: errno.EACCES,
- winerror.ERROR_LOGON_FAILURE: errno.EACCES,
- winerror.ERROR_MAPPED_ALIGNMENT: errno.EINVAL,
- winerror.ERROR_META_EXPANSION_TOO_LONG: errno.E2BIG,
- winerror.ERROR_MORE_DATA: errno.EPIPE,
- winerror.ERROR_NEGATIVE_SEEK: errno.ESPIPE,
- winerror.ERROR_NOACCESS: errno.EFAULT,
- winerror.ERROR_NONE_MAPPED: errno.EINVAL,
- winerror.ERROR_NOT_ENOUGH_MEMORY: errno.ENOMEM,
- winerror.ERROR_NOT_READY: errno.EAGAIN,
- winerror.ERROR_NOT_SAME_DEVICE: errno.EXDEV,
- winerror.ERROR_NO_DATA: errno.EPIPE,
- winerror.ERROR_NO_MORE_SEARCH_HANDLES: errno.EIO,
- winerror.ERROR_NO_PROC_SLOTS: errno.EAGAIN,
- winerror.ERROR_NO_SUCH_PRIVILEGE: errno.EACCES,
- winerror.ERROR_OPEN_FAILED: errno.EIO,
- winerror.ERROR_OPEN_FILES: errno.EBUSY,
- winerror.ERROR_OPERATION_ABORTED: errno.EINTR,
- winerror.ERROR_OUTOFMEMORY: errno.ENOMEM,
- winerror.ERROR_PASSWORD_EXPIRED: errno.EACCES,
- winerror.ERROR_PATH_BUSY: errno.EBUSY,
- winerror.ERROR_PATH_NOT_FOUND: errno.ENOENT,
- winerror.ERROR_PIPE_BUSY: errno.EBUSY,
- winerror.ERROR_PIPE_CONNECTED: errno.EPIPE,
- winerror.ERROR_PIPE_LISTENING: errno.EPIPE,
- winerror.ERROR_PIPE_NOT_CONNECTED: errno.EPIPE,
- winerror.ERROR_PRIVILEGE_NOT_HELD: errno.EACCES,
- winerror.ERROR_READ_FAULT: errno.EIO,
- winerror.ERROR_SEEK: errno.EIO,
- winerror.ERROR_SEEK_ON_DEVICE: errno.ESPIPE,
- winerror.ERROR_SHARING_BUFFER_EXCEEDED: errno.ENFILE,
- winerror.ERROR_SHARING_VIOLATION: errno.EACCES,
- winerror.ERROR_STACK_OVERFLOW: errno.ENOMEM,
- winerror.ERROR_SWAPERROR: errno.ENOENT,
- winerror.ERROR_TOO_MANY_MODULES: errno.EMFILE,
- winerror.ERROR_TOO_MANY_OPEN_FILES: errno.EMFILE,
- winerror.ERROR_UNRECOGNIZED_MEDIA: errno.ENXIO,
- winerror.ERROR_UNRECOGNIZED_VOLUME: errno.ENODEV,
- winerror.ERROR_WAIT_NO_CHILDREN: errno.ECHILD,
- winerror.ERROR_WRITE_FAULT: errno.EIO,
- winerror.ERROR_WRITE_PROTECT: errno.EROFS,
- }
-
- def __init__(self, err):
- self.win_errno, self.win_function, self.win_strerror = err
- if self.win_strerror.endswith('.'):
- self.win_strerror = self.win_strerror[:-1]
-
-class WinIOError(WinError, IOError):
- def __init__(self, err, filename=None):
- WinError.__init__(self, err)
- IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
- self.win_strerror)
- self.filename = filename
-
-class WinOSError(WinError, OSError):
- def __init__(self, err):
- WinError.__init__(self, err)
- OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
- self.win_strerror)
-
-def os_link(src, dst):
- try:
- win32file.CreateHardLink(dst, src)
- # CreateHardLink sometimes succeeds on mapped drives but
- # following nlinks() returns 1. Check it now and bail out.
- if nlinks(src) < 2:
- try:
- win32file.DeleteFile(dst)
- except:
- pass
- # Fake hardlinking error
- raise WinOSError((18, 'CreateHardLink', 'The system cannot '
- 'move the file to a different disk drive'))
- except pywintypes.error, details:
- raise WinOSError(details)
- except NotImplementedError: # Another fake error win Win98
- raise WinOSError((18, 'CreateHardLink', 'Hardlinking not supported'))
-
-def nlinks(pathname):
- """Return number of hardlinks for the given file."""
- try:
- fh = win32file.CreateFile(pathname,
- win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
- None, win32file.OPEN_EXISTING, 0, None)
- res = win32file.GetFileInformationByHandle(fh)
- fh.Close()
- return res[7]
- except pywintypes.error:
- return os.lstat(pathname).st_nlink
-
-def testpid(pid):
- '''return True if pid is still running or unable to
- determine, False otherwise'''
- try:
- handle = win32api.OpenProcess(
- win32con.PROCESS_QUERY_INFORMATION, False, pid)
- if handle:
- status = win32process.GetExitCodeProcess(handle)
- return status == win32con.STILL_ACTIVE
- except pywintypes.error, details:
- return details[0] != winerror.ERROR_INVALID_PARAMETER
- return True
-
-def lookup_reg(key, valname=None, scope=None):
- ''' Look up a key/value name in the Windows registry.
-
- valname: value name. If unspecified, the default value for the key
- is used.
- scope: optionally specify scope for registry lookup, this can be
- a sequence of scopes to look up in order. Default (CURRENT_USER,
- LOCAL_MACHINE).
- '''
- try:
- from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
- QueryValueEx, OpenKey
- except ImportError:
- return None
-
- if scope is None:
- scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
- elif not isinstance(scope, (list, tuple)):
- scope = (scope,)
- for s in scope:
- try:
- val = QueryValueEx(OpenKey(s, key), valname)[0]
- # never let a Unicode string escape into the wild
- return util.tolocal(val.encode('UTF-8'))
- except EnvironmentError:
- pass
-
-def system_rcpath_win32():
- '''return default os-specific hgrc search path'''
- proc = win32api.GetCurrentProcess()
- try:
- # This will fail on windows < NT
- filename = win32process.GetModuleFileNameEx(proc, 0)
- except:
- filename = win32api.GetModuleFileName(0)
- # Use mercurial.ini found in directory with hg.exe
- progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
- if os.path.isfile(progrc):
- return [progrc]
- # else look for a system rcpath in the registry
- try:
- value = win32api.RegQueryValue(
- win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
- rcpath = []
- for p in value.split(os.pathsep):
- if p.lower().endswith('mercurial.ini'):
- rcpath.append(p)
- elif os.path.isdir(p):
- for f, kind in osutil.listdir(p):
- if f.endswith('.rc'):
- rcpath.append(os.path.join(p, f))
- return rcpath
- except pywintypes.error:
- return []
-
-def user_rcpath_win32():
- '''return os-specific hgrc search path to the user dir'''
- userdir = os.path.expanduser('~')
- if sys.getwindowsversion()[3] != 2 and userdir == '~':
- # We are on win < nt: fetch the APPDATA directory location and use
- # the parent directory as the user home dir.
- appdir = shell.SHGetPathFromIDList(
- shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
- userdir = os.path.dirname(appdir)
- return [os.path.join(userdir, 'mercurial.ini'),
- os.path.join(userdir, '.hgrc')]
-
-class posixfile_nt(object):
- '''file object with posix-like semantics. on windows, normal
- files can not be deleted or renamed if they are open. must open
- with win32file.FILE_SHARE_DELETE. this flag does not exist on
- windows < nt, so do not use this class there.'''
-
- # tried to use win32file._open_osfhandle to pass fd to os.fdopen,
- # but does not work at all. wrap win32 file api instead.
-
- def __init__(self, name, mode='rb'):
- self.closed = False
- self.name = name
- self.mode = mode
- access = 0
- if 'r' in mode or '+' in mode:
- access |= win32file.GENERIC_READ
- if 'w' in mode or 'a' in mode or '+' in mode:
- access |= win32file.GENERIC_WRITE
- if 'r' in mode:
- creation = win32file.OPEN_EXISTING
- elif 'a' in mode:
- creation = win32file.OPEN_ALWAYS
- else:
- creation = win32file.CREATE_ALWAYS
- try:
- self.handle = win32file.CreateFile(name,
- access,
- win32file.FILE_SHARE_READ |
- win32file.FILE_SHARE_WRITE |
- win32file.FILE_SHARE_DELETE,
- None,
- creation,
- win32file.FILE_ATTRIBUTE_NORMAL,
- 0)
- except pywintypes.error, err:
- raise WinIOError(err, name)
-
- def __iter__(self):
- for line in self.readlines():
- yield line
-
- def read(self, count=-1):
- try:
- cs = cStringIO.StringIO()
- while count:
- wincount = int(count)
- if wincount == -1:
- wincount = 1048576
- val, data = win32file.ReadFile(self.handle, wincount)
- if not data: break
- cs.write(data)
- if count != -1:
- count -= len(data)
- return cs.getvalue()
- except pywintypes.error, err:
- raise WinIOError(err)
-
- def readlines(self, sizehint=None):
- # splitlines() splits on single '\r' while readlines()
- # does not. cStringIO has a well behaving readlines() and is fast.
- return cStringIO.StringIO(self.read()).readlines()
-
- def write(self, data):
- try:
- if 'a' in self.mode:
- win32file.SetFilePointer(self.handle, 0, win32file.FILE_END)
- nwrit = 0
- while nwrit < len(data):
- val, nwrit = win32file.WriteFile(self.handle, data)
- data = data[nwrit:]
- except pywintypes.error, err:
- raise WinIOError(err)
-
- def writelines(self, sequence):
- for s in sequence:
- self.write(s)
-
- def seek(self, pos, whence=0):
- try:
- win32file.SetFilePointer(self.handle, int(pos), whence)
- except pywintypes.error, err:
- raise WinIOError(err)
-
- def tell(self):
- try:
- return win32file.SetFilePointer(self.handle, 0,
- win32file.FILE_CURRENT)
- except pywintypes.error, err:
- raise WinIOError(err)
-
- def close(self):
- if not self.closed:
- self.handle = None
- self.closed = True
-
- def flush(self):
- # we have no application-level buffering
- pass
-
- def truncate(self, pos=0):
- try:
- win32file.SetFilePointer(self.handle, int(pos),
- win32file.FILE_BEGIN)
- win32file.SetEndOfFile(self.handle)
- except pywintypes.error, err:
- raise WinIOError(err)
-
-getuser_fallback = win32api.GetUserName
-
-def set_signal_handler_win32():
- """Register a termination handler for console events including
- CTRL+C. python signal handlers do not work well with socket
- operations.
- """
- def handler(event):
- win32process.ExitProcess(1)
- win32api.SetConsoleCtrlHandler(handler)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/win32.py Thu Mar 26 13:54:44 2009 -0500
@@ -0,0 +1,379 @@
+'''
+win32.py - utility functions that use win32 API
+
+Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
+
+This software may be used and distributed according to the terms of
+the GNU General Public License, incorporated herein by reference.
+
+Mark Hammond's win32all package allows better functionality on
+Windows. this module overrides definitions in util.py. if not
+available, import of this module will fail, and generic code will be
+used.
+'''
+
+import win32api
+
+import errno, os, sys, pywintypes, win32con, win32file, win32process
+import cStringIO, winerror
+import osutil
+import util
+from win32com.shell import shell,shellcon
+
+class WinError(Exception):
+ winerror_map = {
+ winerror.ERROR_ACCESS_DENIED: errno.EACCES,
+ winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES,
+ winerror.ERROR_ACCOUNT_RESTRICTION: errno.EACCES,
+ winerror.ERROR_ALREADY_ASSIGNED: errno.EBUSY,
+ winerror.ERROR_ALREADY_EXISTS: errno.EEXIST,
+ winerror.ERROR_ARITHMETIC_OVERFLOW: errno.ERANGE,
+ winerror.ERROR_BAD_COMMAND: errno.EIO,
+ winerror.ERROR_BAD_DEVICE: errno.ENODEV,
+ winerror.ERROR_BAD_DRIVER_LEVEL: errno.ENXIO,
+ winerror.ERROR_BAD_EXE_FORMAT: errno.ENOEXEC,
+ winerror.ERROR_BAD_FORMAT: errno.ENOEXEC,
+ winerror.ERROR_BAD_LENGTH: errno.EINVAL,
+ winerror.ERROR_BAD_PATHNAME: errno.ENOENT,
+ winerror.ERROR_BAD_PIPE: errno.EPIPE,
+ winerror.ERROR_BAD_UNIT: errno.ENODEV,
+ winerror.ERROR_BAD_USERNAME: errno.EINVAL,
+ winerror.ERROR_BROKEN_PIPE: errno.EPIPE,
+ winerror.ERROR_BUFFER_OVERFLOW: errno.ENAMETOOLONG,
+ winerror.ERROR_BUSY: errno.EBUSY,
+ winerror.ERROR_BUSY_DRIVE: errno.EBUSY,
+ winerror.ERROR_CALL_NOT_IMPLEMENTED: errno.ENOSYS,
+ winerror.ERROR_CANNOT_MAKE: errno.EACCES,
+ winerror.ERROR_CANTOPEN: errno.EIO,
+ winerror.ERROR_CANTREAD: errno.EIO,
+ winerror.ERROR_CANTWRITE: errno.EIO,
+ winerror.ERROR_CRC: errno.EIO,
+ winerror.ERROR_CURRENT_DIRECTORY: errno.EACCES,
+ winerror.ERROR_DEVICE_IN_USE: errno.EBUSY,
+ winerror.ERROR_DEV_NOT_EXIST: errno.ENODEV,
+ winerror.ERROR_DIRECTORY: errno.EINVAL,
+ winerror.ERROR_DIR_NOT_EMPTY: errno.ENOTEMPTY,
+ winerror.ERROR_DISK_CHANGE: errno.EIO,
+ winerror.ERROR_DISK_FULL: errno.ENOSPC,
+ winerror.ERROR_DRIVE_LOCKED: errno.EBUSY,
+ winerror.ERROR_ENVVAR_NOT_FOUND: errno.EINVAL,
+ winerror.ERROR_EXE_MARKED_INVALID: errno.ENOEXEC,
+ winerror.ERROR_FILENAME_EXCED_RANGE: errno.ENAMETOOLONG,
+ winerror.ERROR_FILE_EXISTS: errno.EEXIST,
+ winerror.ERROR_FILE_INVALID: errno.ENODEV,
+ winerror.ERROR_FILE_NOT_FOUND: errno.ENOENT,
+ winerror.ERROR_GEN_FAILURE: errno.EIO,
+ winerror.ERROR_HANDLE_DISK_FULL: errno.ENOSPC,
+ winerror.ERROR_INSUFFICIENT_BUFFER: errno.ENOMEM,
+ winerror.ERROR_INVALID_ACCESS: errno.EACCES,
+ winerror.ERROR_INVALID_ADDRESS: errno.EFAULT,
+ winerror.ERROR_INVALID_BLOCK: errno.EFAULT,
+ winerror.ERROR_INVALID_DATA: errno.EINVAL,
+ winerror.ERROR_INVALID_DRIVE: errno.ENODEV,
+ winerror.ERROR_INVALID_EXE_SIGNATURE: errno.ENOEXEC,
+ winerror.ERROR_INVALID_FLAGS: errno.EINVAL,
+ winerror.ERROR_INVALID_FUNCTION: errno.ENOSYS,
+ winerror.ERROR_INVALID_HANDLE: errno.EBADF,
+ winerror.ERROR_INVALID_LOGON_HOURS: errno.EACCES,
+ winerror.ERROR_INVALID_NAME: errno.EINVAL,
+ winerror.ERROR_INVALID_OWNER: errno.EINVAL,
+ winerror.ERROR_INVALID_PARAMETER: errno.EINVAL,
+ winerror.ERROR_INVALID_PASSWORD: errno.EPERM,
+ winerror.ERROR_INVALID_PRIMARY_GROUP: errno.EINVAL,
+ winerror.ERROR_INVALID_SIGNAL_NUMBER: errno.EINVAL,
+ winerror.ERROR_INVALID_TARGET_HANDLE: errno.EIO,
+ winerror.ERROR_INVALID_WORKSTATION: errno.EACCES,
+ winerror.ERROR_IO_DEVICE: errno.EIO,
+ winerror.ERROR_IO_INCOMPLETE: errno.EINTR,
+ winerror.ERROR_LOCKED: errno.EBUSY,
+ winerror.ERROR_LOCK_VIOLATION: errno.EACCES,
+ winerror.ERROR_LOGON_FAILURE: errno.EACCES,
+ winerror.ERROR_MAPPED_ALIGNMENT: errno.EINVAL,
+ winerror.ERROR_META_EXPANSION_TOO_LONG: errno.E2BIG,
+ winerror.ERROR_MORE_DATA: errno.EPIPE,
+ winerror.ERROR_NEGATIVE_SEEK: errno.ESPIPE,
+ winerror.ERROR_NOACCESS: errno.EFAULT,
+ winerror.ERROR_NONE_MAPPED: errno.EINVAL,
+ winerror.ERROR_NOT_ENOUGH_MEMORY: errno.ENOMEM,
+ winerror.ERROR_NOT_READY: errno.EAGAIN,
+ winerror.ERROR_NOT_SAME_DEVICE: errno.EXDEV,
+ winerror.ERROR_NO_DATA: errno.EPIPE,
+ winerror.ERROR_NO_MORE_SEARCH_HANDLES: errno.EIO,
+ winerror.ERROR_NO_PROC_SLOTS: errno.EAGAIN,
+ winerror.ERROR_NO_SUCH_PRIVILEGE: errno.EACCES,
+ winerror.ERROR_OPEN_FAILED: errno.EIO,
+ winerror.ERROR_OPEN_FILES: errno.EBUSY,
+ winerror.ERROR_OPERATION_ABORTED: errno.EINTR,
+ winerror.ERROR_OUTOFMEMORY: errno.ENOMEM,
+ winerror.ERROR_PASSWORD_EXPIRED: errno.EACCES,
+ winerror.ERROR_PATH_BUSY: errno.EBUSY,
+ winerror.ERROR_PATH_NOT_FOUND: errno.ENOENT,
+ winerror.ERROR_PIPE_BUSY: errno.EBUSY,
+ winerror.ERROR_PIPE_CONNECTED: errno.EPIPE,
+ winerror.ERROR_PIPE_LISTENING: errno.EPIPE,
+ winerror.ERROR_PIPE_NOT_CONNECTED: errno.EPIPE,
+ winerror.ERROR_PRIVILEGE_NOT_HELD: errno.EACCES,
+ winerror.ERROR_READ_FAULT: errno.EIO,
+ winerror.ERROR_SEEK: errno.EIO,
+ winerror.ERROR_SEEK_ON_DEVICE: errno.ESPIPE,
+ winerror.ERROR_SHARING_BUFFER_EXCEEDED: errno.ENFILE,
+ winerror.ERROR_SHARING_VIOLATION: errno.EACCES,
+ winerror.ERROR_STACK_OVERFLOW: errno.ENOMEM,
+ winerror.ERROR_SWAPERROR: errno.ENOENT,
+ winerror.ERROR_TOO_MANY_MODULES: errno.EMFILE,
+ winerror.ERROR_TOO_MANY_OPEN_FILES: errno.EMFILE,
+ winerror.ERROR_UNRECOGNIZED_MEDIA: errno.ENXIO,
+ winerror.ERROR_UNRECOGNIZED_VOLUME: errno.ENODEV,
+ winerror.ERROR_WAIT_NO_CHILDREN: errno.ECHILD,
+ winerror.ERROR_WRITE_FAULT: errno.EIO,
+ winerror.ERROR_WRITE_PROTECT: errno.EROFS,
+ }
+
+ def __init__(self, err):
+ self.win_errno, self.win_function, self.win_strerror = err
+ if self.win_strerror.endswith('.'):
+ self.win_strerror = self.win_strerror[:-1]
+
+class WinIOError(WinError, IOError):
+ def __init__(self, err, filename=None):
+ WinError.__init__(self, err)
+ IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
+ self.win_strerror)
+ self.filename = filename
+
+class WinOSError(WinError, OSError):
+ def __init__(self, err):
+ WinError.__init__(self, err)
+ OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
+ self.win_strerror)
+
+def os_link(src, dst):
+ try:
+ win32file.CreateHardLink(dst, src)
+ # CreateHardLink sometimes succeeds on mapped drives but
+ # following nlinks() returns 1. Check it now and bail out.
+ if nlinks(src) < 2:
+ try:
+ win32file.DeleteFile(dst)
+ except:
+ pass
+ # Fake hardlinking error
+ raise WinOSError((18, 'CreateHardLink', 'The system cannot '
+ 'move the file to a different disk drive'))
+ except pywintypes.error, details:
+ raise WinOSError(details)
+ except NotImplementedError: # Another fake error win Win98
+ raise WinOSError((18, 'CreateHardLink', 'Hardlinking not supported'))
+
+def nlinks(pathname):
+ """Return number of hardlinks for the given file."""
+ try:
+ fh = win32file.CreateFile(pathname,
+ win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
+ None, win32file.OPEN_EXISTING, 0, None)
+ res = win32file.GetFileInformationByHandle(fh)
+ fh.Close()
+ return res[7]
+ except pywintypes.error:
+ return os.lstat(pathname).st_nlink
+
+def testpid(pid):
+ '''return True if pid is still running or unable to
+ determine, False otherwise'''
+ try:
+ handle = win32api.OpenProcess(
+ win32con.PROCESS_QUERY_INFORMATION, False, pid)
+ if handle:
+ status = win32process.GetExitCodeProcess(handle)
+ return status == win32con.STILL_ACTIVE
+ except pywintypes.error, details:
+ return details[0] != winerror.ERROR_INVALID_PARAMETER
+ return True
+
+def lookup_reg(key, valname=None, scope=None):
+ ''' Look up a key/value name in the Windows registry.
+
+ valname: value name. If unspecified, the default value for the key
+ is used.
+ scope: optionally specify scope for registry lookup, this can be
+ a sequence of scopes to look up in order. Default (CURRENT_USER,
+ LOCAL_MACHINE).
+ '''
+ try:
+ from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
+ QueryValueEx, OpenKey
+ except ImportError:
+ return None
+
+ if scope is None:
+ scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
+ elif not isinstance(scope, (list, tuple)):
+ scope = (scope,)
+ for s in scope:
+ try:
+ val = QueryValueEx(OpenKey(s, key), valname)[0]
+ # never let a Unicode string escape into the wild
+ return util.tolocal(val.encode('UTF-8'))
+ except EnvironmentError:
+ pass
+
+def system_rcpath_win32():
+ '''return default os-specific hgrc search path'''
+ proc = win32api.GetCurrentProcess()
+ try:
+ # This will fail on windows < NT
+ filename = win32process.GetModuleFileNameEx(proc, 0)
+ except:
+ filename = win32api.GetModuleFileName(0)
+ # Use mercurial.ini found in directory with hg.exe
+ progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
+ if os.path.isfile(progrc):
+ return [progrc]
+ # else look for a system rcpath in the registry
+ try:
+ value = win32api.RegQueryValue(
+ win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
+ rcpath = []
+ for p in value.split(os.pathsep):
+ if p.lower().endswith('mercurial.ini'):
+ rcpath.append(p)
+ elif os.path.isdir(p):
+ for f, kind in osutil.listdir(p):
+ if f.endswith('.rc'):
+ rcpath.append(os.path.join(p, f))
+ return rcpath
+ except pywintypes.error:
+ return []
+
+def user_rcpath_win32():
+ '''return os-specific hgrc search path to the user dir'''
+ userdir = os.path.expanduser('~')
+ if sys.getwindowsversion()[3] != 2 and userdir == '~':
+ # We are on win < nt: fetch the APPDATA directory location and use
+ # the parent directory as the user home dir.
+ appdir = shell.SHGetPathFromIDList(
+ shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
+ userdir = os.path.dirname(appdir)
+ return [os.path.join(userdir, 'mercurial.ini'),
+ os.path.join(userdir, '.hgrc')]
+
+class posixfile_nt(object):
+ '''file object with posix-like semantics. on windows, normal
+ files can not be deleted or renamed if they are open. must open
+ with win32file.FILE_SHARE_DELETE. this flag does not exist on
+ windows < nt, so do not use this class there.'''
+
+ # tried to use win32file._open_osfhandle to pass fd to os.fdopen,
+ # but does not work at all. wrap win32 file api instead.
+
+ def __init__(self, name, mode='rb'):
+ self.closed = False
+ self.name = name
+ self.mode = mode
+ access = 0
+ if 'r' in mode or '+' in mode:
+ access |= win32file.GENERIC_READ
+ if 'w' in mode or 'a' in mode or '+' in mode:
+ access |= win32file.GENERIC_WRITE
+ if 'r' in mode:
+ creation = win32file.OPEN_EXISTING
+ elif 'a' in mode:
+ creation = win32file.OPEN_ALWAYS
+ else:
+ creation = win32file.CREATE_ALWAYS
+ try:
+ self.handle = win32file.CreateFile(name,
+ access,
+ win32file.FILE_SHARE_READ |
+ win32file.FILE_SHARE_WRITE |
+ win32file.FILE_SHARE_DELETE,
+ None,
+ creation,
+ win32file.FILE_ATTRIBUTE_NORMAL,
+ 0)
+ except pywintypes.error, err:
+ raise WinIOError(err, name)
+
+ def __iter__(self):
+ for line in self.readlines():
+ yield line
+
+ def read(self, count=-1):
+ try:
+ cs = cStringIO.StringIO()
+ while count:
+ wincount = int(count)
+ if wincount == -1:
+ wincount = 1048576
+ val, data = win32file.ReadFile(self.handle, wincount)
+ if not data: break
+ cs.write(data)
+ if count != -1:
+ count -= len(data)
+ return cs.getvalue()
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+ def readlines(self, sizehint=None):
+ # splitlines() splits on single '\r' while readlines()
+ # does not. cStringIO has a well behaving readlines() and is fast.
+ return cStringIO.StringIO(self.read()).readlines()
+
+ def write(self, data):
+ try:
+ if 'a' in self.mode:
+ win32file.SetFilePointer(self.handle, 0, win32file.FILE_END)
+ nwrit = 0
+ while nwrit < len(data):
+ val, nwrit = win32file.WriteFile(self.handle, data)
+ data = data[nwrit:]
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+ def writelines(self, sequence):
+ for s in sequence:
+ self.write(s)
+
+ def seek(self, pos, whence=0):
+ try:
+ win32file.SetFilePointer(self.handle, int(pos), whence)
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+ def tell(self):
+ try:
+ return win32file.SetFilePointer(self.handle, 0,
+ win32file.FILE_CURRENT)
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+ def close(self):
+ if not self.closed:
+ self.handle = None
+ self.closed = True
+
+ def flush(self):
+ # we have no application-level buffering
+ pass
+
+ def truncate(self, pos=0):
+ try:
+ win32file.SetFilePointer(self.handle, int(pos),
+ win32file.FILE_BEGIN)
+ win32file.SetEndOfFile(self.handle)
+ except pywintypes.error, err:
+ raise WinIOError(err)
+
+def getuser():
+ '''return name of current user'''
+ return win32api.GetUserName()
+
+def set_signal_handler_win32():
+ """Register a termination handler for console events including
+ CTRL+C. python signal handlers do not work well with socket
+ operations.
+ """
+ def handler(event):
+ win32process.ExitProcess(1)
+ win32api.SetConsoleCtrlHandler(handler)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/windows.py Thu Mar 26 13:54:44 2009 -0500
@@ -0,0 +1,266 @@
+"""
+windows.py - Windows utility function implementations for Mercurial
+
+ Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
+
+This software may be used and distributed according to the terms of
+the GNU General Public License version 2, incorporated herein by
+reference.
+"""
+
+import msvcrt, sys, os
+nulldev = 'NUL:'
+
+umask = 002
+
+class winstdout:
+ '''stdout on windows misbehaves if sent through a pipe'''
+
+ def __init__(self, fp):
+ self.fp = fp
+
+ def __getattr__(self, key):
+ return getattr(self.fp, key)
+
+ def close(self):
+ try:
+ self.fp.close()
+ except: pass
+
+ def write(self, s):
+ try:
+ # This is workaround for "Not enough space" error on
+ # writing large size of data to console.
+ limit = 16000
+ l = len(s)
+ start = 0
+ while start < l:
+ end = start + limit
+ self.fp.write(s[start:end])
+ start = end
+ except IOError, inst:
+ if inst.errno != 0: raise
+ self.close()
+ raise IOError(errno.EPIPE, 'Broken pipe')
+
+ def flush(self):
+ try:
+ return self.fp.flush()
+ except IOError, inst:
+ if inst.errno != errno.EINVAL: raise
+ self.close()
+ raise IOError(errno.EPIPE, 'Broken pipe')
+
+sys.stdout = winstdout(sys.stdout)
+
+def _is_win_9x():
+ '''return true if run on windows 95, 98 or me.'''
+ try:
+ return sys.getwindowsversion()[3] == 1
+ except AttributeError:
+ return 'command' in os.environ.get('comspec', '')
+
+def openhardlinks():
+ return not _is_win_9x and "win32api" in locals()
+
+def system_rcpath():
+ try:
+ return system_rcpath_win32()
+ except:
+ return [r'c:\mercurial\mercurial.ini']
+
+def user_rcpath():
+ '''return os-specific hgrc search path to the user dir'''
+ try:
+ path = user_rcpath_win32()
+ except:
+ home = os.path.expanduser('~')
+ path = [os.path.join(home, 'mercurial.ini'),
+ os.path.join(home, '.hgrc')]
+ userprofile = os.environ.get('USERPROFILE')
+ if userprofile:
+ path.append(os.path.join(userprofile, 'mercurial.ini'))
+ path.append(os.path.join(userprofile, '.hgrc'))
+ return path
+
+def parse_patch_output(output_line):
+ """parses the output produced by patch and returns the file name"""
+ pf = output_line[14:]
+ if pf[0] == '`':
+ pf = pf[1:-1] # Remove the quotes
+ return pf
+
+def sshargs(sshcmd, host, user, port):
+ '''Build argument list for ssh or Plink'''
+ pflag = 'plink' in sshcmd.lower() and '-P' or '-p'
+ args = user and ("%s@%s" % (user, host)) or host
+ return port and ("%s %s %s" % (args, pflag, port)) or args
+
+def testpid(pid):
+ '''return False if pid dead, True if running or not known'''
+ return True
+
+def set_flags(f, l, x):
+ pass
+
+def set_binary(fd):
+ # When run without console, pipes may expose invalid
+ # fileno(), usually set to -1.
+ if hasattr(fd, 'fileno') and fd.fileno() >= 0:
+ msvcrt.setmode(fd.fileno(), os.O_BINARY)
+
+def pconvert(path):
+ return '/'.join(path.split(os.sep))
+
+def localpath(path):
+ return path.replace('/', '\\')
+
+def normpath(path):
+ return pconvert(os.path.normpath(path))
+
+def samestat(s1, s2):
+ return False
+
+# A sequence of backslashes is special iff it precedes a double quote:
+# - if there's an even number of backslashes, the double quote is not
+# quoted (i.e. it ends the quoted region)
+# - if there's an odd number of backslashes, the double quote is quoted
+# - in both cases, every pair of backslashes is unquoted into a single
+# backslash
+# (See http://msdn2.microsoft.com/en-us/library/a1y7w461.aspx )
+# So, to quote a string, we must surround it in double quotes, double
+# the number of backslashes that preceed double quotes and add another
+# backslash before every double quote (being careful with the double
+# quote we've appended to the end)
+_quotere = None
+def shellquote(s):
+ global _quotere
+ if _quotere is None:
+ _quotere = re.compile(r'(\\*)("|\\$)')
+ return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
+
+def quotecommand(cmd):
+ """Build a command string suitable for os.popen* calls."""
+ # The extra quotes are needed because popen* runs the command
+ # through the current COMSPEC. cmd.exe suppress enclosing quotes.
+ return '"' + cmd + '"'
+
+def popen(command, mode='r'):
+ # Work around "popen spawned process may not write to stdout
+ # under windows"
+ # http://bugs.python.org/issue1366
+ command += " 2> %s" % nulldev
+ return os.popen(quotecommand(command), mode)
+
+def explain_exit(code):
+ return _("exited with status %d") % code, code
+
+# if you change this stub into a real check, please try to implement the
+# username and groupname functions above, too.
+def isowner(fp, st=None):
+ return True
+
+def find_exe(command):
+ '''Find executable for command searching like cmd.exe does.
+ If command is a basename then PATH is searched for command.
+ PATH isn't searched if command is an absolute or relative path.
+ An extension from PATHEXT is found and added if not present.
+ If command isn't found None is returned.'''
+ pathext = os.environ.get('PATHEXT', '.COM;.EXE;.BAT;.CMD')
+ pathexts = [ext for ext in pathext.lower().split(os.pathsep)]
+ if os.path.splitext(command)[1].lower() in pathexts:
+ pathexts = ['']
+
+ def findexisting(pathcommand):
+ 'Will append extension (if needed) and return existing file'
+ for ext in pathexts:
+ executable = pathcommand + ext
+ if os.path.exists(executable):
+ return executable
+ return None
+
+ if os.sep in command:
+ return findexisting(command)
+
+ for path in os.environ.get('PATH', '').split(os.pathsep):
+ executable = findexisting(os.path.join(path, command))
+ if executable is not None:
+ return executable
+ return None
+
+def set_signal_handler():
+ try:
+ set_signal_handler_win32()
+ except NameError:
+ pass
+
+def statfiles(files):
+ '''Stat each file in files and yield stat or None if file does not exist.
+ Cluster and cache stat per directory to minimize number of OS stat calls.'''
+ ncase = os.path.normcase
+ sep = os.sep
+ dircache = {} # dirname -> filename -> status | None if file does not exist
+ for nf in files:
+ nf = ncase(nf)
+ pos = nf.rfind(sep)
+ if pos == -1:
+ dir, base = '.', nf
+ else:
+ dir, base = nf[:pos+1], nf[pos+1:]
+ cache = dircache.get(dir, None)
+ if cache is None:
+ try:
+ dmap = dict([(ncase(n), s)
+ for n, k, s in osutil.listdir(dir, True)])
+ except OSError, err:
+ # handle directory not found in Python version prior to 2.5
+ # Python <= 2.4 returns native Windows code 3 in errno
+ # Python >= 2.5 returns ENOENT and adds winerror field
+ # EINVAL is raised if dir is not a directory.
+ if err.errno not in (3, errno.ENOENT, errno.EINVAL,
+ errno.ENOTDIR):
+ raise
+ dmap = {}
+ cache = dircache.setdefault(dir, dmap)
+ yield cache.get(base, None)
+
+def getuser():
+ '''return name of current user'''
+ raise Abort(_('user name not available - set USERNAME '
+ 'environment variable'))
+
+def expand_glob(pats):
+ '''On Windows, expand the implicit globs in a list of patterns'''
+ ret = []
+ for p in pats:
+ kind, name = patkind(p, None)
+ if kind is None:
+ globbed = glob.glob(name)
+ if globbed:
+ ret.extend(globbed)
+ continue
+ # if we couldn't expand the glob, just keep it around
+ ret.append(p)
+ return ret
+
+def username(uid=None):
+ """Return the name of the user with the given uid.
+
+ If uid is None, return the name of the current user."""
+ return None
+
+def groupname(gid=None):
+ """Return the name of the group with the given gid.
+
+ If gid is None, return the name of the current group."""
+ return None
+
+posixfile = file
+try:
+ # override functions with win32 versions if possible
+ from util_win32 import *
+ if not _is_win_9x():
+ posixfile = posixfile_nt
+except ImportError:
+ pass
+