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.errors import NoSuchRef
29
from bzrlib.plugins.git.dir import GitDir
30
from bzrlib.plugins.git.foreign import ForeignBranch
31
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 (
38
from dulwich.pack import PackData, Pack
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():
41
87
class GitSmartTransport(Transport):
43
89
def __init__(self, url, _client=None):
44
90
Transport.__init__(self, url)
45
91
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
46
assert scheme == "git"
47
92
hostport, self._path = urllib.splithost(loc)
48
(self._host, self._port) = urllib.splitnport(hostport, git.protocol.TCP_GIT_PORT)
93
(self._host, self._port) = urllib.splitnport(hostport, None)
49
94
self._client = _client
96
def has(self, relpath):
51
99
def _get_client(self):
52
if self._client is not None:
56
return git.client.TCPGitClient(self._host, self._port)
100
raise NotImplementedError(self._get_client)
58
102
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
59
103
if progress is None:
60
104
def progress(text):
61
105
info("git: %s" % text)
62
self._get_client().fetch_pack(self._path, determine_wants,
63
graph_walker, pack_data, progress)
106
client = self._get_client()
108
return client.fetch_pack(self._path, determine_wants,
109
graph_walker, pack_data, progress)
110
except GitProtocolError, e:
113
def send_pack(self, get_changed_refs, generate_pack_contents):
114
client = self._get_client()
116
return client.send_pack(self._path, get_changed_refs,
117
generate_pack_contents)
118
except GitProtocolError, e:
65
121
def get(self, path):
66
122
raise NoSuchFile(path)
98
181
raise NotLocalUrl(self.transport.base)
184
class EmptyObjectStoreIterator(dict):
186
def iterobjects(self):
190
class TemporaryPackIterator(Pack):
192
def __init__(self, path, resolve_ext_ref):
193
super(TemporaryPackIterator, self).__init__(path)
194
self.resolve_ext_ref = resolve_ext_ref
198
if self._idx is None:
199
if self._data is None:
200
self._data = PackData(self._data_path)
201
pb = ui.ui_factory.nested_progress_bar()
203
def report_progress(cur, total):
204
pb.update("generating index", cur, total)
205
self._data.create_index_v2(self._idx_path, self.resolve_ext_ref,
206
progress=report_progress)
209
self._idx = load_pack_index(self._idx_path)
213
os.remove(self._data_path)
214
os.remove(self._idx_path)
101
217
class RemoteGitRepository(GitRepository):
103
219
def __init__(self, gitdir, lockfiles):
104
220
GitRepository.__init__(self, gitdir, lockfiles)
224
def inventories(self):
225
raise GitSmartRemoteNotSupported()
229
raise GitSmartRemoteNotSupported()
233
raise GitSmartRemoteNotSupported()
236
if self._refs is not None:
238
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
239
lambda x: None, lambda x: mutter("git: %s" % x))
106
242
def fetch_pack(self, determine_wants, graph_walker, pack_data,
108
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
111
def fetch_objects(self, determine_wants, graph_walker, progress=None):
244
return self._transport.fetch_pack(determine_wants, graph_walker,
247
def send_pack(self, get_changed_refs, generate_pack_contents):
248
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
250
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
112
251
fd, path = tempfile.mkstemp(suffix=".pack")
113
252
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
254
if os.path.getsize(path) == 0:
255
return EmptyObjectStoreIterator()
256
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
258
def lookup_git_revid(self, bzr_revid):
259
# This won't work for any round-tripped bzr revisions, but it's a start..
116
basename = path[:-len(".pack")]
118
p.create_index_v2(basename+".idx")
119
for o in Pack(basename).iterobjects():
261
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
262
except InvalidRevisionId:
263
raise NoSuchRevision(self, bzr_revid)
266
class RemoteGitTagDict(tag.BasicTags):
268
def __init__(self, branch):
270
self.repository = branch.repository
272
def get_tag_dict(self):
273
return extract_tags(self.repository.get_refs(), self.branch.mapping)
275
def set_tag(self, name, revid):
276
# FIXME: Not supported yet, should do a push of a new ref
277
raise NotImplementedError(self.set_tag)
125
280
class RemoteGitBranch(GitBranch):
127
282
def __init__(self, bzrdir, repository, name, lockfiles):
128
def determine_wants(heads):
129
if not name in heads:
130
raise NoSuchRef(name)
131
self._ref = heads[name]
132
bzrdir.root_transport.fetch_pack(determine_wants, None, lambda x: None,
133
lambda x: mutter("git: %s" % x))
134
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
284
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
287
def revision_history(self):
288
raise GitSmartRemoteNotSupported()
136
290
def last_revision(self):
137
return self.mapping.revision_id_foreign_to_bzr(self._ref)
291
return self.mapping.revision_id_foreign_to_bzr(self.head)
295
if self._ref is not None:
297
heads = self.repository.get_refs()
298
if not self.name in heads:
299
raise NoSuchRef(name)
300
self._ref = heads[self.name]
139
303
def _synchronize_history(self, destination, revision_id):
140
304
"""See Branch._synchronize_history()."""