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:
65
112
def get(self, path):
66
113
raise NoSuchFile(path)
76
123
newurl = urlutils.join(self.base, offset)
78
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)
81
154
class RemoteGitDir(GitDir):
98
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)
101
208
class RemoteGitRepository(GitRepository):
103
210
def __init__(self, gitdir, lockfiles):
104
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))
106
236
def fetch_pack(self, determine_wants, graph_walker, pack_data,
108
238
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
111
def fetch_objects(self, determine_wants, graph_walker, progress=None):
241
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
112
242
fd, path = tempfile.mkstemp(suffix=".pack")
113
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..
116
basename = path[:-len(".pack")]
118
p.create_index_v2(basename+".idx")
119
for o in Pack(basename).iterobjects():
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)
125
277
class RemoteGitBranch(GitBranch):
127
279
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))
280
heads = repository.get_refs()
281
if not name in heads:
282
raise NoSuchRef(name)
283
self._ref = heads[name]
134
284
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
286
def revision_history(self):
287
raise GitSmartRemoteNotSupported()
136
289
def last_revision(self):
137
290
return self.mapping.revision_id_foreign_to_bzr(self._ref)