[PATCH 1 of 5] port win32.py to using the Python ctypes library

Steve Borho steve at borho.org
Tue Feb 8 11:48:00 CST 2011


On Tue, Feb 8, 2011 at 10:52 AM, Adrian Buehlmann <adrian at cadifra.com> wrote:
> # HG changeset patch
> # User Adrian Buehlmann <adrian at cadifra.com>
> # Date 1297121623 -3600
> # Node ID 3ba4920422e9abcdc8b8634c5c12c68051286a8c
> # Parent  69e69b131458023d21ec40aa48fc5299e43ce69b
> port win32.py to using the Python ctypes library
>
> The pywin32 package is no longer needed.
>
> ctypes is now required for running Mercurial on Windows.
>
> ctypes is included in Python since version 2.5. For Python 2.4, ctypes is
> available as an extra installer package for Windows.
>
> Also moved spawndetached() from windows.py to win32.py and fixed it, using
> ctypes as well. spawndetached was defunct with Python 2.6.6 because Python
> removed their undocumented subprocess.CreateProcess. This fixes
> 'hg serve -d' on Windows.
>
> diff --git a/contrib/wix/dist.wxs b/contrib/wix/dist.wxs
> --- a/contrib/wix/dist.wxs
> +++ b/contrib/wix/dist.wxs
> @@ -16,23 +16,14 @@
>         <File Name="mercurial.parsers.pyd" />
>         <File Name="pyexpat.pyd" />
>         <File Name="python26.dll" />
> -        <File Name="pythoncom26.dll" />
> -        <File Name="pywintypes26.dll" />
>         <File Name="bz2.pyd" />
>         <File Name="select.pyd" />
>         <File Name="unicodedata.pyd" />
> -        <File Name="win32api.pyd" />
> -        <File Name="win32com.shell.shell.pyd" />
> -        <File Name="win32console.pyd" />
> -        <File Name="win32file.pyd" />
> -        <File Name="win32gui.pyd" />
> -        <File Name="win32pipe.pyd" />
> -        <File Name="win32process.pyd" />
> +        <File Name="_ctypes.pyd" />
>         <File Name="_elementtree.pyd" />
>         <File Name="_hashlib.pyd" />
>         <File Name="_socket.pyd" />
>         <File Name="_ssl.pyd" />
> -        <File Name="_win32sysloader.pyd" />
>       </Component>
>     </DirectoryRef>
>   </Fragment>
> diff --git a/contrib/wix/guids.wxi b/contrib/wix/guids.wxi
> --- a/contrib/wix/guids.wxi
> +++ b/contrib/wix/guids.wxi
> @@ -9,7 +9,7 @@
>   <?define contrib.vim.guid = {BB04903A-652D-4C4F-9590-2BD07A2304F2} ?>
>
>   <!-- dist.wxs -->
> -  <?define dist.guid = {0F63D160-0740-4BAF-BF25-0C6930310F51} ?>
> +  <?define dist.guid = {C3B634A4-1B05-4A40-94A9-38EE853CF693} ?>
>
>   <!-- doc.wxs -->
>   <?define doc.hg.1.html.guid = {AAAA3FDA-EDC5-4220-B59D-D342722358A2} ?>
> diff --git a/mercurial/posix.py b/mercurial/posix.py
> --- a/mercurial/posix.py
> +++ b/mercurial/posix.py
> @@ -13,6 +13,7 @@ posixfile = open
>  nulldev = '/dev/null'
>  normpath = os.path.normpath
>  samestat = os.path.samestat
> +os_link = os.link
>  unlink = os.unlink
>  rename = os.rename
>  expandglobs = False
> @@ -24,6 +25,10 @@ def openhardlinks():
>     '''return true if it is safe to hold open file handles to hardlinks'''
>     return True
>
> +def nlinks(name):
> +    '''return number of hardlinks for the given file'''
> +    return os.lstat(name).st_nlink
> +
>  def rcfiles(path):
>     rcs = [os.path.join(path, 'hgrc')]
>     rcdir = os.path.join(path, 'hgrc.d')
> diff --git a/mercurial/util.py b/mercurial/util.py
> --- a/mercurial/util.py
> +++ b/mercurial/util.py
> @@ -554,16 +554,6 @@ class path_auditor(object):
>         # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
>         self.auditeddir.update(prefixes)
>
> -def nlinks(pathname):
> -    """Return number of hardlinks for the given file."""
> -    return os.lstat(pathname).st_nlink
> -
> -if hasattr(os, 'link'):
> -    os_link = os.link
> -else:
> -    def os_link(src, dst):
> -        raise OSError(0, _("Hardlinks not supported"))
> -
>  def lookup_reg(key, name=None, scope=None):
>     return None
>
> diff --git a/mercurial/win32.py b/mercurial/win32.py
> --- a/mercurial/win32.py
> +++ b/mercurial/win32.py
> @@ -5,73 +5,174 @@
>  # This software may be used and distributed according to the terms of the
>  # GNU General Public License version 2 or any later version.
>
> -"""Utility functions that use win32 API.
> +import osutil, encoding
> +import ctypes, errno, os, struct, subprocess
>
> -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.
> -"""
> +_kernel32 = ctypes.windll.kernel32
>
> -import win32api
> +_BOOL = ctypes.c_long
> +_WORD = ctypes.c_ushort
> +_DWORD = ctypes.c_ulong
> +_LPCSTR = _LPSTR = ctypes.c_char_p
> +_HANDLE = ctypes.c_void_p
> +_HWND = _HANDLE
>
> -import errno, os, sys, pywintypes, win32con, win32file, win32process
> -import winerror, win32gui, win32console
> -import osutil, encoding
> -from win32com.shell import shell, shellcon
> +_INVALID_HANDLE_VALUE = -1
> +
> +# GetLastError
> +_ERROR_SUCCESS = 0
> +_ERROR_INVALID_PARAMETER = 87
> +
> +# WPARAM is defined as UINT_PTR (unsigned type)
> +# LPARAM is defined as LONG_PTR (signed type)
> +if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
> +    _WPARAM = ctypes.c_ulong
> +    _LPARAM = ctypes.c_long
> +elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
> +    _WPARAM = ctypes.c_ulonglong
> +    _LPARAM = ctypes.c_longlong
> +
> +class _FILETIME(ctypes.Structure):
> +    _fields_ = [('dwLowDateTime', _DWORD),
> +                ('dwHighDateTime', _DWORD)]
> +
> +class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
> +    _fields_ = [('dwFileAttributes', _DWORD),
> +                ('ftCreationTime', _FILETIME),
> +                ('ftLastAccessTime', _FILETIME),
> +                ('ftLastWriteTime', _FILETIME),
> +                ('dwVolumeSerialNumber', _DWORD),
> +                ('nFileSizeHigh', _DWORD),
> +                ('nFileSizeLow', _DWORD),
> +                ('nNumberOfLinks', _DWORD),
> +                ('nFileIndexHigh', _DWORD),
> +                ('nFileIndexLow', _DWORD)]
> +
> +# CreateFile
> +_FILE_SHARE_READ = 0x00000001
> +_FILE_SHARE_WRITE = 0x00000002
> +_FILE_SHARE_DELETE = 0x00000004
> +
> +_OPEN_EXISTING = 3
> +
> +# Process Security and Access Rights
> +_PROCESS_QUERY_INFORMATION = 0x0400
> +
> +# GetExitCodeProcess
> +_STILL_ACTIVE = 259
> +
> +# registry
> +_HKEY_CURRENT_USER = 0x80000001L
> +_HKEY_LOCAL_MACHINE = 0x80000002L
> +_KEY_READ = 0x20019
> +_RRF_RT_ANY = 0x0000ffff
> +_REG_SZ = 1
> +_REG_DWORD = 4
> +
> +class _STARTUPINFO(ctypes.Structure):
> +    _fields_ = [('cb', _DWORD),
> +                ('lpReserved', _LPSTR),
> +                ('lpDesktop', _LPSTR),
> +                ('lpTitle', _LPSTR),
> +                ('dwX', _DWORD),
> +                ('dwY', _DWORD),
> +                ('dwXSize', _DWORD),
> +                ('dwYSize', _DWORD),
> +                ('dwXCountChars', _DWORD),
> +                ('dwYCountChars', _DWORD),
> +                ('dwFillAttribute', _DWORD),
> +                ('dwFlags', _DWORD),
> +                ('wShowWindow', _WORD),
> +                ('cbReserved2', _WORD),
> +                ('lpReserved2', ctypes.c_char_p),
> +                ('hStdInput', _HANDLE),
> +                ('hStdOutput', _HANDLE),
> +                ('hStdError', _HANDLE)]
> +
> +class _PROCESS_INFORMATION(ctypes.Structure):
> +    _fields_ = [('hProcess', _HANDLE),
> +                ('hThread', _HANDLE),
> +                ('dwProcessId', _DWORD),
> +                ('dwThreadId', _DWORD)]
> +
> +_DETACHED_PROCESS = 0x00000008
> +_STARTF_USESHOWWINDOW = 0x00000001
> +_SW_HIDE = 0
> +
> +class _COORD(ctypes.Structure):
> +    _fields_ = [('X', ctypes.c_short),
> +                ('Y', ctypes.c_short)]
> +
> +class _SMALL_RECT(ctypes.Structure):
> +    _fields_ = [('Left', ctypes.c_short),
> +                ('Top', ctypes.c_short),
> +                ('Right', ctypes.c_short),
> +                ('Bottom', ctypes.c_short)]
> +
> +class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
> +    _fields_ = [('dwSize', _COORD),
> +                ('dwCursorPosition', _COORD),
> +                ('wAttributes', _WORD),
> +                ('srWindow', _SMALL_RECT),
> +                ('dwMaximumWindowSize', _COORD)]
> +
> +_STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
> +
> +def _raiseoserror(name):
> +    err = ctypes.WinError()
> +    raise OSError(err.errno, '%s: %s' % (name, err.strerror))
> +
> +def _getfileinfo(name):
> +    fh = _kernel32.CreateFileA(name,
> +            0, _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
> +            None, _OPEN_EXISTING, 0, None)
> +    if fh == _INVALID_HANDLE_VALUE:
> +        _raiseoserror(name)
> +    try:
> +        fi = _BY_HANDLE_FILE_INFORMATION()
> +        if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
> +            _raiseoserror(name)
> +        return fi
> +    finally:
> +        if fh != _INVALID_HANDLE_VALUE:
> +            _kernel32.CloseHandle(fh)
>
>  def os_link(src, dst):
> -    try:
> -        win32file.CreateHardLink(dst, src)
> -    except pywintypes.error:
> -        raise OSError(errno.EINVAL, 'target implements hardlinks improperly')
> -    except NotImplementedError: # Another fake error win Win98
> -        raise OSError(errno.EINVAL, 'Hardlinking not supported')
> +    if not _kernel32.CreateHardLinkA(dst, src, None):
> +        _raiseoserror(src)
>
> -def _getfileinfo(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)
> -    except pywintypes.error:
> -        raise OSError(errno.ENOENT, 'The system cannot find the file specified')
> -    try:
> -        return win32file.GetFileInformationByHandle(fh)
> -    finally:
> -        fh.Close()
> -
> -def nlinks(pathname):
> -    """Return number of hardlinks for the given file."""
> -    return _getfileinfo(pathname)[7]
> +def nlinks(name):
> +    '''return number of hardlinks for the given file'''
> +    return _getfileinfo(name).nNumberOfLinks
>
>  def samefile(fpath1, fpath2):
> -    """Returns whether fpath1 and fpath2 refer to the same file. This is only
> -    guaranteed to work for files, not directories."""
> +    '''Returns whether fpath1 and fpath2 refer to the same file. This is only
> +    guaranteed to work for files, not directories.'''
>     res1 = _getfileinfo(fpath1)
>     res2 = _getfileinfo(fpath2)
> -    # Index 4 is the volume serial number, and 8 and 9 contain the file ID
> -    return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
> +    return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
> +        and res1.nFileIndexHigh == res2.nFileIndexHigh
> +        and res1.nFileIndexLow == res2.nFileIndexLow)
>
>  def samedevice(fpath1, fpath2):
> -    """Returns whether fpath1 and fpath2 are on the same device. This is only
> -    guaranteed to work for files, not directories."""
> +    '''Returns whether fpath1 and fpath2 are on the same device. This is only
> +    guaranteed to work for files, not directories.'''
>     res1 = _getfileinfo(fpath1)
>     res2 = _getfileinfo(fpath2)
> -    return res1[4] == res2[4]
> +    return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
>
>  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
> +    h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
> +    if h:
> +        try:
> +            status = _DWORD()
> +            if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
> +                return status.value == _STILL_ACTIVE
> +        finally:
> +            _kernel32.CloseHandle(h)
> +    return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
>
>  def lookup_reg(key, valname=None, scope=None):
>     ''' Look up a key/value name in the Windows registry.
> @@ -82,101 +183,168 @@ def lookup_reg(key, valname=None, scope=
>     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
> -
> +    adv = ctypes.windll.advapi32
> +    byref = ctypes.byref
>     if scope is None:
> -        scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
> +        scope = (_HKEY_CURRENT_USER, _HKEY_LOCAL_MACHINE)
>     elif not isinstance(scope, (list, tuple)):
>         scope = (scope,)
>     for s in scope:
> +        kh = _HANDLE()
> +        res = adv.RegOpenKeyExA(s, key, 0, _KEY_READ, ctypes.byref(kh))
> +        if res != _ERROR_SUCCESS:
> +            continue
>         try:
> -            val = QueryValueEx(OpenKey(s, key), valname)[0]
> -            # never let a Unicode string escape into the wild
> -            return encoding.tolocal(val.encode('UTF-8'))
> -        except EnvironmentError:
> -            pass
> +            size = _DWORD(600)
> +            type = _DWORD()
> +            buf = ctypes.create_string_buffer(size.value + 1)
> +            res = adv.RegGetValueA(kh.value, None, valname, _RRF_RT_ANY,
> +                                   byref(type), byref(buf), byref(size))
> +            if res != _ERROR_SUCCESS:
> +                continue
> +            if type.value == _REG_SZ:
> +                # never let a Unicode string escape into the wild
> +                return encoding.tolocal(buf.value.encode('UTF-8'))
> +            elif type.value == _REG_DWORD:
> +                fmt = '<L'
> +                s = ctypes.string_at(byref(buf), struct.calcsize(fmt))
> +                return struct.unpack(fmt, s)[0]
> +        finally:
> +            if kh.value:
> +                adv.RegCloseKey(kh.value)
>
>  def system_rcpath_win32():
>     '''return default os-specific hgrc search path'''
> -    filename = win32api.GetModuleFileName(0)
> +    rcpath = []
> +    size = 600
> +    buf = ctypes.create_string_buffer(size + 1)
> +    len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
> +    if not len:
> +        return rcpath
> +    filename = buf.value
>     # 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]
> +        rcpath.append(progrc)
> +        return rcpath
>     # Use hgrc.d found in directory with hg.exe
>     progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
>     if os.path.isdir(progrcd):
> -        rcpath = []
>         for f, kind in osutil.listdir(progrcd):
>             if f.endswith('.rc'):
>                 rcpath.append(os.path.join(progrcd, f))
>         return rcpath
>     # 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))
> +    value = lookup_reg('SOFTWARE\\Mercurial', None, _HKEY_LOCAL_MACHINE)
> +    if not isinstance(value, str) or not value:
>         return rcpath
> -    except pywintypes.error:
> -        return []
> +    value = value.replace('/', os.sep)
> +    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
>
>  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')]
>
>  def getuser():
>     '''return name of current user'''
> -    return win32api.GetUserName()
> +    adv = ctypes.windll.advapi32
> +    size = _DWORD(300)
> +    buf = ctypes.create_string_buffer(size.value + 1)
> +    if not adv.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
> +        raise ctypes.WinError()
> +    return buf.value
> +
> +_SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
> +_signal_handler = []
>
>  def set_signal_handler_win32():
> -    """Register a termination handler for console events including
> +    '''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)
> +        _kernel32.ExitProcess(1)
> +
> +    if _signal_handler:
> +        return # already registered
> +    h = _SIGNAL_HANDLER(handler)
> +    _signal_handler.append(h) # needed to prevent garbage collection
> +    if not _kernel32.SetConsoleCtrlHandler(h, True):
> +        raise ctypes.WinError()
> +
> +_WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
>
>  def hidewindow():
> -    def callback(*args, **kwargs):
> -        hwnd, pid = args
> -        wpid = win32process.GetWindowThreadProcessId(hwnd)[1]
> -        if pid == wpid:
> -            win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
> +    user32 = ctypes.windll.user32
>
> -    pid =  win32process.GetCurrentProcessId()
> -    win32gui.EnumWindows(callback, pid)
> +    def callback(hwnd, pid):
> +        wpid = _DWORD()
> +        user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
> +        if pid == wpid.value:
> +            user32.ShowWindow(hwnd, _SW_HIDE)
> +            return False # stop enumerating windows
> +        return True
> +
> +    pid = _kernel32.GetCurrentProcessId()
> +    user32.EnumWindows(_WNDENUMPROC(callback), pid)
>
>  def termwidth():
> -    try:
> -        # Query stderr to avoid problems with redirections
> -        screenbuf = win32console.GetStdHandle(win32console.STD_ERROR_HANDLE)
> -        if screenbuf is None:
> -            return 79
> -        try:
> -            window = screenbuf.GetConsoleScreenBufferInfo()['Window']
> -            width = window.Right - window.Left
> -            return width
> -        finally:
> -            screenbuf.Detach()
> -    except pywintypes.error:
> -        return 79
> +    # cmd.exe does not handle CR like a unix console, the CR is
> +    # counted in the line length. On 80 columns consoles, if 80
> +    # characters are written, the following CR won't apply on the
> +    # current line but on the new one. Keep room for it.
> +    width = 79
> +    # Query stderr to avoid problems with redirections
> +    screenbuf = _kernel32.GetStdHandle(
> +                  _STD_ERROR_HANDLE) # don't close the handle returned
> +    if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
> +        return width
> +    csbi = _CONSOLE_SCREEN_BUFFER_INFO()
> +    if not _kernel32.GetConsoleScreenBufferInfo(
> +                        screenbuf, ctypes.byref(csbi)):
> +        return width
> +    width = csbi.srWindow.Right - csbi.srWindow.Left
> +    return width
> +
> +def spawndetached(args):
> +    # No standard library function really spawns a fully detached
> +    # process under win32 because they allocate pipes or other objects
> +    # to handle standard streams communications. Passing these objects
> +    # to the child process requires handle inheritance to be enabled
> +    # which makes really detached processes impossible.
> +    si = _STARTUPINFO()
> +    si.cb = ctypes.sizeof(_STARTUPINFO)
> +    si.dwFlags = _STARTF_USESHOWWINDOW
> +    si.wShowWindow = _SW_HIDE
> +
> +    pi = _PROCESS_INFORMATION()
> +
> +    env = ''
> +    for k in os.environ:
> +        env += "%s=%s\0" % (k, os.environ[k])
> +    if not env:
> +        env = '\0'
> +    env += '\0'
> +
> +    args = subprocess.list2cmdline(args)
> +    # Not running the command in shell mode makes python26 hang when
> +    # writing to hgweb output socket.
> +    comspec = os.environ.get("COMSPEC", "cmd.exe")
> +    args = comspec + " /c " + args
> +
> +    res = _kernel32.CreateProcessA(
> +        None, args, None, None, False, _DETACHED_PROCESS,
> +        env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
> +    if not res:
> +        raise ctypes.WinError()
> +
> +    return pi.dwProcessId
> diff --git a/mercurial/windows.py b/mercurial/windows.py
> --- a/mercurial/windows.py
> +++ b/mercurial/windows.py
> @@ -71,7 +71,7 @@ def _is_win_9x():
>         return 'command' in os.environ.get('comspec', '')
>
>  def openhardlinks():
> -    return not _is_win_9x() and "win32api" in globals()
> +    return not _is_win_9x()
>
>  def system_rcpath():
>     try:
> @@ -106,10 +106,6 @@ def sshargs(sshcmd, host, user, port):
>     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
>
> @@ -211,7 +207,7 @@ def find_exe(command):
>  def set_signal_handler():
>     try:
>         set_signal_handler_win32()
> -    except NameError:
> +    except WindowsError:
>         pass
>
>  def statfiles(files):
> @@ -241,11 +237,6 @@ def statfiles(files):
>             cache = dircache.setdefault(dir, dmap)
>         yield cache.get(base, None)
>
> -def getuser():
> -    '''return name of current user'''
> -    raise error.Abort(_('user name not available - set USERNAME '
> -                       'environment variable'))
> -
>  def username(uid=None):
>     """Return the name of the user with the given uid.
>
> @@ -335,37 +326,6 @@ def rename(src, dst):
>         unlink(dst)
>         os.rename(src, dst)
>
> -def spawndetached(args):
> -    # No standard library function really spawns a fully detached
> -    # process under win32 because they allocate pipes or other objects
> -    # to handle standard streams communications. Passing these objects
> -    # to the child process requires handle inheritance to be enabled
> -    # which makes really detached processes impossible.
> -    class STARTUPINFO:
> -        dwFlags = subprocess.STARTF_USESHOWWINDOW
> -        hStdInput = None
> -        hStdOutput = None
> -        hStdError = None
> -        wShowWindow = subprocess.SW_HIDE
> -
> -    args = subprocess.list2cmdline(args)
> -    # Not running the command in shell mode makes python26 hang when
> -    # writing to hgweb output socket.
> -    comspec = os.environ.get("COMSPEC", "cmd.exe")
> -    args = comspec + " /c " + args
> -    hp, ht, pid, tid = subprocess.CreateProcess(
> -        None, args,
> -        # no special security
> -        None, None,
> -        # Do not inherit handles
> -        0,
> -        # DETACHED_PROCESS
> -        0x00000008,
> -        os.environ,
> -        os.getcwd(),
> -        STARTUPINFO())
> -    return pid
> -
>  def gethgcmd():
>     return [sys.executable] + sys.argv[:1]
>
> @@ -380,10 +340,6 @@ def groupmembers(name):
>     # Don't support groups on Windows for now
>     raise KeyError()
>
> -try:
> -    # override functions with win32 versions if possible
> -    from win32 import *
> -except ImportError:
> -    pass
> +from win32 import *

This probably deserves a separate patch, but there's little point in
keeping both a windows.py and win32.py now.

-- 
Steve Borho


More information about the Mercurial-devel mailing list