localrepo: sort hg bookmark output
sort bookmarks before we write them to stdout to get a predictable output.
--- 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)