/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/cmdline.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

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
            return self.exit_state
 
76
        else:
 
77
            context.token.append(next_char)
 
78
            return self
 
79
 
 
80
 
 
81
class _Backslash(object):
 
82
    # See http://msdn.microsoft.com/en-us/library/bb776391(VS.85).aspx
 
83
    def __init__(self, exit_state):
 
84
        self.exit_state = exit_state
 
85
        self.count = 1
 
86
 
 
87
    def process(self, next_char, context):
 
88
        if next_char == u'\\':
 
89
            self.count += 1
 
90
            return self
 
91
        elif next_char in context.allowed_quote_chars:
 
92
            # 2N backslashes followed by a quote are N backslashes
 
93
            context.token.append(u'\\' * (self.count/2))
 
94
            # 2N+1 backslashes follwed by a quote are N backslashes followed by
 
95
            # the quote which should not be processed as the start or end of
 
96
            # the quoted arg
 
97
            if self.count % 2 == 1:
 
98
                # odd number of \ escapes the quote
 
99
                context.token.append(next_char)
 
100
            else:
 
101
                # let exit_state handle next_char
 
102
                context.seq.pushback(next_char)
 
103
            self.count = 0
 
104
            return self.exit_state
 
105
        else:
 
106
            # N backslashes not followed by a quote are just N backslashes
 
107
            if self.count > 0:
 
108
                context.token.append(u'\\' * self.count)
 
109
                self.count = 0
 
110
            # let exit_state handle next_char
 
111
            context.seq.pushback(next_char)
 
112
            return self.exit_state
 
113
 
 
114
    def finish(self, context):
 
115
        if self.count > 0:
 
116
            context.token.append(u'\\' * self.count)
 
117
 
 
118
 
 
119
class _Word(object):
 
120
    def process(self, next_char, context):
 
121
        if _whitespace_match(next_char):
 
122
            return None
 
123
        elif next_char in context.allowed_quote_chars:
 
124
            return _Quotes(next_char, self)
 
125
        elif next_char == u'\\':
 
126
            return _Backslash(self)
 
127
        else:
 
128
            context.token.append(next_char)
 
129
            return self
 
130
 
 
131
 
 
132
class Splitter(object):
 
133
    def __init__(self, command_line, single_quotes_allowed):
 
134
        self.seq = _PushbackSequence(command_line)
 
135
        self.allowed_quote_chars = u'"'
 
136
        if single_quotes_allowed:
 
137
            self.allowed_quote_chars += u"'"
 
138
 
 
139
    def __iter__(self):
 
140
        return self
 
141
 
 
142
    def next(self):
 
143
        quoted, token = self._get_token()
 
144
        if token is None:
 
145
            raise StopIteration
 
146
        return quoted, token
 
147
 
 
148
    def _get_token(self):
 
149
        self.quoted = False
 
150
        self.token = []
 
151
        state = _Whitespace()
 
152
        for next_char in self.seq:
 
153
            state = state.process(next_char, self)
 
154
            if state is None:
 
155
                break
 
156
        if not state is None and not getattr(state, 'finish', None) is None:
 
157
            state.finish(self)
 
158
        result = u''.join(self.token)
 
159
        if not self.quoted and result == '':
 
160
            result = None
 
161
        return self.quoted, result
 
162
 
 
163
 
 
164
def split(unsplit, single_quotes_allowed=True):
 
165
    splitter = Splitter(unsplit, single_quotes_allowed=single_quotes_allowed)
 
166
    return [arg for quoted, arg in splitter]