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,
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)
105
client = self._get_client()
64
for o in p.iterobjects():
107
client.fetch_pack(self._path, determine_wants,
108
graph_walker, pack_data, progress)
109
except GitProtocolError, e:
69
112
def get(self, path):
70
113
raise NoSuchFile(path)
115
def abspath(self, relpath):
116
return urlutils.join(self.base, relpath)
72
118
def clone(self, offset=None):
73
119
"""See Transport.clone()."""
74
120
if offset is None:
77
123
newurl = urlutils.join(self.base, offset)
79
return GitSmartTransport(newurl, self._client)
125
return self.__class__(newurl, self._client)
128
class TCPGitSmartTransport(GitSmartTransport):
132
def _get_client(self):
133
if self._client is not None:
137
return git.client.TCPGitClient(self._host, self._port, thin_packs=False,
138
report_activity=self._report_activity)
141
class SSHGitSmartTransport(GitSmartTransport):
145
def _get_client(self):
146
if self._client is not None:
150
return git.client.SSHGitClient(self._host, self._port, thin_packs=False,
151
report_activity=self._report_activity)
82
154
class RemoteGitDir(GitDir):
99
172
raise NotLocalUrl(self.transport.base)
175
class EmptyObjectStoreIterator(dict):
177
def iterobjects(self):
181
class TemporaryPackIterator(Pack):
183
def __init__(self, path, resolve_ext_ref):
184
super(TemporaryPackIterator, self).__init__(path)
185
self.resolve_ext_ref = resolve_ext_ref
189
if self._idx is None:
190
if self._data is None:
191
self._data = PackData(self._data_path)
192
pb = ui.ui_factory.nested_progress_bar()
194
def report_progress(cur, total):
195
pb.update("generating index", cur, total)
196
self._data.create_index_v2(self._idx_path, self.resolve_ext_ref,
197
progress=report_progress)
200
self._idx = load_pack_index(self._idx_path)
204
os.remove(self._data_path)
205
os.remove(self._idx_path)
102
208
class RemoteGitRepository(GitRepository):
104
210
def __init__(self, gitdir, lockfiles):
105
211
GitRepository.__init__(self, gitdir, lockfiles)
215
def inventories(self):
216
raise GitSmartRemoteNotSupported()
220
raise GitSmartRemoteNotSupported()
224
raise GitSmartRemoteNotSupported()
227
if self._refs is not None:
229
def determine_wants(heads):
232
self.bzrdir.root_transport.fetch_pack(determine_wants, None,
233
lambda x: None, lambda x: mutter("git: %s" % x))
107
236
def fetch_pack(self, determine_wants, graph_walker, pack_data,
109
238
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
241
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
242
fd, path = tempfile.mkstemp(suffix=".pack")
243
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
245
if os.path.getsize(path) == 0:
246
return EmptyObjectStoreIterator()
247
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
249
def lookup_git_revid(self, bzr_revid):
250
# This won't work for any round-tripped bzr revisions, but it's a start..
252
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
253
except InvalidRevisionId:
254
raise NoSuchRevision(self, bzr_revid)
257
class RemoteGitTagDict(tag.BasicTags):
259
def __init__(self, branch):
261
self.repository = branch.repository
263
def get_tag_dict(self):
265
refs = self.repository.get_refs()
266
for k,v in refs.iteritems():
267
if k.startswith("refs/tags/") and not k.endswith("^{}"):
268
v = refs.get(k+"^{}", v)
269
ret[k[len("refs/tags/"):]] = self.branch.mapping.revision_id_foreign_to_bzr(v)
272
def set_tag(self, name, revid):
273
# FIXME: Not supported yet, should do a push of a new ref
274
raise NotImplementedError(self.set_tag)
113
277
class RemoteGitBranch(GitBranch):
115
279
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))
280
heads = repository.get_refs()
281
if not name in heads:
282
raise NoSuchRef(name)
283
self._ref = heads[name]
120
284
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
286
def revision_history(self):
287
raise GitSmartRemoteNotSupported()
122
289
def last_revision(self):
123
290
return self.mapping.revision_id_foreign_to_bzr(self._ref)
292
def _synchronize_history(self, destination, revision_id):
293
"""See Branch._synchronize_history()."""
294
destination.generate_revision_history(self.last_revision())