/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: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
"""
21
21
 
22
22
import glob
23
 
import operator
24
23
import os
25
24
import struct
26
25
import sys
27
26
 
28
 
from bzrlib import (
29
 
    cmdline,
30
 
    symbol_versioning,
31
 
    )
32
 
from bzrlib.i18n import gettext
 
27
from bzrlib import cmdline
33
28
 
34
29
# Windows version
35
30
if sys.platform == 'win32':
67
62
else:
68
63
    if winver == 'Windows 98':
69
64
        create_buffer = ctypes.create_string_buffer
70
 
        def extract_buffer(buf):
71
 
            return buf.value.decode("mbcs")
72
65
        suffix = 'A'
73
66
    else:
74
67
        create_buffer = ctypes.create_unicode_buffer
75
 
        extract_buffer = operator.attrgetter("value")
76
68
        suffix = 'W'
77
69
try:
 
70
    import win32file
78
71
    import pywintypes
79
 
    has_pywintypes = True
80
 
except ImportError:
81
 
    has_pywintypes = has_win32file = has_win32api = False
82
 
else:
83
 
    try:
84
 
        import win32file
85
 
        has_win32file = True
86
 
    except ImportError:
87
 
        has_win32file = False
88
 
    try:
89
 
        import win32api
90
 
        has_win32api = True
91
 
    except ImportError:
92
 
        has_win32api = False
 
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
93
80
 
94
81
# pulling in win32com.shell is a bit of overhead, and normally we don't need
95
82
# it as ctypes is preferred and common.  lazy_imports and "optional"
141
128
            ctypes.byref(mem_struct),
142
129
            ctypes.sizeof(mem_struct))
143
130
        if not ret:
144
 
            trace.note(gettext('Failed to GetProcessMemoryInfo()'))
 
131
            trace.note('Failed to GetProcessMemoryInfo()')
145
132
            return
146
133
        info = {'PageFaultCount': mem_struct.PageFaultCount,
147
134
                'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
162
149
        proc = win32process.GetCurrentProcess()
163
150
        info = win32process.GetProcessMemoryInfo(proc)
164
151
    else:
165
 
        trace.note(gettext('Cannot debug memory on win32 without ctypes'
166
 
                   ' or win32process'))
 
152
        trace.note('Cannot debug memory on win32 without ctypes'
 
153
                   ' or win32process')
167
154
        return
168
155
    if short:
169
156
        # using base-2 units (see HACKING.txt).
170
 
        trace.note(gettext('WorkingSize {0:>7}KiB'
171
 
                   '\tPeakWorking {1:>7}KiB\t{2}').format(
 
157
        trace.note('WorkingSize %7dKiB'
 
158
                   '\tPeakWorking %7dKiB\t%s',
172
159
                   info['WorkingSetSize'] / 1024,
173
160
                   info['PeakWorkingSetSize'] / 1024,
174
 
                   message))
 
161
                   message)
175
162
        return
176
163
    if message:
177
164
        trace.note('%s', message)
178
 
    trace.note(gettext('WorkingSize       %8d KiB'), info['WorkingSetSize'] / 1024)
179
 
    trace.note(gettext('PeakWorking       %8d KiB'), info['PeakWorkingSetSize'] / 1024)
180
 
    trace.note(gettext('PagefileUsage     %8d KiB'), info.get('PagefileUsage', 0) / 1024)
181
 
    trace.note(gettext('PeakPagefileUsage %8d KiB'),
 
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',
182
169
               info.get('PeakPagefileUsage', 0) / 1024)
183
 
    trace.note(gettext('PrivateUsage      %8d KiB'), info.get('PrivateUsage', 0) / 1024)
184
 
    trace.note(gettext('PageFaultCount    %8d'), info.get('PageFaultCount', 0))
 
170
    trace.note('PrivateUsage      %8d KiB', info.get('PrivateUsage', 0) / 1024)
 
171
    trace.note('PageFaultCount    %8d', info.get('PageFaultCount', 0))
185
172
 
186
173
 
187
174
def get_console_size(defaultx=80, defaulty=25):
255
242
    one that moves with the user as they logon to different machines, and
256
243
    a 'local' one that stays local to the machine.  This returns the 'roaming'
257
244
    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')
258
250
    """
259
251
    appdata = _get_sh_special_folder_path(CSIDL_APPDATA)
260
252
    if appdata:
261
253
        return appdata
262
 
    # Use APPDATA if defined, will return None if not
263
 
    return get_environ_unicode('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
264
267
 
265
268
 
266
269
def get_local_appdata_location():
272
275
    a 'local' one that stays local to the machine.  This returns the 'local'
273
276
    directory, and thus is suitable for caches, temp files and other things
274
277
    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')
275
283
    """
276
284
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
277
285
    if local:
278
286
        return local
279
287
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
280
 
    local = get_environ_unicode('LOCALAPPDATA')
 
288
    local = os.environ.get('LOCALAPPDATA')
281
289
    if local:
282
290
        return local
283
291
    return get_appdata_location()
288
296
    Assume on win32 it's the <My Documents> folder.
289
297
    If location cannot be obtained return system drive root,
290
298
    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())
291
303
    """
292
304
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
293
305
    if home:
294
306
        return home
295
 
    home = get_environ_unicode('HOME')
296
 
    if home is not None:
 
307
    # try for HOME env variable
 
308
    home = os.path.expanduser('~')
 
309
    if home != '~':
297
310
        return home
298
 
    homepath = get_environ_unicode('HOMEPATH')
299
 
    if homepath is not None:
300
 
        return os.path.join(get_environ_unicode('HOMEDIR', ''), home)
301
311
    # at least return windows root directory
302
 
    windir = get_environ_unicode('WINDIR')
 
312
    windir = os.environ.get('windir')
303
313
    if windir:
304
314
        return os.path.splitdrive(windir)[0] + '/'
305
315
    # otherwise C:\ is good enough for 98% users
306
 
    return unicode('C:/')
 
316
    return 'C:/'
307
317
 
308
318
 
309
319
def get_user_name():
310
320
    """Return user name as login name.
311
321
    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())
312
326
    """
313
327
    if has_ctypes:
314
328
        try:
320
334
            buf = create_buffer(UNLEN+1)
321
335
            n = ctypes.c_int(UNLEN+1)
322
336
            if GetUserName(buf, ctypes.byref(n)):
323
 
                return extract_buffer(buf)
 
337
                return buf.value
324
338
    # otherwise try env variables
325
 
    return get_environ_unicode('USERNAME')
 
339
    return os.environ.get('USERNAME', None)
326
340
 
327
341
 
328
342
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
333
347
    """Return host machine name.
334
348
    If name cannot be obtained return None.
335
349
 
336
 
    :return: A unicode string representing the host name.
 
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.
337
352
    """
338
353
    if has_win32api:
339
354
        try:
356
371
            if (GetComputerNameEx is not None
357
372
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
358
373
                                      buf, ctypes.byref(n))):
359
 
                return extract_buffer(buf)
 
374
                return buf.value
360
375
 
361
376
            # Try GetComputerName in case GetComputerNameEx wasn't found
362
377
            # It returns the NETBIOS name, which isn't as good, but still ok.
366
381
                                      None)
367
382
            if (GetComputerName is not None
368
383
                and GetComputerName(buf, ctypes.byref(n))):
369
 
                return extract_buffer(buf)
370
 
    return get_environ_unicode('COMPUTERNAME')
371
 
 
372
 
 
373
 
@symbol_versioning.deprecated_method(
374
 
    symbol_versioning.deprecated_in((2, 5, 0)))
 
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
 
375
396
def _ensure_unicode(s):
376
397
    if s and type(s) != unicode:
377
398
        from bzrlib import osutils
379
400
    return s
380
401
 
381
402
 
382
 
get_appdata_location_unicode = symbol_versioning.deprecated_method(
383
 
    symbol_versioning.deprecated_in((2, 5, 0)))(get_appdata_location)
384
 
 
385
 
get_home_location_unicode = symbol_versioning.deprecated_method(
386
 
    symbol_versioning.deprecated_in((2, 5, 0)))(get_home_location)
387
 
 
388
 
get_user_name_unicode = symbol_versioning.deprecated_method(
389
 
    symbol_versioning.deprecated_in((2, 5, 0)))(get_user_name)
390
 
 
391
 
get_host_name_unicode = symbol_versioning.deprecated_method(
392
 
    symbol_versioning.deprecated_in((2, 5, 0)))(get_host_name)
 
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())
393
414
 
394
415
 
395
416
def _ensure_with_dir(path):
406
427
        return path
407
428
 
408
429
 
 
430
 
409
431
def glob_one(possible_glob):
410
432
    """Same as glob.glob().
411
433
 
446
468
 
447
469
 
448
470
def get_app_path(appname):
449
 
    r"""Look up in Windows registry for full path to application executable.
 
471
    """Look up in Windows registry for full path to application executable.
450
472
    Typically, applications create subkey with their basename
451
473
    in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
452
474
 
500
522
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
501
523
 
502
524
 
503
 
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
 
525
def _command_line_to_argv(command_line, single_quotes_allowed=False):
504
526
    """Convert a Unicode command line into a list of argv arguments.
505
527
 
506
528
    It performs wildcard expansion to make wildcards act closer to how they
513
535
                                  default.
514
536
    :return: A list of unicode strings.
515
537
    """
516
 
    # First, spit the command line
517
538
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
518
 
    
519
 
    # Bug #587868 Now make sure that the length of s agrees with sys.argv 
520
 
    # we do this by simply counting the number of arguments in each. The counts should 
521
 
    # agree no matter what encoding sys.argv is in (AFAIK) 
522
 
    # len(arguments) < len(sys.argv) should be an impossibility since python gets 
523
 
    # args from the very same PEB as does GetCommandLineW
524
 
    arguments = list(s)
525
 
    
526
 
    # Now shorten the command line we get from GetCommandLineW to match sys.argv
527
 
    if len(arguments) < len(argv):
528
 
        raise AssertionError("Split command line can't be shorter than argv")
529
 
    arguments = arguments[len(arguments) - len(argv):]
530
 
    
531
 
    # Carry on to process globs (metachars) in the command line
532
 
    # expand globs if necessary
 
539
    # Now that we've split the content, expand globs if necessary
533
540
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
534
541
    #       '**/' style globs
535
542
    args = []
536
 
    for is_quoted, arg in arguments:
 
543
    for is_quoted, arg in s:
537
544
        if is_quoted or not glob.has_magic(arg):
538
545
            args.append(arg)
539
546
        else:
541
548
    return args
542
549
 
543
550
 
544
 
if has_ctypes and winver == 'Windows NT':
 
551
if has_ctypes and winver != 'Windows 98':
545
552
    def get_unicode_argv():
546
553
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
547
554
        GetCommandLineW = prototype(("GetCommandLineW",
550
557
        if command_line is None:
551
558
            raise ctypes.WinError()
552
559
        # Skip the first argument, since we only care about parameters
553
 
        argv = _command_line_to_argv(command_line, sys.argv)[1:]
 
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:]
554
571
        return argv
555
 
    
556
 
 
557
 
    def get_environ_unicode(key, default=None):
558
 
        """Get `key` from environment as unicode or `default` if unset
559
 
 
560
 
        The environment is natively unicode on modern windows versions but
561
 
        Python 2 only accesses it through the legacy bytestring api.
562
 
 
563
 
        Environmental variable names are case insenstive on Windows.
564
 
 
565
 
        A large enough buffer will be allocated to retrieve the value, though
566
 
        it may take two calls to the underlying library function.
567
 
 
568
 
        This needs ctypes because pywin32 does not expose the wide version.
569
 
        """
570
 
        cfunc = getattr(get_environ_unicode, "_c_function", None)
571
 
        if cfunc is None:
572
 
            from ctypes.wintypes import DWORD, LPCWSTR, LPWSTR
573
 
            cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
574
 
                ("GetEnvironmentVariableW", ctypes.windll.kernel32))
575
 
            get_environ_unicode._c_function = cfunc
576
 
        buffer_size = 256 # heuristic, 256 characters often enough
577
 
        while True:
578
 
            buffer = ctypes.create_unicode_buffer(buffer_size)
579
 
            length = cfunc(key, buffer, buffer_size)
580
 
            if not length:
581
 
                code = ctypes.GetLastError()
582
 
                if code == 203: # ERROR_ENVVAR_NOT_FOUND
583
 
                    return default
584
 
                raise ctypes.WinError(code)
585
 
            if buffer_size > length:
586
 
                return buffer[:length]
587
 
            buffer_size = length
588
572
else:
589
573
    get_unicode_argv = None
590
 
    def get_environ_unicode(key, default=None):
591
 
        """Get `key` from environment as unicode or `default` if unset
592
 
 
593
 
        Fallback version that should basically never be needed.
594
 
        """
595
 
        try:
596
 
            return os.environ[key].decode("mbcs")
597
 
        except KeyError:
598
 
            return default
599
 
 
600
 
 
601
 
if has_win32api:
602
 
    def _pywin32_is_local_pid_dead(pid):
603
 
        """True if pid doesn't correspond to live process on this machine"""
604
 
        try:
605
 
            handle = win32api.OpenProcess(1, False, pid) # PROCESS_TERMINATE
606
 
        except pywintypes.error, e:
607
 
            if e[0] == 5: # ERROR_ACCESS_DENIED
608
 
                # Probably something alive we're not allowed to kill
609
 
                return False
610
 
            elif e[0] == 87: # ERROR_INVALID_PARAMETER
611
 
                return True
612
 
            raise
613
 
        handle.close()
614
 
        return False
615
 
    is_local_pid_dead = _pywin32_is_local_pid_dead
616
 
elif has_ctypes and sys.platform == 'win32':
617
 
    from ctypes.wintypes import BOOL, DWORD, HANDLE
618
 
    _kernel32 = ctypes.windll.kernel32
619
 
    _CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
620
 
        ("CloseHandle", _kernel32))
621
 
    _OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
622
 
        ("OpenProcess", _kernel32))
623
 
    def _ctypes_is_local_pid_dead(pid):
624
 
        """True if pid doesn't correspond to live process on this machine"""
625
 
        handle = _OpenProcess(1, False, pid) # PROCESS_TERMINATE
626
 
        if not handle:
627
 
            errorcode = ctypes.GetLastError()
628
 
            if errorcode == 5: # ERROR_ACCESS_DENIED
629
 
                # Probably something alive we're not allowed to kill
630
 
                return False
631
 
            elif errorcode == 87: # ERROR_INVALID_PARAMETER
632
 
                return True
633
 
            raise ctypes.WinError(errorcode)
634
 
        _CloseHandle(handle)
635
 
        return False
636
 
    is_local_pid_dead = _ctypes_is_local_pid_dead
637
 
 
638
 
 
639
 
def _is_pywintypes_error(evalue):
640
 
    """True if exception instance is an error from pywin32"""
641
 
    if has_pywintypes and isinstance(evalue, pywintypes.error):
642
 
        return True
643
 
    return False