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
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
def determine_wants(heads):
240
self.bzrdir.root_transport.fetch_pack(determine_wants, None,
241
lambda x: None, lambda x: mutter("git: %s" % x))
106
244
def fetch_pack(self, determine_wants, graph_walker, pack_data,
108
246
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
111
def fetch_objects(self, determine_wants, graph_walker, progress=None):
249
def send_pack(self, get_changed_refs, generate_pack_contents):
250
self._transport.send_pack(get_changed_refs, generate_pack_contents)
252
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
112
253
fd, path = tempfile.mkstemp(suffix=".pack")
113
254
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
256
if os.path.getsize(path) == 0:
257
return EmptyObjectStoreIterator()
258
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
260
def lookup_git_revid(self, bzr_revid):
261
# 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():
263
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
264
except InvalidRevisionId:
265
raise NoSuchRevision(self, bzr_revid)
268
class RemoteGitTagDict(tag.BasicTags):
270
def __init__(self, branch):
272
self.repository = branch.repository
274
def get_tag_dict(self):
276
refs = self.repository.get_refs()
277
for k,v in refs.iteritems():
278
if k.startswith("refs/tags/") and not k.endswith("^{}"):
279
v = refs.get(k+"^{}", v)
280
ret[k[len("refs/tags/"):]] = self.branch.mapping.revision_id_foreign_to_bzr(v)
283
def set_tag(self, name, revid):
284
# FIXME: Not supported yet, should do a push of a new ref
285
raise NotImplementedError(self.set_tag)
125
288
class RemoteGitBranch(GitBranch):
127
290
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))
291
heads = repository.get_refs()
292
if not name in heads:
293
raise NoSuchRef(name)
294
self._ref = heads[name]
134
295
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
297
def revision_history(self):
298
raise GitSmartRemoteNotSupported()
136
300
def last_revision(self):
137
301
return self.mapping.revision_id_foreign_to_bzr(self._ref)