~bzr/bzr/daily-ppa-natty

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: Jelmer Vernooij
  • Date: 2011-12-21 01:46:15 UTC
  • mfrom: (3815.3194.253 +trunk)
  • Revision ID: jelmer@samba.org-20111221014615-so5xxk2z179oedty
Merge bzr.dev.

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
80
    import pywintypes
248
257
    one that moves with the user as they logon to different machines, and
249
258
    a 'local' one that stays local to the machine.  This returns the 'roaming'
250
259
    directory, and thus is suitable for storing user-preferences, etc.
251
 
 
252
 
    Returned value can be unicode or plain string.
253
 
    To convert plain string to unicode use
254
 
    s.decode(osutils.get_user_encoding())
255
 
    (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs')
256
260
    """
257
261
    appdata = _get_sh_special_folder_path(CSIDL_APPDATA)
258
262
    if appdata:
259
263
        return appdata
260
 
    # from env variable
261
 
    appdata = os.environ.get('APPDATA')
262
 
    if appdata:
263
 
        return appdata
264
 
    # if we fall to this point we on win98
265
 
    # at least try C:/WINDOWS/Application Data
266
 
    windir = os.environ.get('windir')
267
 
    if windir:
268
 
        appdata = os.path.join(windir, 'Application Data')
269
 
        if os.path.isdir(appdata):
270
 
            return appdata
271
 
    # did not find anything
272
 
    return None
 
264
    # Use APPDATA if defined, will return None if not
 
265
    return get_environ_unicode('APPDATA')
273
266
 
274
267
 
275
268
def get_local_appdata_location():
281
274
    a 'local' one that stays local to the machine.  This returns the 'local'
282
275
    directory, and thus is suitable for caches, temp files and other things
283
276
    which don't need to move with the user.
284
 
 
285
 
    Returned value can be unicode or plain string.
286
 
    To convert plain string to unicode use
287
 
    s.decode(osutils.get_user_encoding())
288
 
    (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs')
289
277
    """
290
278
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
291
279
    if local:
292
280
        return local
293
281
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
294
 
    local = os.environ.get('LOCALAPPDATA')
 
282
    local = get_environ_unicode('LOCALAPPDATA')
295
283
    if local:
296
284
        return local
297
285
    return get_appdata_location()
302
290
    Assume on win32 it's the <My Documents> folder.
303
291
    If location cannot be obtained return system drive root,
304
292
    i.e. C:\
305
 
 
306
 
    Returned value can be unicode or plain string.
307
 
    To convert plain string to unicode use
308
 
    s.decode(osutils.get_user_encoding())
309
293
    """
310
294
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
311
295
    if home:
312
296
        return home
313
 
    # try for HOME env variable
314
 
    home = os.path.expanduser('~')
315
 
    if home != '~':
 
297
    home = get_environ_unicode('HOME')
 
298
    if home is not None:
316
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)
317
303
    # at least return windows root directory
318
 
    windir = os.environ.get('windir')
 
304
    windir = get_environ_unicode('WINDIR')
319
305
    if windir:
320
306
        return os.path.splitdrive(windir)[0] + '/'
321
307
    # otherwise C:\ is good enough for 98% users
322
 
    return 'C:/'
 
308
    return unicode('C:/')
323
309
 
324
310
 
325
311
def get_user_name():
326
312
    """Return user name as login name.
327
313
    If name cannot be obtained return None.
328
 
 
329
 
    Returned value can be unicode or plain string.
330
 
    To convert plain string to unicode use
331
 
    s.decode(osutils.get_user_encoding())
332
314
    """
333
315
    if has_ctypes:
334
316
        try:
340
322
            buf = create_buffer(UNLEN+1)
341
323
            n = ctypes.c_int(UNLEN+1)
342
324
            if GetUserName(buf, ctypes.byref(n)):
343
 
                return buf.value
 
325
                return extract_buffer(buf)
344
326
    # otherwise try env variables
345
 
    return os.environ.get('USERNAME', None)
 
327
    return get_environ_unicode('USERNAME')
346
328
 
347
329
 
348
330
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
353
335
    """Return host machine name.
354
336
    If name cannot be obtained return None.
355
337
 
356
 
    :return: A unicode string representing the host name. On win98, this may be
357
 
        a plain string as win32 api doesn't support unicode.
 
338
    :return: A unicode string representing the host name.
358
339
    """
359
340
    if has_win32api:
360
341
        try:
377
358
            if (GetComputerNameEx is not None
378
359
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
379
360
                                      buf, ctypes.byref(n))):
380
 
                return buf.value
 
361
                return extract_buffer(buf)
381
362
 
382
363
            # Try GetComputerName in case GetComputerNameEx wasn't found
383
364
            # It returns the NETBIOS name, which isn't as good, but still ok.
387
368
                                      None)
388
369
            if (GetComputerName is not None
389
370
                and GetComputerName(buf, ctypes.byref(n))):
390
 
                return buf.value
391
 
    # otherwise try env variables, which will be 'mbcs' encoded
392
 
    # on Windows (Python doesn't expose the native win32 unicode environment)
393
 
    # According to this:
394
 
    # http://msdn.microsoft.com/en-us/library/aa246807.aspx
395
 
    # environment variables should always be encoded in 'mbcs'.
396
 
    try:
397
 
        return os.environ['COMPUTERNAME'].decode("mbcs")
398
 
    except KeyError:
399
 
        return None
400
 
 
401
 
 
 
371
                return extract_buffer(buf)
 
372
    return get_environ_unicode('COMPUTERNAME')
 
373
 
 
374
 
 
375
@symbol_versioning.deprecated_method(
 
376
    symbol_versioning.deprecated_in((2, 5, 0)))
402
377
def _ensure_unicode(s):
403
378
    if s and type(s) != unicode:
404
379
        from bzrlib import osutils
406
381
    return s
407
382
 
408
383
 
409
 
def get_appdata_location_unicode():
410
 
    return _ensure_unicode(get_appdata_location())
411
 
 
412
 
def get_home_location_unicode():
413
 
    return _ensure_unicode(get_home_location())
414
 
 
415
 
def get_user_name_unicode():
416
 
    return _ensure_unicode(get_user_name())
417
 
 
418
 
def get_host_name_unicode():
419
 
    return _ensure_unicode(get_host_name())
 
384
get_appdata_location_unicode = symbol_versioning.deprecated_method(
 
385
    symbol_versioning.deprecated_in((2, 5, 0)))(get_appdata_location)
 
386
 
 
387
get_home_location_unicode = symbol_versioning.deprecated_method(
 
388
    symbol_versioning.deprecated_in((2, 5, 0)))(get_home_location)
 
389
 
 
390
get_user_name_unicode = symbol_versioning.deprecated_method(
 
391
    symbol_versioning.deprecated_in((2, 5, 0)))(get_user_name)
 
392
 
 
393
get_host_name_unicode = symbol_versioning.deprecated_method(
 
394
    symbol_versioning.deprecated_in((2, 5, 0)))(get_host_name)
420
395
 
421
396
 
422
397
def _ensure_with_dir(path):
433
408
        return path
434
409
 
435
410
 
436
 
 
437
411
def glob_one(possible_glob):
438
412
    """Same as glob.glob().
439
413
 
569
543
    return args
570
544
 
571
545
 
572
 
if has_ctypes and winver != 'Windows 98':
 
546
if has_ctypes and winver == 'Windows NT':
573
547
    def get_unicode_argv():
574
548
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
575
549
        GetCommandLineW = prototype(("GetCommandLineW",
580
554
        # Skip the first argument, since we only care about parameters
581
555
        argv = _command_line_to_argv(command_line, sys.argv)[1:]
582
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
583
590
else:
584
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
        try:
 
598
            return os.environ[key].decode("mbcs")
 
599
        except KeyError:
 
600
            return default
585
601
 
586
602
 
587
603
if has_win32api: