~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: Patch Queue Manager
  • Date: 2015-12-17 18:39:00 UTC
  • mfrom: (6606.1.2 fix-float)
  • Revision ID: pqm@pqm.ubuntu.com-20151217183900-0719du2uv1kwu3lc
(vila) Inline testtools private method to fix an issue in xenial (the
 private implementation has changed in an backward incompatible way).
 (Jelmer Vernooij)

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
 
30
from bzrlib import (
 
31
    cmdline,
 
32
    symbol_versioning,
 
33
    )
28
34
from bzrlib.i18n import gettext
29
35
 
30
36
# Windows version
63
69
else:
64
70
    if winver == 'Windows 98':
65
71
        create_buffer = ctypes.create_string_buffer
 
72
        def extract_buffer(buf):
 
73
            return buf.value.decode("mbcs")
66
74
        suffix = 'A'
67
75
    else:
68
76
        create_buffer = ctypes.create_unicode_buffer
 
77
        extract_buffer = operator.attrgetter("value")
69
78
        suffix = 'W'
70
79
try:
71
 
    import win32file
72
80
    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
    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
81
95
 
82
96
# pulling in win32com.shell is a bit of overhead, and normally we don't need
83
97
# it as ctypes is preferred and common.  lazy_imports and "optional"
243
257
    one that moves with the user as they logon to different machines, and
244
258
    a 'local' one that stays local to the machine.  This returns the 'roaming'
245
259
    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')
251
260
    """
252
261
    appdata = _get_sh_special_folder_path(CSIDL_APPDATA)
253
262
    if appdata:
254
263
        return 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
 
264
    # Use APPDATA if defined, will return None if not
 
265
    return get_environ_unicode('APPDATA')
268
266
 
269
267
 
270
268
def get_local_appdata_location():
276
274
    a 'local' one that stays local to the machine.  This returns the 'local'
277
275
    directory, and thus is suitable for caches, temp files and other things
278
276
    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')
284
277
    """
285
278
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
286
279
    if local:
287
280
        return local
288
281
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
289
 
    local = os.environ.get('LOCALAPPDATA')
 
282
    local = get_environ_unicode('LOCALAPPDATA')
290
283
    if local:
291
284
        return local
292
285
    return get_appdata_location()
297
290
    Assume on win32 it's the <My Documents> folder.
298
291
    If location cannot be obtained return system drive root,
299
292
    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())
304
293
    """
305
294
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
306
295
    if home:
307
296
        return home
308
 
    # try for HOME env variable
309
 
    home = os.path.expanduser('~')
310
 
    if home != '~':
 
297
    home = get_environ_unicode('HOME')
 
298
    if home is not None:
311
299
        return home
 
300
    homepath = get_environ_unicode('HOMEPATH')
 
301
    if homepath is not None:
 
302
        return os.path.join(get_environ_unicode('HOMEDIR', ''), home)
312
303
    # at least return windows root directory
313
 
    windir = os.environ.get('windir')
 
304
    windir = get_environ_unicode('WINDIR')
314
305
    if windir:
315
306
        return os.path.splitdrive(windir)[0] + '/'
316
307
    # otherwise C:\ is good enough for 98% users
317
 
    return 'C:/'
 
308
    return unicode('C:/')
318
309
 
319
310
 
320
311
def get_user_name():
321
312
    """Return user name as login name.
322
313
    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())
327
314
    """
328
315
    if has_ctypes:
329
316
        try:
335
322
            buf = create_buffer(UNLEN+1)
336
323
            n = ctypes.c_int(UNLEN+1)
337
324
            if GetUserName(buf, ctypes.byref(n)):
338
 
                return buf.value
 
325
                return extract_buffer(buf)
339
326
    # otherwise try env variables
340
 
    return os.environ.get('USERNAME', None)
 
327
    return get_environ_unicode('USERNAME')
341
328
 
342
329
 
343
330
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
348
335
    """Return host machine name.
349
336
    If name cannot be obtained return None.
350
337
 
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.
 
338
    :return: A unicode string representing the host name.
353
339
    """
354
340
    if has_win32api:
355
341
        try:
372
358
            if (GetComputerNameEx is not None
373
359
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
374
360
                                      buf, ctypes.byref(n))):
375
 
                return buf.value
 
361
                return extract_buffer(buf)
376
362
 
377
363
            # Try GetComputerName in case GetComputerNameEx wasn't found
378
364
            # It returns the NETBIOS name, which isn't as good, but still ok.
382
368
                                      None)
383
369
            if (GetComputerName is not None
384
370
                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
 
 
 
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)))
397
377
def _ensure_unicode(s):
398
378
    if s and type(s) != unicode:
399
379
        from bzrlib import osutils
401
381
    return s
402
382
 
403
383
 
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())
 
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)
415
395
 
416
396
 
417
397
def _ensure_with_dir(path):
428
408
        return path
429
409
 
430
410
 
431
 
 
432
411
def glob_one(possible_glob):
433
412
    """Same as glob.glob().
434
413
 
536
515
                                  default.
537
516
    :return: A list of unicode strings.
538
517
    """
539
 
    # First, spit the command line
 
518
    # First, split the command line
540
519
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
541
520
    
542
521
    # Bug #587868 Now make sure that the length of s agrees with sys.argv 
564
543
    return args
565
544
 
566
545
 
567
 
if has_ctypes and winver != 'Windows 98':
 
546
if has_ctypes and winver == 'Windows NT':
568
547
    def get_unicode_argv():
569
548
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
570
549
        GetCommandLineW = prototype(("GetCommandLineW",
575
554
        # Skip the first argument, since we only care about parameters
576
555
        argv = _command_line_to_argv(command_line, sys.argv)[1:]
577
556
        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
578
590
else:
579
591
    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
580
602
 
581
603
 
582
604
if has_win32api:
615
637
        _CloseHandle(handle)
616
638
        return False
617
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