~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/branch.py

(parthm) Better regex compile errors (Parth Malwankar)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 Canonical Ltd
 
1
# Copyright (C) 2006-2010 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Server-side branch related request implmentations."""
18
18
 
19
19
 
20
 
from bzrlib import errors
 
20
from bzrlib import (
 
21
    bencode,
 
22
    errors,
 
23
    )
21
24
from bzrlib.bzrdir import BzrDir
22
25
from bzrlib.smart.request import (
23
26
    FailedSmartServerResponse,
27
30
 
28
31
 
29
32
class SmartServerBranchRequest(SmartServerRequest):
30
 
    """Base class for handling common branch request logic."""
 
33
    """Base class for handling common branch request logic.
 
34
    """
31
35
 
32
36
    def do(self, path, *args):
33
37
        """Execute a request for a branch at path.
34
38
 
 
39
        All Branch requests take a path to the branch as their first argument.
 
40
 
35
41
        If the branch is a branch reference, NotBranchError is raised.
 
42
 
 
43
        :param path: The path for the repository as received from the
 
44
            client.
 
45
        :return: A SmartServerResponse from self.do_with_branch().
36
46
        """
37
 
        transport = self._backing_transport.clone(path)
 
47
        transport = self.transport_from_client_path(path)
38
48
        bzrdir = BzrDir.open_from_transport(transport)
39
49
        if bzrdir.get_branch_reference() is not None:
40
50
            raise errors.NotBranchError(transport.base)
41
 
        branch = bzrdir.open_branch()
 
51
        branch = bzrdir.open_branch(ignore_fallbacks=True)
42
52
        return self.do_with_branch(branch, *args)
43
53
 
44
54
 
67
77
 
68
78
 
69
79
class SmartServerBranchGetConfigFile(SmartServerBranchRequest):
70
 
    
 
80
 
71
81
    def do_with_branch(self, branch):
72
 
        """Return the content of branch.control_files.get('branch.conf').
73
 
        
 
82
        """Return the content of branch.conf
 
83
 
74
84
        The body is not utf8 decoded - its the literal bytestream from disk.
75
85
        """
76
86
        try:
77
 
            content = branch.control_files.get('branch.conf').read()
 
87
            content = branch._transport.get_bytes('branch.conf')
78
88
        except errors.NoSuchFile:
79
89
            content = ''
80
90
        return SuccessfulSmartServerResponse( ('ok', ), content)
81
91
 
82
92
 
 
93
class SmartServerBranchGetParent(SmartServerBranchRequest):
 
94
 
 
95
    def do_with_branch(self, branch):
 
96
        """Return the parent of branch."""
 
97
        parent = branch._get_parent_location() or ''
 
98
        return SuccessfulSmartServerResponse((parent,))
 
99
 
 
100
 
 
101
class SmartServerBranchGetTagsBytes(SmartServerBranchRequest):
 
102
 
 
103
    def do_with_branch(self, branch):
 
104
        """Return the _get_tags_bytes for a branch."""
 
105
        bytes = branch._get_tags_bytes()
 
106
        return SuccessfulSmartServerResponse((bytes,))
 
107
 
 
108
 
 
109
class SmartServerBranchSetTagsBytes(SmartServerLockedBranchRequest):
 
110
 
 
111
    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
 
112
        SmartServerLockedBranchRequest.__init__(
 
113
            self, backing_transport, root_client_path, jail_root)
 
114
        self.locked = False
 
115
        
 
116
    def do_with_locked_branch(self, branch):
 
117
        """Call _set_tags_bytes for a branch.
 
118
 
 
119
        New in 1.18.
 
120
        """
 
121
        # We need to keep this branch locked until we get a body with the tags
 
122
        # bytes.
 
123
        self.branch = branch
 
124
        self.branch.lock_write()
 
125
        self.locked = True
 
126
 
 
127
    def do_body(self, bytes):
 
128
        self.branch._set_tags_bytes(bytes)
 
129
        return SuccessfulSmartServerResponse(())
 
130
 
 
131
    def do_end(self):
 
132
        # TODO: this request shouldn't have to do this housekeeping manually.
 
133
        # Some of this logic probably belongs in a base class.
 
134
        if not self.locked:
 
135
            # We never acquired the branch successfully in the first place, so
 
136
            # there's nothing more to do.
 
137
            return
 
138
        try:
 
139
            return SmartServerLockedBranchRequest.do_end(self)
 
140
        finally:
 
141
            # Only try unlocking if we locked successfully in the first place
 
142
            self.branch.unlock()
 
143
 
 
144
 
 
145
class SmartServerBranchRequestGetStackedOnURL(SmartServerBranchRequest):
 
146
 
 
147
    def do_with_branch(self, branch):
 
148
        stacked_on_url = branch.get_stacked_on_url()
 
149
        return SuccessfulSmartServerResponse(('ok', stacked_on_url))
 
150
 
 
151
 
83
152
class SmartServerRequestRevisionHistory(SmartServerBranchRequest):
84
153
 
85
154
    def do_with_branch(self, branch):
93
162
 
94
163
 
95
164
class SmartServerBranchRequestLastRevisionInfo(SmartServerBranchRequest):
96
 
    
 
165
 
97
166
    def do_with_branch(self, branch):
98
167
        """Return branch.last_revision_info().
99
 
        
 
168
 
100
169
        The revno is encoded in decimal, the revision_id is encoded as utf8.
101
170
        """
102
171
        revno, last_revision = branch.last_revision_info()
103
172
        return SuccessfulSmartServerResponse(('ok', str(revno), last_revision))
104
173
 
105
174
 
106
 
class SmartServerBranchRequestSetLastRevision(SmartServerLockedBranchRequest):
 
175
class SmartServerSetTipRequest(SmartServerLockedBranchRequest):
 
176
    """Base class for handling common branch request logic for requests that
 
177
    update the branch tip.
 
178
    """
 
179
 
 
180
    def do_with_locked_branch(self, branch, *args):
 
181
        try:
 
182
            return self.do_tip_change_with_locked_branch(branch, *args)
 
183
        except errors.TipChangeRejected, e:
 
184
            msg = e.msg
 
185
            if isinstance(msg, unicode):
 
186
                msg = msg.encode('utf-8')
 
187
            return FailedSmartServerResponse(('TipChangeRejected', msg))
 
188
 
 
189
 
 
190
class SmartServerBranchRequestSetConfigOption(SmartServerLockedBranchRequest):
 
191
    """Set an option in the branch configuration."""
 
192
 
 
193
    def do_with_locked_branch(self, branch, value, name, section):
 
194
        if not section:
 
195
            section = None
 
196
        branch._get_config().set_option(value.decode('utf8'), name, section)
 
197
        return SuccessfulSmartServerResponse(())
 
198
 
 
199
 
 
200
class SmartServerBranchRequestSetConfigOptionDict(SmartServerLockedBranchRequest):
 
201
    """Set an option in the branch configuration.
107
202
    
108
 
    def do_with_locked_branch(self, branch, new_last_revision_id):
 
203
    New in 2.2.
 
204
    """
 
205
 
 
206
    def do_with_locked_branch(self, branch, value_dict, name, section):
 
207
        utf8_dict = bencode.bdecode(value_dict)
 
208
        value_dict = {}
 
209
        for key, value in utf8_dict.items():
 
210
            value_dict[key.decode('utf8')] = value.decode('utf8')
 
211
        if not section:
 
212
            section = None
 
213
        branch._get_config().set_option(value_dict, name, section)
 
214
        return SuccessfulSmartServerResponse(())
 
215
 
 
216
 
 
217
class SmartServerBranchRequestSetLastRevision(SmartServerSetTipRequest):
 
218
 
 
219
    def do_tip_change_with_locked_branch(self, branch, new_last_revision_id):
109
220
        if new_last_revision_id == 'null:':
110
221
            branch.set_revision_history([])
111
222
        else:
112
223
            if not branch.repository.has_revision(new_last_revision_id):
113
224
                return FailedSmartServerResponse(
114
225
                    ('NoSuchRevision', new_last_revision_id))
115
 
            branch.generate_revision_history(new_last_revision_id)
116
 
        return SuccessfulSmartServerResponse(('ok',))
 
226
            branch.set_revision_history(branch._lefthand_history(
 
227
                new_last_revision_id, None, None))
 
228
        return SuccessfulSmartServerResponse(('ok',))
 
229
 
 
230
 
 
231
class SmartServerBranchRequestSetLastRevisionEx(SmartServerSetTipRequest):
 
232
 
 
233
    def do_tip_change_with_locked_branch(self, branch, new_last_revision_id,
 
234
            allow_divergence, allow_overwrite_descendant):
 
235
        """Set the last revision of the branch.
 
236
 
 
237
        New in 1.6.
 
238
 
 
239
        :param new_last_revision_id: the revision ID to set as the last
 
240
            revision of the branch.
 
241
        :param allow_divergence: A flag.  If non-zero, change the revision ID
 
242
            even if the new_last_revision_id's ancestry has diverged from the
 
243
            current last revision.  If zero, a 'Diverged' error will be
 
244
            returned if new_last_revision_id is not a descendant of the current
 
245
            last revision.
 
246
        :param allow_overwrite_descendant:  A flag.  If zero and
 
247
            new_last_revision_id is not a descendant of the current last
 
248
            revision, then the last revision will not be changed.  If non-zero
 
249
            and there is no divergence, then the last revision is always
 
250
            changed.
 
251
 
 
252
        :returns: on success, a tuple of ('ok', revno, revision_id), where
 
253
            revno and revision_id are the new values of the current last
 
254
            revision info.  The revision_id might be different to the
 
255
            new_last_revision_id if allow_overwrite_descendant was not set.
 
256
        """
 
257
        do_not_overwrite_descendant = not allow_overwrite_descendant
 
258
        try:
 
259
            last_revno, last_rev = branch.last_revision_info()
 
260
            graph = branch.repository.get_graph()
 
261
            if not allow_divergence or do_not_overwrite_descendant:
 
262
                relation = branch._revision_relations(
 
263
                    last_rev, new_last_revision_id, graph)
 
264
                if relation == 'diverged' and not allow_divergence:
 
265
                    return FailedSmartServerResponse(('Diverged',))
 
266
                if relation == 'a_descends_from_b' and do_not_overwrite_descendant:
 
267
                    return SuccessfulSmartServerResponse(
 
268
                        ('ok', last_revno, last_rev))
 
269
            new_revno = graph.find_distance_to_null(
 
270
                new_last_revision_id, [(last_rev, last_revno)])
 
271
            branch.set_last_revision_info(new_revno, new_last_revision_id)
 
272
        except errors.GhostRevisionsHaveNoRevno:
 
273
            return FailedSmartServerResponse(
 
274
                ('NoSuchRevision', new_last_revision_id))
 
275
        return SuccessfulSmartServerResponse(
 
276
            ('ok', new_revno, new_last_revision_id))
 
277
 
 
278
 
 
279
class SmartServerBranchRequestSetLastRevisionInfo(SmartServerSetTipRequest):
 
280
    """Branch.set_last_revision_info.  Sets the revno and the revision ID of
 
281
    the specified branch.
 
282
 
 
283
    New in bzrlib 1.4.
 
284
    """
 
285
 
 
286
    def do_tip_change_with_locked_branch(self, branch, new_revno,
 
287
            new_last_revision_id):
 
288
        try:
 
289
            branch.set_last_revision_info(int(new_revno), new_last_revision_id)
 
290
        except errors.NoSuchRevision:
 
291
            return FailedSmartServerResponse(
 
292
                ('NoSuchRevision', new_last_revision_id))
 
293
        return SuccessfulSmartServerResponse(('ok',))
 
294
 
 
295
 
 
296
class SmartServerBranchRequestSetParentLocation(SmartServerLockedBranchRequest):
 
297
    """Set the parent location for a branch.
 
298
    
 
299
    Takes a location to set, which must be utf8 encoded.
 
300
    """
 
301
 
 
302
    def do_with_locked_branch(self, branch, location):
 
303
        branch._set_parent_location(location)
 
304
        return SuccessfulSmartServerResponse(())
117
305
 
118
306
 
119
307
class SmartServerBranchRequestLockWrite(SmartServerBranchRequest):
120
 
    
 
308
 
121
309
    def do_with_branch(self, branch, branch_token='', repo_token=''):
122
310
        if branch_token == '':
123
311
            branch_token = None
124
312
        if repo_token == '':
125
313
            repo_token = None
126
314
        try:
127
 
            repo_token = branch.repository.lock_write(token=repo_token)
 
315
            repo_token = branch.repository.lock_write(
 
316
                token=repo_token).repository_token
128
317
            try:
129
 
                branch_token = branch.lock_write(token=branch_token)
 
318
                branch_token = branch.lock_write(
 
319
                    token=branch_token).branch_token
130
320
            finally:
 
321
                # this leaves the repository with 1 lock
131
322
                branch.repository.unlock()
132
323
        except errors.LockContention:
133
324
            return FailedSmartServerResponse(('LockContention',))
135
326
            return FailedSmartServerResponse(('TokenMismatch',))
136
327
        except errors.UnlockableTransport:
137
328
            return FailedSmartServerResponse(('UnlockableTransport',))
138
 
        branch.repository.leave_lock_in_place()
 
329
        except errors.LockFailed, e:
 
330
            return FailedSmartServerResponse(('LockFailed', str(e.lock), str(e.why)))
 
331
        if repo_token is None:
 
332
            repo_token = ''
 
333
        else:
 
334
            branch.repository.leave_lock_in_place()
139
335
        branch.leave_lock_in_place()
140
336
        branch.unlock()
141
337
        return SuccessfulSmartServerResponse(('ok', branch_token, repo_token))
152
348
                branch.repository.unlock()
153
349
        except errors.TokenMismatch:
154
350
            return FailedSmartServerResponse(('TokenMismatch',))
155
 
        branch.repository.dont_leave_lock_in_place()
 
351
        if repo_token:
 
352
            branch.repository.dont_leave_lock_in_place()
156
353
        branch.dont_leave_lock_in_place()
157
354
        branch.unlock()
158
355
        return SuccessfulSmartServerResponse(('ok',))
159
 
        
 
356