/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

Merge fixes for SHA1s of symlinks.

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