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 (
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 (
38
from dulwich.pack import PackData, Pack
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():
41
86
class GitSmartTransport(Transport):
43
88
def __init__(self, url, _client=None):
44
89
Transport.__init__(self, url)
45
90
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
46
assert scheme == "git"
47
91
hostport, self._path = urllib.splithost(loc)
48
(self._host, self._port) = urllib.splitnport(hostport, git.protocol.TCP_GIT_PORT)
92
(self._host, self._port) = urllib.splitnport(hostport, None)
49
93
self._client = _client
95
def has(self, relpath):
51
98
def _get_client(self):
52
if self._client is not None:
56
return git.client.TCPGitClient(self._host, self._port)
99
raise NotImplementedError(self._get_client)
58
101
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
59
102
if progress is None:
60
103
def progress(text):
61
104
info("git: %s" % text)
62
self._get_client().fetch_pack(self._path, determine_wants,
63
graph_walker, pack_data, progress)
105
client = self._get_client()
107
return client.fetch_pack(self._path, determine_wants,
108
graph_walker, pack_data, progress)
109
except GitProtocolError, e:
112
def send_pack(self, get_changed_refs, generate_pack_contents):
113
client = self._get_client()
115
client.send_pack(self._path, get_changed_refs,
116
generate_pack_contents)
117
except GitProtocolError, e:
65
120
def get(self, path):
66
121
raise NoSuchFile(path)
76
131
newurl = urlutils.join(self.base, offset)
78
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)
81
162
class RemoteGitDir(GitDir):
98
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)
101
216
class RemoteGitRepository(GitRepository):
103
218
def __init__(self, gitdir, lockfiles):
104
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))
106
241
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):
243
return self._transport.fetch_pack(determine_wants, graph_walker,
246
def send_pack(self, get_changed_refs, generate_pack_contents):
247
self._transport.send_pack(get_changed_refs, generate_pack_contents)
249
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
112
250
fd, path = tempfile.mkstemp(suffix=".pack")
113
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..
116
basename = path[:-len(".pack")]
118
p.create_index_v2(basename+".idx")
119
for o in Pack(basename).iterobjects():
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)
125
285
class RemoteGitBranch(GitBranch):
127
287
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))
288
heads = repository.get_refs()
289
if not name in heads:
290
raise NoSuchRef(name)
291
self._ref = heads[name]
134
292
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
294
def revision_history(self):
295
raise GitSmartRemoteNotSupported()
136
297
def last_revision(self):
137
298
return self.mapping.revision_id_foreign_to_bzr(self._ref)