/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-04-06 06:59:03 UTC
  • mfrom: (5051.5.1 subunit)
  • Revision ID: pqm@pqm.ubuntu.com-20100406065903-y9dxgwmog1pmw7dz
Use subunit when running tests in PQM.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
Only one dependency: ctypes should be installed.
20
20
"""
21
21
 
22
 
from __future__ import absolute_import
23
 
 
24
22
import glob
25
23
import os
 
24
import re
26
25
import struct
27
26
import sys
28
27
 
29
 
from breezy import (
30
 
    cmdline,
31
 
    )
32
 
from breezy.i18n import gettext
 
28
from bzrlib import cmdline
33
29
 
34
 
has_ctypes_win32 = False
 
30
# Windows version
35
31
if sys.platform == 'win32':
36
 
    try:
37
 
        import ctypes
38
 
    except ImportError:
39
 
        has_ctypes_win32 = False
40
 
 
 
32
    _major,_minor,_build,_platform,_text = sys.getwindowsversion()
 
33
    # from MSDN:
 
34
    # dwPlatformId
 
35
    #   The operating system platform.
 
36
    #   This member can be one of the following values.
 
37
    #   ==========================  ======================================
 
38
    #   Value                       Meaning
 
39
    #   --------------------------  --------------------------------------
 
40
    #   VER_PLATFORM_WIN32_NT       The operating system is Windows Vista,
 
41
    #   2                           Windows Server "Longhorn",
 
42
    #                               Windows Server 2003, Windows XP,
 
43
    #                               Windows 2000, or Windows NT.
 
44
    #
 
45
    #   VER_PLATFORM_WIN32_WINDOWS  The operating system is Windows Me,
 
46
    #   1                           Windows 98, or Windows 95.
 
47
    #   ==========================  ======================================
 
48
    if _platform == 2:
 
49
        winver = 'Windows NT'
 
50
    else:
 
51
        # don't care about real Windows name, just to force safe operations
 
52
        winver = 'Windows 98'
 
53
else:
 
54
    winver = None
 
55
 
 
56
 
 
57
# We can cope without it; use a separate variable to help pyflakes
 
58
try:
 
59
    import ctypes
 
60
    has_ctypes = True
 
61
except ImportError:
 
62
    has_ctypes = False
 
63
else:
 
64
    if winver == 'Windows 98':
 
65
        create_buffer = ctypes.create_string_buffer
 
66
        suffix = 'A'
 
67
    else:
 
68
        create_buffer = ctypes.create_unicode_buffer
 
69
        suffix = 'W'
 
70
try:
 
71
    import win32file
 
72
    import pywintypes
 
73
    has_win32file = True
 
74
except ImportError:
 
75
    has_win32file = False
 
76
try:
 
77
    import win32api
 
78
    has_win32api = True
 
79
except ImportError:
 
80
    has_win32api = False
 
81
 
 
82
# pulling in win32com.shell is a bit of overhead, and normally we don't need
 
83
# it as ctypes is preferred and common.  lazy_imports and "optional"
 
84
# modules don't work well, so we do our own lazy thing...
 
85
has_win32com_shell = None # Set to True or False once we know for sure...
41
86
 
42
87
# Special Win32 API constants
43
88
# Handles of std streams
47
92
 
48
93
# CSIDL constants (from MSDN 2003)
49
94
CSIDL_APPDATA = 0x001A      # Application Data folder
50
 
# <user name>\Local Settings\Application Data (non roaming)
51
 
CSIDL_LOCAL_APPDATA = 0x001c
 
95
CSIDL_LOCAL_APPDATA = 0x001c# <user name>\Local Settings\Application Data (non roaming)
52
96
CSIDL_PERSONAL = 0x0005     # My Documents folder
53
97
 
54
98
# from winapi C headers
63
107
 
64
108
def debug_memory_win32api(message='', short=True):
65
109
    """Use trace.note() to dump the running memory info."""
66
 
    from breezy import trace
67
 
    if has_ctypes_win32:
 
110
    from bzrlib import trace
 
111
    if has_ctypes:
68
112
        class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
69
113
            """Used by GetProcessMemoryInfo"""
70
114
            _fields_ = [('cb', ctypes.c_ulong),
78
122
                        ('PagefileUsage', ctypes.c_size_t),
79
123
                        ('PeakPagefileUsage', ctypes.c_size_t),
80
124
                        ('PrivateUsage', ctypes.c_size_t),
81
 
                        ]
 
125
                       ]
82
126
        cur_process = ctypes.windll.kernel32.GetCurrentProcess()
83
127
        mem_struct = PROCESS_MEMORY_COUNTERS_EX()
84
 
        ret = ctypes.windll.psapi.GetProcessMemoryInfo(
85
 
            cur_process, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
 
128
        ret = ctypes.windll.psapi.GetProcessMemoryInfo(cur_process,
 
129
            ctypes.byref(mem_struct),
 
130
            ctypes.sizeof(mem_struct))
86
131
        if not ret:
87
 
            trace.note(gettext('Failed to GetProcessMemoryInfo()'))
 
132
            trace.note('Failed to GetProcessMemoryInfo()')
88
133
            return
89
134
        info = {'PageFaultCount': mem_struct.PageFaultCount,
90
135
                'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
97
142
                'PagefileUsage': mem_struct.PagefileUsage,
98
143
                'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
99
144
                'PrivateUsage': mem_struct.PrivateUsage,
100
 
                }
 
145
               }
 
146
    elif has_win32api:
 
147
        import win32process
 
148
        # win32process does not return PrivateUsage, because it doesn't use
 
149
        # PROCESS_MEMORY_COUNTERS_EX (it uses the one without _EX).
 
150
        proc = win32process.GetCurrentProcess()
 
151
        info = win32process.GetProcessMemoryInfo(proc)
101
152
    else:
102
 
        trace.note(gettext('Cannot debug memory on win32 without ctypes'
103
 
                           ' or win32process'))
 
153
        trace.note('Cannot debug memory on win32 without ctypes'
 
154
                   ' or win32process')
104
155
        return
105
156
    if short:
106
157
        # using base-2 units (see HACKING.txt).
107
 
        trace.note(gettext('WorkingSize {0:>7}KiB'
108
 
                           '\tPeakWorking {1:>7}KiB\t{2}').format(
 
158
        trace.note('WorkingSize %7dKiB'
 
159
                   '\tPeakWorking %7dKiB\t%s',
109
160
                   info['WorkingSetSize'] / 1024,
110
161
                   info['PeakWorkingSetSize'] / 1024,
111
 
                   message))
 
162
                   message)
112
163
        return
113
164
    if message:
114
165
        trace.note('%s', message)
115
 
    trace.note(gettext('WorkingSize       %8d KiB'),
116
 
               info['WorkingSetSize'] / 1024)
117
 
    trace.note(gettext('PeakWorking       %8d KiB'),
118
 
               info['PeakWorkingSetSize'] / 1024)
119
 
    trace.note(gettext('PagefileUsage     %8d KiB'),
120
 
               info.get('PagefileUsage', 0) / 1024)
121
 
    trace.note(gettext('PeakPagefileUsage %8d KiB'),
 
166
    trace.note('WorkingSize       %8d KiB', info['WorkingSetSize'] / 1024)
 
167
    trace.note('PeakWorking       %8d KiB', info['PeakWorkingSetSize'] / 1024)
 
168
    trace.note('PagefileUsage     %8d KiB', info.get('PagefileUsage', 0) / 1024)
 
169
    trace.note('PeakPagefileUsage %8d KiB',
122
170
               info.get('PeakPagefileUsage', 0) / 1024)
123
 
    trace.note(gettext('PrivateUsage      %8d KiB'),
124
 
               info.get('PrivateUsage', 0) / 1024)
125
 
    trace.note(gettext('PageFaultCount    %8d'), info.get('PageFaultCount', 0))
 
171
    trace.note('PrivateUsage      %8d KiB', info.get('PrivateUsage', 0) / 1024)
 
172
    trace.note('PageFaultCount    %8d', info.get('PageFaultCount', 0))
126
173
 
127
174
 
128
175
def get_console_size(defaultx=80, defaulty=25):
132
179
    console window and return tuple (sizex, sizey) if success,
133
180
    or default size (defaultx, defaulty) otherwise.
134
181
    """
135
 
    if not has_ctypes_win32:
 
182
    if not has_ctypes:
136
183
        # no ctypes is found
137
184
        return (defaultx, defaulty)
138
185
 
144
191
 
145
192
    if res:
146
193
        (bufx, bufy, curx, cury, wattr,
147
 
         left, top, right, bottom, maxx, maxy) = struct.unpack(
 
194
        left, top, right, bottom, maxx, maxy) = struct.unpack(
148
195
            "hhhhHhhhhhh", csbi.raw)
149
196
        sizex = right - left + 1
150
197
        sizey = bottom - top + 1
158
205
 
159
206
    Result is always unicode (or None).
160
207
    """
161
 
    if has_ctypes_win32:
 
208
    if has_ctypes:
162
209
        try:
163
210
            SHGetSpecialFolderPath = \
164
211
                ctypes.windll.shell32.SHGetSpecialFolderPathW
166
213
            pass
167
214
        else:
168
215
            buf = ctypes.create_unicode_buffer(MAX_PATH)
169
 
            if SHGetSpecialFolderPath(None, buf, csidl, 0):
 
216
            if SHGetSpecialFolderPath(None,buf,csidl,0):
170
217
                return buf.value
 
218
 
 
219
    global has_win32com_shell
 
220
    if has_win32com_shell is None:
 
221
        try:
 
222
            from win32com.shell import shell
 
223
            has_win32com_shell = True
 
224
        except ImportError:
 
225
            has_win32com_shell = False
 
226
    if has_win32com_shell:
 
227
        # still need to bind the name locally, but this is fast.
 
228
        from win32com.shell import shell
 
229
        try:
 
230
            return shell.SHGetSpecialFolderPath(0, csidl, 0)
 
231
        except shell.error:
 
232
            # possibly E_NOTIMPL meaning we can't load the function pointer,
 
233
            # or E_FAIL meaning the function failed - regardless, just ignore it
 
234
            pass
171
235
    return None
172
236
 
173
237
 
179
243
    one that moves with the user as they logon to different machines, and
180
244
    a 'local' one that stays local to the machine.  This returns the 'roaming'
181
245
    directory, and thus is suitable for storing user-preferences, etc.
 
246
 
 
247
    Returned value can be unicode or plain string.
 
248
    To convert plain string to unicode use
 
249
    s.decode(osutils.get_user_encoding())
 
250
    (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs')
182
251
    """
183
252
    appdata = _get_sh_special_folder_path(CSIDL_APPDATA)
184
253
    if appdata:
185
254
        return appdata
186
 
    # Use APPDATA if defined, will return None if not
187
 
    return get_environ_unicode('APPDATA')
 
255
    # from env variable
 
256
    appdata = os.environ.get('APPDATA')
 
257
    if appdata:
 
258
        return appdata
 
259
    # if we fall to this point we on win98
 
260
    # at least try C:/WINDOWS/Application Data
 
261
    windir = os.environ.get('windir')
 
262
    if windir:
 
263
        appdata = os.path.join(windir, 'Application Data')
 
264
        if os.path.isdir(appdata):
 
265
            return appdata
 
266
    # did not find anything
 
267
    return None
188
268
 
189
269
 
190
270
def get_local_appdata_location():
196
276
    a 'local' one that stays local to the machine.  This returns the 'local'
197
277
    directory, and thus is suitable for caches, temp files and other things
198
278
    which don't need to move with the user.
 
279
 
 
280
    Returned value can be unicode or plain string.
 
281
    To convert plain string to unicode use
 
282
    s.decode(osutils.get_user_encoding())
 
283
    (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs')
199
284
    """
200
285
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
201
286
    if local:
202
287
        return local
203
288
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
204
 
    local = get_environ_unicode('LOCALAPPDATA')
 
289
    local = os.environ.get('LOCALAPPDATA')
205
290
    if local:
206
291
        return local
207
292
    return get_appdata_location()
212
297
    Assume on win32 it's the <My Documents> folder.
213
298
    If location cannot be obtained return system drive root,
214
299
    i.e. C:\
 
300
 
 
301
    Returned value can be unicode or plain string.
 
302
    To convert plain string to unicode use
 
303
    s.decode(osutils.get_user_encoding())
215
304
    """
216
305
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
217
306
    if home:
218
307
        return home
219
 
    home = get_environ_unicode('HOME')
220
 
    if home is not None:
 
308
    # try for HOME env variable
 
309
    home = os.path.expanduser('~')
 
310
    if home != '~':
221
311
        return home
222
 
    homepath = get_environ_unicode('HOMEPATH')
223
 
    if homepath is not None:
224
 
        return os.path.join(get_environ_unicode('HOMEDIR', ''), home)
225
312
    # at least return windows root directory
226
 
    windir = get_environ_unicode('WINDIR')
 
313
    windir = os.environ.get('windir')
227
314
    if windir:
228
315
        return os.path.splitdrive(windir)[0] + '/'
229
316
    # otherwise C:\ is good enough for 98% users
230
 
    return u'C:/'
 
317
    return 'C:/'
231
318
 
232
319
 
233
320
def get_user_name():
234
321
    """Return user name as login name.
235
322
    If name cannot be obtained return None.
 
323
 
 
324
    Returned value can be unicode or plain string.
 
325
    To convert plain string to unicode use
 
326
    s.decode(osutils.get_user_encoding())
236
327
    """
237
 
    if has_ctypes_win32:
 
328
    if has_ctypes:
238
329
        try:
239
330
            advapi32 = ctypes.windll.advapi32
240
 
            GetUserName = getattr(advapi32, 'GetUserNameW')
 
331
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
241
332
        except AttributeError:
242
333
            pass
243
334
        else:
244
 
            buf = ctypes.create_unicode_buffer(UNLEN + 1)
245
 
            n = ctypes.c_int(UNLEN + 1)
 
335
            buf = create_buffer(UNLEN+1)
 
336
            n = ctypes.c_int(UNLEN+1)
246
337
            if GetUserName(buf, ctypes.byref(n)):
247
338
                return buf.value
248
339
    # otherwise try env variables
249
 
    return get_environ_unicode('USERNAME')
 
340
    return os.environ.get('USERNAME', None)
250
341
 
251
342
 
252
343
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
253
344
# computer or the cluster associated with the local computer."
254
345
_WIN32_ComputerNameDnsHostname = 1
255
346
 
256
 
 
257
347
def get_host_name():
258
348
    """Return host machine name.
259
349
    If name cannot be obtained return None.
260
350
 
261
 
    :return: A unicode string representing the host name.
 
351
    :return: A unicode string representing the host name. On win98, this may be
 
352
        a plain string as win32 api doesn't support unicode.
262
353
    """
263
 
    if has_ctypes_win32:
 
354
    if has_win32api:
 
355
        try:
 
356
            return win32api.GetComputerNameEx(_WIN32_ComputerNameDnsHostname)
 
357
        except (NotImplementedError, win32api.error):
 
358
            # NotImplemented will happen on win9x...
 
359
            pass
 
360
    if has_ctypes:
264
361
        try:
265
362
            kernel32 = ctypes.windll.kernel32
266
363
        except AttributeError:
267
 
            pass  # Missing the module we need
 
364
            pass # Missing the module we need
268
365
        else:
269
 
            buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
270
 
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
 
366
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
 
367
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
271
368
 
272
369
            # Try GetComputerNameEx which gives a proper Unicode hostname
273
 
            GetComputerNameEx = getattr(kernel32, 'GetComputerNameExW', None)
 
370
            GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
 
371
                                        None)
274
372
            if (GetComputerNameEx is not None
275
373
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
276
374
                                      buf, ctypes.byref(n))):
277
375
                return buf.value
278
 
    return get_environ_unicode('COMPUTERNAME')
 
376
 
 
377
            # Try GetComputerName in case GetComputerNameEx wasn't found
 
378
            # It returns the NETBIOS name, which isn't as good, but still ok.
 
379
            # The first GetComputerNameEx might have changed 'n', so reset it
 
380
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
 
381
            GetComputerName = getattr(kernel32, 'GetComputerName'+suffix,
 
382
                                      None)
 
383
            if (GetComputerName is not None
 
384
                and GetComputerName(buf, ctypes.byref(n))):
 
385
                return buf.value
 
386
    # otherwise try env variables, which will be 'mbcs' encoded
 
387
    # on Windows (Python doesn't expose the native win32 unicode environment)
 
388
    # According to this:
 
389
    # http://msdn.microsoft.com/en-us/library/aa246807.aspx
 
390
    # environment variables should always be encoded in 'mbcs'.
 
391
    try:
 
392
        return os.environ['COMPUTERNAME'].decode("mbcs")
 
393
    except KeyError:
 
394
        return None
 
395
 
 
396
 
 
397
def _ensure_unicode(s):
 
398
    if s and type(s) != unicode:
 
399
        from bzrlib import osutils
 
400
        s = s.decode(osutils.get_user_encoding())
 
401
    return s
 
402
 
 
403
 
 
404
def get_appdata_location_unicode():
 
405
    return _ensure_unicode(get_appdata_location())
 
406
 
 
407
def get_home_location_unicode():
 
408
    return _ensure_unicode(get_home_location())
 
409
 
 
410
def get_user_name_unicode():
 
411
    return _ensure_unicode(get_user_name())
 
412
 
 
413
def get_host_name_unicode():
 
414
    return _ensure_unicode(get_host_name())
279
415
 
280
416
 
281
417
def _ensure_with_dir(path):
282
418
    if (not os.path.split(path)[0] or path.startswith(u'*')
283
 
            or path.startswith(u'?')):
 
419
        or path.startswith(u'?')):
284
420
        return u'./' + path, True
285
421
    else:
286
422
        return path, False
287
423
 
288
 
 
289
424
def _undo_ensure_with_dir(path, corrected):
290
425
    if corrected:
291
426
        return path[2:]
293
428
        return path
294
429
 
295
430
 
 
431
 
296
432
def glob_one(possible_glob):
297
433
    """Same as glob.glob().
298
434
 
322
458
    :param file_list: A list of filenames which may include shell globs.
323
459
    :return: An expanded list of filenames.
324
460
 
325
 
    Introduced in breezy 0.18.
 
461
    Introduced in bzrlib 0.18.
326
462
    """
327
463
    if not file_list:
328
464
        return []
333
469
 
334
470
 
335
471
def get_app_path(appname):
336
 
    r"""Look up in Windows registry for full path to application executable.
 
472
    """Look up in Windows registry for full path to application executable.
337
473
    Typically, applications create subkey with their basename
338
474
    in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
339
475
 
350
486
 
351
487
    try:
352
488
        hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
353
 
                               'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
354
 
                               basename)
 
489
            'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
 
490
            basename)
355
491
    except EnvironmentError:
356
492
        return appname
357
493
 
375
511
 
376
512
def set_file_attr_hidden(path):
377
513
    """Set file attributes to hidden if possible"""
378
 
    if not has_ctypes_win32:
379
 
        return
380
 
    from ctypes.wintypes import BOOL, DWORD, LPCWSTR
381
 
    _kernel32 = ctypes.windll.kernel32
382
 
    # <https://docs.microsoft.com/windows/desktop/api/fileapi/nf-fileapi-setfileattributesw>
383
 
    _SetFileAttributesW = ctypes.WINFUNCTYPE(BOOL, LPCWSTR, DWORD)(
384
 
        ("SetFileAttributesW", _kernel32))
385
 
    FILE_ATTRIBUTE_HIDDEN = 2
386
 
    if not SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN):
387
 
        e = ctypes.WinError()
388
 
        from . import trace
389
 
        trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
390
 
 
391
 
 
392
 
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
 
514
    if has_win32file:
 
515
        if winver != 'Windows 98':
 
516
            SetFileAttributes = win32file.SetFileAttributesW
 
517
        else:
 
518
            SetFileAttributes = win32file.SetFileAttributes
 
519
        try:
 
520
            SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
 
521
        except pywintypes.error, e:
 
522
            from bzrlib import trace
 
523
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
 
524
 
 
525
 
 
526
def _command_line_to_argv(command_line, single_quotes_allowed=False):
393
527
    """Convert a Unicode command line into a list of argv arguments.
394
528
 
395
529
    It performs wildcard expansion to make wildcards act closer to how they
402
536
                                  default.
403
537
    :return: A list of unicode strings.
404
538
    """
405
 
    # First, split the command line
406
 
    s = cmdline.Splitter(
407
 
        command_line, single_quotes_allowed=single_quotes_allowed)
408
 
 
409
 
    # Bug #587868 Now make sure that the length of s agrees with sys.argv
410
 
    # we do this by simply counting the number of arguments in each. The counts should
411
 
    # agree no matter what encoding sys.argv is in (AFAIK)
412
 
    # len(arguments) < len(sys.argv) should be an impossibility since python gets
413
 
    # args from the very same PEB as does GetCommandLineW
414
 
    arguments = list(s)
415
 
 
416
 
    # Now shorten the command line we get from GetCommandLineW to match sys.argv
417
 
    if len(arguments) < len(argv):
418
 
        raise AssertionError("Split command line can't be shorter than argv")
419
 
    arguments = arguments[len(arguments) - len(argv):]
420
 
 
421
 
    # Carry on to process globs (metachars) in the command line
422
 
    # expand globs if necessary
 
539
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
 
540
    # Now that we've split the content, expand globs if necessary
423
541
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
424
542
    #       '**/' style globs
425
543
    args = []
426
 
    for is_quoted, arg in arguments:
 
544
    for is_quoted, arg in s:
427
545
        if is_quoted or not glob.has_magic(arg):
428
546
            args.append(arg)
429
547
        else:
431
549
    return args
432
550
 
433
551
 
434
 
if has_ctypes_win32:
 
552
if has_ctypes and winver != 'Windows 98':
435
553
    def get_unicode_argv():
436
554
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
437
555
        GetCommandLineW = prototype(("GetCommandLineW",
440
558
        if command_line is None:
441
559
            raise ctypes.WinError()
442
560
        # Skip the first argument, since we only care about parameters
443
 
        argv = _command_line_to_argv(command_line, sys.argv)[1:]
 
561
        argv = _command_line_to_argv(command_line)[1:]
 
562
        if getattr(sys, 'frozen', None) is None:
 
563
            # Invoked via 'python.exe' which takes the form:
 
564
            #   python.exe [PYTHON_OPTIONS] C:\Path\bzr [BZR_OPTIONS]
 
565
            # we need to get only BZR_OPTIONS part,
 
566
            # We already removed 'python.exe' so we remove everything up to and
 
567
            # including the first non-option ('-') argument.
 
568
            for idx in xrange(len(argv)):
 
569
                if argv[idx][:1] != '-':
 
570
                    break
 
571
            argv = argv[idx+1:]
444
572
        return argv
445
 
 
446
 
    def get_environ_unicode(key, default=None):
447
 
        """Get `key` from environment as unicode or `default` if unset
448
 
 
449
 
        The environment is natively unicode on modern windows versions but
450
 
        Python 2 only accesses it through the legacy bytestring api.
451
 
 
452
 
        Environmental variable names are case insenstive on Windows.
453
 
 
454
 
        A large enough buffer will be allocated to retrieve the value, though
455
 
        it may take two calls to the underlying library function.
456
 
        """
457
 
        cfunc = getattr(get_environ_unicode, "_c_function", None)
458
 
        if cfunc is None:
459
 
            from ctypes.wintypes import DWORD, LPCWSTR, LPWSTR
460
 
            cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
461
 
                ("GetEnvironmentVariableW", ctypes.windll.kernel32))
462
 
            get_environ_unicode._c_function = cfunc
463
 
        buffer_size = 256  # heuristic, 256 characters often enough
464
 
        while True:
465
 
            buf = ctypes.create_unicode_buffer(buffer_size)
466
 
            length = cfunc(key, buf, buffer_size)
467
 
            if not length:
468
 
                code = ctypes.GetLastError()
469
 
                if code == 203:  # ERROR_ENVVAR_NOT_FOUND
470
 
                    return default
471
 
                raise ctypes.WinError(code)
472
 
            if buffer_size > length:
473
 
                return buf[:length]
474
 
            buffer_size = length
475
 
 
476
 
 
477
 
if has_ctypes_win32:
478
 
    from ctypes.wintypes import BOOL, DWORD, HANDLE
479
 
    _kernel32 = ctypes.windll.kernel32
480
 
    _CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
481
 
        ("CloseHandle", _kernel32))
482
 
    _OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
483
 
        ("OpenProcess", _kernel32))
484
 
 
485
 
    def _ctypes_is_local_pid_dead(pid):
486
 
        """True if pid doesn't correspond to live process on this machine"""
487
 
        handle = _OpenProcess(1, False, pid)  # PROCESS_TERMINATE
488
 
        if not handle:
489
 
            errorcode = ctypes.GetLastError()
490
 
            if errorcode == 5:  # ERROR_ACCESS_DENIED
491
 
                # Probably something alive we're not allowed to kill
492
 
                return False
493
 
            elif errorcode == 87:  # ERROR_INVALID_PARAMETER
494
 
                return True
495
 
            raise ctypes.WinError(errorcode)
496
 
        _CloseHandle(handle)
497
 
        return False
498
 
 
499
 
    is_local_pid_dead = _ctypes_is_local_pid_dead
 
573
else:
 
574
    get_unicode_argv = None