~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/cmdline.py

  • Committer: John Arbash Meinel
  • Date: 2008-07-09 21:42:24 UTC
  • mto: This revision was merged to the branch mainline in revision 3543.
  • Revision ID: john@arbash-meinel.com-20080709214224-r75k87r6a01pfc3h
Restore a real weave merge to 'bzr merge --weave'.

To do so efficiently, we only add the simple LCAs to the final weave
object, unless we run into complexities with the merge graph.
This gives the same effective result as adding all the texts,
with the advantage of not having to extract all of them.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010-2011 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
"""Unicode-compatible command-line splitter for all platforms.
18
 
 
19
 
The user-visible behaviour of this module is described in
20
 
configuring_bazaar.txt.
21
 
"""
22
 
 
23
 
from __future__ import absolute_import
24
 
 
25
 
import re
26
 
 
27
 
 
28
 
_whitespace_match = re.compile(u'\s', re.UNICODE).match
29
 
 
30
 
 
31
 
class _PushbackSequence(object):
32
 
    def __init__(self, orig):
33
 
        self._iter = iter(orig)
34
 
        self._pushback_buffer = []
35
 
 
36
 
    def next(self):
37
 
        if len(self._pushback_buffer) > 0:
38
 
            return self._pushback_buffer.pop()
39
 
        else:
40
 
            return self._iter.next()
41
 
 
42
 
    def pushback(self, char):
43
 
        self._pushback_buffer.append(char)
44
 
 
45
 
    def __iter__(self):
46
 
        return self
47
 
 
48
 
 
49
 
class _Whitespace(object):
50
 
    def process(self, next_char, context):
51
 
        if _whitespace_match(next_char):
52
 
            if len(context.token) > 0:
53
 
                return None
54
 
            else:
55
 
                return self
56
 
        elif next_char in context.allowed_quote_chars:
57
 
            context.quoted = True
58
 
            return _Quotes(next_char, self)
59
 
        elif next_char == u'\\':
60
 
            return _Backslash(self)
61
 
        else:
62
 
            context.token.append(next_char)
63
 
            return _Word()
64
 
 
65
 
 
66
 
class _Quotes(object):
67
 
    def __init__(self, quote_char, exit_state):
68
 
        self.quote_char = quote_char
69
 
        self.exit_state = exit_state
70
 
 
71
 
    def process(self, next_char, context):
72
 
        if next_char == u'\\':
73
 
            return _Backslash(self)
74
 
        elif next_char == self.quote_char:
75
 
            context.token.append(u'')
76
 
            return self.exit_state
77
 
        else:
78
 
            context.token.append(next_char)
79
 
            return self
80
 
 
81
 
 
82
 
class _Backslash(object):
83
 
    # See http://msdn.microsoft.com/en-us/library/bb776391(VS.85).aspx
84
 
    def __init__(self, exit_state):
85
 
        self.exit_state = exit_state
86
 
        self.count = 1
87
 
 
88
 
    def process(self, next_char, context):
89
 
        if next_char == u'\\':
90
 
            self.count += 1
91
 
            return self
92
 
        elif next_char in context.allowed_quote_chars:
93
 
            # 2N backslashes followed by a quote are N backslashes
94
 
            context.token.append(u'\\' * (self.count/2))
95
 
            # 2N+1 backslashes follwed by a quote are N backslashes followed by
96
 
            # the quote which should not be processed as the start or end of
97
 
            # the quoted arg
98
 
            if self.count % 2 == 1:
99
 
                # odd number of \ escapes the quote
100
 
                context.token.append(next_char)
101
 
            else:
102
 
                # let exit_state handle next_char
103
 
                context.seq.pushback(next_char)
104
 
            self.count = 0
105
 
            return self.exit_state
106
 
        else:
107
 
            # N backslashes not followed by a quote are just N backslashes
108
 
            if self.count > 0:
109
 
                context.token.append(u'\\' * self.count)
110
 
                self.count = 0
111
 
            # let exit_state handle next_char
112
 
            context.seq.pushback(next_char)
113
 
            return self.exit_state
114
 
 
115
 
    def finish(self, context):
116
 
        if self.count > 0:
117
 
            context.token.append(u'\\' * self.count)
118
 
 
119
 
 
120
 
class _Word(object):
121
 
    def process(self, next_char, context):
122
 
        if _whitespace_match(next_char):
123
 
            return None
124
 
        elif next_char in context.allowed_quote_chars:
125
 
            return _Quotes(next_char, self)
126
 
        elif next_char == u'\\':
127
 
            return _Backslash(self)
128
 
        else:
129
 
            context.token.append(next_char)
130
 
            return self
131
 
 
132
 
 
133
 
class Splitter(object):
134
 
    def __init__(self, command_line, single_quotes_allowed):
135
 
        self.seq = _PushbackSequence(command_line)
136
 
        self.allowed_quote_chars = u'"'
137
 
        if single_quotes_allowed:
138
 
            self.allowed_quote_chars += u"'"
139
 
 
140
 
    def __iter__(self):
141
 
        return self
142
 
 
143
 
    def next(self):
144
 
        quoted, token = self._get_token()
145
 
        if token is None:
146
 
            raise StopIteration
147
 
        return quoted, token
148
 
 
149
 
    def _get_token(self):
150
 
        self.quoted = False
151
 
        self.token = []
152
 
        state = _Whitespace()
153
 
        for next_char in self.seq:
154
 
            state = state.process(next_char, self)
155
 
            if state is None:
156
 
                break
157
 
        if not state is None and not getattr(state, 'finish', None) is None:
158
 
            state.finish(self)
159
 
        result = u''.join(self.token)
160
 
        if not self.quoted and result == '':
161
 
            result = None
162
 
        return self.quoted, result
163
 
 
164
 
 
165
 
def split(unsplit, single_quotes_allowed=True):
166
 
    splitter = Splitter(unsplit, single_quotes_allowed=single_quotes_allowed)
167
 
    return [arg for quoted, arg in splitter]