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
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 (
35
from dulwich.pack import PackData
74
from dulwich.pack import load_pack_index
77
# Don't run any tests on GitSmartTransport as it is not intended to be
78
# a full implementation of Transport
79
def get_test_permutations():
38
83
class GitSmartTransport(Transport):
40
85
def __init__(self, url, _client=None):
41
86
Transport.__init__(self, url)
42
87
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
assert scheme == "git"
44
88
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)
89
(self._username, hostport) = urllib.splituser(hostport)
90
(self._host, self._port) = urllib.splitnport(hostport, None)
91
self._client = _client
93
def external_url(self):
96
def has(self, relpath):
99
def _get_client(self, thin_packs):
100
raise NotImplementedError(self._get_client)
51
105
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
52
106
if progress is None:
53
107
def progress(text):
54
108
info("git: %s" % text)
55
self._client.fetch_pack(self._path, determine_wants, graph_walker,
109
client = self._get_client(thin_packs=False)
111
return client.fetch_pack(self._get_path(), determine_wants,
112
graph_walker, pack_data, progress)
113
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)
116
def send_pack(self, get_changed_refs, generate_pack_contents):
117
client = self._get_client(thin_packs=False)
64
for o in p.iterobjects():
119
return client.send_pack(self._get_path(), get_changed_refs,
120
generate_pack_contents)
121
except GitProtocolError, e:
69
124
def get(self, path):
70
125
raise NoSuchFile(path)
127
def abspath(self, relpath):
128
return urlutils.join(self.base, relpath)
72
130
def clone(self, offset=None):
73
131
"""See Transport.clone()."""
74
132
if offset is None:
77
135
newurl = urlutils.join(self.base, offset)
79
return GitSmartTransport(newurl, self._client)
137
return self.__class__(newurl, self._client)
140
class TCPGitSmartTransport(GitSmartTransport):
144
def _get_client(self, thin_packs):
145
if self._client is not None:
149
return git.client.TCPGitClient(self._host, self._port, thin_packs=thin_packs,
150
report_activity=self._report_activity)
153
class SSHGitSmartTransport(GitSmartTransport):
158
if self._path.startswith("/~/"):
159
return self._path[3:]
162
def _get_client(self, thin_packs):
163
if self._client is not None:
167
return git.client.SSHGitClient(self._host, self._port, self._username,
168
thin_packs=thin_packs, report_activity=self._report_activity)
82
171
class RemoteGitDir(GitDir):
99
189
raise NotLocalUrl(self.transport.base)
192
class EmptyObjectStoreIterator(dict):
194
def iterobjects(self):
198
class TemporaryPackIterator(Pack):
200
def __init__(self, path, resolve_ext_ref):
201
super(TemporaryPackIterator, self).__init__(path)
202
self.resolve_ext_ref = resolve_ext_ref
206
if self._idx is None:
207
if not os.path.exists(self._idx_path):
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)
102
224
class RemoteGitRepository(GitRepository):
104
226
def __init__(self, gitdir, lockfiles):
105
227
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: trace.mutter("git: %s" % x))
107
249
def fetch_pack(self, determine_wants, graph_walker, pack_data,
109
self._transport.fetch_pack(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)
113
287
class RemoteGitBranch(GitBranch):
115
289
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)
291
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
294
def revision_history(self):
295
raise GitSmartRemoteNotSupported()
122
297
def last_revision(self):
123
return self.mapping.revision_id_foreign_to_bzr(self._ref)
298
return self.mapping.revision_id_foreign_to_bzr(self.head)
300
def _get_config(self):
301
class EmptyConfig(object):
303
def _get_configobj(self):
304
return config.ConfigObj()
310
if self._ref is not None:
312
heads = self.repository.get_refs()
313
if not self.name in heads:
314
raise NoSuchRef(self.name)
315
self._ref = heads[self.name]
318
def _synchronize_history(self, destination, revision_id):
319
"""See Branch._synchronize_history()."""
320
destination.generate_revision_history(self.last_revision())
322
def get_push_location(self):
325
def set_push_location(self, url):