Mercurial > hg
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)