/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
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
19
import sys
20
import tempfile
21
import tarfile
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
22
23
from bzrlib import errors
24
from bzrlib.bzrdir import BzrDir
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
25
from bzrlib.smart.request import (
26
    FailedSmartServerResponse,
27
    SmartServerRequest,
28
    SuccessfulSmartServerResponse,
29
    )
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
30
31
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
32
class SmartServerRepositoryRequest(SmartServerRequest):
33
    """Common base class for Repository requests."""
34
35
    def do(self, path, *args):
36
        """Execute a repository request.
37
        
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
38
        The repository must be at the exact path - no searching is done.
39
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
40
        The actual logic is delegated to self.do_repository_request.
41
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
42
        :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).
43
        :return: A smart server from self.do_repository_request().
44
        """
45
        transport = self._backing_transport.clone(path)
46
        bzrdir = BzrDir.open_from_transport(transport)
47
        repository = bzrdir.open_repository()
48
        return self.do_repository_request(repository, *args)
49
50
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
51
class SmartServerRepositoryGetRevisionGraph(SmartServerRepositoryRequest):
52
    
53
    def do_repository_request(self, repository, revision_id):
54
        """Return the result of repository.get_revision_graph(revision_id).
55
        
56
        :param repository: The repository to query in.
57
        :param revision_id: The utf8 encoded revision_id to get a graph from.
58
        :return: A smart server response where the body contains an utf8
59
            encoded flattened list of the revision graph.
60
        """
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
61
        if not revision_id:
62
            revision_id = None
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
63
64
        lines = []
65
        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.
66
            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)
67
        except errors.NoSuchRevision:
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
68
            # Note that we return an empty body, rather than omitting the body.
69
            # This way the client knows that it can always expect to find a body
70
            # 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.
71
            return FailedSmartServerResponse(('nosuchrevision', revision_id), '')
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
72
73
        for revision, parents in revision_graph.items():
74
            lines.append(' '.join([revision,] + parents))
75
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
76
        return SuccessfulSmartServerResponse(('ok', ), '\n'.join(lines))
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
77
78
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
79
class SmartServerRequestHasRevision(SmartServerRepositoryRequest):
80
81
    def do_repository_request(self, repository, revision_id):
82
        """Return ok if a specific revision is in the repository at path.
83
84
        :param repository: The repository to query in.
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
85
        :param revision_id: The utf8 encoded revision_id to lookup.
86
        :return: A smart server response of ('ok', ) if the revision is
87
            present.
88
        """
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
89
        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.
90
            return SuccessfulSmartServerResponse(('yes', ))
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
91
        else:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
92
            return SuccessfulSmartServerResponse(('no', ))
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
93
94
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
95
class SmartServerRepositoryGatherStats(SmartServerRepositoryRequest):
96
97
    def do_repository_request(self, repository, revid, committers):
98
        """Return the result of repository.gather_stats().
99
100
        :param repository: The repository to query in.
101
        :param revid: utf8 encoded rev id or an empty string to indicate None
102
        :param committers: 'yes' or 'no'.
103
104
        :return: A SmartServerResponse ('ok',), a encoded body looking like
105
              committers: 1
106
              firstrev: 1234.230 0
107
              latestrev: 345.700 3600
108
              revisions: 2
109
              size:45
110
111
              But containing only fields returned by the gather_stats() call
112
        """
113
        if revid == '':
114
            decoded_revision_id = None
115
        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.
116
            decoded_revision_id = revid
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
117
        if committers == 'yes':
118
            decoded_committers = True
119
        else:
120
            decoded_committers = None
121
        stats = repository.gather_stats(decoded_revision_id, decoded_committers)
122
123
        body = ''
124
        if stats.has_key('committers'):
125
            body += 'committers: %d\n' % stats['committers']
126
        if stats.has_key('firstrev'):
127
            body += 'firstrev: %.3f %d\n' % stats['firstrev']
128
        if stats.has_key('latestrev'):
129
             body += 'latestrev: %.3f %d\n' % stats['latestrev']
130
        if stats.has_key('revisions'):
131
            body += 'revisions: %d\n' % stats['revisions']
132
        if stats.has_key('size'):
133
            body += 'size: %d\n' % stats['size']
134
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
135
        return SuccessfulSmartServerResponse(('ok', ), body)
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
136
137
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
138
class SmartServerRepositoryIsShared(SmartServerRepositoryRequest):
139
140
    def do_repository_request(self, repository):
141
        """Return the result of repository.is_shared().
142
143
        :param repository: The repository to query in.
144
        :return: A smart server response of ('yes', ) if the repository is
145
            shared, and ('no', ) if it is not.
146
        """
147
        if repository.is_shared():
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
148
            return SuccessfulSmartServerResponse(('yes', ))
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
149
        else:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
150
            return SuccessfulSmartServerResponse(('no', ))
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
151
152
153
class SmartServerRepositoryLockWrite(SmartServerRepositoryRequest):
154
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
155
    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
156
        # XXX: this probably should not have a token.
157
        if token == '':
158
            token = None
159
        try:
160
            token = repository.lock_write(token=token)
161
        except errors.LockContention, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
162
            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.
163
        except errors.UnlockableTransport:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
164
            return FailedSmartServerResponse(('UnlockableTransport',))
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
165
        repository.leave_lock_in_place()
166
        repository.unlock()
167
        if token is None:
168
            token = ''
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
169
        return SuccessfulSmartServerResponse(('ok', token))
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
170
171
172
class SmartServerRepositoryUnlock(SmartServerRepositoryRequest):
173
174
    def do_repository_request(self, repository, token):
175
        try:
176
            repository.lock_write(token=token)
177
        except errors.TokenMismatch, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
178
            return FailedSmartServerResponse(('TokenMismatch',))
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
179
        repository.dont_leave_lock_in_place()
180
        repository.unlock()
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
181
        return SuccessfulSmartServerResponse(('ok',))
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
182
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
183
184
class SmartServerRepositoryTarball(SmartServerRepositoryRequest):
2018.18.11 by Martin Pool
merge hpss changes
185
    """Get the raw repository files as a tarball.
186
187
    The returned tarball contains a .bzr control directory which in turn
188
    contains a repository.
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
189
    
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
190
    This takes one parameter, compression, which currently must be 
191
    "", "gz", or "bz2".
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
192
193
    This is used to implement the Repository.copy_content_into operation.
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
194
    """
195
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
196
    def do_repository_request(self, repository, compression):
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
197
        from bzrlib import osutils
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
198
        repo_transport = repository.control_files._transport
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
199
        tmp_dirname, tmp_repo = self._copy_to_tempdir(repository)
2018.18.5 by Martin Pool
Repository.tarball locks repository while running for consistency
200
        try:
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
201
            controldir_name = tmp_dirname + '/.bzr'
202
            return self._tarfile_response(controldir_name, compression)
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
203
        finally:
204
            osutils.rmtree(tmp_dirname)
205
206
    def _copy_to_tempdir(self, from_repo):
207
        tmp_dirname = tempfile.mkdtemp(prefix='tmpbzrclone')
208
        tmp_bzrdir = from_repo.bzrdir._format.initialize(tmp_dirname)
209
        tmp_repo = from_repo._format.initialize(tmp_bzrdir)
210
        from_repo.copy_content_into(tmp_repo)
211
        return tmp_dirname, tmp_repo
212
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
213
    def _tarfile_response(self, tmp_dirname, compression):
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
214
        temp = tempfile.NamedTemporaryFile()
215
        try:
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
216
            self._tarball_of_dir(tmp_dirname, compression, temp.name)
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
217
            # all finished; write the tempfile out to the network
218
            temp.seek(0)
2420.2.2 by Andrew Bennetts
Merge tarball branch that's already with PQM, resolving conflicts.
219
            return SuccessfulSmartServerResponse(('ok',), temp.read())
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
220
            # FIXME: Don't read the whole thing into memory here; rather stream it
221
            # out from the file onto the network. mbp 20070411
2018.18.2 by Martin Pool
smart method Repository.tarball actually returns the tarball
222
        finally:
223
            temp.close()
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
224
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
225
    def _tarball_of_dir(self, dirname, compression, tarfile_name):
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
226
        tarball = tarfile.open(tarfile_name, mode='w:' + compression)
227
        try:
228
            # The tarball module only accepts ascii names, and (i guess)
229
            # packs them with their 8bit names.  We know all the files
230
            # within the repository have ASCII names so the should be safe
231
            # to pack in.
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
232
            dirname = dirname.encode(sys.getfilesystemencoding())
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
233
            # python's tarball module includes the whole path by default so
234
            # override it
2018.18.10 by Martin Pool
copy_content_into from Remote repositories by using temporary directories on both ends.
235
            assert dirname.endswith('.bzr')
236
            tarball.add(dirname, '.bzr') # recursive by default
2018.18.9 by Martin Pool
remote Repository.tarball builds a temporary directory and tars that
237
        finally:
238
            tarball.close()