/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
1
# Copyright (C) 2006, 2007 Canonical Ltd
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Server-side repository related request implmentations."""
18
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
19
from cStringIO import StringIO
2571.2.2 by Ian Clatworthy
use basename as poolie recommended
20
import os
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
21
import sys
22
import tempfile
23
import tarfile
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
24
25
from bzrlib import errors
26
from bzrlib.bzrdir import BzrDir
2535.4.30 by Andrew Bennetts
Use ContainerSerialiser rather than ContainerWriter in bzrlib/smart/repository.py.
27
from bzrlib.pack import ContainerSerialiser
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
28
from bzrlib.smart.request import (
29
    FailedSmartServerResponse,
30
    SmartServerRequest,
31
    SuccessfulSmartServerResponse,
32
    )
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
33
from bzrlib import revision as _mod_revision
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
34
35
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
36
class SmartServerRepositoryRequest(SmartServerRequest):
37
    """Common base class for Repository requests."""
38
39
    def do(self, path, *args):
40
        """Execute a repository request.
41
        
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
42
        The repository must be at the exact path - no searching is done.
43
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
44
        The actual logic is delegated to self.do_repository_request.
45
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
46
        :param path: The path for the repository.
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
47
        :return: A smart server from self.do_repository_request().
48
        """
49
        transport = self._backing_transport.clone(path)
50
        bzrdir = BzrDir.open_from_transport(transport)
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
51
        # Save the repository for use with do_body.
52
        self._repository = bzrdir.open_repository()
53
        return self.do_repository_request(self._repository, *args)
54
55
    def do_repository_request(self, repository, *args):
56
        """Override to provide an implementation for a verb."""
57
        # No-op for verbs that take bodies (None as a result indicates a body
58
        # is expected)
59
        return None
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
60
61
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
62
class SmartServerRepositoryGetParentMap(SmartServerRepositoryRequest):
63
    
64
    def do_repository_request(self, repository, *revision_ids):
65
        repository.lock_read()
66
        try:
67
            return self._do_repository_request(repository, revision_ids)
68
        finally:
69
            repository.unlock()
70
71
    def _do_repository_request(self, repository, revision_ids):
72
        """Get parent details for some revisions.
73
        
74
        All the parents for revision_ids are returned. Additionally up to 64KB
75
        of additional parent data found by performing a breadth first search
76
        from revision_ids is returned.
77
78
        :param repository: The repository to query in.
3172.5.8 by Robert Collins
Review feedback.
79
        :param revision_ids: The utf8 encoded revision_id to answer for.
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
80
        :return: A smart server response where the body contains an utf8
3172.5.8 by Robert Collins
Review feedback.
81
            encoded flattened list of the parents of the revisions, (the same
82
            format as Repository.get_revision_graph).
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
83
        """
84
        lines = []
85
        repo_graph = repository.get_graph()
86
        result = {}
87
        queried_revs = set()
88
        size_so_far = 0
89
        next_revs = revision_ids
90
        first_loop_done = False
91
        while next_revs:
92
            queried_revs.update(next_revs)
93
            parent_map = repo_graph.get_parent_map(next_revs)
94
            next_revs = set()
95
            for revision_id, parents in parent_map.iteritems():
96
                # adjust for the wire
97
                if parents == (_mod_revision.NULL_REVISION,):
98
                    parents = ()
99
                # add parents to the result
100
                result[revision_id] = parents
101
                # prepare the next query
102
                next_revs.update(parents)
3172.5.8 by Robert Collins
Review feedback.
103
                # Approximate the serialized cost of this revision_id.
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
104
                size_so_far += 2 + len(revision_id) + sum(map(len, parents))
105
                # get all the directly asked for parents, and then flesh out to
106
                # 64K or so.
107
                if first_loop_done and size_so_far > 65000:
108
                    next_revs = set()
109
                    break
110
            # don't query things we've already queried
111
            next_revs.difference_update(queried_revs)
112
            first_loop_done = True
113
114
        for revision, parents in result.items():
115
            lines.append(' '.join((revision, ) + tuple(parents)))
116
117
        return SuccessfulSmartServerResponse(('ok', ), '\n'.join(lines))
118
119
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
120
class SmartServerRepositoryGetRevisionGraph(SmartServerRepositoryRequest):
121
    
122
    def do_repository_request(self, repository, revision_id):
123
        """Return the result of repository.get_revision_graph(revision_id).
124
        
125
        :param repository: The repository to query in.
126
        :param revision_id: The utf8 encoded revision_id to get a graph from.
127
        :return: A smart server response where the body contains an utf8
128
            encoded flattened list of the revision graph.
129
        """
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
130
        if not revision_id:
131
            revision_id = None
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
132
133
        lines = []
134
        try:
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
135
            revision_graph = repository.get_revision_graph(revision_id)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
136
        except errors.NoSuchRevision:
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
137
            # Note that we return an empty body, rather than omitting the body.
138
            # This way the client knows that it can always expect to find a body
139
            # in the response for this method, even in the error case.
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
140
            return FailedSmartServerResponse(('nosuchrevision', revision_id), '')
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
141
142
        for revision, parents in revision_graph.items():
2592.3.50 by Robert Collins
Merge bzr.dev.
143
            lines.append(' '.join((revision, ) + tuple(parents)))
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
144
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
145
        return SuccessfulSmartServerResponse(('ok', ), '\n'.join(lines))
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
146
147
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
148
class SmartServerRequestHasRevision(SmartServerRepositoryRequest):
149
150
    def do_repository_request(self, repository, revision_id):
151
        """Return ok if a specific revision is in the repository at path.
152
153
        :param repository: The repository to query in.
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
154
        :param revision_id: The utf8 encoded revision_id to lookup.
155
        :return: A smart server response of ('ok', ) if the revision is
156
            present.
157
        """
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
158
        if repository.has_revision(revision_id):
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
159
            return SuccessfulSmartServerResponse(('yes', ))
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
160
        else:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
161
            return SuccessfulSmartServerResponse(('no', ))
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
162
163
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
164
class SmartServerRepositoryGatherStats(SmartServerRepositoryRequest):
165
166
    def do_repository_request(self, repository, revid, committers):
167
        """Return the result of repository.gather_stats().
168
169
        :param repository: The repository to query in.
170
        :param revid: utf8 encoded rev id or an empty string to indicate None
171
        :param committers: 'yes' or 'no'.
172
173
        :return: A SmartServerResponse ('ok',), a encoded body looking like
174
              committers: 1
175
              firstrev: 1234.230 0
176
              latestrev: 345.700 3600
177
              revisions: 2
178
              size:45
179
180
              But containing only fields returned by the gather_stats() call
181
        """
182
        if revid == '':
183
            decoded_revision_id = None
184
        else:
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
185
            decoded_revision_id = revid
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
186
        if committers == 'yes':
187
            decoded_committers = True
188
        else:
189
            decoded_committers = None
190
        stats = repository.gather_stats(decoded_revision_id, decoded_committers)
191
192
        body = ''
193
        if stats.has_key('committers'):
194
            body += 'committers: %d\n' % stats['committers']
195
        if stats.has_key('firstrev'):
196
            body += 'firstrev: %.3f %d\n' % stats['firstrev']
197
        if stats.has_key('latestrev'):
198
             body += 'latestrev: %.3f %d\n' % stats['latestrev']
199
        if stats.has_key('revisions'):
200
            body += 'revisions: %d\n' % stats['revisions']
201
        if stats.has_key('size'):
202
            body += 'size: %d\n' % stats['size']
203
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
204
        return SuccessfulSmartServerResponse(('ok', ), body)
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
205
206
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
207
class SmartServerRepositoryIsShared(SmartServerRepositoryRequest):
208
209
    def do_repository_request(self, repository):
210
        """Return the result of repository.is_shared().
211
212
        :param repository: The repository to query in.
213
        :return: A smart server response of ('yes', ) if the repository is
214
            shared, and ('no', ) if it is not.
215
        """
216
        if repository.is_shared():
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
217
            return SuccessfulSmartServerResponse(('yes', ))
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
218
        else:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
219
            return SuccessfulSmartServerResponse(('no', ))
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
220
221
222
class SmartServerRepositoryLockWrite(SmartServerRepositoryRequest):
223
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
224
    def do_repository_request(self, repository, token=''):
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
225
        # XXX: this probably should not have a token.
226
        if token == '':
227
            token = None
228
        try:
229
            token = repository.lock_write(token=token)
230
        except errors.LockContention, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
231
            return FailedSmartServerResponse(('LockContention',))
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
232
        except errors.UnlockableTransport:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
233
            return FailedSmartServerResponse(('UnlockableTransport',))
2872.5.3 by Martin Pool
Pass back LockFailed from smart server lock methods
234
        except errors.LockFailed, e:
235
            return FailedSmartServerResponse(('LockFailed',
236
                str(e.lock), str(e.why)))
3015.2.7 by Robert Collins
In the RemoteServer repository methods handle repositories that cannot be remotely locked like pack repositories, and add a read lock in SmartServerRepositoryStreamKnitDataForRevisions.
237
        if token is not None:
238
            repository.leave_lock_in_place()
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
239
        repository.unlock()
240
        if token is None:
241
            token = ''
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
242
        return SuccessfulSmartServerResponse(('ok', token))
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
243
244
245
class SmartServerRepositoryUnlock(SmartServerRepositoryRequest):
246
247
    def do_repository_request(self, repository, token):
248
        try:
249
            repository.lock_write(token=token)
250
        except errors.TokenMismatch, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
251
            return FailedSmartServerResponse(('TokenMismatch',))
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
252
        repository.dont_leave_lock_in_place()
253
        repository.unlock()
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
254
        return SuccessfulSmartServerResponse(('ok',))
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
255
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
256
257
class SmartServerRepositoryTarball(SmartServerRepositoryRequest):
2018.18.11 by Martin Pool
merge hpss changes
258
    """Get the raw repository files as a tarball.
259
260
    The returned tarball contains a .bzr control directory which in turn
261
    contains a repository.
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
262
    
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
263
    This takes one parameter, compression, which currently must be 
264
    "", "gz", or "bz2".
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
265
266
    This is used to implement the Repository.copy_content_into operation.
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
267
    """
268
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
269
    def do_repository_request(self, repository, compression):
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
270
        from bzrlib import osutils
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
271
        repo_transport = repository.control_files._transport
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
272
        tmp_dirname, tmp_repo = self._copy_to_tempdir(repository)
2018.18.5 by Martin Pool
Repository.tarball locks repository while running for consistency
273
        try:
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
274
            controldir_name = tmp_dirname + '/.bzr'
275
            return self._tarfile_response(controldir_name, compression)
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
276
        finally:
277
            osutils.rmtree(tmp_dirname)
278
279
    def _copy_to_tempdir(self, from_repo):
280
        tmp_dirname = tempfile.mkdtemp(prefix='tmpbzrclone')
281
        tmp_bzrdir = from_repo.bzrdir._format.initialize(tmp_dirname)
282
        tmp_repo = from_repo._format.initialize(tmp_bzrdir)
283
        from_repo.copy_content_into(tmp_repo)
284
        return tmp_dirname, tmp_repo
285
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
286
    def _tarfile_response(self, tmp_dirname, compression):
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
287
        temp = tempfile.NamedTemporaryFile()
288
        try:
2557.1.1 by Martin Pool
[BUG 119330] Fix tempfile permissions error in smart server tar bundling (under windows) (Martin_)
289
            self._tarball_of_dir(tmp_dirname, compression, temp.file)
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
290
            # all finished; write the tempfile out to the network
291
            temp.seek(0)
2420.2.2 by Andrew Bennetts
Merge tarball branch that's already with PQM, resolving conflicts.
292
            return SuccessfulSmartServerResponse(('ok',), temp.read())
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
293
            # FIXME: Don't read the whole thing into memory here; rather stream it
294
            # out from the file onto the network. mbp 20070411
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
295
        finally:
296
            temp.close()
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
297
2557.1.1 by Martin Pool
[BUG 119330] Fix tempfile permissions error in smart server tar bundling (under windows) (Martin_)
298
    def _tarball_of_dir(self, dirname, compression, ofile):
2571.2.2 by Ian Clatworthy
use basename as poolie recommended
299
        filename = os.path.basename(ofile.name)
300
        tarball = tarfile.open(fileobj=ofile, name=filename,
2571.2.1 by Ian Clatworthy
fix #123485 - selftest broken under Python 2.5.1 because of tafile API change
301
            mode='w|' + compression)
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
302
        try:
303
            # The tarball module only accepts ascii names, and (i guess)
304
            # packs them with their 8bit names.  We know all the files
305
            # within the repository have ASCII names so the should be safe
306
            # to pack in.
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
307
            dirname = dirname.encode(sys.getfilesystemencoding())
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
308
            # python's tarball module includes the whole path by default so
309
            # override it
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
310
            assert dirname.endswith('.bzr')
311
            tarball.add(dirname, '.bzr') # recursive by default
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
312
        finally:
313
            tarball.close()
2535.3.12 by Andrew Bennetts
Add a first cut of a get_data_stream method to Repository.
314
315
2535.3.49 by Andrew Bennetts
Rename 'Repository.fetch_revisions' smart request to 'Repository.stream_knit_data_for_revisions'.
316
class SmartServerRepositoryStreamKnitDataForRevisions(SmartServerRepositoryRequest):
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
317
    """Bzr <= 1.1 streaming pull, buffers all data on server."""
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
318
319
    def do_repository_request(self, repository, *revision_ids):
3015.2.7 by Robert Collins
In the RemoteServer repository methods handle repositories that cannot be remotely locked like pack repositories, and add a read lock in SmartServerRepositoryStreamKnitDataForRevisions.
320
        repository.lock_read()
321
        try:
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
322
            return self._do_repository_request(repository, revision_ids)
323
        finally:
324
            repository.unlock()
325
326
    def _do_repository_request(self, repository, revision_ids):
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
327
        stream = repository.get_data_stream_for_search(
328
            repository.revision_ids_to_search_result(set(revision_ids)))
2535.4.30 by Andrew Bennetts
Use ContainerSerialiser rather than ContainerWriter in bzrlib/smart/repository.py.
329
        buffer = StringIO()
330
        pack = ContainerSerialiser()
331
        buffer.write(pack.begin())
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
332
        try:
333
            for name_tuple, bytes in stream:
2535.4.30 by Andrew Bennetts
Use ContainerSerialiser rather than ContainerWriter in bzrlib/smart/repository.py.
334
                buffer.write(pack.bytes_record(bytes, [name_tuple]))
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
335
        except errors.RevisionNotPresent, e:
336
            return FailedSmartServerResponse(('NoSuchRevision', e.revision_id))
2535.4.30 by Andrew Bennetts
Use ContainerSerialiser rather than ContainerWriter in bzrlib/smart/repository.py.
337
        buffer.write(pack.end())
338
        return SuccessfulSmartServerResponse(('ok',), buffer.getvalue())
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
339
340
341
class SmartServerRepositoryStreamRevisionsChunked(SmartServerRepositoryRequest):
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
342
    """Bzr 1.1+ streaming pull."""
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
343
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
344
    def do_body(self, body_bytes):
345
        lines = body_bytes.split('\n')
346
        start_keys = set(lines[0].split(' '))
347
        exclude_keys = set(lines[1].split(' '))
348
        revision_count = int(lines[2])
349
        repository = self._repository
2535.4.29 by Andrew Bennetts
Add a new smart method, Repository.stream_revisions_chunked, rather than changing the behaviour of an existing method.
350
        repository.lock_read()
351
        try:
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
352
            search = repository.get_graph()._make_breadth_first_searcher(
353
                start_keys)
354
            while True:
355
                try:
356
                    next_revs = search.next()
357
                except StopIteration:
358
                    break
359
                search.stop_searching_any(exclude_keys.intersection(next_revs))
360
            search_result = search.get_result()
361
            if search_result.get_recipe()[2] != revision_count:
362
                # we got back a different amount of data than expected, this
363
                # gets reported as NoSuchRevision, because less revisions
364
                # indicates missing revisions, and more should never happen as
365
                # the excludes list considers ghosts and ensures that ghost
366
                # filling races are not a problem.
367
                return FailedSmartServerResponse(('NoSuchRevision',))
368
            stream = repository.get_data_stream_for_search(search_result)
2535.4.26 by Andrew Bennetts
Fix locking problem that was hanging the tests.
369
        except Exception:
3015.2.7 by Robert Collins
In the RemoteServer repository methods handle repositories that cannot be remotely locked like pack repositories, and add a read lock in SmartServerRepositoryStreamKnitDataForRevisions.
370
            repository.unlock()
2535.4.26 by Andrew Bennetts
Fix locking problem that was hanging the tests.
371
            raise
2535.4.2 by Andrew Bennetts
Nasty hackery to make stream_knit_data_for_revisions response use streaming.
372
        return SuccessfulSmartServerResponse(('ok',),
2535.4.26 by Andrew Bennetts
Fix locking problem that was hanging the tests.
373
            body_stream=self.body_stream(stream, repository))
2535.4.2 by Andrew Bennetts
Nasty hackery to make stream_knit_data_for_revisions response use streaming.
374
2535.4.26 by Andrew Bennetts
Fix locking problem that was hanging the tests.
375
    def body_stream(self, stream, repository):
2535.4.18 by Andrew Bennetts
Use pack.ContainerSerialiser to remove some nasty cruft.
376
        pack = ContainerSerialiser()
377
        yield pack.begin()
2535.3.40 by Andrew Bennetts
Tidy up more XXXs.
378
        try:
2535.3.50 by Andrew Bennetts
Use tuple names in data streams rather than concatenated strings.
379
            for name_tuple, bytes in stream:
2535.4.18 by Andrew Bennetts
Use pack.ContainerSerialiser to remove some nasty cruft.
380
                yield pack.bytes_record(bytes, [name_tuple])
2535.3.40 by Andrew Bennetts
Tidy up more XXXs.
381
        except errors.RevisionNotPresent, e:
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
382
            # This shouldn't be able to happen, but as we don't buffer
383
            # everything it can in theory happen.
2535.4.5 by Andrew Bennetts
Merge latest chunking protocol, including support for errors, fixing a test failure.
384
            yield FailedSmartServerResponse(('NoSuchRevision', e.revision_id))
2535.4.26 by Andrew Bennetts
Fix locking problem that was hanging the tests.
385
        repository.unlock()
2535.3.14 by Andrew Bennetts
Move serialising repo data stream to bytes into smart protocol.
386
        pack.end()
2535.3.15 by Andrew Bennetts
Add KnitVersionedFile.get_stream_as_bytes, start smart implementation of RemoteRepository.get_data_stream.
387