bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 1 | # Copyright (C) 2006, 2007 Canonical Ltd
 | 
| 2 | #
 | |
| 2052.3.1
by John Arbash Meinel Add tests to cleanup the copyright of all source files | 3 | # This program is free software; you can redistribute it and/or modify
 | 
| 4 | # it under the terms of the GNU General Public License as published by
 | |
| 5 | # the Free Software Foundation; either version 2 of the License, or
 | |
| 6 | # (at your option) any later version.
 | |
| 7 | #
 | |
| 8 | # This program is distributed in the hope that it will be useful,
 | |
| 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| 11 | # GNU General Public License for more details.
 | |
| 12 | #
 | |
| 13 | # You should have received a copy of the GNU General Public License
 | |
| 14 | # along with this program; if not, write to the Free Software
 | |
| 15 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
| 16 | ||
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 17 | """Win32-specific helper functions
 | 
| 18 | ||
| 19 | Only one dependency: ctypes should be installed.
 | |
| 20 | """
 | |
| 21 | ||
| 22 | import os | |
| 1185.16.86
by mbp at sourcefrog - win32 get_console_size from Alexander | 23 | import struct | 
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 24 | import sys | 
| 25 | ||
| 26 | ||
| 27 | # Windows version
 | |
| 28 | if sys.platform == 'win32': | |
| 29 | _major,_minor,_build,_platform,_text = sys.getwindowsversion() | |
| 2245.4.11
by Alexander Belchenko Small fixes after John's review; added NEWS entry | 30 |     # from MSDN:
 | 
| 31 |     # dwPlatformId
 | |
| 32 |     #   The operating system platform.
 | |
| 33 |     #   This member can be one of the following values.
 | |
| 34 |     #   ==========================  ======================================
 | |
| 35 |     #   Value                       Meaning
 | |
| 36 |     #   --------------------------  --------------------------------------
 | |
| 37 |     #   VER_PLATFORM_WIN32_NT       The operating system is Windows Vista,
 | |
| 38 |     #   2                           Windows Server "Longhorn",
 | |
| 39 |     #                               Windows Server 2003, Windows XP,
 | |
| 40 |     #                               Windows 2000, or Windows NT.
 | |
| 41 |     #
 | |
| 42 |     #   VER_PLATFORM_WIN32_WINDOWS  The operating system is Windows Me,
 | |
| 43 |     #   1                           Windows 98, or Windows 95.
 | |
| 44 |     #   ==========================  ======================================
 | |
| 45 | if _platform == 2: | |
| 46 | winver = 'Windows NT' | |
| 47 | else: | |
| 48 |         # don't care about real Windows name, just to force safe operations
 | |
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 49 | winver = 'Windows 98' | 
| 50 | else: | |
| 51 | winver = None | |
| 52 | ||
| 1185.16.86
by mbp at sourcefrog - win32 get_console_size from Alexander | 53 | |
| 1773.4.1
by Martin Pool Add pyflakes makefile target; fix many warnings | 54 | # We can cope without it; use a separate variable to help pyflakes
 | 
| 1185.16.86
by mbp at sourcefrog - win32 get_console_size from Alexander | 55 | try: | 
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 56 | import ctypes | 
| 57 | has_ctypes = True | |
| 1185.16.86
by mbp at sourcefrog - win32 get_console_size from Alexander | 58 | except ImportError: | 
| 1773.4.1
by Martin Pool Add pyflakes makefile target; fix many warnings | 59 | has_ctypes = False | 
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 60 | else: | 
| 61 | if winver == 'Windows 98': | |
| 62 | create_buffer = ctypes.create_string_buffer | |
| 63 | suffix = 'A' | |
| 64 | else: | |
| 65 | create_buffer = ctypes.create_unicode_buffer | |
| 66 | suffix = 'W' | |
| 3023.1.2
by Alexander Belchenko Martin's review. | 67 | try: | 
| 68 | import win32file | |
| 69 | has_win32file = True | |
| 70 | except ImportError: | |
| 71 | has_win32file = False | |
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 72 | |
| 73 | ||
| 74 | # Special Win32 API constants
 | |
| 75 | # Handles of std streams
 | |
| 1704.2.3
by Martin Pool (win32) Detect terminal width using GetConsoleScreenBufferInfo (Alexander) | 76 | WIN32_STDIN_HANDLE = -10 | 
| 77 | WIN32_STDOUT_HANDLE = -11 | |
| 78 | WIN32_STDERR_HANDLE = -12 | |
| 79 | ||
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 80 | # CSIDL constants (from MSDN 2003)
 | 
| 81 | CSIDL_APPDATA = 0x001A # Application Data folder | |
| 82 | CSIDL_PERSONAL = 0x0005 # My Documents folder | |
| 83 | ||
| 84 | # from winapi C headers
 | |
| 85 | MAX_PATH = 260 | |
| 86 | UNLEN = 256 | |
| 87 | MAX_COMPUTERNAME_LENGTH = 31 | |
| 88 | ||
| 1704.2.3
by Martin Pool (win32) Detect terminal width using GetConsoleScreenBufferInfo (Alexander) | 89 | |
| 1185.16.86
by mbp at sourcefrog - win32 get_console_size from Alexander | 90 | def get_console_size(defaultx=80, defaulty=25): | 
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 91 | """Return size of current console. | 
| 92 | ||
| 93 |     This function try to determine actual size of current working
 | |
| 94 |     console window and return tuple (sizex, sizey) if success,
 | |
| 95 |     or default size (defaultx, defaulty) otherwise.
 | |
| 96 |     """
 | |
| 97 | if not has_ctypes: | |
| 98 |         # no ctypes is found
 | |
| 99 | return (defaultx, defaulty) | |
| 100 | ||
| 101 |     # To avoid problem with redirecting output via pipe
 | |
| 102 |     # need to use stderr instead of stdout
 | |
| 103 | h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE) | |
| 104 | csbi = ctypes.create_string_buffer(22) | |
| 105 | res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) | |
| 106 | ||
| 107 | if res: | |
| 108 | (bufx, bufy, curx, cury, wattr, | |
| 1185.16.86
by mbp at sourcefrog - win32 get_console_size from Alexander | 109 | left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw) | 
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 110 | sizex = right - left + 1 | 
| 111 | sizey = bottom - top + 1 | |
| 112 | return (sizex, sizey) | |
| 113 | else: | |
| 114 | return (defaultx, defaulty) | |
| 115 | ||
| 116 | ||
| 117 | def get_appdata_location(): | |
| 118 | """Return Application Data location. | |
| 119 |     Return None if we cannot obtain location.
 | |
| 120 | ||
| 121 |     Returned value can be unicode or plain sring.
 | |
| 122 |     To convert plain string to unicode use
 | |
| 123 |     s.decode(bzrlib.user_encoding)
 | |
| 124 |     """
 | |
| 125 | if has_ctypes: | |
| 126 | try: | |
| 127 | SHGetSpecialFolderPath = \ | |
| 128 | ctypes.windll.shell32.SHGetSpecialFolderPathW | |
| 129 | except AttributeError: | |
| 130 |             pass
 | |
| 131 | else: | |
| 132 | buf = ctypes.create_unicode_buffer(MAX_PATH) | |
| 133 | if SHGetSpecialFolderPath(None,buf,CSIDL_APPDATA,0): | |
| 134 | return buf.value | |
| 135 |     # from env variable
 | |
| 136 | appdata = os.environ.get('APPDATA') | |
| 137 | if appdata: | |
| 138 | return appdata | |
| 139 |     # if we fall to this point we on win98
 | |
| 140 |     # at least try C:/WINDOWS/Application Data
 | |
| 141 | windir = os.environ.get('windir') | |
| 142 | if windir: | |
| 143 | appdata = os.path.join(windir, 'Application Data') | |
| 144 | if os.path.isdir(appdata): | |
| 145 | return appdata | |
| 146 |     # did not find anything
 | |
| 147 | return None | |
| 148 | ||
| 149 | ||
| 150 | def get_home_location(): | |
| 151 | """Return user's home location. | |
| 152 |     Assume on win32 it's the <My Documents> folder.
 | |
| 153 |     If location cannot be obtained return system drive root,
 | |
| 154 |     i.e. C:\
 | |
| 155 | ||
| 156 |     Returned value can be unicode or plain sring.
 | |
| 157 |     To convert plain string to unicode use
 | |
| 158 |     s.decode(bzrlib.user_encoding)
 | |
| 159 |     """
 | |
| 160 | if has_ctypes: | |
| 161 | try: | |
| 162 | SHGetSpecialFolderPath = \ | |
| 163 | ctypes.windll.shell32.SHGetSpecialFolderPathW | |
| 164 | except AttributeError: | |
| 165 |             pass
 | |
| 166 | else: | |
| 167 | buf = ctypes.create_unicode_buffer(MAX_PATH) | |
| 168 | if SHGetSpecialFolderPath(None,buf,CSIDL_PERSONAL,0): | |
| 169 | return buf.value | |
| 170 |     # try for HOME env variable
 | |
| 171 | home = os.path.expanduser('~') | |
| 172 | if home != '~': | |
| 173 | return home | |
| 174 |     # at least return windows root directory
 | |
| 175 | windir = os.environ.get('windir') | |
| 176 | if windir: | |
| 2610.1.1
by Martin Pool Fix get_home_location on Win98 (gzlist,r=john,r=alexander) | 177 | return os.path.splitdrive(windir)[0] + '/' | 
| 2245.4.1
by Alexander Belchenko win32utils: Windows-specific functions that use Win32 API via ctypes | 178 |     # otherwise C:\ is good enough for 98% users
 | 
| 179 | return 'C:/' | |
| 180 | ||
| 181 | ||
| 182 | def get_user_name(): | |
| 183 | """Return user name as login name. | |
| 184 |     If name cannot be obtained return None.
 | |
| 185 | ||
| 186 |     Returned value can be unicode or plain sring.
 | |
| 187 |     To convert plain string to unicode use
 | |
| 188 |     s.decode(bzrlib.user_encoding)
 | |
| 189 |     """
 | |
| 190 | if has_ctypes: | |
| 191 | try: | |
| 192 | advapi32 = ctypes.windll.advapi32 | |
| 193 | GetUserName = getattr(advapi32, 'GetUserName'+suffix) | |
| 194 | except AttributeError: | |
| 195 |             pass
 | |
| 196 | else: | |
| 197 | buf = create_buffer(UNLEN+1) | |
| 198 | n = ctypes.c_int(UNLEN+1) | |
| 199 | if GetUserName(buf, ctypes.byref(n)): | |
| 200 | return buf.value | |
| 201 |     # otherwise try env variables
 | |
| 202 | return os.environ.get('USERNAME', None) | |
| 203 | ||
| 204 | ||
| 205 | def get_host_name(): | |
| 206 | """Return host machine name. | |
| 207 |     If name cannot be obtained return None.
 | |
| 208 | ||
| 209 |     Returned value can be unicode or plain sring.
 | |
| 210 |     To convert plain string to unicode use
 | |
| 211 |     s.decode(bzrlib.user_encoding)
 | |
| 212 |     """
 | |
| 213 | if has_ctypes: | |
| 214 | try: | |
| 215 | kernel32 = ctypes.windll.kernel32 | |
| 216 | GetComputerName = getattr(kernel32, 'GetComputerName'+suffix) | |
| 217 | except AttributeError: | |
| 218 |             pass
 | |
| 219 | else: | |
| 220 | buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1) | |
| 221 | n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1) | |
| 222 | if GetComputerName(buf, ctypes.byref(n)): | |
| 223 | return buf.value | |
| 224 |     # otherwise try env variables
 | |
| 225 | return os.environ.get('COMPUTERNAME', None) | |
| 226 | ||
| 227 | ||
| 228 | def _ensure_unicode(s): | |
| 229 | if s and type(s) != unicode: | |
| 230 | import bzrlib | |
| 231 | s = s.decode(bzrlib.user_encoding) | |
| 232 | return s | |
| 233 | ||
| 234 | ||
| 235 | def get_appdata_location_unicode(): | |
| 236 | return _ensure_unicode(get_appdata_location()) | |
| 237 | ||
| 238 | def get_home_location_unicode(): | |
| 239 | return _ensure_unicode(get_home_location()) | |
| 240 | ||
| 241 | def get_user_name_unicode(): | |
| 242 | return _ensure_unicode(get_user_name()) | |
| 243 | ||
| 244 | def get_host_name_unicode(): | |
| 245 | return _ensure_unicode(get_host_name()) | |
| 2568.2.2
by Robert Collins * New method ``_glob_expand_file_list_if_needed`` on the ``Command`` class | 246 | |
| 247 | ||
| 2617.5.8
by Kuno Meyer Extended tests for unicode chars outside of the iso-8859-* range | 248 | def _ensure_with_dir(path): | 
| 249 | if not os.path.split(path)[0] or path.startswith(u'*') or path.startswith(u'?'): | |
| 250 | return u'./' + path, True | |
| 251 | else: | |
| 252 | return path, False | |
| 253 | ||
| 254 | def _undo_ensure_with_dir(path, corrected): | |
| 255 | if corrected: | |
| 256 | return path[2:] | |
| 257 | else: | |
| 258 | return path | |
| 259 | ||
| 260 | ||
| 261 | ||
| 2598.3.1
by Kuno Meyer fix method rename glob_expand_for_win32 -> win32utils.glob_expand | 262 | def glob_expand(file_list): | 
| 2568.2.2
by Robert Collins * New method ``_glob_expand_file_list_if_needed`` on the ``Command`` class | 263 | """Replacement for glob expansion by the shell. | 
| 264 | ||
| 265 |     Win32's cmd.exe does not do glob expansion (eg ``*.py``), so we do our own
 | |
| 266 |     here.
 | |
| 267 | ||
| 268 |     :param file_list: A list of filenames which may include shell globs.
 | |
| 269 |     :return: An expanded list of filenames.
 | |
| 270 | ||
| 271 |     Introduced in bzrlib 0.18.
 | |
| 272 |     """
 | |
| 273 | if not file_list: | |
| 274 | return [] | |
| 275 | import glob | |
| 276 | expanded_file_list = [] | |
| 277 | for possible_glob in file_list: | |
| 2617.5.8
by Kuno Meyer Extended tests for unicode chars outside of the iso-8859-* range | 278 | |
| 279 |         # work around bugs in glob.glob()
 | |
| 280 |         # - Python bug #1001604 ("glob doesn't return unicode with ...")
 | |
| 281 |         # - failing expansion for */* with non-iso-8859-* chars
 | |
| 282 | possible_glob, corrected = _ensure_with_dir(possible_glob) | |
| 2568.2.2
by Robert Collins * New method ``_glob_expand_file_list_if_needed`` on the ``Command`` class | 283 | glob_files = glob.glob(possible_glob) | 
| 284 | ||
| 285 | if glob_files == []: | |
| 286 |             # special case to let the normal code path handle
 | |
| 287 |             # files that do not exists
 | |
| 2617.5.8
by Kuno Meyer Extended tests for unicode chars outside of the iso-8859-* range | 288 | expanded_file_list.append( | 
| 289 | _undo_ensure_with_dir(possible_glob, corrected)) | |
| 2568.2.2
by Robert Collins * New method ``_glob_expand_file_list_if_needed`` on the ``Command`` class | 290 | else: | 
| 2617.5.8
by Kuno Meyer Extended tests for unicode chars outside of the iso-8859-* range | 291 | glob_files = [_undo_ensure_with_dir(elem, corrected) for elem in glob_files] | 
| 2568.2.2
by Robert Collins * New method ``_glob_expand_file_list_if_needed`` on the ``Command`` class | 292 | expanded_file_list += glob_files | 
| 2617.5.8
by Kuno Meyer Extended tests for unicode chars outside of the iso-8859-* range | 293 | |
| 294 | return [elem.replace(u'\\', u'/') for elem in expanded_file_list] | |
| 2681.4.1
by Alexander Belchenko win32: looking for full path of mail client executable in registry | 295 | |
| 296 | ||
| 297 | def get_app_path(appname): | |
| 298 | """Look up in Windows registry for full path to application executable. | |
| 299 |     Typicaly, applications create subkey with their basename
 | |
| 300 |     in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
 | |
| 301 | ||
| 302 |     :param  appname:    name of application (if no filename extension
 | |
| 303 |                         is specified, .exe used)
 | |
| 304 |     :return:    full path to aplication executable from registry,
 | |
| 305 |                 or appname itself if nothing found.
 | |
| 306 |     """
 | |
| 2681.4.3
by Alexander Belchenko move import _winreg into function get_app_path to avoid ImportError on non-win32 platforms | 307 | import _winreg | 
| 2681.4.1
by Alexander Belchenko win32: looking for full path of mail client executable in registry | 308 | try: | 
| 309 | hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, | |
| 310 | r'SOFTWARE\Microsoft\Windows' | |
| 311 | r'\CurrentVersion\App Paths') | |
| 312 | except EnvironmentError: | |
| 313 | return appname | |
| 314 | ||
| 315 | basename = appname | |
| 316 | if not os.path.splitext(basename)[1]: | |
| 317 | basename = appname + '.exe' | |
| 318 | try: | |
| 319 | try: | |
| 320 | fullpath = _winreg.QueryValue(hkey, basename) | |
| 321 | except WindowsError: | |
| 322 | fullpath = appname | |
| 323 | finally: | |
| 324 | _winreg.CloseKey(hkey) | |
| 325 | ||
| 326 | return fullpath | |
| 3023.1.2
by Alexander Belchenko Martin's review. | 327 | |
| 328 | ||
| 329 | def set_file_attr_hidden(path): | |
| 330 | """Set file attributes to hidden if possible""" | |
| 331 | if has_win32file: | |
| 332 | win32file.SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN) |