/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
1
# Copyright (C) 2006, 2007 Canonical Ltd
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
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
1752.2.39 by Martin Pool
[broken] implement upgrade apis on remote bzrdirs
17
# TODO: At some point, handle upgrades by just passing the whole request
18
# across to run on the server.
19
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
20
from cStringIO import StringIO
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
21
from urlparse import urlparse
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
22
2018.5.25 by Andrew Bennetts
Make sure RemoteBzrDirFormat is always registered (John Arbash Meinel, Robert Collins, Andrew Bennetts).
23
from bzrlib import branch, errors, repository
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
24
from bzrlib.branch import BranchReferenceFormat
2018.5.25 by Andrew Bennetts
Make sure RemoteBzrDirFormat is always registered (John Arbash Meinel, Robert Collins, Andrew Bennetts).
25
from bzrlib.bzrdir import BzrDir, BzrDirFormat, RemoteBzrDirFormat
2018.14.2 by Andrew Bennetts
All but one repository_implementation tests for RemoteRepository passing.
26
from bzrlib.config import BranchConfig, TreeConfig
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
27
from bzrlib.decorators import needs_read_lock, needs_write_lock
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
28
from bzrlib.errors import NoSuchRevision
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
29
from bzrlib.revision import NULL_REVISION
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
30
from bzrlib.smart import client, vfs
2018.5.32 by Robert Collins
Unescape urls before handing over the wire to the smart server for the probe_transport method.
31
from bzrlib.urlutils import unescape
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
32
2018.5.25 by Andrew Bennetts
Make sure RemoteBzrDirFormat is always registered (John Arbash Meinel, Robert Collins, Andrew Bennetts).
33
# Note: RemoteBzrDirFormat is in bzrdir.py
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
34
35
class RemoteBzrDir(BzrDir):
36
    """Control directory on a remote server, accessed by HPSS."""
37
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
38
    def __init__(self, transport, _client=None):
39
        """Construct a RemoteBzrDir.
40
41
        :param _client: Private parameter for testing. Disables probing and the
42
            use of a real bzrdir.
43
        """
1752.2.39 by Martin Pool
[broken] implement upgrade apis on remote bzrdirs
44
        BzrDir.__init__(self, transport, RemoteBzrDirFormat())
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
45
        # this object holds a delegated bzrdir that uses file-level operations
46
        # to talk to the other side
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
47
        # XXX: We should go into find_format, but not allow it to find
48
        # RemoteBzrDirFormat and make sure it finds the real underlying format.
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
49
        self._real_bzrdir = None
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
50
51
        if _client is None:
52
            self._medium = transport.get_smart_client()
53
            self._client = client.SmartClient(self._medium)
54
        else:
55
            self._client = _client
56
            self._medium = None
57
            return
58
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
59
        self._ensure_real()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
60
        path = self._path_for_remote_call(self._client)
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
61
        #self._real_bzrdir._format.probe_transport(transport)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
62
        response = self._client.call('probe_dont_use', path)
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
63
        if response == ('no',):
64
            raise errors.NotBranchError(path=transport.base)
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
65
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
66
    def _ensure_real(self):
67
        """Ensure that there is a _real_bzrdir set.
68
69
        used before calls to self._real_bzrdir.
70
        """
71
        if not self._real_bzrdir:
72
            default_format = BzrDirFormat.get_default_format()
73
            self._real_bzrdir = default_format.open(self.root_transport,
74
                _found=True)
75
1752.2.39 by Martin Pool
[broken] implement upgrade apis on remote bzrdirs
76
    def create_repository(self, shared=False):
1752.2.72 by Andrew Bennetts
Make Remote* classes in remote.py more consistent and remove some dead code.
77
        return RemoteRepository(
78
            self, self._real_bzrdir.create_repository(shared=shared))
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
79
80
    def create_branch(self):
1752.2.72 by Andrew Bennetts
Make Remote* classes in remote.py more consistent and remove some dead code.
81
        real_branch = self._real_bzrdir.create_branch()
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
82
        return RemoteBranch(self, self.find_repository(), real_branch)
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
83
84
    def create_workingtree(self, revision_id=None):
1752.2.72 by Andrew Bennetts
Make Remote* classes in remote.py more consistent and remove some dead code.
85
        real_workingtree = self._real_bzrdir.create_workingtree(revision_id=revision_id)
86
        return RemoteWorkingTree(self, real_workingtree)
1752.2.39 by Martin Pool
[broken] implement upgrade apis on remote bzrdirs
87
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
88
    def open_branch(self, _unsupported=False):
89
        assert _unsupported == False, 'unsupported flag support not implemented yet.'
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
90
        path = self._path_for_remote_call(self._client)
91
        response = self._client.call('BzrDir.open_branch', path)
92
        if response[0] == 'ok':
93
            if response[1] == '':
94
                # branch at this location.
95
                return RemoteBranch(self, self.find_repository())
96
            else:
97
                # a branch reference, use the existing BranchReference logic.
98
                format = BranchReferenceFormat()
99
                return format.open(self, _found=True, location=response[1])
100
        elif response == ('nobranch',):
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
101
            raise errors.NotBranchError(path=self.root_transport.base)
102
        else:
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
103
            assert False, 'unexpected response code %r' % (response,)
104
                
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
105
    def open_repository(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
106
        path = self._path_for_remote_call(self._client)
107
        response = self._client.call('BzrDir.find_repository', path)
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
108
        assert response[0] in ('ok', 'norepository'), \
2018.5.52 by Wouter van Heyst
Provide more information when encountering unexpected responses from a smart
109
            'unexpected response code %s' % (response,)
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
110
        if response[0] == 'norepository':
111
            raise errors.NoRepositoryPresent(self)
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
112
        if response[1] == '':
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
113
            return RemoteRepository(self)
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
114
        else:
115
            raise errors.NoRepositoryPresent(self)
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
116
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
117
    def open_workingtree(self):
1752.2.72 by Andrew Bennetts
Make Remote* classes in remote.py more consistent and remove some dead code.
118
        return RemoteWorkingTree(self, self._real_bzrdir.open_workingtree())
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
119
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
120
    def _path_for_remote_call(self, client):
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
121
        """Return the path to be used for this bzrdir in a remote call."""
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
122
        return client.remote_path_from_transport(self.root_transport)
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
123
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
124
    def get_branch_transport(self, branch_format):
125
        return self._real_bzrdir.get_branch_transport(branch_format)
126
1752.2.43 by Andrew Bennetts
Fix get_{branch,repository,workingtree}_transport.
127
    def get_repository_transport(self, repository_format):
128
        return self._real_bzrdir.get_repository_transport(repository_format)
129
130
    def get_workingtree_transport(self, workingtree_format):
131
        return self._real_bzrdir.get_workingtree_transport(workingtree_format)
132
1752.2.39 by Martin Pool
[broken] implement upgrade apis on remote bzrdirs
133
    def can_convert_format(self):
134
        """Upgrading of remote bzrdirs is not supported yet."""
135
        return False
136
137
    def needs_format_conversion(self, format=None):
138
        """Upgrading of remote bzrdirs is not supported yet."""
139
        return False
140
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
141
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
142
class RemoteRepositoryFormat(repository.RepositoryFormat):
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
143
    """Format for repositories accessed over rpc.
144
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
145
    Instances of this repository are represented by RemoteRepository
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
146
    instances.
147
    """
148
149
    _matchingbzrdir = RemoteBzrDirFormat
150
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
151
    def initialize(self, a_bzrdir, shared=False):
1752.2.72 by Andrew Bennetts
Make Remote* classes in remote.py more consistent and remove some dead code.
152
        assert isinstance(a_bzrdir, RemoteBzrDir)
153
        return a_bzrdir.create_repository(shared=shared)
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
154
    
155
    def open(self, a_bzrdir):
1752.2.72 by Andrew Bennetts
Make Remote* classes in remote.py more consistent and remove some dead code.
156
        assert isinstance(a_bzrdir, RemoteBzrDir)
157
        return a_bzrdir.open_repository()
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
158
159
    def get_format_description(self):
160
        return 'bzr remote repository'
161
162
    def __eq__(self, other):
1752.2.87 by Andrew Bennetts
Make tests pass.
163
        return self.__class__ == other.__class__
164
165
    rich_root_data = False
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
166
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
167
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
168
class RemoteRepository(object):
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
169
    """Repository accessed over rpc.
170
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
171
    For the moment everything is delegated to IO-like operations over
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
172
    the transport.
173
    """
174
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
175
    def __init__(self, remote_bzrdir, real_repository=None, _client=None):
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
176
        """Create a RemoteRepository instance.
177
        
178
        :param remote_bzrdir: The bzrdir hosting this repository.
179
        :param real_repository: If not None, a local implementation of the
180
            repository logic for the repository, usually accessing the data
181
            via the VFS.
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
182
        :param _client: Private testing parameter - override the smart client
183
            to be used by the repository.
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
184
        """
185
        if real_repository:
2018.5.36 by Andrew Bennetts
Fix typo, and clean up some ununsed import warnings from pyflakes at the same time.
186
            self._real_repository = real_repository
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
187
        else:
188
            self._real_repository = None
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
189
        self.bzrdir = remote_bzrdir
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
190
        if _client is None:
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
191
            self._client = client.SmartClient(self.bzrdir._medium)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
192
        else:
193
            self._client = _client
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
194
        self._format = RemoteRepositoryFormat()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
195
        self._lock_mode = None
196
        self._lock_token = None
197
        self._lock_count = 0
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
198
        self._leave_lock = False
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
199
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
200
    def _ensure_real(self):
201
        """Ensure that there is a _real_repository set.
202
203
        used before calls to self._real_repository.
204
        """
205
        if not self._real_repository:
206
            self.bzrdir._ensure_real()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
207
            #self._real_repository = self.bzrdir._real_bzrdir.open_repository()
208
            self._set_real_repository(self.bzrdir._real_bzrdir.open_repository())
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
209
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
210
    def get_revision_graph(self, revision_id=None):
211
        """See Repository.get_revision_graph()."""
212
        if revision_id is None:
213
            revision_id = ''
214
        elif revision_id == NULL_REVISION:
215
            return {}
216
217
        path = self.bzrdir._path_for_remote_call(self._client)
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
218
        assert type(revision_id) is str
219
        response = self._client.call2(
220
            'Repository.get_revision_graph', path, revision_id)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
221
        assert response[0][0] in ('ok', 'nosuchrevision'), 'unexpected response code %s' % (response[0],)
222
        if response[0][0] == 'ok':
223
            coded = response[1].read_body_bytes()
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
224
            lines = coded.split('\n')
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
225
            revision_graph = {}
226
            # FIXME
227
            for line in lines:
228
                d = list(line.split())
229
                revision_graph[d[0]] = d[1:]
230
                
231
            return revision_graph
232
        else:
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
233
            response_body = response[1].read_body_bytes()
234
            assert response_body == ''
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
235
            raise NoSuchRevision(self, revision_id)
236
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
237
    def has_revision(self, revision_id):
238
        """See Repository.has_revision()."""
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
239
        if revision_id is None:
240
            # The null revision is always present.
241
            return True
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
242
        path = self.bzrdir._path_for_remote_call(self._client)
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
243
        response = self._client.call('Repository.has_revision', path, revision_id)
2018.5.52 by Wouter van Heyst
Provide more information when encountering unexpected responses from a smart
244
        assert response[0] in ('ok', 'no'), 'unexpected response code %s' % (response,)
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
245
        return response[0] == 'ok'
246
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
247
    def gather_stats(self, revid=None, committers=None):
2018.5.62 by Robert Collins
Stub out RemoteRepository.gather_stats while its implemented in parallel.
248
        """See Repository.gather_stats()."""
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
249
        path = self.bzrdir._path_for_remote_call(self._client)
250
        if revid in (None, NULL_REVISION):
251
            fmt_revid = ''
252
        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.
253
            fmt_revid = revid
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
254
        if committers is None or not committers:
2018.10.3 by v.ladeuil+lp at free
more tests for gather_stats
255
            fmt_committers = 'no'
256
        else:
257
            fmt_committers = 'yes'
258
        response = self._client.call2('Repository.gather_stats', path,
259
                                      fmt_revid, fmt_committers)
260
        assert response[0][0] == 'ok', \
261
            'unexpected response code %s' % (response[0],)
262
263
        body = response[1].read_body_bytes()
264
        result = {}
265
        for line in body.split('\n'):
266
            if not line:
267
                continue
268
            key, val_text = line.split(':')
269
            if key in ('revisions', 'size', 'committers'):
270
                result[key] = int(val_text)
271
            elif key in ('firstrev', 'latestrev'):
272
                values = val_text.split(' ')[1:]
273
                result[key] = (float(values[0]), long(values[1]))
274
275
        return result
2018.5.62 by Robert Collins
Stub out RemoteRepository.gather_stats while its implemented in parallel.
276
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
277
    def get_physical_lock_status(self):
278
        """See Repository.get_physical_lock_status()."""
279
        return False
280
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
281
    def is_shared(self):
282
        """See Repository.is_shared()."""
283
        path = self.bzrdir._path_for_remote_call(self._client)
284
        response = self._client.call('Repository.is_shared', path)
285
        assert response[0] in ('yes', 'no'), 'unexpected response code %s' % (response,)
286
        return response[0] == 'yes'
287
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
288
    def lock_read(self):
289
        # wrong eventually - want a local lock cache context
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
290
        if not self._lock_mode:
291
            self._lock_mode = 'r'
292
            self._lock_count = 1
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
293
            if self._real_repository is not None:
294
                self._real_repository.lock_read()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
295
        else:
296
            self._lock_count += 1
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
297
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
298
    def _remote_lock_write(self, token):
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
299
        path = self.bzrdir._path_for_remote_call(self._client)
300
        if token is None:
301
            token = ''
302
        response = self._client.call('Repository.lock_write', path, token)
303
        if response[0] == 'ok':
304
            ok, token = response
305
            return token
306
        elif response[0] == 'LockContention':
307
            raise errors.LockContention('(remote lock)')
308
        else:
309
            assert False, 'unexpected response code %s' % (response,)
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
310
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
311
    def lock_write(self, token=None):
312
        if not self._lock_mode:
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
313
            self._lock_token = self._remote_lock_write(token)
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
314
            assert self._lock_token, 'Remote server did not return a token!'
315
            if self._real_repository is not None:
316
                self._real_repository.lock_write(token=self._lock_token)
317
            if token is not None:
318
                self._leave_lock = True
319
            else:
320
                self._leave_lock = False
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
321
            self._lock_mode = 'w'
322
            self._lock_count = 1
323
        elif self._lock_mode == 'r':
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
324
            raise errors.ReadOnlyError(self)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
325
        else:
326
            self._lock_count += 1
327
        return self._lock_token
328
329
    def leave_lock_in_place(self):
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
330
        self._leave_lock = True
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
331
332
    def dont_leave_lock_in_place(self):
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
333
        self._leave_lock = False
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
334
335
    def _set_real_repository(self, repository):
336
        """Set the _real_repository for this repository.
337
338
        :param repository: The repository to fallback to for non-hpss
339
            implemented operations.
340
        """
341
        self._real_repository = repository
342
        if self._lock_mode == 'w':
343
            # if we are already locked, the real repository must be able to
344
            # acquire the lock with our token.
345
            self._real_repository.lock_write(self._lock_token)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
346
        elif self._lock_mode == 'r':
347
            self._real_repository.lock_read()
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
348
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
349
    def _unlock(self, token):
350
        path = self.bzrdir._path_for_remote_call(self._client)
351
        response = self._client.call('Repository.unlock', path, token)
352
        if response == ('ok',):
353
            return
354
        elif response[0] == 'TokenMismatch':
355
            raise errors.TokenMismatch(token, '(remote token)')
356
        else:
357
            assert False, 'unexpected response code %s' % (response,)
358
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
359
    def unlock(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
360
        self._lock_count -= 1
361
        if not self._lock_count:
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
362
            mode = self._lock_mode
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
363
            self._lock_mode = None
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
364
            if self._real_repository is not None:
365
                self._real_repository.unlock()
366
            if mode != 'w':
367
                return
368
            assert self._lock_token, 'Locked, but no token!'
369
            token = self._lock_token
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
370
            self._lock_token = None
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
371
            if not self._leave_lock:
372
                self._unlock(token)
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
373
374
    def break_lock(self):
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
375
        # should hand off to the network
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
376
        self._ensure_real()
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
377
        return self._real_repository.break_lock()
378
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
379
    ### These methods are just thin shims to the VFS object for now.
380
381
    def revision_tree(self, revision_id):
382
        self._ensure_real()
383
        return self._real_repository.revision_tree(revision_id)
384
385
    def get_commit_builder(self, branch, parents, config, timestamp=None,
386
                           timezone=None, committer=None, revprops=None,
387
                           revision_id=None):
388
        # FIXME: It ought to be possible to call this without immediately
389
        # triggering _ensure_real.  For now it's the easiest thing to do.
390
        self._ensure_real()
391
        builder = self._real_repository.get_commit_builder(branch, parents,
392
                config, timestamp=timestamp, timezone=timezone,
393
                committer=committer, revprops=revprops, revision_id=revision_id)
394
        # Make the builder use this RemoteRepository rather than the real one.
395
        builder.repository = self
396
        return builder
397
398
    @needs_write_lock
399
    def add_inventory(self, revid, inv, parents):
400
        self._ensure_real()
401
        return self._real_repository.add_inventory(revid, inv, parents)
402
403
    @needs_write_lock
404
    def add_revision(self, rev_id, rev, inv=None, config=None):
405
        self._ensure_real()
406
        return self._real_repository.add_revision(
407
            rev_id, rev, inv=inv, config=config)
408
409
    @needs_read_lock
410
    def get_inventory(self, revision_id):
411
        self._ensure_real()
412
        return self._real_repository.get_inventory(revision_id)
413
414
    @needs_read_lock
415
    def get_revision(self, revision_id):
416
        self._ensure_real()
417
        return self._real_repository.get_revision(revision_id)
418
419
    @property
420
    def weave_store(self):
421
        self._ensure_real()
422
        return self._real_repository.weave_store
423
424
    def get_transaction(self):
425
        self._ensure_real()
426
        return self._real_repository.get_transaction()
427
428
    @needs_read_lock
429
    def clone(self, a_bzrdir, revision_id=None, basis=None):
430
        self._ensure_real()
431
        return self._real_repository.clone(
432
            a_bzrdir, revision_id=revision_id, basis=basis)
433
434
    def make_working_trees(self):
435
        return False
436
437
    def fetch(self, source, revision_id=None, pb=None):
438
        self._ensure_real()
439
        return self._real_repository.fetch(
440
            source, revision_id=revision_id, pb=pb)
441
442
    @property
443
    def control_weaves(self):
444
        self._ensure_real()
445
        return self._real_repository.control_weaves
446
447
    @needs_read_lock
448
    def get_ancestry(self, revision_id):
449
        self._ensure_real()
450
        return self._real_repository.get_ancestry(revision_id)
451
452
    @needs_read_lock
453
    def get_inventory_weave(self):
454
        self._ensure_real()
455
        return self._real_repository.get_inventory_weave()
456
457
    def fileids_altered_by_revision_ids(self, revision_ids):
458
        self._ensure_real()
459
        return self._real_repository.fileids_altered_by_revision_ids(revision_ids)
460
461
    @needs_read_lock
462
    def get_signature_text(self, revision_id):
463
        self._ensure_real()
464
        return self._real_repository.get_signature_text(revision_id)
465
466
    @needs_read_lock
467
    def get_revision_graph_with_ghosts(self, revision_ids=None):
468
        self._ensure_real()
469
        return self._real_repository.get_revision_graph_with_ghosts(
470
            revision_ids=revision_ids)
471
472
    @needs_read_lock
473
    def get_inventory_xml(self, revision_id):
474
        self._ensure_real()
475
        return self._real_repository.get_inventory_xml(revision_id)
476
477
    def deserialise_inventory(self, revision_id, xml):
478
        self._ensure_real()
479
        return self._real_repository.deserialise_inventory(revision_id, xml)
480
481
    def reconcile(self, other=None, thorough=False):
482
        self._ensure_real()
483
        return self._real_repository.reconcile(other=other, thorough=thorough)
484
        
485
    def all_revision_ids(self):
486
        self._ensure_real()
487
        return self._real_repository.all_revision_ids()
488
    
489
    @needs_read_lock
490
    def get_deltas_for_revisions(self, revisions):
491
        self._ensure_real()
492
        return self._real_repository.get_deltas_for_revisions(revisions)
493
494
    @needs_read_lock
495
    def get_revision_delta(self, revision_id):
496
        self._ensure_real()
497
        return self._real_repository.get_revision_delta(revision_id)
498
499
    @needs_read_lock
500
    def revision_trees(self, revision_ids):
501
        self._ensure_real()
502
        return self._real_repository.revision_trees(revision_ids)
503
504
    @needs_read_lock
505
    def get_revision_reconcile(self, revision_id):
506
        self._ensure_real()
507
        return self._real_repository.get_revision_reconcile(revision_id)
508
509
    @needs_read_lock
510
    def check(self, revision_ids):
511
        self._ensure_real()
512
        return self._real_repository.check(revision_ids)
513
514
    def copy_content_into(self, destination, revision_id=None, basis=None):
515
        self._ensure_real()
516
        return self._real_repository.copy_content_into(
517
            destination, revision_id=revision_id, basis=basis)
518
519
    def set_make_working_trees(self, new_value):
520
        raise NotImplementedError(self.set_make_working_trees)
521
522
    @needs_write_lock
523
    def sign_revision(self, revision_id, gpg_strategy):
524
        self._ensure_real()
525
        return self._real_repository.sign_revision(revision_id, gpg_strategy)
526
527
    @needs_read_lock
528
    def get_revisions(self, revision_ids):
529
        self._ensure_real()
530
        return self._real_repository.get_revisions(revision_ids)
531
532
    def supports_rich_root(self):
2018.5.84 by Andrew Bennetts
Merge in supports-rich-root, another test passing.
533
        self._ensure_real()
534
        return self._real_repository.supports_rich_root()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
535
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
536
    def iter_reverse_revision_history(self, revision_id):
537
        self._ensure_real()
538
        return self._real_repository.iter_reverse_revision_history(revision_id)
539
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
540
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
541
class RemoteBranchLockableFiles(object):
542
    """A 'LockableFiles' implementation that talks to a smart server.
543
    
544
    This is not a public interface class.
545
    """
546
547
    def __init__(self, bzrdir, _client):
548
        self.bzrdir = bzrdir
549
        self._client = _client
550
551
    def get(self, path):
552
        """'get' a remote path as per the LockableFiles interface.
553
554
        :param path: the file to 'get'. If this is 'branch.conf', we do not
555
             just retrieve a file, instead we ask the smart server to generate
556
             a configuration for us - which is retrieved as an INI file.
557
        """
558
        assert path == 'branch.conf'
559
        path = self.bzrdir._path_for_remote_call(self._client)
560
        response = self._client.call2('Branch.get_config_file', path)
2018.10.1 by v.ladeuil+lp at free
Line too long
561
        assert response[0][0] == 'ok', \
562
            'unexpected response code %s' % (response[0],)
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
563
        return StringIO(response[1].read_body_bytes())
564
565
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
566
class RemoteBranchFormat(branch.BranchFormat):
567
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
568
    def get_format_description(self):
569
        return 'Remote BZR Branch'
570
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
571
    def get_format_string(self):
572
        return 'Remote BZR Branch'
573
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
574
    def open(self, a_bzrdir):
1752.2.72 by Andrew Bennetts
Make Remote* classes in remote.py more consistent and remove some dead code.
575
        assert isinstance(a_bzrdir, RemoteBzrDir)
576
        return a_bzrdir.open_branch()
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
577
578
    def initialize(self, a_bzrdir):
579
        assert isinstance(a_bzrdir, RemoteBzrDir)
580
        return a_bzrdir.create_branch()
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
581
582
583
class RemoteBranch(branch.Branch):
584
    """Branch stored on a server accessed by HPSS RPC.
585
586
    At the moment most operations are mapped down to simple file operations.
587
    """
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
588
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
589
    def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
590
        _client=None):
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
591
        """Create a RemoteBranch instance.
592
593
        :param real_branch: An optional local implementation of the branch
594
            format, usually accessing the data via the VFS.
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
595
        :param _client: Private parameter for testing.
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
596
        """
1752.2.64 by Andrew Bennetts
Improve how RemoteBzrDir.open_branch works to handle references and not double-open repositories.
597
        self.bzrdir = remote_bzrdir
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
598
        if _client is not None:
599
            self._client = _client
600
        else:
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
601
            self._client = client.SmartClient(self.bzrdir._medium)
1752.2.64 by Andrew Bennetts
Improve how RemoteBzrDir.open_branch works to handle references and not double-open repositories.
602
        self.repository = remote_repository
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
603
        if real_branch is not None:
604
            self._real_branch = real_branch
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
605
            # Give the remote repository the matching real repo.
606
            self.repository._set_real_repository(self._real_branch.repository)
607
            # Give the branch the remote repository to let fast-pathing happen.
608
            self._real_branch.repository = self.repository
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
609
        else:
610
            self._real_branch = None
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
611
        # Fill out expected attributes of branch for bzrlib api users.
1752.2.64 by Andrew Bennetts
Improve how RemoteBzrDir.open_branch works to handle references and not double-open repositories.
612
        self._format = RemoteBranchFormat()
2018.5.55 by Robert Collins
Give RemoteBranch a base url in line with the Branch protocol.
613
        self.base = self.bzrdir.root_transport.base
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
614
        self.control_files = RemoteBranchLockableFiles(self.bzrdir, self._client)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
615
        self._lock_mode = None
616
        self._lock_token = None
617
        self._lock_count = 0
618
        self._leave_lock = False
1752.2.64 by Andrew Bennetts
Improve how RemoteBzrDir.open_branch works to handle references and not double-open repositories.
619
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
620
    def _ensure_real(self):
621
        """Ensure that there is a _real_branch set.
622
623
        used before calls to self._real_branch.
624
        """
625
        if not self._real_branch:
626
            assert vfs.vfs_enabled()
627
            self.bzrdir._ensure_real()
628
            self._real_branch = self.bzrdir._real_bzrdir.open_branch()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
629
            # Give the remote repository the matching real repo.
630
            self.repository._set_real_repository(self._real_branch.repository)
631
            # Give the branch the remote repository to let fast-pathing happen.
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
632
            self._real_branch.repository = self.repository
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
633
            # XXX: deal with _lock_mode == 'w'
634
            if self._lock_mode == 'r':
635
                self._real_branch.lock_read()
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
636
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
637
    def get_physical_lock_status(self):
638
        """See Branch.get_physical_lock_status()."""
639
        # should be an API call to the server, as branches must be lockable.
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
640
        self._ensure_real()
2018.5.60 by Robert Collins
More missing methods from RemoteBranch and RemoteRepository to let 'info' get further.
641
        return self._real_branch.get_physical_lock_status()
642
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
643
    def lock_read(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
644
        if not self._lock_mode:
645
            self._lock_mode = 'r'
646
            self._lock_count = 1
647
            if self._real_branch is not None:
648
                self._real_branch.lock_read()
649
        else:
650
            self._lock_count += 1
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
651
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
652
    def _remote_lock_write(self, tokens):
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
653
        if tokens is None:
654
            branch_token = repo_token = ''
655
        else:
656
            branch_token, repo_token = tokens
657
        path = self.bzrdir._path_for_remote_call(self._client)
658
        response = self._client.call('Branch.lock_write', path, branch_token,
659
                                     repo_token)
660
        if response[0] == 'ok':
661
            ok, branch_token, repo_token = response
662
            return branch_token, repo_token
663
        elif response[0] == 'LockContention':
664
            raise errors.LockContention('(remote lock)')
665
        elif response[0] == 'TokenMismatch':
666
            raise errors.TokenMismatch(tokens, '(remote tokens)')
667
        else:
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
668
            assert False, 'unexpected response code %r' % (response,)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
669
            
670
    def lock_write(self, tokens=None):
671
        if not self._lock_mode:
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
672
            remote_tokens = self._remote_lock_write(tokens)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
673
            self._lock_token, self._repo_lock_token = remote_tokens
674
            assert self._lock_token, 'Remote server did not return a token!'
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
675
            # TODO: We really, really, really don't want to call _ensure_real
676
            # here, but it's the easiest way to ensure coherency between the
677
            # state of the RemoteBranch and RemoteRepository objects and the
678
            # physical locks.  If we don't materialise the real objects here,
679
            # then getting everything in the right state later is complex, so
680
            # for now we just do it the lazy way.
681
            #   -- Andrew Bennetts, 2007-02-22.
682
            self._ensure_real()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
683
            if self._real_branch is not None:
684
                self._real_branch.lock_write(tokens=remote_tokens)
685
            if tokens is not None:
686
                self._leave_lock = True
687
            else:
688
                # XXX: this case seems to be unreachable; tokens cannot be None.
689
                self._leave_lock = False
690
            self._lock_mode = 'w'
691
            self._lock_count = 1
692
        elif self._lock_mode == 'r':
693
            raise errors.ReadOnlyTransaction
694
        else:
695
            if tokens is not None:
696
                # Tokens were given to lock_write, and we're relocking, so check
697
                # that the given tokens actually match the ones we already have.
698
                held_tokens = (self._lock_token, self._repo_lock_token)
699
                if tokens != held_tokens:
700
                    raise errors.TokenMismatch(str(tokens), str(held_tokens))
701
            self._lock_count += 1
702
        return self._lock_token, self._repo_lock_token
703
704
    def _unlock(self, branch_token, repo_token):
705
        path = self.bzrdir._path_for_remote_call(self._client)
706
        response = self._client.call('Branch.unlock', path, branch_token,
707
                                     repo_token)
708
        if response == ('ok',):
709
            return
710
        elif response[0] == 'TokenMismatch':
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
711
            raise errors.TokenMismatch(
712
                str((branch_token, repo_token)), '(remote tokens)')
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
713
        else:
714
            assert False, 'unexpected response code %s' % (response,)
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
715
716
    def unlock(self):
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
717
        self._lock_count -= 1
718
        if not self._lock_count:
719
            mode = self._lock_mode
720
            self._lock_mode = None
721
            if self._real_branch is not None:
2018.15.1 by Andrew Bennetts
All branch_implementations/test_locking tests passing.
722
                if not self._leave_lock:
723
                    # If this RemoteBranch will remove the physical lock for the
724
                    # repository, make sure the _real_branch doesn't do it
725
                    # first.  (Because the _real_branch's repository is set to
726
                    # be the RemoteRepository.)
727
                    self._real_branch.repository.leave_lock_in_place()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
728
                self._real_branch.unlock()
729
            if mode != 'w':
730
                return
731
            assert self._lock_token, 'Locked, but no token!'
732
            branch_token = self._lock_token
733
            repo_token = self._repo_lock_token
734
            self._lock_token = None
735
            self._repo_lock_token = None
736
            if not self._leave_lock:
737
                self._unlock(branch_token, repo_token)
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
738
739
    def break_lock(self):
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
740
        self._ensure_real()
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
741
        return self._real_branch.break_lock()
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
742
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
743
    def leave_lock_in_place(self):
744
        self._leave_lock = True
745
746
    def dont_leave_lock_in_place(self):
747
        self._leave_lock = False
748
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
749
    def last_revision_info(self):
750
        """See Branch.last_revision_info()."""
751
        path = self.bzrdir._path_for_remote_call(self._client)
752
        response = self._client.call('Branch.last_revision_info', path)
2018.5.52 by Wouter van Heyst
Provide more information when encountering unexpected responses from a smart
753
        assert response[0] == 'ok', 'unexpected response code %s' % (response,)
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
754
        revno = int(response[1])
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
755
        last_revision = response[2]
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
756
        if last_revision == '':
757
            last_revision = NULL_REVISION
758
        return (revno, last_revision)
759
1752.2.31 by Martin Pool
[broken] some support for write operations over hpss
760
    def revision_history(self):
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
761
        """See Branch.revision_history()."""
762
        # XXX: TODO: this does not cache the revision history for the duration
763
        # of a lock, which is a bug - see the code for regular branches
764
        # for details.
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
765
        path = self.bzrdir._path_for_remote_call(self._client)
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
766
        response = self._client.call2('Branch.revision_history', path)
2018.5.52 by Wouter van Heyst
Provide more information when encountering unexpected responses from a smart
767
        assert response[0][0] == 'ok', 'unexpected response code %s' % (response[0],)
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
768
        result = response[1].read_body_bytes().split('\x00')
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
769
        if result == ['']:
770
            return []
771
        return result
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
772
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
773
    @needs_write_lock
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
774
    def set_revision_history(self, rev_history):
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
775
        # Send just the tip revision of the history; the server will generate
776
        # the full history from that.  If the revision doesn't exist in this
777
        # branch, NoSuchRevision will be raised.
778
        path = self.bzrdir._path_for_remote_call(self._client)
779
        if rev_history == []:
780
            rev_id = ''
781
        else:
782
            rev_id = rev_history[-1]
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
783
        response = self._client.call('Branch.set_last_revision',
784
            path, self._lock_token, self._repo_lock_token, rev_id)
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
785
        if response[0] == 'NoSuchRevision':
786
            raise NoSuchRevision(self, rev_id)
787
        else:
788
            assert response == ('ok',), (
789
                'unexpected response code %r' % (response,))
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
790
791
    def get_parent(self):
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
792
        self._ensure_real()
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
793
        return self._real_branch.get_parent()
794
        
1752.2.63 by Andrew Bennetts
Delegate set_parent.
795
    def set_parent(self, url):
2018.5.70 by Robert Collins
Only try to get real repositories when an operation requires them.
796
        self._ensure_real()
1752.2.63 by Andrew Bennetts
Delegate set_parent.
797
        return self._real_branch.set_parent(url)
798
        
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
799
    def get_config(self):
800
        return RemoteBranchConfig(self)
801
802
    @needs_write_lock
803
    def append_revision(self, *revision_ids):
804
        self._ensure_real()
805
        return self._real_branch.append_revision(*revision_ids)
806
807
    @needs_write_lock
808
    def pull(self, source, overwrite=False, stop_revision=None):
809
        self._ensure_real()
810
        self._real_branch.pull(
811
            source, overwrite=overwrite, stop_revision=stop_revision)
812
2018.14.3 by Andrew Bennetts
Make a couple more branch_implementations tests pass.
813
    @needs_read_lock
814
    def push(self, target, overwrite=False, stop_revision=None):
815
        self._ensure_real()
816
        self._real_branch.push(
817
            target, overwrite=overwrite, stop_revision=stop_revision)
818
819
    def is_locked(self):
820
        return self._lock_count >= 1
821
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
822
    def set_last_revision_info(self, revno, revision_id):
823
        self._ensure_real()
824
        return self._real_branch.set_last_revision_info(revno, revision_id)
825
1752.2.30 by Martin Pool
Start adding a RemoteBzrDir, etc
826
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
827
class RemoteWorkingTree(object):
828
1752.2.72 by Andrew Bennetts
Make Remote* classes in remote.py more consistent and remove some dead code.
829
    def __init__(self, remote_bzrdir, real_workingtree):
1752.2.50 by Andrew Bennetts
Implement RemoteBzrDir.create_{branch,workingtree}
830
        self.real_workingtree = real_workingtree
831
        self.bzrdir = remote_bzrdir
832
833
    def __getattr__(self, name):
834
        # XXX: temporary way to lazily delegate everything to the real
835
        # workingtree
836
        return getattr(self.real_workingtree, name)
837
1752.2.52 by Andrew Bennetts
Flesh out more Remote* methods needed to open and initialise remote branches/trees/repositories.
838
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
839
class RemoteBranchConfig(BranchConfig):
840
841
    def username(self):
842
        self.branch._ensure_real()
843
        return self.branch._real_branch.get_config().username()
844
2018.14.2 by Andrew Bennetts
All but one repository_implementation tests for RemoteRepository passing.
845
    def _get_branch_data_config(self):
846
        self.branch._ensure_real()
847
        if self._branch_data_config is None:
848
            self._branch_data_config = TreeConfig(self.branch._real_branch)
849
        return self._branch_data_config
850