~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: Gordon Tyler
  • Date: 2010-02-02 06:30:43 UTC
  • mto: (5037.3.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5046.
  • Revision ID: gordon@doxxx.net-20100202063043-3ygr1114d25m3f7m
Added cmdline.split function, which replaces commands.shlex_split_unicode.

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
import glob
22
23
import os
 
24
import re
23
25
import struct
24
26
import sys
25
27
 
 
28
from bzrlib import cmdline
26
29
 
27
30
# Windows version
28
31
if sys.platform == 'win32':
66
69
        suffix = 'W'
67
70
try:
68
71
    import win32file
 
72
    import pywintypes
69
73
    has_win32file = True
70
74
except ImportError:
71
75
    has_win32file = False
96
100
UNLEN = 256
97
101
MAX_COMPUTERNAME_LENGTH = 31
98
102
 
 
103
# Registry data type ids
 
104
REG_SZ = 1
 
105
REG_EXPAND_SZ = 2
 
106
 
99
107
 
100
108
def debug_memory_win32api(message='', short=True):
101
109
    """Use trace.note() to dump the running memory info."""
173
181
        return (defaultx, defaulty)
174
182
 
175
183
    # To avoid problem with redirecting output via pipe
176
 
    # need to use stderr instead of stdout
 
184
    # we need to use stderr instead of stdout
177
185
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
178
186
    csbi = ctypes.create_string_buffer(22)
179
187
    res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
267
275
 
268
276
    Returned value can be unicode or plain string.
269
277
    To convert plain string to unicode use
270
 
    s.decode(bzrlib.user_encoding)
 
278
    s.decode(osutils.get_user_encoding())
271
279
    (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs')
272
280
    """
273
281
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
286
294
    If location cannot be obtained return system drive root,
287
295
    i.e. C:\
288
296
 
289
 
    Returned value can be unicode or plain sring.
 
297
    Returned value can be unicode or plain string.
290
298
    To convert plain string to unicode use
291
299
    s.decode(osutils.get_user_encoding())
292
300
    """
309
317
    """Return user name as login name.
310
318
    If name cannot be obtained return None.
311
319
 
312
 
    Returned value can be unicode or plain sring.
 
320
    Returned value can be unicode or plain string.
313
321
    To convert plain string to unicode use
314
322
    s.decode(osutils.get_user_encoding())
315
323
    """
383
391
 
384
392
 
385
393
def _ensure_unicode(s):
386
 
    from bzrlib import osutils
387
394
    if s and type(s) != unicode:
388
395
        from bzrlib import osutils
389
396
        s = s.decode(osutils.get_user_encoding())
417
424
 
418
425
 
419
426
 
 
427
def glob_one(possible_glob):
 
428
    """Same as glob.glob().
 
429
 
 
430
    work around bugs in glob.glob()
 
431
    - Python bug #1001604 ("glob doesn't return unicode with ...")
 
432
    - failing expansion for */* with non-iso-8859-* chars
 
433
    """
 
434
    corrected_glob, corrected = _ensure_with_dir(possible_glob)
 
435
    glob_files = glob.glob(corrected_glob)
 
436
 
 
437
    if not glob_files:
 
438
        # special case to let the normal code path handle
 
439
        # files that do not exist, etc.
 
440
        glob_files = [possible_glob]
 
441
    elif corrected:
 
442
        glob_files = [_undo_ensure_with_dir(elem, corrected)
 
443
                      for elem in glob_files]
 
444
    return [elem.replace(u'\\', u'/') for elem in glob_files]
 
445
 
 
446
 
420
447
def glob_expand(file_list):
421
448
    """Replacement for glob expansion by the shell.
422
449
 
430
457
    """
431
458
    if not file_list:
432
459
        return []
433
 
    import glob
434
460
    expanded_file_list = []
435
461
    for possible_glob in file_list:
436
 
 
437
 
        # work around bugs in glob.glob()
438
 
        # - Python bug #1001604 ("glob doesn't return unicode with ...")
439
 
        # - failing expansion for */* with non-iso-8859-* chars
440
 
        possible_glob, corrected = _ensure_with_dir(possible_glob)
441
 
        glob_files = glob.glob(possible_glob)
442
 
 
443
 
        if glob_files == []:
444
 
            # special case to let the normal code path handle
445
 
            # files that do not exists
446
 
            expanded_file_list.append(
447
 
                _undo_ensure_with_dir(possible_glob, corrected))
448
 
        else:
449
 
            glob_files = [_undo_ensure_with_dir(elem, corrected) for elem in glob_files]
450
 
            expanded_file_list += glob_files
451
 
 
452
 
    return [elem.replace(u'\\', u'/') for elem in expanded_file_list]
 
462
        expanded_file_list.extend(glob_one(possible_glob))
 
463
    return expanded_file_list
453
464
 
454
465
 
455
466
def get_app_path(appname):
456
467
    """Look up in Windows registry for full path to application executable.
457
 
    Typicaly, applications create subkey with their basename
 
468
    Typically, applications create subkey with their basename
458
469
    in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
459
470
 
460
471
    :param  appname:    name of application (if no filename extension
463
474
                or appname itself if nothing found.
464
475
    """
465
476
    import _winreg
 
477
 
 
478
    basename = appname
 
479
    if not os.path.splitext(basename)[1]:
 
480
        basename = appname + '.exe'
 
481
 
466
482
    try:
467
483
        hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
468
 
                               r'SOFTWARE\Microsoft\Windows'
469
 
                               r'\CurrentVersion\App Paths')
 
484
            'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
 
485
            basename)
470
486
    except EnvironmentError:
471
487
        return appname
472
488
 
473
 
    basename = appname
474
 
    if not os.path.splitext(basename)[1]:
475
 
        basename = appname + '.exe'
476
489
    try:
477
490
        try:
478
 
            fullpath = _winreg.QueryValue(hkey, basename)
 
491
            path, type_id = _winreg.QueryValueEx(hkey, '')
479
492
        except WindowsError:
480
 
            fullpath = appname
 
493
            return appname
481
494
    finally:
482
495
        _winreg.CloseKey(hkey)
483
496
 
484
 
    return fullpath
 
497
    if type_id == REG_SZ:
 
498
        return path
 
499
    if type_id == REG_EXPAND_SZ and has_win32api:
 
500
        fullpath = win32api.ExpandEnvironmentStrings(path)
 
501
        if len(fullpath) > 1 and fullpath[0] == '"' and fullpath[-1] == '"':
 
502
            fullpath = fullpath[1:-1]   # remove quotes around value
 
503
        return fullpath
 
504
    return appname
485
505
 
486
506
 
487
507
def set_file_attr_hidden(path):
488
508
    """Set file attributes to hidden if possible"""
489
509
    if has_win32file:
490
 
        win32file.SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
 
510
        if winver != 'Windows 98':
 
511
            SetFileAttributes = win32file.SetFileAttributesW
 
512
        else:
 
513
            SetFileAttributes = win32file.SetFileAttributes
 
514
        try:
 
515
            SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
 
516
        except pywintypes.error, e:
 
517
            from bzrlib import trace
 
518
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
 
519
 
 
520
 
 
521
def command_line_to_argv(command_line, wildcard_expansion=True,
 
522
                         single_quotes_allowed=False):
 
523
    """Convert a Unicode command line into a list of argv arguments.
 
524
 
 
525
    This optionally does wildcard expansion, etc. It is intended to make
 
526
    wildcards act closer to how they work in posix shells, versus how they
 
527
    work by default on Windows. Quoted arguments are left untouched.
 
528
 
 
529
    :param command_line: The unicode string to split into an arg list.
 
530
    :param wildcard_expansion: Whether wildcard expansion should be applied to
 
531
                               each argument. True by default.
 
532
    :param single_quotes_allowed: Whether single quotes are accepted as quoting
 
533
                                  characters like double quotes. False by
 
534
                                  default.
 
535
    :return: A list of unicode strings.
 
536
    """
 
537
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
 
538
    # Now that we've split the content, expand globs if necessary
 
539
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
 
540
    #       '**/' style globs
 
541
    args = []
 
542
    for is_quoted, arg in s:
 
543
        if is_quoted or not glob.has_magic(arg) or not wildcard_expansion:
 
544
            args.append(arg)
 
545
        else:
 
546
            args.extend(glob_one(arg))
 
547
    return args
 
548
 
 
549
 
 
550
if has_ctypes and winver != 'Windows 98':
 
551
    def get_unicode_argv():
 
552
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
 
553
        GetCommandLineW = prototype(("GetCommandLineW",
 
554
                                     ctypes.windll.kernel32))
 
555
        command_line = GetCommandLineW()
 
556
        if command_line is None:
 
557
            raise ctypes.WinError()
 
558
        # Skip the first argument, since we only care about parameters
 
559
        argv = command_line_to_argv(command_line)[1:]
 
560
        if getattr(sys, 'frozen', None) is None:
 
561
            # Invoked via 'python.exe' which takes the form:
 
562
            #   python.exe [PYTHON_OPTIONS] C:\Path\bzr [BZR_OPTIONS]
 
563
            # we need to get only BZR_OPTIONS part,
 
564
            # We already removed 'python.exe' so we remove everything up to and
 
565
            # including the first non-option ('-') argument.
 
566
            for idx in xrange(len(argv)):
 
567
                if argv[idx][:1] != '-':
 
568
                    break
 
569
            argv = argv[idx+1:]
 
570
        return argv
 
571
else:
 
572
    get_unicode_argv = None