426
def glob_one(possible_glob):
427
"""Same as glob.glob().
429
work around bugs in glob.glob()
430
- Python bug #1001604 ("glob doesn't return unicode with ...")
431
- failing expansion for */* with non-iso-8859-* chars
433
corrected_glob, corrected = _ensure_with_dir(possible_glob)
434
glob_files = glob.glob(corrected_glob)
437
# special case to let the normal code path handle
438
# files that do not exist, etc.
439
glob_files = [possible_glob]
441
glob_files = [_undo_ensure_with_dir(elem, corrected)
442
for elem in glob_files]
443
return [elem.replace(u'\\', u'/') for elem in glob_files]
425
446
def glob_expand(file_list):
426
447
"""Replacement for glob expansion by the shell.
436
457
if not file_list:
439
459
expanded_file_list = []
440
460
for possible_glob in file_list:
441
# work around bugs in glob.glob()
442
# - Python bug #1001604 ("glob doesn't return unicode with ...")
443
# - failing expansion for */* with non-iso-8859-* chars
444
possible_glob, corrected = _ensure_with_dir(possible_glob)
445
glob_files = glob.glob(possible_glob)
448
# special case to let the normal code path handle
449
# files that do not exists
450
expanded_file_list.append(
451
_undo_ensure_with_dir(possible_glob, corrected))
453
glob_files = [_undo_ensure_with_dir(elem, corrected) for elem in glob_files]
454
expanded_file_list += glob_files
456
return [elem.replace(u'\\', u'/') for elem in expanded_file_list]
461
expanded_file_list.extend(glob_one(possible_glob))
462
return expanded_file_list
459
465
def get_app_path(appname):
511
517
trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
521
class UnicodeShlex(object):
522
"""This is a very simplified version of shlex.shlex.
524
The main change is that it supports non-ascii input streams. The internal
525
structure is quite simplified relative to shlex.shlex, since we aren't
526
trying to handle multiple input streams, etc. In fact, we don't use a
527
file-like api either.
530
def __init__(self, uni_string):
531
self._input = uni_string
532
self._input_iter = iter(self._input)
533
self._whitespace_match = re.compile(u'\s').match
534
self._word_match = re.compile(u'\S').match
535
self._quote_chars = u'"'
536
# self._quote_match = re.compile(u'[\'"]').match
537
self._escape_match = lambda x: None # Never matches
540
# ' ' - after whitespace, starting a new token
541
# 'a' - after text, currently working on a token
542
# '"' - after ", currently in a "-delimited quoted section
543
# "\" - after '\', checking the next char
545
self._token = [] # Current token being parsed
547
def _get_token(self):
548
# Were there quote chars as part of this token?
551
for nextchar in self._input_iter:
552
if self._state == ' ':
553
if self._whitespace_match(nextchar):
554
# if self._token: return token
556
elif nextchar in self._quote_chars:
557
self._state = nextchar # quoted state
558
elif self._word_match(nextchar):
559
self._token.append(nextchar)
562
raise AssertionError('wtttf?')
563
elif self._state in self._quote_chars:
565
if nextchar == self._state: # End of quote
566
self._state = 'a' # posix allows 'foo'bar to translate to
568
elif self._state == '"' and nextchar == self._escape:
569
quoted_state = self._state
570
self._state = nextchar
572
self._token.append(nextchar)
573
elif self._state == self._escape:
575
self._token.append('\\')
576
elif nextchar == '"':
577
self._token.append(nextchar)
579
self._token.append('\\' + nextchar)
580
self._state = quoted_state
581
elif self._state == 'a':
582
if self._whitespace_match(nextchar):
584
break # emit this token
586
continue # no token to emit
587
elif nextchar in self._quote_chars:
588
# Start a new quoted section
589
self._state = nextchar
591
elif (self._word_match(nextchar)
592
or nextchar in self._quote_chars
593
# or whitespace_split?
595
self._token.append(nextchar)
597
raise AssertionError('state == "a", char: %r'
600
raise AssertionError('unknown state: %r' % (self._state,))
601
result = ''.join(self._token)
603
if not quoted and result == '':
605
return quoted, result
611
quoted, token = self._get_token()
617
def _command_line_to_argv(command_line):
618
"""Convert a Unicode command line into a set of argv arguments.
620
This does wildcard expansion, etc. It is intended to make wildcards act
621
closer to how they work in posix shells, versus how they work by default on
624
s = UnicodeShlex(command_line)
625
# Now that we've split the content, expand globs
626
# TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
629
for is_quoted, arg in s:
630
if is_quoted or not glob.has_magic(arg):
633
args.extend(glob_one(arg))
514
637
if has_ctypes and winver != 'Windows 98':
515
638
def get_unicode_argv():
516
639
LPCWSTR = ctypes.c_wchar_p
520
643
GetCommandLine = prototype(("GetCommandLineW",
521
644
ctypes.windll.kernel32))
522
645
prototype = ctypes.WINFUNCTYPE(POINTER(LPCWSTR), LPCWSTR, POINTER(INT))
523
CommandLineToArgv = prototype(("CommandLineToArgvW",
524
ctypes.windll.shell32))
526
pargv = CommandLineToArgv(GetCommandLine(), ctypes.byref(c))
646
command_line = GetCommandLine()
527
647
# Skip the first argument, since we only care about parameters
528
argv = [pargv[i] for i in range(1, c.value)]
648
argv = _command_line_to_argv(command_line)[1:]
529
649
if getattr(sys, 'frozen', None) is None:
530
650
# Invoked via 'python.exe' which takes the form:
531
651
# python.exe [PYTHON_OPTIONS] C:\Path\bzr [BZR_OPTIONS]
532
652
# we need to get only BZR_OPTIONS part,
533
# so let's using sys.argv[1:] as reference to get the tail
535
tail_len = len(sys.argv[1:])
536
ix = len(argv) - tail_len
653
# We already removed 'python.exe' so we remove everything up to and
654
# including the first non-option ('-') argument.
655
for idx in xrange(len(argv)):
656
if argv[idx][:1] != '-':
540
661
get_unicode_argv = None