/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

cope with branch argument to _warn_if_deprecated

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2008 Canonical Ltd
 
1
# Copyright (C) 2007-2009 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
    tag,
 
21
    trace,
 
22
    ui,
 
23
    urlutils,
 
24
    )
 
25
from bzrlib.errors import (
 
26
    BzrError,
 
27
    InvalidRevisionId,
 
28
    NoSuchFile,
 
29
    NoSuchRevision,
 
30
    NotLocalUrl,
 
31
    )
 
32
from bzrlib.transport import (
 
33
    Transport,
 
34
    )
 
35
 
 
36
from bzrlib.plugins.git import (
 
37
    lazy_check_versions,
 
38
    )
 
39
lazy_check_versions()
 
40
 
 
41
from bzrlib.plugins.git.branch import (
 
42
    GitBranch,
 
43
    extract_tags,
 
44
    )
 
45
from bzrlib.plugins.git.errors import (
 
46
    GitSmartRemoteNotSupported,
 
47
    NoSuchRef,
 
48
    )
 
49
from bzrlib.plugins.git.dir import (
 
50
    GitDir,
 
51
    )
 
52
from bzrlib.plugins.git.mapping import (
 
53
    mapping_registry,
 
54
    )
 
55
from bzrlib.plugins.git.repository import (
 
56
    GitRepository,
 
57
    )
 
58
 
 
59
import dulwich as git
 
60
from dulwich.errors import (
 
61
    GitProtocolError,
 
62
    )
 
63
from dulwich.pack import (
 
64
    Pack,
 
65
    PackData,
 
66
    )
 
67
import os
 
68
import tempfile
32
69
import urllib
33
70
import urlparse
34
71
 
35
 
from dulwich.pack import PackData
 
72
from dulwich.pack import load_pack_index
 
73
 
 
74
 
 
75
# Don't run any tests on GitSmartTransport as it is not intended to be
 
76
# a full implementation of Transport
 
77
def get_test_permutations():
 
78
    return []
 
79
 
 
80
 
 
81
def split_git_url(url):
 
82
    """Split a Git URL.
 
83
 
 
84
    :param url: Git URL
 
85
    :return: Tuple with host, port, username, path.
 
86
    """
 
87
    (scheme, _, loc, _, _) = urlparse.urlsplit(url)
 
88
    hostport, escaped_path = urllib.splithost(loc)
 
89
    path = urllib.unquote(escaped_path)
 
90
    if path.startswith("/~"):
 
91
        path = path[1:]
 
92
    (username, hostport) = urllib.splituser(hostport)
 
93
    (host, port) = urllib.splitnport(hostport, None)
 
94
    return (host, port, username, path)
36
95
 
37
96
 
38
97
class GitSmartTransport(Transport):
39
98
 
40
99
    def __init__(self, url, _client=None):
41
100
        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)
 
101
        (self._host, self._port, self._username, self._path) = \
 
102
            split_git_url(url)
 
103
        if 'transport' in debug.debug_flags:
 
104
            trace.mutter('host: %r, user: %r, port: %r, path: %r',
 
105
                         self._host, self._username, self._port, self._path)
 
106
        self._client = _client
 
107
 
 
108
    def external_url(self):
 
109
        return self.base
 
110
 
 
111
    def has(self, relpath):
 
112
        return False
 
113
 
 
114
    def _get_client(self, thin_packs):
 
115
        raise NotImplementedError(self._get_client)
 
116
 
 
117
    def _get_path(self):
 
118
        return self._path
50
119
 
51
120
    def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
52
121
        if progress is None:
53
122
            def progress(text):
54
 
                info("git: %s" % text)
55
 
        self._client.fetch_pack(self._path, determine_wants, graph_walker, 
56
 
                pack_data, progress)
 
123
                trace.info("git: %s" % text)
 
124
        client = self._get_client(thin_packs=False)
 
125
        try:
 
126
            return client.fetch_pack(self._get_path(), determine_wants,
 
127
                graph_walker, pack_data, progress)
 
128
        except GitProtocolError, e:
 
129
            raise BzrError(e)
57
130
 
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)
 
131
    def send_pack(self, get_changed_refs, generate_pack_contents):
 
132
        client = self._get_client(thin_packs=False)
62
133
        try:
63
 
            p = PackData(path)
64
 
            for o in p.iterobjects():
65
 
                yield o
66
 
        finally:
67
 
            os.remove(path)
 
134
            return client.send_pack(self._get_path(), get_changed_refs,
 
135
                generate_pack_contents)
 
136
        except GitProtocolError, e:
 
137
            raise BzrError(e)
68
138
 
69
139
    def get(self, path):
70
140
        raise NoSuchFile(path)
71
141
 
 
142
    def abspath(self, relpath):
 
143
        return urlutils.join(self.base, relpath)
 
144
 
72
145
    def clone(self, offset=None):
73
146
        """See Transport.clone()."""
74
147
        if offset is None:
76
149
        else:
77
150
            newurl = urlutils.join(self.base, offset)
78
151
 
79
 
        return GitSmartTransport(newurl, self._client)
 
152
        return self.__class__(newurl, self._client)
 
153
 
 
154
 
 
155
class TCPGitSmartTransport(GitSmartTransport):
 
156
 
 
157
    _scheme = 'git'
 
158
 
 
159
    def _get_client(self, thin_packs):
 
160
        if self._client is not None:
 
161
            ret = self._client
 
162
            self._client = None
 
163
            return ret
 
164
        return git.client.TCPGitClient(self._host, self._port, thin_packs=thin_packs,
 
165
            report_activity=self._report_activity)
 
166
 
 
167
 
 
168
class SSHGitSmartTransport(GitSmartTransport):
 
169
 
 
170
    _scheme = 'git+ssh'
 
171
 
 
172
    def _get_path(self):
 
173
        if self._path.startswith("/~/"):
 
174
            return self._path[3:]
 
175
        return self._path
 
176
 
 
177
    def _get_client(self, thin_packs):
 
178
        if self._client is not None:
 
179
            ret = self._client
 
180
            self._client = None
 
181
            return ret
 
182
        return git.client.SSHGitClient(self._host, self._port, self._username,
 
183
            thin_packs=thin_packs, report_activity=self._report_activity)
80
184
 
81
185
 
82
186
class RemoteGitDir(GitDir):
86
190
        self.root_transport = transport
87
191
        self.transport = transport
88
192
        self._lockfiles = lockfiles
 
193
        self._mode_check_done = None
89
194
 
90
195
    def open_repository(self):
91
196
        return RemoteGitRepository(self, self._lockfiles)
92
197
 
93
 
    def open_branch(self):
 
198
    def open_branch(self, name=None, ignore_fallbacks=False):
94
199
        repo = self.open_repository()
95
200
        # TODO: Support for multiple branches in one bzrdir in bzrlib!
96
 
        return RemoteGitBranch(self, repo, "HEAD", self._lockfiles)
 
201
        if name is None:
 
202
            name = "HEAD"
 
203
        return RemoteGitBranch(self, repo, name, self._lockfiles)
97
204
 
98
 
    def open_workingtree(self):
 
205
    def open_workingtree(self, recommend_upgrade=False):
99
206
        raise NotLocalUrl(self.transport.base)
100
207
 
101
208
 
 
209
class EmptyObjectStoreIterator(dict):
 
210
 
 
211
    def iterobjects(self):
 
212
        return []
 
213
 
 
214
 
 
215
class TemporaryPackIterator(Pack):
 
216
 
 
217
    def __init__(self, path, resolve_ext_ref):
 
218
        super(TemporaryPackIterator, self).__init__(path)
 
219
        self.resolve_ext_ref = resolve_ext_ref
 
220
 
 
221
    @property
 
222
    def data(self):
 
223
        if self._data is None:
 
224
            self._data = PackData(self._data_path)
 
225
        return self._data
 
226
 
 
227
    @property
 
228
    def index(self):
 
229
        if self._idx is None:
 
230
            if not os.path.exists(self._idx_path):
 
231
                pb = ui.ui_factory.nested_progress_bar()
 
232
                try:
 
233
                    def report_progress(cur, total):
 
234
                        pb.update("generating index", cur, total)
 
235
                    self.data.create_index(self._idx_path, self.resolve_ext_ref,
 
236
                        progress=report_progress)
 
237
                finally:
 
238
                    pb.finished()
 
239
            self._idx = load_pack_index(self._idx_path)
 
240
        return self._idx
 
241
 
 
242
    def __del__(self):
 
243
        if self._idx is not None:
 
244
            self._idx.close()
 
245
            os.remove(self._idx_path)
 
246
        if self._data is not None:
 
247
            self._data.close()
 
248
            os.remove(self._data_path)
 
249
 
 
250
 
102
251
class RemoteGitRepository(GitRepository):
103
252
 
104
253
    def __init__(self, gitdir, lockfiles):
105
254
        GitRepository.__init__(self, gitdir, lockfiles)
106
 
 
107
 
    def fetch_pack(self, determine_wants, graph_walker, pack_data, 
 
255
        self._refs = None
 
256
 
 
257
    @property
 
258
    def inventories(self):
 
259
        raise GitSmartRemoteNotSupported()
 
260
 
 
261
    @property
 
262
    def revisions(self):
 
263
        raise GitSmartRemoteNotSupported()
 
264
 
 
265
    @property
 
266
    def texts(self):
 
267
        raise GitSmartRemoteNotSupported()
 
268
 
 
269
    def get_refs(self):
 
270
        if self._refs is not None:
 
271
            return self._refs
 
272
        self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
 
273
            lambda x: None, lambda x: trace.mutter("git: %s" % x))
 
274
        return self._refs
 
275
 
 
276
    def fetch_pack(self, determine_wants, graph_walker, pack_data,
108
277
                   progress=None):
109
 
        self._transport.fetch_pack(determine_wants, graph_walker, pack_data, 
110
 
            progress)
 
278
        return self._transport.fetch_pack(determine_wants, graph_walker,
 
279
                                          pack_data, progress)
 
280
 
 
281
    def send_pack(self, get_changed_refs, generate_pack_contents):
 
282
        return self._transport.send_pack(get_changed_refs, generate_pack_contents)
 
283
 
 
284
    def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
 
285
                      progress=None):
 
286
        fd, path = tempfile.mkstemp(suffix=".pack")
 
287
        self.fetch_pack(determine_wants, graph_walker,
 
288
            lambda x: os.write(fd, x), progress)
 
289
        os.close(fd)
 
290
        if os.path.getsize(path) == 0:
 
291
            return EmptyObjectStoreIterator()
 
292
        return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
 
293
 
 
294
    def lookup_bzr_revision_id(self, bzr_revid):
 
295
        # This won't work for any round-tripped bzr revisions, but it's a start..
 
296
        try:
 
297
            return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
 
298
        except InvalidRevisionId:
 
299
            raise NoSuchRevision(self, bzr_revid)
 
300
 
 
301
 
 
302
class RemoteGitTagDict(tag.BasicTags):
 
303
 
 
304
    def __init__(self, branch):
 
305
        self.branch = branch
 
306
        self.repository = branch.repository
 
307
 
 
308
    def get_tag_dict(self):
 
309
        tags = {}
 
310
        for k, v in extract_tags(self.repository.get_refs()).iteritems():
 
311
            tags[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
 
312
        return tags
 
313
 
 
314
    def set_tag(self, name, revid):
 
315
        # FIXME: Not supported yet, should do a push of a new ref
 
316
        raise NotImplementedError(self.set_tag)
111
317
 
112
318
 
113
319
class RemoteGitBranch(GitBranch):
114
320
 
115
321
    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)
 
322
        self._ref = None
 
323
        super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
 
324
                lockfiles)
 
325
 
 
326
    def revision_history(self):
 
327
        raise GitSmartRemoteNotSupported()
121
328
 
122
329
    def last_revision(self):
123
 
        return self.mapping.revision_id_foreign_to_bzr(self._ref)
124
 
 
 
330
        return self.mapping.revision_id_foreign_to_bzr(self.head)
 
331
 
 
332
    def _get_config(self):
 
333
        class EmptyConfig(object):
 
334
 
 
335
            def _get_configobj(self):
 
336
                return config.ConfigObj()
 
337
 
 
338
        return EmptyConfig()
 
339
 
 
340
    @property
 
341
    def head(self):
 
342
        if self._ref is not None:
 
343
            return self._ref
 
344
        heads = self.repository.get_refs()
 
345
        if not self.name in heads:
 
346
            raise NoSuchRef(self.name)
 
347
        self._ref = heads[self.name]
 
348
        return self._ref
 
349
 
 
350
    def _synchronize_history(self, destination, revision_id):
 
351
        """See Branch._synchronize_history()."""
 
352
        destination.generate_revision_history(self.last_revision())
 
353
 
 
354
    def get_push_location(self):
 
355
        return None
 
356
 
 
357
    def set_push_location(self, url):
 
358
        pass