/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

update copyright years

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.errors import NoSuchRef
29
 
from bzrlib.plugins.git.dir import GitDir
30
 
from bzrlib.plugins.git.foreign import ForeignBranch
31
 
from bzrlib.plugins.git.repository import GitFormat, GitRepository
32
 
 
 
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
    )
 
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
    )
33
70
import os
34
71
import tempfile
35
72
import urllib
36
73
import urlparse
37
 
 
38
 
from dulwich.pack import PackData, Pack
 
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)
39
98
 
40
99
 
41
100
class GitSmartTransport(Transport):
42
101
 
43
102
    def __init__(self, url, _client=None):
44
103
        Transport.__init__(self, url)
45
 
        (scheme, _, loc, _, _) = urlparse.urlsplit(url)
46
 
        assert scheme == "git"
47
 
        hostport, self._path = urllib.splithost(loc)
48
 
        (self._host, self._port) = urllib.splitnport(hostport, git.protocol.TCP_GIT_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)
49
109
        self._client = _client
50
110
 
51
 
    def _get_client(self):
52
 
        if self._client is not None:
53
 
            ret = self._client
54
 
            self._client = None
55
 
            return ret
56
 
        return git.client.TCPGitClient(self._host, self._port)
 
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
57
122
 
58
123
    def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
59
124
        if progress is None:
60
125
            def progress(text):
61
 
                info("git: %s" % text)
62
 
        self._get_client().fetch_pack(self._path, determine_wants, 
63
 
            graph_walker, 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)
 
133
 
 
134
    def send_pack(self, get_changed_refs, generate_pack_contents):
 
135
        client = self._get_client(thin_packs=False)
 
136
        try:
 
137
            return client.send_pack(self._get_path(), get_changed_refs,
 
138
                generate_pack_contents)
 
139
        except GitProtocolError, e:
 
140
            raise BzrError(e)
64
141
 
65
142
    def get(self, path):
66
143
        raise NoSuchFile(path)
75
152
        else:
76
153
            newurl = urlutils.join(self.base, offset)
77
154
 
78
 
        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
        return git.client.SSHGitClient(self._host, self._port, self._username,
 
186
            thin_packs=thin_packs, report_activity=self._report_activity)
79
187
 
80
188
 
81
189
class RemoteGitDir(GitDir):
85
193
        self.root_transport = transport
86
194
        self.transport = transport
87
195
        self._lockfiles = lockfiles
 
196
        self._mode_check_done = None
 
197
 
 
198
    def _branch_name_to_ref(self, name):
 
199
        return branch_name_to_ref(name, default="HEAD")
88
200
 
89
201
    def open_repository(self):
90
202
        return RemoteGitRepository(self, self._lockfiles)
91
203
 
92
 
    def open_branch(self):
 
204
    def _open_branch(self, name=None, ignore_fallbacks=False, 
 
205
                    unsupported=False):
93
206
        repo = self.open_repository()
94
 
        # TODO: Support for multiple branches in one bzrdir in bzrlib!
95
 
        return RemoteGitBranch(self, repo, "HEAD", self._lockfiles)
 
207
        refname = self._branch_name_to_ref(name)
 
208
        return RemoteGitBranch(self, repo, refname, self._lockfiles)
96
209
 
97
 
    def open_workingtree(self):
 
210
    def open_workingtree(self, recommend_upgrade=False):
98
211
        raise NotLocalUrl(self.transport.base)
99
212
 
100
213
 
 
214
class EmptyObjectStoreIterator(dict):
 
215
 
 
216
    def iterobjects(self):
 
217
        return []
 
218
 
 
219
 
 
220
class TemporaryPackIterator(Pack):
 
221
 
 
222
    def __init__(self, path, resolve_ext_ref):
 
223
        super(TemporaryPackIterator, self).__init__(path)
 
224
        self.resolve_ext_ref = resolve_ext_ref
 
225
 
 
226
    @property
 
227
    def data(self):
 
228
        if self._data is None:
 
229
            self._data = ThinPackData(self.resolve_ext_ref, self._data_path)
 
230
        return self._data
 
231
 
 
232
    @property
 
233
    def index(self):
 
234
        if self._idx is None:
 
235
            if not os.path.exists(self._idx_path):
 
236
                pb = ui.ui_factory.nested_progress_bar()
 
237
                try:
 
238
                    def report_progress(cur, total):
 
239
                        pb.update("generating index", cur, total)
 
240
                    self.data.create_index(self._idx_path, 
 
241
                        progress=report_progress)
 
242
                finally:
 
243
                    pb.finished()
 
244
            self._idx = load_pack_index(self._idx_path)
 
245
        return self._idx
 
246
 
 
247
    def __del__(self):
 
248
        if self._idx is not None:
 
249
            self._idx.close()
 
250
            os.remove(self._idx_path)
 
251
        if self._data is not None:
 
252
            self._data.close()
 
253
            os.remove(self._data_path)
 
254
 
 
255
 
101
256
class RemoteGitRepository(GitRepository):
102
257
 
103
258
    def __init__(self, gitdir, lockfiles):
104
259
        GitRepository.__init__(self, gitdir, lockfiles)
105
 
 
106
 
    def fetch_pack(self, determine_wants, graph_walker, pack_data, 
 
260
        self._refs = None
 
261
 
 
262
    @property
 
263
    def inventories(self):
 
264
        raise GitSmartRemoteNotSupported()
 
265
 
 
266
    @property
 
267
    def revisions(self):
 
268
        raise GitSmartRemoteNotSupported()
 
269
 
 
270
    @property
 
271
    def texts(self):
 
272
        raise GitSmartRemoteNotSupported()
 
273
 
 
274
    def get_refs(self):
 
275
        if self._refs is not None:
 
276
            return self._refs
 
277
        self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
 
278
            lambda x: None, lambda x: trace.mutter("git: %s" % x))
 
279
        return self._refs
 
280
 
 
281
    def fetch_pack(self, determine_wants, graph_walker, pack_data,
107
282
                   progress=None):
108
 
        self._transport.fetch_pack(determine_wants, graph_walker, pack_data, 
109
 
            progress)
110
 
 
111
 
    def fetch_objects(self, determine_wants, graph_walker, progress=None):
 
283
        return self._transport.fetch_pack(determine_wants, graph_walker,
 
284
                                          pack_data, progress)
 
285
 
 
286
    def send_pack(self, get_changed_refs, generate_pack_contents):
 
287
        return self._transport.send_pack(get_changed_refs, generate_pack_contents)
 
288
 
 
289
    def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
 
290
                      progress=None):
112
291
        fd, path = tempfile.mkstemp(suffix=".pack")
113
 
        self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
 
292
        self.fetch_pack(determine_wants, graph_walker,
 
293
            lambda x: os.write(fd, x), progress)
114
294
        os.close(fd)
 
295
        if os.path.getsize(path) == 0:
 
296
            return EmptyObjectStoreIterator()
 
297
        return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
 
298
 
 
299
    def lookup_bzr_revision_id(self, bzr_revid):
 
300
        # This won't work for any round-tripped bzr revisions, but it's a start..
115
301
        try:
116
 
            basename = path[:-len(".pack")]
117
 
            p = PackData(path)
118
 
            p.create_index_v2(basename+".idx")
119
 
            for o in Pack(basename).iterobjects():
120
 
                yield o
121
 
        finally:
122
 
            os.remove(path)
 
302
            return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
 
303
        except InvalidRevisionId:
 
304
            raise NoSuchRevision(self, bzr_revid)
 
305
 
 
306
 
 
307
class RemoteGitTagDict(tag.BasicTags):
 
308
 
 
309
    def __init__(self, branch):
 
310
        self.branch = branch
 
311
        self.repository = branch.repository
 
312
 
 
313
    def get_tag_dict(self):
 
314
        tags = {}
 
315
        for k, v in extract_tags(self.repository.get_refs()).iteritems():
 
316
            tags[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
 
317
        return tags
 
318
 
 
319
    def set_tag(self, name, revid):
 
320
        # FIXME: Not supported yet, should do a push of a new ref
 
321
        raise NotImplementedError(self.set_tag)
123
322
 
124
323
 
125
324
class RemoteGitBranch(GitBranch):
126
325
 
127
326
    def __init__(self, bzrdir, repository, name, lockfiles):
128
 
        def determine_wants(heads):
129
 
            if not name in heads:
130
 
                raise NoSuchRef(name)
131
 
            self._ref = heads[name]
132
 
        bzrdir.root_transport.fetch_pack(determine_wants, None, lambda x: None, 
133
 
                             lambda x: mutter("git: %s" % x))
134
 
        super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
 
327
        self._ref = None
 
328
        super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
 
329
                lockfiles)
 
330
 
 
331
    def revision_history(self):
 
332
        raise GitSmartRemoteNotSupported()
135
333
 
136
334
    def last_revision(self):
137
 
        return self.mapping.revision_id_foreign_to_bzr(self._ref)
 
335
        return self.mapping.revision_id_foreign_to_bzr(self.head)
 
336
 
 
337
    def _get_config(self):
 
338
        class EmptyConfig(object):
 
339
 
 
340
            def _get_configobj(self):
 
341
                return config.ConfigObj()
 
342
 
 
343
        return EmptyConfig()
 
344
 
 
345
    @property
 
346
    def head(self):
 
347
        if self._ref is not None:
 
348
            return self._ref
 
349
        heads = self.repository.get_refs()
 
350
        if self.name in heads:
 
351
            self._ref = heads[self.name]
 
352
        elif ("refs/heads/" + self.name) in heads:
 
353
            self._ref = heads["refs/heads/" + self.name]
 
354
        else:
 
355
            raise NoSuchRef(self.name)
 
356
        return self._ref
138
357
 
139
358
    def _synchronize_history(self, destination, revision_id):
140
359
        """See Branch._synchronize_history()."""
141
360
        destination.generate_revision_history(self.last_revision())
142
 
 
 
361
 
 
362
    def get_push_location(self):
 
363
        return None
 
364
 
 
365
    def set_push_location(self, url):
 
366
        pass