15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 (
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
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():
35
from dulwich.pack import PackData
87
38
class GitSmartTransport(Transport):
89
40
def __init__(self, url, _client=None):
90
41
Transport.__init__(self, url)
91
42
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
assert scheme == "git"
92
44
hostport, self._path = urllib.splithost(loc)
93
(self._username, hostport) = urllib.splituser(hostport)
94
(self._host, self._port) = urllib.splitnport(hostport, None)
95
self._client = _client
97
def has(self, relpath):
100
def _get_client(self):
101
raise NotImplementedError(self._get_client)
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)
106
51
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
107
52
if progress is None:
108
53
def progress(text):
109
54
info("git: %s" % text)
110
client = self._get_client()
112
return client.fetch_pack(self._get_path(), determine_wants,
113
graph_walker, pack_data, progress)
114
except GitProtocolError, e:
55
self._client.fetch_pack(self._path, determine_wants, graph_walker,
117
def send_pack(self, get_changed_refs, generate_pack_contents):
118
client = self._get_client()
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
return client.send_pack(self._get_path(), get_changed_refs,
121
generate_pack_contents)
122
except GitProtocolError, e:
64
for o in p.iterobjects():
125
69
def get(self, path):
126
70
raise NoSuchFile(path)
128
def abspath(self, relpath):
129
return urlutils.join(self.base, relpath)
131
72
def clone(self, offset=None):
132
73
"""See Transport.clone()."""
133
74
if offset is None:
136
77
newurl = urlutils.join(self.base, offset)
138
return self.__class__(newurl, self._client)
141
class TCPGitSmartTransport(GitSmartTransport):
145
def _get_client(self):
146
if self._client is not None:
150
return git.client.TCPGitClient(self._host, self._port, thin_packs=False,
151
report_activity=self._report_activity)
154
class SSHGitSmartTransport(GitSmartTransport):
159
if self._path.startswith("/~/"):
160
return self._path[3:]
163
def _get_client(self):
164
if self._client is not None:
168
return git.client.SSHGitClient(self._host, self._port, self._username,
169
thin_packs=False, report_activity=self._report_activity)
79
return GitSmartTransport(newurl, self._client)
172
82
class RemoteGitDir(GitDir):
190
99
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._idx is None:
208
pb = ui.ui_factory.nested_progress_bar()
210
def report_progress(cur, total):
211
pb.update("generating index", cur, total)
212
self.data.create_index(self._idx_path, self.resolve_ext_ref,
213
progress=report_progress)
216
self._idx = load_pack_index(self._idx_path)
220
os.remove(self._data_path)
221
os.remove(self._idx_path)
224
102
class RemoteGitRepository(GitRepository):
226
104
def __init__(self, gitdir, lockfiles):
227
105
GitRepository.__init__(self, gitdir, lockfiles)
231
def inventories(self):
232
raise GitSmartRemoteNotSupported()
236
raise GitSmartRemoteNotSupported()
240
raise GitSmartRemoteNotSupported()
243
if self._refs is not None:
245
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
246
lambda x: None, lambda x: mutter("git: %s" % x))
249
107
def fetch_pack(self, determine_wants, graph_walker, pack_data,
251
return self._transport.fetch_pack(determine_wants, graph_walker,
254
def send_pack(self, get_changed_refs, generate_pack_contents):
255
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
257
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
258
fd, path = tempfile.mkstemp(suffix=".pack")
259
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
261
if os.path.getsize(path) == 0:
262
return EmptyObjectStoreIterator()
263
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
265
def lookup_git_revid(self, bzr_revid):
266
# This won't work for any round-tripped bzr revisions, but it's a start..
268
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
269
except InvalidRevisionId:
270
raise NoSuchRevision(self, bzr_revid)
273
class RemoteGitTagDict(tag.BasicTags):
275
def __init__(self, branch):
277
self.repository = branch.repository
279
def get_tag_dict(self):
280
return extract_tags(self.repository.get_refs(), self.branch.mapping)
282
def set_tag(self, name, revid):
283
# FIXME: Not supported yet, should do a push of a new ref
284
raise NotImplementedError(self.set_tag)
109
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
287
113
class RemoteGitBranch(GitBranch):
289
115
def __init__(self, bzrdir, repository, name, lockfiles):
291
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
294
def revision_history(self):
295
raise GitSmartRemoteNotSupported()
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)
297
122
def last_revision(self):
298
return self.mapping.revision_id_foreign_to_bzr(self.head)
302
if self._ref is not None:
304
heads = self.repository.get_refs()
305
if not self.name in heads:
306
raise NoSuchRef(name)
307
self._ref = heads[self.name]
310
def _synchronize_history(self, destination, revision_id):
311
"""See Branch._synchronize_history()."""
312
destination.generate_revision_history(self.last_revision())
314
def get_push_location(self):
317
def set_push_location(self, url):
123
return self.mapping.revision_id_foreign_to_bzr(self._ref)