~bzr-pqm/bzr/bzr.dev

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