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
25
from bzrlib.errors import (
32
from bzrlib.trace import (
35
from bzrlib.transport import (
39
from bzrlib.plugins.git import (
44
from bzrlib.plugins.git.branch import (
48
from bzrlib.plugins.git.errors import (
49
GitSmartRemoteNotSupported,
52
from bzrlib.plugins.git.dir import (
55
from bzrlib.plugins.git.mapping import (
58
from bzrlib.plugins.git.repository import (
63
from dulwich.errors import (
66
from dulwich.pack import (
35
from dulwich.pack import PackData
75
from dulwich.pack import load_pack_index
78
# Don't run any tests on GitSmartTransport as it is not intended to be
79
# a full implementation of Transport
80
def get_test_permutations():
38
84
class GitSmartTransport(Transport):
40
86
def __init__(self, url, _client=None):
41
87
Transport.__init__(self, url)
42
88
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
assert scheme == "git"
44
89
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)
90
(self._username, hostport) = urllib.splituser(hostport)
91
(self._host, self._port) = urllib.splitnport(hostport, None)
92
self._client = _client
94
def external_url(self):
97
def has(self, relpath):
100
def _get_client(self, thin_packs):
101
raise NotImplementedError(self._get_client)
51
106
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
52
107
if progress is None:
53
108
def progress(text):
54
109
info("git: %s" % text)
55
self._client.fetch_pack(self._path, determine_wants, graph_walker,
110
client = self._get_client(thin_packs=False)
112
return client.fetch_pack(self._get_path(), determine_wants,
113
graph_walker, pack_data, progress)
114
except GitProtocolError, e:
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)
117
def send_pack(self, get_changed_refs, generate_pack_contents):
118
client = self._get_client(thin_packs=False)
64
for o in p.iterobjects():
120
return client.send_pack(self._get_path(), get_changed_refs,
121
generate_pack_contents)
122
except GitProtocolError, e:
69
125
def get(self, path):
70
126
raise NoSuchFile(path)
128
def abspath(self, relpath):
129
return urlutils.join(self.base, relpath)
72
131
def clone(self, offset=None):
73
132
"""See Transport.clone()."""
74
133
if offset is None:
77
136
newurl = urlutils.join(self.base, offset)
79
return GitSmartTransport(newurl, self._client)
138
return self.__class__(newurl, self._client)
141
class TCPGitSmartTransport(GitSmartTransport):
145
def _get_client(self, thin_packs):
146
if self._client is not None:
150
return git.client.TCPGitClient(self._host, self._port, thin_packs=thin_packs,
151
report_activity=self._report_activity)
154
class SSHGitSmartTransport(GitSmartTransport):
159
if self._path.startswith("/~/"):
160
return self._path[3:]
163
def _get_client(self, thin_packs):
164
if self._client is not None:
168
return git.client.SSHGitClient(self._host, self._port, self._username,
169
thin_packs=thin_packs, report_activity=self._report_activity)
82
172
class RemoteGitDir(GitDir):
99
190
raise NotLocalUrl(self.transport.base)
193
class EmptyObjectStoreIterator(dict):
195
def iterobjects(self):
199
class TemporaryPackIterator(Pack):
201
def __init__(self, path, resolve_ext_ref):
202
super(TemporaryPackIterator, self).__init__(path)
203
self.resolve_ext_ref = resolve_ext_ref
207
if self._data is None:
208
self._data = PackData(self._data_path)
213
if self._idx is None:
214
if not os.path.exists(self._idx_path):
215
pb = ui.ui_factory.nested_progress_bar()
217
def report_progress(cur, total):
218
pb.update("generating index", cur, total)
219
self.data.create_index(self._idx_path, self.resolve_ext_ref,
220
progress=report_progress)
223
self._idx = load_pack_index(self._idx_path)
227
os.remove(self._data_path)
228
os.remove(self._idx_path)
102
231
class RemoteGitRepository(GitRepository):
104
233
def __init__(self, gitdir, lockfiles):
105
234
GitRepository.__init__(self, gitdir, lockfiles)
238
def inventories(self):
239
raise GitSmartRemoteNotSupported()
243
raise GitSmartRemoteNotSupported()
247
raise GitSmartRemoteNotSupported()
250
if self._refs is not None:
252
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
253
lambda x: None, lambda x: trace.mutter("git: %s" % x))
107
256
def fetch_pack(self, determine_wants, graph_walker, pack_data,
109
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
258
return self._transport.fetch_pack(determine_wants, graph_walker,
261
def send_pack(self, get_changed_refs, generate_pack_contents):
262
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
264
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
265
fd, path = tempfile.mkstemp(suffix=".pack")
266
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
268
if os.path.getsize(path) == 0:
269
return EmptyObjectStoreIterator()
270
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
272
def lookup_git_revid(self, bzr_revid):
273
# This won't work for any round-tripped bzr revisions, but it's a start..
275
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
276
except InvalidRevisionId:
277
raise NoSuchRevision(self, bzr_revid)
280
class RemoteGitTagDict(tag.BasicTags):
282
def __init__(self, branch):
284
self.repository = branch.repository
286
def get_tag_dict(self):
287
return extract_tags(self.repository.get_refs(), self.branch.mapping)
289
def set_tag(self, name, revid):
290
# FIXME: Not supported yet, should do a push of a new ref
291
raise NotImplementedError(self.set_tag)
113
294
class RemoteGitBranch(GitBranch):
115
296
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))
120
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
298
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
301
def revision_history(self):
302
raise GitSmartRemoteNotSupported()
122
304
def last_revision(self):
123
return self.mapping.revision_id_foreign_to_bzr(self._ref)
305
return self.mapping.revision_id_foreign_to_bzr(self.head)
307
def _get_config(self):
308
class EmptyConfig(object):
310
def _get_configobj(self):
311
return config.ConfigObj()
317
if self._ref is not None:
319
heads = self.repository.get_refs()
320
if not self.name in heads:
321
raise NoSuchRef(self.name)
322
self._ref = heads[self.name]
325
def _synchronize_history(self, destination, revision_id):
326
"""See Branch._synchronize_history()."""
327
destination.generate_revision_history(self.last_revision())
329
def get_push_location(self):
332
def set_push_location(self, url):