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 (
46
from bzrlib.plugins.git.errors import (
47
GitSmartRemoteNotSupported,
50
from bzrlib.plugins.git.dir import (
53
from bzrlib.plugins.git.mapping import (
56
from bzrlib.plugins.git.repository import (
62
from dulwich.errors import (
65
from dulwich.pack import (
35
from dulwich.pack import PackData
75
from dulwich.pack import load_pack_index
77
from dulwich.pack import PackIndex as load_pack_index
80
# Don't run any tests on GitSmartTransport as it is not intended to be
81
# a full implementation of Transport
82
def get_test_permutations():
38
86
class GitSmartTransport(Transport):
40
88
def __init__(self, url, _client=None):
41
89
Transport.__init__(self, url)
42
90
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
assert scheme == "git"
44
91
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)
92
(self._host, self._port) = urllib.splitnport(hostport, None)
93
self._client = _client
95
def has(self, relpath):
98
def _get_client(self):
99
raise NotImplementedError(self._get_client)
51
101
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
52
102
if progress is None:
53
103
def progress(text):
54
104
info("git: %s" % text)
55
self._client.fetch_pack(self._path, determine_wants, graph_walker,
105
client = self._get_client()
107
return client.fetch_pack(self._path, determine_wants,
108
graph_walker, pack_data, progress)
109
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)
112
def send_pack(self, get_changed_refs, generate_pack_contents):
113
client = self._get_client()
64
for o in p.iterobjects():
115
return client.send_pack(self._path, get_changed_refs,
116
generate_pack_contents)
117
except GitProtocolError, e:
69
120
def get(self, path):
70
121
raise NoSuchFile(path)
123
def abspath(self, relpath):
124
return urlutils.join(self.base, relpath)
72
126
def clone(self, offset=None):
73
127
"""See Transport.clone()."""
74
128
if offset is None:
77
131
newurl = urlutils.join(self.base, offset)
79
return GitSmartTransport(newurl, self._client)
133
return self.__class__(newurl, self._client)
136
class TCPGitSmartTransport(GitSmartTransport):
140
def _get_client(self):
141
if self._client is not None:
145
return git.client.TCPGitClient(self._host, self._port, thin_packs=False,
146
report_activity=self._report_activity)
149
class SSHGitSmartTransport(GitSmartTransport):
153
def _get_client(self):
154
if self._client is not None:
158
return git.client.SSHGitClient(self._host, self._port, thin_packs=False,
159
report_activity=self._report_activity)
82
162
class RemoteGitDir(GitDir):
99
180
raise NotLocalUrl(self.transport.base)
183
class EmptyObjectStoreIterator(dict):
185
def iterobjects(self):
189
class TemporaryPackIterator(Pack):
191
def __init__(self, path, resolve_ext_ref):
192
super(TemporaryPackIterator, self).__init__(path)
193
self.resolve_ext_ref = resolve_ext_ref
197
if self._idx is None:
198
if self._data is None:
199
self._data = PackData(self._data_path)
200
pb = ui.ui_factory.nested_progress_bar()
202
def report_progress(cur, total):
203
pb.update("generating index", cur, total)
204
self._data.create_index_v2(self._idx_path, self.resolve_ext_ref,
205
progress=report_progress)
208
self._idx = load_pack_index(self._idx_path)
212
os.remove(self._data_path)
213
os.remove(self._idx_path)
102
216
class RemoteGitRepository(GitRepository):
104
218
def __init__(self, gitdir, lockfiles):
105
219
GitRepository.__init__(self, gitdir, lockfiles)
223
def inventories(self):
224
raise GitSmartRemoteNotSupported()
228
raise GitSmartRemoteNotSupported()
232
raise GitSmartRemoteNotSupported()
235
if self._refs is not None:
237
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
238
lambda x: None, lambda x: mutter("git: %s" % x))
107
241
def fetch_pack(self, determine_wants, graph_walker, pack_data,
109
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
243
return self._transport.fetch_pack(determine_wants, graph_walker,
246
def send_pack(self, get_changed_refs, generate_pack_contents):
247
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
249
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
250
fd, path = tempfile.mkstemp(suffix=".pack")
251
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
253
if os.path.getsize(path) == 0:
254
return EmptyObjectStoreIterator()
255
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
257
def lookup_git_revid(self, bzr_revid):
258
# This won't work for any round-tripped bzr revisions, but it's a start..
260
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
261
except InvalidRevisionId:
262
raise NoSuchRevision(self, bzr_revid)
265
class RemoteGitTagDict(tag.BasicTags):
267
def __init__(self, branch):
269
self.repository = branch.repository
271
def get_tag_dict(self):
273
refs = self.repository.get_refs()
274
for k,v in refs.iteritems():
275
if k.startswith("refs/tags/") and not k.endswith("^{}"):
276
v = refs.get(k+"^{}", v)
277
ret[k[len("refs/tags/"):]] = self.branch.mapping.revision_id_foreign_to_bzr(v)
280
def set_tag(self, name, revid):
281
# FIXME: Not supported yet, should do a push of a new ref
282
raise NotImplementedError(self.set_tag)
113
285
class RemoteGitBranch(GitBranch):
115
287
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)
289
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
292
def revision_history(self):
293
raise GitSmartRemoteNotSupported()
122
295
def last_revision(self):
123
return self.mapping.revision_id_foreign_to_bzr(self._ref)
296
return self.mapping.revision_id_foreign_to_bzr(self.head)
300
if self._ref is None:
302
heads = repository.get_refs()
303
if not name in heads:
304
raise NoSuchRef(name)
305
self._ref = heads[name]
308
def _synchronize_history(self, destination, revision_id):
309
"""See Branch._synchronize_history()."""
310
destination.generate_revision_history(self.last_revision())