15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
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
25
from bzrlib.errors import (
32
from bzrlib.trace import (
35
from bzrlib.transport import (
39
from bzrlib.plugins.git import (
44
from bzrlib.plugins.git.branch import (
48
from bzrlib.plugins.git.errors import (
49
GitSmartRemoteNotSupported,
52
from bzrlib.plugins.git.dir import (
55
from bzrlib.plugins.git.mapping import (
58
from bzrlib.plugins.git.repository import (
63
from dulwich.errors import (
66
from dulwich.pack import (
38
from dulwich.pack import PackData, Pack
75
from dulwich.pack import load_pack_index
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():
41
84
class GitSmartTransport(Transport):
43
86
def __init__(self, url, _client=None):
44
87
Transport.__init__(self, url)
45
88
(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)
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)
49
93
self._client = _client
51
def _get_client(self):
52
if self._client is not None:
56
return git.client.TCPGitClient(self._host, self._port)
95
def external_url(self):
98
def has(self, relpath):
101
def _get_client(self, thin_packs):
102
raise NotImplementedError(self._get_client)
58
107
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
59
108
if progress is None:
60
109
def progress(text):
61
110
info("git: %s" % text)
62
self._get_client().fetch_pack(self._path, determine_wants,
63
graph_walker, pack_data, progress)
111
client = self._get_client(thin_packs=False)
113
return client.fetch_pack(self._get_path(), determine_wants,
114
graph_walker, pack_data, progress)
115
except GitProtocolError, e:
118
def send_pack(self, get_changed_refs, generate_pack_contents):
119
client = self._get_client(thin_packs=False)
121
return client.send_pack(self._get_path(), get_changed_refs,
122
generate_pack_contents)
123
except GitProtocolError, e:
65
126
def get(self, path):
66
127
raise NoSuchFile(path)
85
177
self.root_transport = transport
86
178
self.transport = transport
87
179
self._lockfiles = lockfiles
180
self._mode_check_done = None
89
182
def open_repository(self):
90
183
return RemoteGitRepository(self, self._lockfiles)
92
def open_branch(self):
185
def open_branch(self, ignore_fallbacks=False):
93
186
repo = self.open_repository()
94
187
# TODO: Support for multiple branches in one bzrdir in bzrlib!
95
188
return RemoteGitBranch(self, repo, "HEAD", self._lockfiles)
97
def open_workingtree(self):
190
def open_workingtree(self, recommend_upgrade=False):
98
191
raise NotLocalUrl(self.transport.base)
194
class EmptyObjectStoreIterator(dict):
196
def iterobjects(self):
200
class TemporaryPackIterator(Pack):
202
def __init__(self, path, resolve_ext_ref):
203
super(TemporaryPackIterator, self).__init__(path)
204
self.resolve_ext_ref = resolve_ext_ref
208
if self._data is None:
209
self._data = PackData(self._data_path)
214
if self._idx is None:
215
if not os.path.exists(self._idx_path):
216
pb = ui.ui_factory.nested_progress_bar()
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)
224
self._idx = load_pack_index(self._idx_path)
228
if self._idx is not None:
230
os.remove(self._idx_path)
231
if self._data is not None:
233
os.remove(self._data_path)
101
236
class RemoteGitRepository(GitRepository):
103
238
def __init__(self, gitdir, lockfiles):
104
239
GitRepository.__init__(self, gitdir, lockfiles)
106
def fetch_pack(self, determine_wants, graph_walker, pack_data,
243
def inventories(self):
244
raise GitSmartRemoteNotSupported()
248
raise GitSmartRemoteNotSupported()
252
raise GitSmartRemoteNotSupported()
255
if self._refs is not None:
257
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
258
lambda x: None, lambda x: trace.mutter("git: %s" % x))
261
def fetch_pack(self, determine_wants, graph_walker, pack_data,
108
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
111
def fetch_objects(self, determine_wants, graph_walker, progress=None):
263
return self._transport.fetch_pack(determine_wants, graph_walker,
266
def send_pack(self, get_changed_refs, generate_pack_contents):
267
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
269
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
112
271
fd, path = tempfile.mkstemp(suffix=".pack")
113
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
272
self.fetch_pack(determine_wants, graph_walker,
273
lambda x: os.write(fd, x), progress)
275
if os.path.getsize(path) == 0:
276
return EmptyObjectStoreIterator()
277
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
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..
116
basename = path[:-len(".pack")]
118
p.create_index_v2(basename+".idx")
119
for o in Pack(basename).iterobjects():
282
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
283
except InvalidRevisionId:
284
raise NoSuchRevision(self, bzr_revid)
287
class RemoteGitTagDict(tag.BasicTags):
289
def __init__(self, branch):
291
self.repository = branch.repository
293
def get_tag_dict(self):
295
for k, v in extract_tags(self.repository.get_refs()).iteritems():
296
tags[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
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)
125
304
class RemoteGitBranch(GitBranch):
127
306
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)
308
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
311
def revision_history(self):
312
raise GitSmartRemoteNotSupported()
136
314
def last_revision(self):
137
return self.mapping.revision_id_foreign_to_bzr(self._ref)
315
return self.mapping.revision_id_foreign_to_bzr(self.head)
317
def _get_config(self):
318
class EmptyConfig(object):
320
def _get_configobj(self):
321
return config.ConfigObj()
327
if self._ref is not None:
329
heads = self.repository.get_refs()
330
if not self.name in heads:
331
raise NoSuchRef(self.name)
332
self._ref = heads[self.name]
139
335
def _synchronize_history(self, destination, revision_id):
140
336
"""See Branch._synchronize_history()."""
141
337
destination.generate_revision_history(self.last_revision())
339
def get_push_location(self):
342
def set_push_location(self, url):