/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/smart/branch.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

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