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