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