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.dir import GitDir
29
from bzrlib.plugins.git.foreign import ForeignBranch
30
from bzrlib.plugins.git.repository import GitFormat, GitRepository
24
from bzrlib.errors import (
31
from bzrlib.trace import (
34
from bzrlib.transport import (
38
from bzrlib.plugins.git import (
43
from bzrlib.plugins.git.branch import (
47
from bzrlib.plugins.git.errors import (
48
GitSmartRemoteNotSupported,
51
from bzrlib.plugins.git.dir import (
54
from bzrlib.plugins.git.mapping import (
57
from bzrlib.plugins.git.repository import (
63
from dulwich.errors import (
66
from dulwich.pack import (
35
from dulwich.pack import PackData
76
from dulwich.pack import load_pack_index
78
from dulwich.pack import PackIndex as load_pack_index
81
# Don't run any tests on GitSmartTransport as it is not intended to be
82
# a full implementation of Transport
83
def get_test_permutations():
38
87
class GitSmartTransport(Transport):
40
89
def __init__(self, url, _client=None):
41
90
Transport.__init__(self, url)
42
91
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
assert scheme == "git"
44
92
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
49
self._client = git.client.TCPGitClient(self._host, self._port)
93
(self._username, hostport) = urllib.splituser(hostport)
94
(self._host, self._port) = urllib.splitnport(hostport, None)
95
self._client = _client
97
def external_url(self):
100
def has(self, relpath):
103
def _get_client(self, thin_packs):
104
raise NotImplementedError(self._get_client)
51
109
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
52
110
if progress is None:
53
111
def progress(text):
54
112
info("git: %s" % text)
55
self._client.fetch_pack(self._path, determine_wants, graph_walker,
113
client = self._get_client(thin_packs=False)
115
return client.fetch_pack(self._get_path(), determine_wants,
116
graph_walker, pack_data, progress)
117
except GitProtocolError, e:
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)
120
def send_pack(self, get_changed_refs, generate_pack_contents):
121
client = self._get_client(thin_packs=False)
64
for o in p.iterobjects():
123
return client.send_pack(self._get_path(), get_changed_refs,
124
generate_pack_contents)
125
except GitProtocolError, e:
69
128
def get(self, path):
70
129
raise NoSuchFile(path)
131
def abspath(self, relpath):
132
return urlutils.join(self.base, relpath)
72
134
def clone(self, offset=None):
73
135
"""See Transport.clone()."""
74
136
if offset is None:
77
139
newurl = urlutils.join(self.base, offset)
79
return GitSmartTransport(newurl, self._client)
141
return self.__class__(newurl, self._client)
144
class TCPGitSmartTransport(GitSmartTransport):
148
def _get_client(self, thin_packs):
149
if self._client is not None:
153
return git.client.TCPGitClient(self._host, self._port, thin_packs=thin_packs,
154
report_activity=self._report_activity)
157
class SSHGitSmartTransport(GitSmartTransport):
162
if self._path.startswith("/~/"):
163
return self._path[3:]
166
def _get_client(self, thin_packs):
167
if self._client is not None:
171
return git.client.SSHGitClient(self._host, self._port, self._username,
172
thin_packs=thin_packs, report_activity=self._report_activity)
82
175
class RemoteGitDir(GitDir):
99
193
raise NotLocalUrl(self.transport.base)
196
class EmptyObjectStoreIterator(dict):
198
def iterobjects(self):
202
class TemporaryPackIterator(Pack):
204
def __init__(self, path, resolve_ext_ref):
205
super(TemporaryPackIterator, self).__init__(path)
206
self.resolve_ext_ref = resolve_ext_ref
210
if self._idx is None:
211
if not os.path.exists(self._idx_path):
212
pb = ui.ui_factory.nested_progress_bar()
214
def report_progress(cur, total):
215
pb.update("generating index", cur, total)
216
self.data.create_index(self._idx_path, self.resolve_ext_ref,
217
progress=report_progress)
220
self._idx = load_pack_index(self._idx_path)
224
os.remove(self._data_path)
225
os.remove(self._idx_path)
102
228
class RemoteGitRepository(GitRepository):
104
230
def __init__(self, gitdir, lockfiles):
105
231
GitRepository.__init__(self, gitdir, lockfiles)
235
def inventories(self):
236
raise GitSmartRemoteNotSupported()
240
raise GitSmartRemoteNotSupported()
244
raise GitSmartRemoteNotSupported()
247
if self._refs is not None:
249
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
250
lambda x: None, lambda x: mutter("git: %s" % x))
107
253
def fetch_pack(self, determine_wants, graph_walker, pack_data,
109
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
255
return self._transport.fetch_pack(determine_wants, graph_walker,
258
def send_pack(self, get_changed_refs, generate_pack_contents):
259
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
261
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
262
fd, path = tempfile.mkstemp(suffix=".pack")
263
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
265
if os.path.getsize(path) == 0:
266
return EmptyObjectStoreIterator()
267
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
269
def lookup_git_revid(self, bzr_revid):
270
# This won't work for any round-tripped bzr revisions, but it's a start..
272
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
273
except InvalidRevisionId:
274
raise NoSuchRevision(self, bzr_revid)
277
class RemoteGitTagDict(tag.BasicTags):
279
def __init__(self, branch):
281
self.repository = branch.repository
283
def get_tag_dict(self):
284
return extract_tags(self.repository.get_refs(), self.branch.mapping)
286
def set_tag(self, name, revid):
287
# FIXME: Not supported yet, should do a push of a new ref
288
raise NotImplementedError(self.set_tag)
113
291
class RemoteGitBranch(GitBranch):
115
293
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)
295
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
298
def revision_history(self):
299
raise GitSmartRemoteNotSupported()
122
301
def last_revision(self):
123
return self.mapping.revision_id_foreign_to_bzr(self._ref)
302
return self.mapping.revision_id_foreign_to_bzr(self.head)
306
if self._ref is not None:
308
heads = self.repository.get_refs()
309
if not self.name in heads:
310
raise NoSuchRef(name)
311
self._ref = heads[self.name]
314
def _synchronize_history(self, destination, revision_id):
315
"""See Branch._synchronize_history()."""
316
destination.generate_revision_history(self.last_revision())
318
def get_push_location(self):
321
def set_push_location(self, url):