/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: 2018-06-17 20:56:36 UTC
  • mto: (6973.12.2 python3-k)
  • mto: This revision was merged to the branch mainline in revision 7003.
  • Revision ID: jelmer@jelmer.uk-20180617205636-vgy3bum6d9gkg4ds
Port multiparent.

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
 
25
import operator
23
26
import os
24
27
import struct
25
28
import sys
26
29
 
27
 
from bzrlib import cmdline
28
 
 
29
 
# Windows version
30
 
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
 
 
 
30
from breezy import (
 
31
    cmdline,
 
32
    )
 
33
from breezy.i18n import gettext
 
34
from breezy.sixish import text_type
55
35
 
56
36
# We can cope without it; use a separate variable to help pyflakes
57
37
try:
60
40
except ImportError:
61
41
    has_ctypes = False
62
42
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'
 
43
    create_buffer = ctypes.create_unicode_buffer
 
44
    extract_buffer = operator.attrgetter("value")
 
45
    suffix = 'W'
69
46
try:
70
 
    import win32file
71
47
    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
 
48
    has_pywintypes = True
 
49
except ImportError:
 
50
    has_pywintypes = has_win32file = has_win32api = False
 
51
else:
 
52
    try:
 
53
        import win32file
 
54
        has_win32file = True
 
55
    except ImportError:
 
56
        has_win32file = False
 
57
    try:
 
58
        import win32api
 
59
        has_win32api = True
 
60
    except ImportError:
 
61
        has_win32api = False
80
62
 
81
63
# pulling in win32com.shell is a bit of overhead, and normally we don't need
82
64
# it as ctypes is preferred and common.  lazy_imports and "optional"
106
88
 
107
89
def debug_memory_win32api(message='', short=True):
108
90
    """Use trace.note() to dump the running memory info."""
109
 
    from bzrlib import trace
 
91
    from breezy import trace
110
92
    if has_ctypes:
111
93
        class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
112
94
            """Used by GetProcessMemoryInfo"""
128
110
            ctypes.byref(mem_struct),
129
111
            ctypes.sizeof(mem_struct))
130
112
        if not ret:
131
 
            trace.note('Failed to GetProcessMemoryInfo()')
 
113
            trace.note(gettext('Failed to GetProcessMemoryInfo()'))
132
114
            return
133
115
        info = {'PageFaultCount': mem_struct.PageFaultCount,
134
116
                'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
149
131
        proc = win32process.GetCurrentProcess()
150
132
        info = win32process.GetProcessMemoryInfo(proc)
151
133
    else:
152
 
        trace.note('Cannot debug memory on win32 without ctypes'
153
 
                   ' or win32process')
 
134
        trace.note(gettext('Cannot debug memory on win32 without ctypes'
 
135
                   ' or win32process'))
154
136
        return
155
137
    if short:
156
138
        # using base-2 units (see HACKING.txt).
157
 
        trace.note('WorkingSize %7dKiB'
158
 
                   '\tPeakWorking %7dKiB\t%s',
 
139
        trace.note(gettext('WorkingSize {0:>7}KiB'
 
140
                   '\tPeakWorking {1:>7}KiB\t{2}').format(
159
141
                   info['WorkingSetSize'] / 1024,
160
142
                   info['PeakWorkingSetSize'] / 1024,
161
 
                   message)
 
143
                   message))
162
144
        return
163
145
    if message:
164
146
        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',
 
147
    trace.note(gettext('WorkingSize       %8d KiB'), info['WorkingSetSize'] / 1024)
 
148
    trace.note(gettext('PeakWorking       %8d KiB'), info['PeakWorkingSetSize'] / 1024)
 
149
    trace.note(gettext('PagefileUsage     %8d KiB'), info.get('PagefileUsage', 0) / 1024)
 
150
    trace.note(gettext('PeakPagefileUsage %8d KiB'),
169
151
               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))
 
152
    trace.note(gettext('PrivateUsage      %8d KiB'), info.get('PrivateUsage', 0) / 1024)
 
153
    trace.note(gettext('PageFaultCount    %8d'), info.get('PageFaultCount', 0))
172
154
 
173
155
 
174
156
def get_console_size(defaultx=80, defaulty=25):
212
194
            pass
213
195
        else:
214
196
            buf = ctypes.create_unicode_buffer(MAX_PATH)
215
 
            if SHGetSpecialFolderPath(None,buf,csidl,0):
 
197
            if SHGetSpecialFolderPath(None, buf, csidl, 0):
216
198
                return buf.value
217
199
 
218
200
    global has_win32com_shell
242
224
    one that moves with the user as they logon to different machines, and
243
225
    a 'local' one that stays local to the machine.  This returns the 'roaming'
244
226
    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
227
    """
251
228
    appdata = _get_sh_special_folder_path(CSIDL_APPDATA)
252
229
    if appdata:
253
230
        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
 
231
    # Use APPDATA if defined, will return None if not
 
232
    return get_environ_unicode('APPDATA')
267
233
 
268
234
 
269
235
def get_local_appdata_location():
275
241
    a 'local' one that stays local to the machine.  This returns the 'local'
276
242
    directory, and thus is suitable for caches, temp files and other things
277
243
    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
244
    """
284
245
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
285
246
    if local:
286
247
        return local
287
248
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
288
 
    local = os.environ.get('LOCALAPPDATA')
 
249
    local = get_environ_unicode('LOCALAPPDATA')
289
250
    if local:
290
251
        return local
291
252
    return get_appdata_location()
296
257
    Assume on win32 it's the <My Documents> folder.
297
258
    If location cannot be obtained return system drive root,
298
259
    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
260
    """
304
261
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
305
262
    if home:
306
263
        return home
307
 
    # try for HOME env variable
308
 
    home = os.path.expanduser('~')
309
 
    if home != '~':
 
264
    home = get_environ_unicode('HOME')
 
265
    if home is not None:
310
266
        return home
 
267
    homepath = get_environ_unicode('HOMEPATH')
 
268
    if homepath is not None:
 
269
        return os.path.join(get_environ_unicode('HOMEDIR', ''), home)
311
270
    # at least return windows root directory
312
 
    windir = os.environ.get('windir')
 
271
    windir = get_environ_unicode('WINDIR')
313
272
    if windir:
314
273
        return os.path.splitdrive(windir)[0] + '/'
315
274
    # otherwise C:\ is good enough for 98% users
316
 
    return 'C:/'
 
275
    return text_type('C:/')
317
276
 
318
277
 
319
278
def get_user_name():
320
279
    """Return user name as login name.
321
280
    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
281
    """
327
282
    if has_ctypes:
328
283
        try:
334
289
            buf = create_buffer(UNLEN+1)
335
290
            n = ctypes.c_int(UNLEN+1)
336
291
            if GetUserName(buf, ctypes.byref(n)):
337
 
                return buf.value
 
292
                return extract_buffer(buf)
338
293
    # otherwise try env variables
339
 
    return os.environ.get('USERNAME', None)
 
294
    return get_environ_unicode('USERNAME')
340
295
 
341
296
 
342
297
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
347
302
    """Return host machine name.
348
303
    If name cannot be obtained return None.
349
304
 
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.
 
305
    :return: A unicode string representing the host name.
352
306
    """
353
307
    if has_win32api:
354
308
        try:
371
325
            if (GetComputerNameEx is not None
372
326
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
373
327
                                      buf, ctypes.byref(n))):
374
 
                return buf.value
 
328
                return extract_buffer(buf)
375
329
 
376
330
            # Try GetComputerName in case GetComputerNameEx wasn't found
377
331
            # It returns the NETBIOS name, which isn't as good, but still ok.
381
335
                                      None)
382
336
            if (GetComputerName is not None
383
337
                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())
 
338
                return extract_buffer(buf)
 
339
    return get_environ_unicode('COMPUTERNAME')
414
340
 
415
341
 
416
342
def _ensure_with_dir(path):
427
353
        return path
428
354
 
429
355
 
430
 
 
431
356
def glob_one(possible_glob):
432
357
    """Same as glob.glob().
433
358
 
457
382
    :param file_list: A list of filenames which may include shell globs.
458
383
    :return: An expanded list of filenames.
459
384
 
460
 
    Introduced in bzrlib 0.18.
 
385
    Introduced in breezy 0.18.
461
386
    """
462
387
    if not file_list:
463
388
        return []
468
393
 
469
394
 
470
395
def get_app_path(appname):
471
 
    """Look up in Windows registry for full path to application executable.
 
396
    r"""Look up in Windows registry for full path to application executable.
472
397
    Typically, applications create subkey with their basename
473
398
    in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
474
399
 
511
436
def set_file_attr_hidden(path):
512
437
    """Set file attributes to hidden if possible"""
513
438
    if has_win32file:
514
 
        if winver != 'Windows 98':
515
 
            SetFileAttributes = win32file.SetFileAttributesW
516
 
        else:
517
 
            SetFileAttributes = win32file.SetFileAttributes
 
439
        SetFileAttributes = win32file.SetFileAttributesW
518
440
        try:
519
441
            SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
520
 
        except pywintypes.error, e:
521
 
            from bzrlib import trace
 
442
        except pywintypes.error as e:
 
443
            from . import trace
522
444
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
523
445
 
524
446
 
525
 
def _command_line_to_argv(command_line, single_quotes_allowed=False):
 
447
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
526
448
    """Convert a Unicode command line into a list of argv arguments.
527
449
 
528
450
    It performs wildcard expansion to make wildcards act closer to how they
535
457
                                  default.
536
458
    :return: A list of unicode strings.
537
459
    """
 
460
    # First, split the command line
538
461
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
539
 
    # Now that we've split the content, expand globs if necessary
 
462
    
 
463
    # Bug #587868 Now make sure that the length of s agrees with sys.argv 
 
464
    # we do this by simply counting the number of arguments in each. The counts should 
 
465
    # agree no matter what encoding sys.argv is in (AFAIK) 
 
466
    # len(arguments) < len(sys.argv) should be an impossibility since python gets 
 
467
    # args from the very same PEB as does GetCommandLineW
 
468
    arguments = list(s)
 
469
    
 
470
    # Now shorten the command line we get from GetCommandLineW to match sys.argv
 
471
    if len(arguments) < len(argv):
 
472
        raise AssertionError("Split command line can't be shorter than argv")
 
473
    arguments = arguments[len(arguments) - len(argv):]
 
474
    
 
475
    # Carry on to process globs (metachars) in the command line
 
476
    # expand globs if necessary
540
477
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
541
478
    #       '**/' style globs
542
479
    args = []
543
 
    for is_quoted, arg in s:
 
480
    for is_quoted, arg in arguments:
544
481
        if is_quoted or not glob.has_magic(arg):
545
482
            args.append(arg)
546
483
        else:
548
485
    return args
549
486
 
550
487
 
551
 
if has_ctypes and winver != 'Windows 98':
 
488
if has_ctypes:
552
489
    def get_unicode_argv():
553
490
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
554
491
        GetCommandLineW = prototype(("GetCommandLineW",
557
494
        if command_line is None:
558
495
            raise ctypes.WinError()
559
496
        # 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:]
 
497
        argv = _command_line_to_argv(command_line, sys.argv)[1:]
571
498
        return argv
572
 
else:
573
 
    get_unicode_argv = None
 
499
 
 
500
 
 
501
    def get_environ_unicode(key, default=None):
 
502
        """Get `key` from environment as unicode or `default` if unset
 
503
 
 
504
        The environment is natively unicode on modern windows versions but
 
505
        Python 2 only accesses it through the legacy bytestring api.
 
506
 
 
507
        Environmental variable names are case insenstive on Windows.
 
508
 
 
509
        A large enough buffer will be allocated to retrieve the value, though
 
510
        it may take two calls to the underlying library function.
 
511
 
 
512
        This needs ctypes because pywin32 does not expose the wide version.
 
513
        """
 
514
        cfunc = getattr(get_environ_unicode, "_c_function", None)
 
515
        if cfunc is None:
 
516
            from ctypes.wintypes import DWORD, LPCWSTR, LPWSTR
 
517
            cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
 
518
                ("GetEnvironmentVariableW", ctypes.windll.kernel32))
 
519
            get_environ_unicode._c_function = cfunc
 
520
        buffer_size = 256 # heuristic, 256 characters often enough
 
521
        while True:
 
522
            buffer = ctypes.create_unicode_buffer(buffer_size)
 
523
            length = cfunc(key, buffer, buffer_size)
 
524
            if not length:
 
525
                code = ctypes.GetLastError()
 
526
                if code == 203: # ERROR_ENVVAR_NOT_FOUND
 
527
                    return default
 
528
                raise ctypes.WinError(code)
 
529
            if buffer_size > length:
 
530
                return buffer[:length]
 
531
            buffer_size = length
 
532
 
 
533
 
 
534
if has_win32api:
 
535
    def _pywin32_is_local_pid_dead(pid):
 
536
        """True if pid doesn't correspond to live process on this machine"""
 
537
        try:
 
538
            handle = win32api.OpenProcess(1, False, pid) # PROCESS_TERMINATE
 
539
        except pywintypes.error as e:
 
540
            if e[0] == 5: # ERROR_ACCESS_DENIED
 
541
                # Probably something alive we're not allowed to kill
 
542
                return False
 
543
            elif e[0] == 87: # ERROR_INVALID_PARAMETER
 
544
                return True
 
545
            raise
 
546
        handle.close()
 
547
        return False
 
548
    is_local_pid_dead = _pywin32_is_local_pid_dead
 
549
elif has_ctypes and sys.platform == 'win32':
 
550
    from ctypes.wintypes import BOOL, DWORD, HANDLE
 
551
    _kernel32 = ctypes.windll.kernel32
 
552
    _CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
 
553
        ("CloseHandle", _kernel32))
 
554
    _OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
 
555
        ("OpenProcess", _kernel32))
 
556
    def _ctypes_is_local_pid_dead(pid):
 
557
        """True if pid doesn't correspond to live process on this machine"""
 
558
        handle = _OpenProcess(1, False, pid) # PROCESS_TERMINATE
 
559
        if not handle:
 
560
            errorcode = ctypes.GetLastError()
 
561
            if errorcode == 5: # ERROR_ACCESS_DENIED
 
562
                # Probably something alive we're not allowed to kill
 
563
                return False
 
564
            elif errorcode == 87: # ERROR_INVALID_PARAMETER
 
565
                return True
 
566
            raise ctypes.WinError(errorcode)
 
567
        _CloseHandle(handle)
 
568
        return False
 
569
    is_local_pid_dead = _ctypes_is_local_pid_dead
 
570
 
 
571
 
 
572
def _is_pywintypes_error(evalue):
 
573
    """True if exception instance is an error from pywin32"""
 
574
    if has_pywintypes and isinstance(evalue, pywintypes.error):
 
575
        return True
 
576
    return False