/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to remote.py

Fix teardown of object store tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2008 Canonical Ltd
 
1
# Copyright (C) 2007-2010 Jelmer Vernooij <jelmer@samba.org>
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
import bzrlib
18
 
from bzrlib import urlutils
19
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
20
 
from bzrlib.errors import NoSuchFile, NotLocalUrl
21
 
from bzrlib.lockable_files import TransportLock
22
 
from bzrlib.repository import Repository
23
 
from bzrlib.trace import info
24
 
from bzrlib.transport import Transport
25
 
 
26
 
from bzrlib.plugins.git import git
27
 
from bzrlib.plugins.git.branch import GitBranch
28
 
from bzrlib.plugins.git.dir import GitDir
29
 
from bzrlib.plugins.git.foreign import ForeignBranch
30
 
from bzrlib.plugins.git.repository import GitFormat, GitRepository
31
 
 
 
17
from bzrlib import (
 
18
    config,
 
19
    debug,
 
20
    trace,
 
21
    ui,
 
22
    urlutils,
 
23
    )
 
24
from bzrlib.errors import (
 
25
    BzrError,
 
26
    InvalidRevisionId,
 
27
    NoSuchFile,
 
28
    NoSuchRevision,
 
29
    NotLocalUrl,
 
30
    )
 
31
from bzrlib.transport import (
 
32
    Transport,
 
33
    )
 
34
 
 
35
from bzrlib.plugins.git import (
 
36
    lazy_check_versions,
 
37
    )
 
38
lazy_check_versions()
 
39
 
 
40
from bzrlib.plugins.git.branch import (
 
41
    GitBranch,
 
42
    GitTags,
 
43
    )
 
44
from bzrlib.plugins.git.errors import (
 
45
    GitSmartRemoteNotSupported,
 
46
    NoSuchRef,
 
47
    )
 
48
from bzrlib.plugins.git.dir import (
 
49
    GitDir,
 
50
    )
 
51
from bzrlib.plugins.git.mapping import (
 
52
    mapping_registry,
 
53
    )
 
54
from bzrlib.plugins.git.repository import (
 
55
    GitRepository,
 
56
    )
 
57
from bzrlib.plugins.git.refs import (
 
58
    extract_tags,
 
59
    branch_name_to_ref,
 
60
    )
 
61
 
 
62
import dulwich as git
 
63
from dulwich.errors import (
 
64
    GitProtocolError,
 
65
    )
 
66
from dulwich.pack import (
 
67
    Pack,
 
68
    ThinPackData,
 
69
    )
 
70
import os
 
71
import tempfile
32
72
import urllib
33
73
import urlparse
34
 
 
35
 
from dulwich.pack import PackData
 
74
urlparse.uses_netloc.extend(['git', 'git+ssh'])
 
75
 
 
76
from dulwich.pack import load_pack_index
 
77
 
 
78
 
 
79
# Don't run any tests on GitSmartTransport as it is not intended to be
 
80
# a full implementation of Transport
 
81
def get_test_permutations():
 
82
    return []
 
83
 
 
84
 
 
85
def split_git_url(url):
 
86
    """Split a Git URL.
 
87
 
 
88
    :param url: Git URL
 
89
    :return: Tuple with host, port, username, path.
 
90
    """
 
91
    (scheme, netloc, loc, _, _) = urlparse.urlsplit(url)
 
92
    path = urllib.unquote(loc)
 
93
    if path.startswith("/~"):
 
94
        path = path[1:]
 
95
    (username, hostport) = urllib.splituser(netloc)
 
96
    (host, port) = urllib.splitnport(hostport, None)
 
97
    return (host, port, username, path)
36
98
 
37
99
 
38
100
class GitSmartTransport(Transport):
39
101
 
40
102
    def __init__(self, url, _client=None):
41
103
        Transport.__init__(self, url)
42
 
        (scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
 
        assert scheme == "git"
44
 
        hostport, self._path = urllib.splithost(loc)
45
 
        (self._host, self._port) = urllib.splitnport(hostport, git.protocol.TCP_GIT_PORT)
46
 
        if _client is not None:
47
 
            self._client = _client
48
 
        else:
49
 
            self._client = git.client.TCPGitClient(self._host, self._port)
 
104
        (self._host, self._port, self._username, self._path) = \
 
105
            split_git_url(url)
 
106
        if 'transport' in debug.debug_flags:
 
107
            trace.mutter('host: %r, user: %r, port: %r, path: %r',
 
108
                         self._host, self._username, self._port, self._path)
 
109
        self._client = _client
 
110
 
 
111
    def external_url(self):
 
112
        return self.base
 
113
 
 
114
    def has(self, relpath):
 
115
        return False
 
116
 
 
117
    def _get_client(self, thin_packs):
 
118
        raise NotImplementedError(self._get_client)
 
119
 
 
120
    def _get_path(self):
 
121
        return self._path
50
122
 
51
123
    def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
52
124
        if progress is None:
53
125
            def progress(text):
54
 
                info("git: %s" % text)
55
 
        self._client.fetch_pack(self._path, determine_wants, graph_walker, 
56
 
                pack_data, progress)
 
126
                trace.info("git: %s" % text)
 
127
        client = self._get_client(thin_packs=False)
 
128
        try:
 
129
            return client.fetch_pack(self._get_path(), determine_wants,
 
130
                graph_walker, pack_data, progress)
 
131
        except GitProtocolError, e:
 
132
            raise BzrError(e)
57
133
 
58
 
    def fetch_objects(self, determine_wants, graph_walker, progress=None):
59
 
        fd, path = tempfile.mkstemp(dir=self.pack_dir(), suffix=".pack")
60
 
        self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
61
 
        os.close(fd)
 
134
    def send_pack(self, get_changed_refs, generate_pack_contents):
 
135
        client = self._get_client(thin_packs=False)
62
136
        try:
63
 
            p = PackData(path)
64
 
            for o in p.iterobjects():
65
 
                yield o
66
 
        finally:
67
 
            os.remove(path)
 
137
            return client.send_pack(self._get_path(), get_changed_refs,
 
138
                generate_pack_contents)
 
139
        except GitProtocolError, e:
 
140
            raise BzrError(e)
68
141
 
69
142
    def get(self, path):
70
143
        raise NoSuchFile(path)
71
144
 
 
145
    def abspath(self, relpath):
 
146
        return urlutils.join(self.base, relpath)
 
147
 
72
148
    def clone(self, offset=None):
73
149
        """See Transport.clone()."""
74
150
        if offset is None:
76
152
        else:
77
153
            newurl = urlutils.join(self.base, offset)
78
154
 
79
 
        return GitSmartTransport(newurl, self._client)
 
155
        return self.__class__(newurl, self._client)
 
156
 
 
157
 
 
158
class TCPGitSmartTransport(GitSmartTransport):
 
159
 
 
160
    _scheme = 'git'
 
161
 
 
162
    def _get_client(self, thin_packs):
 
163
        if self._client is not None:
 
164
            ret = self._client
 
165
            self._client = None
 
166
            return ret
 
167
        return git.client.TCPGitClient(self._host, self._port,
 
168
            thin_packs=thin_packs, report_activity=self._report_activity)
 
169
 
 
170
 
 
171
class SSHGitSmartTransport(GitSmartTransport):
 
172
 
 
173
    _scheme = 'git+ssh'
 
174
 
 
175
    def _get_path(self):
 
176
        if self._path.startswith("/~/"):
 
177
            return self._path[3:]
 
178
        return self._path
 
179
 
 
180
    def _get_client(self, thin_packs):
 
181
        if self._client is not None:
 
182
            ret = self._client
 
183
            self._client = None
 
184
            return ret
 
185
        location_config = config.LocationConfig(self.base)
 
186
        client = git.client.SSHGitClient(self._host, self._port, self._username,
 
187
            thin_packs=thin_packs, report_activity=self._report_activity)
 
188
        # Set up alternate pack program paths
 
189
        upload_pack = location_config.get_user_option('git_upload_pack')
 
190
        if upload_pack:
 
191
            client.alternative_paths["upload-pack"] = upload_pack
 
192
        receive_pack = location_config.get_user_option('git_receive_pack')
 
193
        if receive_pack:
 
194
            client.alternative_paths["receive-pack"] = receive_pack
 
195
        return client
80
196
 
81
197
 
82
198
class RemoteGitDir(GitDir):
86
202
        self.root_transport = transport
87
203
        self.transport = transport
88
204
        self._lockfiles = lockfiles
 
205
        self._mode_check_done = None
 
206
 
 
207
    @property
 
208
    def user_url(self):
 
209
        return self.control_url
 
210
 
 
211
    def _branch_name_to_ref(self, name, default=None):
 
212
        return branch_name_to_ref(name, default=default)
89
213
 
90
214
    def open_repository(self):
91
215
        return RemoteGitRepository(self, self._lockfiles)
92
216
 
93
 
    def open_branch(self):
 
217
    def _open_branch(self, name=None, ignore_fallbacks=False, 
 
218
                    unsupported=False):
94
219
        repo = self.open_repository()
95
 
        # TODO: Support for multiple branches in one bzrdir in bzrlib!
96
 
        return RemoteGitBranch(self, repo, "HEAD", self._lockfiles)
 
220
        refname = self._branch_name_to_ref(name)
 
221
        return RemoteGitBranch(self, repo, refname, self._lockfiles)
97
222
 
98
 
    def open_workingtree(self):
 
223
    def open_workingtree(self, recommend_upgrade=False):
99
224
        raise NotLocalUrl(self.transport.base)
100
225
 
101
226
 
 
227
class EmptyObjectStoreIterator(dict):
 
228
 
 
229
    def iterobjects(self):
 
230
        return []
 
231
 
 
232
 
 
233
class TemporaryPackIterator(Pack):
 
234
 
 
235
    def __init__(self, path, resolve_ext_ref):
 
236
        super(TemporaryPackIterator, self).__init__(path)
 
237
        self.resolve_ext_ref = resolve_ext_ref
 
238
 
 
239
    @property
 
240
    def data(self):
 
241
        if self._data is None:
 
242
            self._data = ThinPackData(self.resolve_ext_ref, self._data_path)
 
243
        return self._data
 
244
 
 
245
    @property
 
246
    def index(self):
 
247
        if self._idx is None:
 
248
            if not os.path.exists(self._idx_path):
 
249
                pb = ui.ui_factory.nested_progress_bar()
 
250
                try:
 
251
                    def report_progress(cur, total):
 
252
                        pb.update("generating index", cur, total)
 
253
                    self.data.create_index(self._idx_path, 
 
254
                        progress=report_progress)
 
255
                finally:
 
256
                    pb.finished()
 
257
            self._idx = load_pack_index(self._idx_path)
 
258
        return self._idx
 
259
 
 
260
    def __del__(self):
 
261
        if self._idx is not None:
 
262
            self._idx.close()
 
263
            os.remove(self._idx_path)
 
264
        if self._data is not None:
 
265
            self._data.close()
 
266
            os.remove(self._data_path)
 
267
 
 
268
 
102
269
class RemoteGitRepository(GitRepository):
103
270
 
104
271
    def __init__(self, gitdir, lockfiles):
105
272
        GitRepository.__init__(self, gitdir, lockfiles)
106
 
 
107
 
    def fetch_pack(self, determine_wants, graph_walker, pack_data, 
 
273
        self._refs = None
 
274
 
 
275
    @property
 
276
    def user_url(self):
 
277
        return self.control_url
 
278
 
 
279
    @property
 
280
    def inventories(self):
 
281
        raise GitSmartRemoteNotSupported()
 
282
 
 
283
    @property
 
284
    def revisions(self):
 
285
        raise GitSmartRemoteNotSupported()
 
286
 
 
287
    @property
 
288
    def texts(self):
 
289
        raise GitSmartRemoteNotSupported()
 
290
 
 
291
    def get_refs(self):
 
292
        if self._refs is not None:
 
293
            return self._refs
 
294
        self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
 
295
            lambda x: None, lambda x: trace.mutter("git: %s" % x))
 
296
        return self._refs
 
297
 
 
298
    def fetch_pack(self, determine_wants, graph_walker, pack_data,
108
299
                   progress=None):
109
 
        self._transport.fetch_pack(determine_wants, graph_walker, pack_data, 
110
 
            progress)
 
300
        return self._transport.fetch_pack(determine_wants, graph_walker,
 
301
                                          pack_data, progress)
 
302
 
 
303
    def send_pack(self, get_changed_refs, generate_pack_contents):
 
304
        return self._transport.send_pack(get_changed_refs, generate_pack_contents)
 
305
 
 
306
    def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
 
307
                      progress=None):
 
308
        fd, path = tempfile.mkstemp(suffix=".pack")
 
309
        self.fetch_pack(determine_wants, graph_walker,
 
310
            lambda x: os.write(fd, x), progress)
 
311
        os.close(fd)
 
312
        if os.path.getsize(path) == 0:
 
313
            return EmptyObjectStoreIterator()
 
314
        return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
 
315
 
 
316
    def lookup_bzr_revision_id(self, bzr_revid):
 
317
        # This won't work for any round-tripped bzr revisions, but it's a start..
 
318
        try:
 
319
            return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
 
320
        except InvalidRevisionId:
 
321
            raise NoSuchRevision(self, bzr_revid)
 
322
 
 
323
    def lookup_foreign_revision_id(self, foreign_revid, mapping=None):
 
324
        """Lookup a revision id.
 
325
 
 
326
        """
 
327
        if mapping is None:
 
328
            mapping = self.get_mapping()
 
329
        # Not really an easy way to parse foreign revids here..
 
330
        return mapping.revision_id_foreign_to_bzr(foreign_revid)
 
331
 
 
332
 
 
333
class RemoteGitTagDict(GitTags):
 
334
 
 
335
    def get_refs(self):
 
336
        return self.repository.get_refs()
 
337
 
 
338
    def _iter_tag_refs(self, refs):
 
339
        for k, (peeled, unpeeled) in extract_tags(refs).iteritems():
 
340
            yield (k, peeled, unpeeled,
 
341
                  self.branch.mapping.revision_id_foreign_to_bzr(peeled))
 
342
 
 
343
    def set_tag(self, name, revid):
 
344
        # FIXME: Not supported yet, should do a push of a new ref
 
345
        raise NotImplementedError(self.set_tag)
111
346
 
112
347
 
113
348
class RemoteGitBranch(GitBranch):
114
349
 
115
350
    def __init__(self, bzrdir, repository, name, lockfiles):
116
 
        def determine_wants(heads):
117
 
            self._ref = heads[name]
118
 
        bzrdir.root_transport.fetch_pack(determine_wants, None, lambda x: None, 
119
 
                             lambda x: mutter("git: %s" % x))
120
 
        super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
 
351
        self._sha = None
 
352
        super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
 
353
                lockfiles)
 
354
 
 
355
    @property
 
356
    def user_url(self):
 
357
        return self.control_url
 
358
 
 
359
    @property
 
360
    def control_url(self):
 
361
        return self.base
 
362
 
 
363
    def revision_history(self):
 
364
        raise GitSmartRemoteNotSupported()
121
365
 
122
366
    def last_revision(self):
123
 
        return self.mapping.revision_id_foreign_to_bzr(self._ref)
124
 
 
 
367
        return self.lookup_foreign_revision_id(self.head)
 
368
 
 
369
    def _get_config(self):
 
370
        class EmptyConfig(object):
 
371
 
 
372
            def _get_configobj(self):
 
373
                return config.ConfigObj()
 
374
 
 
375
        return EmptyConfig()
 
376
 
 
377
    @property
 
378
    def head(self):
 
379
        if self._sha is not None:
 
380
            return self._sha
 
381
        heads = self.repository.get_refs()
 
382
        name = self.bzrdir._branch_name_to_ref(self.name, "HEAD")
 
383
        if name in heads:
 
384
            self._sha = heads[name]
 
385
        else:
 
386
            raise NoSuchRef(self.name)
 
387
        return self._sha
 
388
 
 
389
    def _synchronize_history(self, destination, revision_id):
 
390
        """See Branch._synchronize_history()."""
 
391
        destination.generate_revision_history(self.last_revision())
 
392
 
 
393
    def get_push_location(self):
 
394
        return None
 
395
 
 
396
    def set_push_location(self, url):
 
397
        pass