/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 breezy/win32utils.py

  • Committer: Jelmer Vernooij
  • Date: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

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