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
89
hostport, self._path = urllib.splithost(loc)
48
(self._host, self._port) = urllib.splitnport(hostport, git.protocol.TCP_GIT_PORT)
90
(self._username, hostport) = urllib.splituser(hostport)
91
(self._host, self._port) = urllib.splitnport(hostport, None)
49
92
self._client = _client
51
def _get_client(self):
52
if self._client is not None:
56
return git.client.TCPGitClient(self._host, self._port)
94
def external_url(self):
97
def has(self, relpath):
100
def _get_client(self, thin_packs):
101
raise NotImplementedError(self._get_client)
58
106
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
59
107
if progress is None:
60
108
def progress(text):
61
109
info("git: %s" % text)
62
self._get_client().fetch_pack(self._path, determine_wants,
63
graph_walker, pack_data, progress)
110
client = self._get_client(thin_packs=False)
112
return client.fetch_pack(self._get_path(), determine_wants,
113
graph_walker, pack_data, progress)
114
except GitProtocolError, e:
117
def send_pack(self, get_changed_refs, generate_pack_contents):
118
client = self._get_client(thin_packs=False)
120
return client.send_pack(self._get_path(), get_changed_refs,
121
generate_pack_contents)
122
except GitProtocolError, e:
65
125
def get(self, path):
66
126
raise NoSuchFile(path)
85
176
self.root_transport = transport
86
177
self.transport = transport
87
178
self._lockfiles = lockfiles
179
self._mode_check_done = None
89
181
def open_repository(self):
90
182
return RemoteGitRepository(self, self._lockfiles)
92
def open_branch(self):
184
def open_branch(self, ignore_fallbacks=False):
93
185
repo = self.open_repository()
94
186
# TODO: Support for multiple branches in one bzrdir in bzrlib!
95
187
return RemoteGitBranch(self, repo, "HEAD", self._lockfiles)
97
def open_workingtree(self):
189
def open_workingtree(self, recommend_upgrade=False):
98
190
raise NotLocalUrl(self.transport.base)
193
class EmptyObjectStoreIterator(dict):
195
def iterobjects(self):
199
class TemporaryPackIterator(Pack):
201
def __init__(self, path, resolve_ext_ref):
202
super(TemporaryPackIterator, self).__init__(path)
203
self.resolve_ext_ref = resolve_ext_ref
207
if self._data is None:
208
self._data = PackData(self._data_path)
213
if self._idx is None:
214
if not os.path.exists(self._idx_path):
215
pb = ui.ui_factory.nested_progress_bar()
217
def report_progress(cur, total):
218
pb.update("generating index", cur, total)
219
self.data.create_index(self._idx_path, self.resolve_ext_ref,
220
progress=report_progress)
223
self._idx = load_pack_index(self._idx_path)
227
if self._idx is not None:
229
os.remove(self._idx_path)
230
if self._data is not None:
232
os.remove(self._data_path)
101
235
class RemoteGitRepository(GitRepository):
103
237
def __init__(self, gitdir, lockfiles):
104
238
GitRepository.__init__(self, gitdir, lockfiles)
242
def inventories(self):
243
raise GitSmartRemoteNotSupported()
247
raise GitSmartRemoteNotSupported()
251
raise GitSmartRemoteNotSupported()
254
if self._refs is not None:
256
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
257
lambda x: None, lambda x: trace.mutter("git: %s" % x))
106
260
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):
262
return self._transport.fetch_pack(determine_wants, graph_walker,
265
def send_pack(self, get_changed_refs, generate_pack_contents):
266
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
268
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
112
269
fd, path = tempfile.mkstemp(suffix=".pack")
113
270
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
272
if os.path.getsize(path) == 0:
273
return EmptyObjectStoreIterator()
274
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
276
def lookup_bzr_revision_id(self, bzr_revid):
277
# 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():
279
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
280
except InvalidRevisionId:
281
raise NoSuchRevision(self, bzr_revid)
284
class RemoteGitTagDict(tag.BasicTags):
286
def __init__(self, branch):
288
self.repository = branch.repository
290
def get_tag_dict(self):
292
for k, v in extract_tags(self.repository.get_refs()).iteritems():
293
tags[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
296
def set_tag(self, name, revid):
297
# FIXME: Not supported yet, should do a push of a new ref
298
raise NotImplementedError(self.set_tag)
125
301
class RemoteGitBranch(GitBranch):
127
303
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)
305
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
308
def revision_history(self):
309
raise GitSmartRemoteNotSupported()
136
311
def last_revision(self):
137
return self.mapping.revision_id_foreign_to_bzr(self._ref)
312
return self.mapping.revision_id_foreign_to_bzr(self.head)
314
def _get_config(self):
315
class EmptyConfig(object):
317
def _get_configobj(self):
318
return config.ConfigObj()
324
if self._ref is not None:
326
heads = self.repository.get_refs()
327
if not self.name in heads:
328
raise NoSuchRef(self.name)
329
self._ref = heads[self.name]
139
332
def _synchronize_history(self, destination, revision_id):
140
333
"""See Branch._synchronize_history()."""
141
334
destination.generate_revision_history(self.last_revision())
336
def get_push_location(self):
339
def set_push_location(self, url):