~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/win32utils.py

  • Committer: Gordon Tyler
  • Date: 2010-01-14 15:24:04 UTC
  • mto: (5037.3.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5046.
  • Revision ID: gordon@doxxx.net-20100114152404-d64ik2afl96lcml0
Reverted changes to test_rules since the original should work now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
21
21
 
22
22
import glob
23
23
import os
 
24
import re
24
25
import struct
25
26
import sys
26
27
 
27
 
from bzrlib import cmdline
28
28
 
29
29
# Windows version
30
30
if sys.platform == 'win32':
135
135
                'WorkingSetSize': mem_struct.WorkingSetSize,
136
136
                'QuotaPeakPagedPoolUsage': mem_struct.QuotaPeakPagedPoolUsage,
137
137
                'QuotaPagedPoolUsage': mem_struct.QuotaPagedPoolUsage,
138
 
                'QuotaPeakNonPagedPoolUsage':
139
 
                    mem_struct.QuotaPeakNonPagedPoolUsage,
 
138
                'QuotaPeakNonPagedPoolUsage': mem_struct.QuotaPeakNonPagedPoolUsage,
140
139
                'QuotaNonPagedPoolUsage': mem_struct.QuotaNonPagedPoolUsage,
141
140
                'PagefileUsage': mem_struct.PagefileUsage,
142
141
                'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
153
152
                   ' or win32process')
154
153
        return
155
154
    if short:
156
 
        # using base-2 units (see HACKING.txt).
157
 
        trace.note('WorkingSize %7dKiB'
158
 
                   '\tPeakWorking %7dKiB\t%s',
 
155
        trace.note('WorkingSize %7dKB'
 
156
                   '\tPeakWorking %7dKB\t%s',
159
157
                   info['WorkingSetSize'] / 1024,
160
158
                   info['PeakWorkingSetSize'] / 1024,
161
159
                   message)
162
160
        return
163
161
    if message:
164
162
        trace.note('%s', message)
165
 
    trace.note('WorkingSize       %8d KiB', info['WorkingSetSize'] / 1024)
166
 
    trace.note('PeakWorking       %8d KiB', info['PeakWorkingSetSize'] / 1024)
167
 
    trace.note('PagefileUsage     %8d KiB', info.get('PagefileUsage', 0) / 1024)
168
 
    trace.note('PeakPagefileUsage %8d KiB',
169
 
               info.get('PeakPagefileUsage', 0) / 1024)
170
 
    trace.note('PrivateUsage      %8d KiB', info.get('PrivateUsage', 0) / 1024)
 
163
    trace.note('WorkingSize       %8d KB', info['WorkingSetSize'] / 1024)
 
164
    trace.note('PeakWorking       %8d KB', info['PeakWorkingSetSize'] / 1024)
 
165
    trace.note('PagefileUsage     %8d KB', info.get('PagefileUsage', 0) / 1024)
 
166
    trace.note('PeakPagefileUsage %8d KB', info.get('PeakPagefileUsage', 0) / 1024)
 
167
    trace.note('PrivateUsage      %8d KB', info.get('PrivateUsage', 0) / 1024)
171
168
    trace.note('PageFaultCount    %8d', info.get('PageFaultCount', 0))
172
169
 
173
170
 
190
187
 
191
188
    if res:
192
189
        (bufx, bufy, curx, cury, wattr,
193
 
        left, top, right, bottom, maxx, maxy) = struct.unpack(
194
 
            "hhhhHhhhhhh", csbi.raw)
 
190
        left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
195
191
        sizex = right - left + 1
196
192
        sizey = bottom - top + 1
197
193
        return (sizex, sizey)
414
410
 
415
411
 
416
412
def _ensure_with_dir(path):
417
 
    if (not os.path.split(path)[0] or path.startswith(u'*')
418
 
        or path.startswith(u'?')):
 
413
    if not os.path.split(path)[0] or path.startswith(u'*') or path.startswith(u'?'):
419
414
        return u'./' + path, True
420
415
    else:
421
416
        return path, False
522
517
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
523
518
 
524
519
 
525
 
def _command_line_to_argv(command_line, single_quotes_allowed=False):
 
520
_whitespace_match = re.compile(u'\s').match
 
521
 
 
522
 
 
523
class _PushbackSequence(object):
 
524
    def __init__(self, orig):
 
525
        self._iter = iter(orig)
 
526
        self._pushback_buffer = []
 
527
        
 
528
    def next(self):
 
529
        if len(self._pushback_buffer) > 0:
 
530
            return self._pushback_buffer.pop()
 
531
        else:
 
532
            return self._iter.next()
 
533
    
 
534
    def pushback(self, char):
 
535
        self._pushback_buffer.append(char)
 
536
        
 
537
    def __iter__(self):
 
538
        return self
 
539
 
 
540
 
 
541
class _Whitespace(object):
 
542
    def process(self, next_char, seq, context):
 
543
        if _whitespace_match(next_char):
 
544
            if len(context.token) > 0:
 
545
                return None
 
546
            else:
 
547
                return self
 
548
        elif (next_char == u'"'
 
549
              or (context.single_quotes_allowed and next_char == u"'")):
 
550
            context.quoted = True
 
551
            return _Quotes(next_char, self)
 
552
        elif next_char == u'\\':
 
553
            return _Backslash(self)
 
554
        else:
 
555
            context.token.append(next_char)
 
556
            return _Word()
 
557
 
 
558
 
 
559
class _Quotes(object):
 
560
    def __init__(self, quote_char, exit_state):
 
561
        self.quote_char = quote_char
 
562
        self.exit_state = exit_state
 
563
 
 
564
    def process(self, next_char, seq, context):
 
565
        if next_char == u'\\':
 
566
            return _Backslash(self)
 
567
        elif next_char == self.quote_char:
 
568
            return self.exit_state
 
569
        else:
 
570
            context.token.append(next_char)
 
571
            return self
 
572
 
 
573
 
 
574
class _Backslash(object):
 
575
    # See http://msdn.microsoft.com/en-us/library/bb776391(VS.85).aspx
 
576
    def __init__(self, exit_state):
 
577
        self.exit_state = exit_state
 
578
        self.count = 1
 
579
        
 
580
    def process(self, next_char, seq, context):
 
581
        if next_char == u'\\':
 
582
            self.count += 1
 
583
            return self
 
584
        elif next_char == u'"':
 
585
            # 2N backslashes followed by '"' are N backslashes
 
586
            context.token.append(u'\\' * (self.count/2))
 
587
            # 2N+1 backslashes follwed by '"' are N backslashes followed by '"'
 
588
            # which should not be processed as the start or end of quoted arg
 
589
            if self.count % 2 == 1:
 
590
                context.token.append(next_char) # odd number of '\' escapes the '"'
 
591
            else:
 
592
                seq.pushback(next_char) # let exit_state handle next_char
 
593
            self.count = 0
 
594
            return self.exit_state
 
595
        else:
 
596
            # N backslashes not followed by '"' are just N backslashes
 
597
            if self.count > 0:
 
598
                context.token.append(u'\\' * self.count)
 
599
                self.count = 0
 
600
            seq.pushback(next_char) # let exit_state handle next_char
 
601
            return self.exit_state
 
602
    
 
603
    def finish(self, context):
 
604
        if self.count > 0:
 
605
            context.token.append(u'\\' * self.count)
 
606
 
 
607
 
 
608
class _Word(object):
 
609
    def process(self, next_char, seq, context):
 
610
        if _whitespace_match(next_char):
 
611
            return None
 
612
        elif (next_char == u'"'
 
613
              or (context.single_quotes_allowed and next_char == u"'")):
 
614
            return _Quotes(next_char, self)
 
615
        elif next_char == u'\\':
 
616
            return _Backslash(self)
 
617
        else:
 
618
            context.token.append(next_char)
 
619
            return self
 
620
 
 
621
 
 
622
class UnicodeShlex(object):
 
623
    def __init__(self, command_line, single_quotes_allowed=False):
 
624
        self._seq = _PushbackSequence(command_line)
 
625
        self.single_quotes_allowed = single_quotes_allowed
 
626
    
 
627
    def __iter__(self):
 
628
        return self
 
629
    
 
630
    def next(self):
 
631
        quoted, token = self._get_token()
 
632
        if token is None:
 
633
            raise StopIteration
 
634
        return quoted, token
 
635
    
 
636
    def _get_token(self):
 
637
        self.quoted = False
 
638
        self.token = []
 
639
        state = _Whitespace()
 
640
        for next_char in self._seq:
 
641
            state = state.process(next_char, self._seq, self)
 
642
            if state is None:
 
643
                break
 
644
        if not state is None and not getattr(state, 'finish', None) is None:
 
645
            state.finish(self)
 
646
        result = u''.join(self.token)
 
647
        if not self.quoted and result == '':
 
648
            result = None
 
649
        return self.quoted, result
 
650
 
 
651
 
 
652
def command_line_to_argv(command_line, wildcard_expansion=True,
 
653
                         single_quotes_allowed=False):
526
654
    """Convert a Unicode command line into a list of argv arguments.
527
655
 
528
 
    It performs wildcard expansion to make wildcards act closer to how they
529
 
    work in posix shells, versus how they work by default on Windows. Quoted
530
 
    arguments are left untouched.
 
656
    This optionally does wildcard expansion, etc. It is intended to make
 
657
    wildcards act closer to how they work in posix shells, versus how they
 
658
    work by default on Windows. Quoted arguments are left untouched.
531
659
 
532
660
    :param command_line: The unicode string to split into an arg list.
 
661
    :param wildcard_expansion: Whether wildcard expansion should be applied to
 
662
                               each argument. True by default.
533
663
    :param single_quotes_allowed: Whether single quotes are accepted as quoting
534
664
                                  characters like double quotes. False by
535
665
                                  default.
536
666
    :return: A list of unicode strings.
537
667
    """
538
 
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
 
668
    s = UnicodeShlex(command_line, single_quotes_allowed=single_quotes_allowed)
539
669
    # Now that we've split the content, expand globs if necessary
540
670
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
541
671
    #       '**/' style globs
542
672
    args = []
543
673
    for is_quoted, arg in s:
544
 
        if is_quoted or not glob.has_magic(arg):
 
674
        if is_quoted or not glob.has_magic(arg) or not wildcard_expansion:
545
675
            args.append(arg)
546
676
        else:
547
677
            args.extend(glob_one(arg))
550
680
 
551
681
if has_ctypes and winver != 'Windows 98':
552
682
    def get_unicode_argv():
553
 
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
 
683
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p, use_last_error=True)
554
684
        GetCommandLineW = prototype(("GetCommandLineW",
555
685
                                     ctypes.windll.kernel32))
556
686
        command_line = GetCommandLineW()
557
687
        if command_line is None:
558
688
            raise ctypes.WinError()
559
689
        # Skip the first argument, since we only care about parameters
560
 
        argv = _command_line_to_argv(command_line)[1:]
 
690
        argv = command_line_to_argv(command_line)[1:]
561
691
        if getattr(sys, 'frozen', None) is None:
562
692
            # Invoked via 'python.exe' which takes the form:
563
693
            #   python.exe [PYTHON_OPTIONS] C:\Path\bzr [BZR_OPTIONS]