changeset 13388:a184dbd9b2c5

localrepo: sort hg bookmark output sort bookmarks before we write them to stdout to get a predictable output.
author David Soria Parra <dsp@php.net>
date Fri, 11 Feb 2011 20:35:32 +0100
parents 900a92862a7b (current diff) 0be2fe6a0843 (diff)
children 3efc99ac2ac4
files mercurial/commands.py tests/test-bookmarks-pushpull.t tests/test-bookmarks-rebase.t tests/test-bookmarks.t
diffstat 23 files changed, 384 insertions(+), 253 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/hgk	Mon Feb 14 14:12:48 2011 -0600
+++ b/contrib/hgk	Fri Feb 11 20:35:32 2011 +0100
@@ -482,7 +482,7 @@
     .bar.file add command -label "Quit" -command doquit
     menu .bar.help
     .bar add cascade -label "Help" -menu .bar.help
-    .bar.help add command -label "About gitk" -command about
+    .bar.help add command -label "About hgk" -command about
     . configure -menu .bar
 
     if {![info exists geometry(canv1)]} {
@@ -867,9 +867,9 @@
 	return
     }
     toplevel $w
-    wm title $w "About gitk"
+    wm title $w "About hgk"
     message $w.m -text {
-Gitk version 1.2
+Hgk version 1.2
 
 Copyright © 2005 Paul Mackerras
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/win32/buildlocal.bat	Fri Feb 11 20:35:32 2011 +0100
@@ -0,0 +1,9 @@
+@echo off
+rem Double-click this file to (re)build Mercurial for Windows in place.
+rem Useful for testing and development.
+cd ..\..
+del /Q mercurial\*.pyd
+del /Q mercurial\*.pyc
+rmdir /Q /S mercurial\locale
+python setup.py build_py -c -d . build_ext -i build_mo
+pause
--- a/contrib/wix/dist.wxs	Mon Feb 14 14:12:48 2011 -0600
+++ b/contrib/wix/dist.wxs	Fri Feb 11 20:35:32 2011 +0100
@@ -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>
--- a/contrib/wix/guids.wxi	Mon Feb 14 14:12:48 2011 -0600
+++ b/contrib/wix/guids.wxi	Fri Feb 11 20:35:32 2011 +0100
@@ -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} ?>
--- a/mercurial/bookmarks.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/bookmarks.py	Fri Feb 11 20:35:32 2011 +0100
@@ -38,7 +38,7 @@
     if os.path.exists(repo.join('bookmarks.current')):
         file = repo.opener('bookmarks.current')
         # No readline() in posixfile_nt, reading everything is cheap
-        mark = (file.readlines() or [''])[0]
+        mark = encoding.tolocal((file.readlines() or [''])[0])
         if mark == '':
             mark = None
         file.close()
--- a/mercurial/bundlerepo.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/bundlerepo.py	Fri Feb 11 20:35:32 2011 +0100
@@ -251,11 +251,6 @@
         self.bundle.close()
         if self.tempfile is not None:
             os.unlink(self.tempfile)
-
-    def __del__(self):
-        del self.bundle
-        if self.tempfile is not None:
-            os.unlink(self.tempfile)
         if self._tempparent:
             shutil.rmtree(self._tempparent, True)
 
--- a/mercurial/cmdutil.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/cmdutil.py	Fri Feb 11 20:35:32 2011 +0100
@@ -806,6 +806,9 @@
         if branch != 'default':
             self.ui.write(_("branch:      %s\n") % branch,
                           label='log.branch')
+        for bookmark in self.repo.nodebookmarks(changenode):
+            self.ui.write(_("bookmark:    %s\n") % bookmark,
+                    label='log.bookmark')
         for tag in self.repo.nodetags(changenode):
             self.ui.write(_("tag:         %s\n") % tag,
                           label='log.tag')
--- a/mercurial/commands.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/commands.py	Fri Feb 11 20:35:32 2011 +0100
@@ -530,7 +530,7 @@
         if len(marks) == 0:
             ui.status(_("no bookmarks set\n"))
         else:
-            for bmark, n in marks.iteritems():
+            for bmark, n in sorted(marks.iteritems()):
                 if ui.configbool('bookmarks', 'track.current'):
                     current = repo._bookmarkcurrent
                     if bmark == current and n == cur:
--- a/mercurial/context.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/context.py	Fri Feb 11 20:35:32 2011 +0100
@@ -114,6 +114,8 @@
         return self._changeset[5]
     def tags(self):
         return self._repo.nodetags(self._node)
+    def bookmarks(self):
+        return self._repo.nodebookmarks(self._node)
 
     def parents(self):
         """return contexts for each parent changeset"""
--- a/mercurial/dispatch.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/dispatch.py	Fri Feb 11 20:35:32 2011 +0100
@@ -589,8 +589,12 @@
     msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
     ui.log("command", msg + "\n")
     d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
-    return runcommand(lui, repo, cmd, fullargs, ui, options, d,
-                      cmdpats, cmdoptions)
+    try:
+        return runcommand(lui, repo, cmd, fullargs, ui, options, d,
+                          cmdpats, cmdoptions)
+    finally:
+        if repo:
+            repo.close()
 
 def _runcommand(ui, options, cmd, cmdfunc):
     def checkargs():
--- a/mercurial/localrepo.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/localrepo.py	Fri Feb 11 20:35:32 2011 +0100
@@ -360,7 +360,6 @@
             if node != nullid:
                 tags[encoding.tolocal(name)] = node
         tags['tip'] = self.changelog.tip()
-        tags.update(self._bookmarks)
         tagtypes = dict([(encoding.tolocal(name), value)
                          for (name, value) in tagtypes.iteritems()])
         return (tags, tagtypes)
@@ -399,6 +398,13 @@
                 tags.sort()
         return self.nodetagscache.get(node, [])
 
+    def nodebookmarks(self, node):
+        marks = []
+        for bookmark, n in self._bookmarks.iteritems():
+            if n == node:
+                marks.append(bookmark)
+        return sorted(marks)
+
     def _branchtags(self, partial, lrev):
         # TODO: rename this function?
         tiprev = len(self) - 1
--- a/mercurial/posix.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/posix.py	Fri Feb 11 20:35:32 2011 +0100
@@ -13,6 +13,7 @@
 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 @@
     '''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')
--- a/mercurial/repo.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/repo.py	Fri Feb 11 20:35:32 2011 +0100
@@ -35,3 +35,6 @@
 
     def cancopy(self):
         return self.local()
+
+    def close(self):
+        pass
--- a/mercurial/templatekw.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/templatekw.py	Fri Feb 11 20:35:32 2011 +0100
@@ -153,6 +153,10 @@
     if branch != 'default':
         return showlist('branch', [branch], plural='branches', **args)
 
+def showbookmarks(**args):
+    bookmarks = args['ctx'].bookmarks()
+    return showlist('bookmark', bookmarks, **args)
+
 def showchildren(**args):
     ctx = args['ctx']
     childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
@@ -252,6 +256,7 @@
     'author': showauthor,
     'branch': showbranch,
     'branches': showbranches,
+    'bookmarks': showbookmarks,
     'children': showchildren,
     'date': showdate,
     'desc': showdescription,
--- a/mercurial/templates/map-cmdline.default	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/templates/map-cmdline.default	Fri Feb 11 20:35:32 2011 +0100
@@ -1,7 +1,7 @@
-changeset = 'changeset:   {rev}:{node|short}\n{branches}{tags}{parents}user:        {author}\ndate:        {date|date}\nsummary:     {desc|firstline}\n\n'
+changeset = 'changeset:   {rev}:{node|short}\n{branches}{bookmarks}{tags}{parents}user:        {author}\ndate:        {date|date}\nsummary:     {desc|firstline}\n\n'
 changeset_quiet = '{rev}:{node|short}\n'
-changeset_verbose = 'changeset:   {rev}:{node|short}\n{branches}{tags}{parents}user:        {author}\ndate:        {date|date}\n{files}{file_copies_switch}description:\n{desc|strip}\n\n\n'
-changeset_debug = 'changeset:   {rev}:{node}\n{branches}{tags}{parents}{manifest}user:        {author}\ndate:        {date|date}\n{file_mods}{file_adds}{file_dels}{file_copies_switch}{extras}description:\n{desc|strip}\n\n\n'
+changeset_verbose = 'changeset:   {rev}:{node|short}\n{branches}{bookmarks}{tags}{parents}user:        {author}\ndate:        {date|date}\n{files}{file_copies_switch}description:\n{desc|strip}\n\n\n'
+changeset_debug = 'changeset:   {rev}:{node}\n{branches}{bookmarks}{tags}{parents}{manifest}user:        {author}\ndate:        {date|date}\n{file_mods}{file_adds}{file_dels}{file_copies_switch}{extras}description:\n{desc|strip}\n\n\n'
 start_files = 'files:      '
 file = ' {file}'
 end_files = '\n'
@@ -21,4 +21,5 @@
 manifest = 'manifest:    {rev}:{node}\n'
 branch = 'branch:      {branch}\n'
 tag = 'tag:         {tag}\n'
+bookmark = 'bookmark:    {bookmark}\n'
 extra = 'extra:       {key}={value|stringescape}\n'
--- a/mercurial/templates/map-cmdline.xml	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/templates/map-cmdline.xml	Fri Feb 11 20:35:32 2011 +0100
@@ -1,9 +1,9 @@
 header = '<?xml version="1.0"?>\n<log>\n'
 footer = '</log>\n'
 
-changeset = '<logentry revision="{rev}" node="{node}">\n{branches}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n</logentry>\n'
-changeset_verbose = '<logentry revision="{rev}" node="{node}">\n{branches}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n<paths>\n{file_adds}{file_dels}{file_mods}</paths>\n{file_copies}</logentry>\n'
-changeset_debug = '<logentry revision="{rev}" node="{node}">\n{branches}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n<paths>\n{file_adds}{file_dels}{file_mods}</paths>\n{file_copies}{extras}</logentry>\n'
+changeset = '<logentry revision="{rev}" node="{node}">\n{branches}{bookmarks}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n</logentry>\n'
+changeset_verbose = '<logentry revision="{rev}" node="{node}">\n{branches}{bookmarks}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n<paths>\n{file_adds}{file_dels}{file_mods}</paths>\n{file_copies}</logentry>\n'
+changeset_debug = '<logentry revision="{rev}" node="{node}">\n{branches}{bookmarks}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n<paths>\n{file_adds}{file_dels}{file_mods}</paths>\n{file_copies}{extras}</logentry>\n'
 
 file_add  = '<path action="A">{file_add|xmlescape}</path>\n'
 file_mod  = '<path action="M">{file_mod|xmlescape}</path>\n'
@@ -16,4 +16,5 @@
 parent = '<parent revision="{rev}" node="{node}" />\n'
 branch = '<branch>{branch|xmlescape}</branch>\n'
 tag = '<tag>{tag|xmlescape}</tag>\n'
+bookmark = '<bookmark>{bookmark|xmlescape}</bookmark>\n'
 extra = '<extra key="{key|xmlescape}">{value|xmlescape}</extra>\n'
--- a/mercurial/util.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/util.py	Fri Feb 11 20:35:32 2011 +0100
@@ -554,16 +554,6 @@
         # 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
 
--- a/mercurial/win32.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/win32.py	Fri Feb 11 20:35:32 2011 +0100
@@ -5,73 +5,173 @@
 # 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 encoding
+import ctypes, errno, os, struct, subprocess
+
+_kernel32 = ctypes.windll.kernel32
+
+_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
+
+_INVALID_HANDLE_VALUE = -1
+
+# GetLastError
+_ERROR_SUCCESS = 0
+_ERROR_INVALID_PARAMETER = 87
+_ERROR_INSUFFICIENT_BUFFER = 122
+
+# 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
+_REG_SZ = 1
+_REG_DWORD = 4
 
-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.
-"""
+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
 
-import win32api
+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)]
 
-import errno, os, sys, pywintypes, win32con, win32file, win32process
-import winerror, win32gui, win32console
-import osutil, encoding
-from win32com.shell import shell, shellcon
+_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:
+        _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 +182,137 @@
     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.RegQueryValueExA(kh.value, valname, None,
+                                       byref(type), 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:
+            adv.RegCloseKey(kh.value)
 
-def system_rcpath_win32():
-    '''return default os-specific hgrc search path'''
-    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]
-    # 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))
-        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')]
+def executable_path():
+    '''return full path of hg.exe'''
+    size = 600
+    buf = ctypes.create_string_buffer(size + 1)
+    len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
+    if len == 0:
+        raise ctypes.WinError()
+    elif len == size:
+        raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
+    return buf.value
 
 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
 
-def set_signal_handler_win32():
-    """Register a termination handler for console events including
+_SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
+_signal_handler = []
+
+def set_signal_handler():
+    '''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
--- a/mercurial/windows.py	Mon Feb 14 14:12:48 2011 -0600
+++ b/mercurial/windows.py	Fri Feb 11 20:35:32 2011 +0100
@@ -71,22 +71,45 @@
         return 'command' in os.environ.get('comspec', '')
 
 def openhardlinks():
-    return not _is_win_9x() and "win32api" in globals()
+    return not _is_win_9x()
+
+_HKEY_LOCAL_MACHINE = 0x80000002L
 
 def system_rcpath():
-    try:
-        return system_rcpath_win32()
-    except:
-        return [r'c:\mercurial\mercurial.ini']
+    '''return default os-specific hgrc search path'''
+    rcpath = []
+    filename = executable_path()
+    # Use mercurial.ini found in directory with hg.exe
+    progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
+    if os.path.isfile(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):
+        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
+    value = lookup_reg('SOFTWARE\\Mercurial', None, _HKEY_LOCAL_MACHINE)
+    if not isinstance(value, str) or not value:
+        return rcpath
+    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():
     '''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')]
+    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'))
@@ -106,10 +129,6 @@
     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
 
@@ -208,12 +227,6 @@
             return executable
     return findexisting(os.path.expanduser(os.path.expandvars(command)))
 
-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.'''
@@ -241,11 +254,6 @@
             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 +343,6 @@
         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 +357,6 @@
     # 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 *
 
 expandglobs = True
--- a/tests/test-bookmarks-pushpull.t	Mon Feb 14 14:12:48 2011 -0600
+++ b/tests/test-bookmarks-pushpull.t	Fri Feb 11 20:35:32 2011 +0100
@@ -48,8 +48,8 @@
   no changes found
   importing bookmark X
   $ hg bookmark
+     X                         0:4e3505fd9583
      Y                         0:4e3505fd9583
-     X                         0:4e3505fd9583
 
 export bookmark by name
 
@@ -62,10 +62,10 @@
   no changes found
   exporting bookmark W
   $ hg -R ../a bookmarks
-     Y                         0:4e3505fd9583
+     W                         -1:000000000000
      X                         0:4e3505fd9583
+     Y                         0:4e3505fd9583
    * Z                         0:4e3505fd9583
-     W                         -1:000000000000
 
 delete a remote bookmark
 
@@ -97,8 +97,8 @@
   adding f1
   $ hg book -f X
   $ hg book
+   * X                         1:0d2164f0ce0d
      Y                         0:4e3505fd9583
-   * X                         1:0d2164f0ce0d
      Z                         1:0d2164f0ce0d
 
   $ cd ../b
@@ -109,8 +109,8 @@
   adding f2
   $ hg book -f X
   $ hg book
+   * X                         1:9b140be10808
      Y                         0:4e3505fd9583
-   * X                         1:9b140be10808
      foo                       -1:000000000000
      foobar                    -1:000000000000
 
@@ -124,8 +124,8 @@
   not updating divergent bookmark X
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hg book
+   * X                         1:9b140be10808
      Y                         0:4e3505fd9583
-   * X                         1:9b140be10808
      foo                       -1:000000000000
      foobar                    -1:000000000000
   $ hg push -f ../a
@@ -136,8 +136,8 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
   $ hg -R ../a book
+   * X                         1:0d2164f0ce0d
      Y                         0:4e3505fd9583
-   * X                         1:0d2164f0ce0d
      Z                         1:0d2164f0ce0d
 
 hgweb
--- a/tests/test-bookmarks-rebase.t	Mon Feb 14 14:12:48 2011 -0600
+++ b/tests/test-bookmarks-rebase.t	Fri Feb 11 20:35:32 2011 +0100
@@ -31,8 +31,8 @@
 bookmark list
 
   $ hg bookmark
+     one                       1:925d80f479bb
    * two                       3:2ae46b1d99a7
-     one                       1:925d80f479bb
 
 rebase
 
@@ -41,9 +41,9 @@
 
   $ hg log
   changeset:   3:9163974d1cb5
-  tag:         one
+  bookmark:    one
+  bookmark:    two
   tag:         tip
-  tag:         two
   parent:      1:925d80f479bb
   parent:      2:db815d6d32e6
   user:        test
--- a/tests/test-bookmarks.t	Mon Feb 14 14:12:48 2011 -0600
+++ b/tests/test-bookmarks.t	Fri Feb 11 20:35:32 2011 +0100
@@ -36,7 +36,7 @@
 
   $ hg log -r X
   changeset:   0:f7b1eb17ad24
-  tag:         X
+  bookmark:    X
   tag:         tip
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
@@ -54,8 +54,8 @@
 list bookmarks
 
   $ hg bookmarks
+   * X                         0:f7b1eb17ad24
    * X2                        0:f7b1eb17ad24
-   * X                         0:f7b1eb17ad24
      Y                         -1:000000000000
 
   $ echo b > b
@@ -66,8 +66,8 @@
 
   $ hg log -r 'bookmark()'
   changeset:   1:925d80f479bb
-  tag:         X
-  tag:         X2
+  bookmark:    X
+  bookmark:    X2
   tag:         tip
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
@@ -76,8 +76,8 @@
   $ hg log -r 'bookmark(Y)'
   $ hg log -r 'bookmark(X2)'
   changeset:   1:925d80f479bb
-  tag:         X
-  tag:         X2
+  bookmark:    X
+  bookmark:    X2
   tag:         tip
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
@@ -89,8 +89,8 @@
 bookmarks X and X2 moved to rev 1, Y at rev -1
 
   $ hg bookmarks
+   * X                         1:925d80f479bb
    * X2                        1:925d80f479bb
-   * X                         1:925d80f479bb
      Y                         -1:000000000000
 
 bookmark rev 0 again
@@ -104,10 +104,10 @@
 bookmarks X and X2 moved to rev 2, Y at rev -1, Z at rev 0
 
   $ hg bookmarks
+   * X                         2:0316ce92851d
    * X2                        2:0316ce92851d
-   * X                         2:0316ce92851d
+     Y                         -1:000000000000
      Z                         0:f7b1eb17ad24
-     Y                         -1:000000000000
 
 rename nonexistent bookmark
 
@@ -166,10 +166,10 @@
 
   $ hg log -r '"x  y"'
   changeset:   2:0316ce92851d
-  tag:         X2
-  tag:         Y
+  bookmark:    X2
+  bookmark:    Y
+  bookmark:    x  y
   tag:         tip
-  tag:         x  y
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     2
--- a/tests/test-bundle.t	Mon Feb 14 14:12:48 2011 -0600
+++ b/tests/test-bundle.t	Fri Feb 11 20:35:32 2011 +0100
@@ -188,6 +188,13 @@
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     0.0
   
+Make sure bundlerepo doesn't leak tempfiles (issue2491)
+
+  $ ls .hg
+  00changelog.i
+  cache
+  requires
+  store
 
 Pull ../full.hg into empty (with hook)