~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: John Arbash Meinel
  • Date: 2011-04-20 15:06:17 UTC
  • mto: This revision was merged to the branch mainline in revision 5836.
  • Revision ID: john@arbash-meinel.com-20110420150617-i41caxgemg32tq1r
Start adding tests that _worth_saving_limit works as expected.

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