/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

UseĀ get_file_revision.

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