14
14
# along with this program; if not, write to the Free Software
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
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 (
62
from dulwich.errors import (
65
from dulwich.pack import (
35
from dulwich.pack import PackData
74
from dulwich.pack import load_pack_index
77
# Don't run any tests on GitSmartTransport as it is not intended to be
78
# a full implementation of Transport
79
def get_test_permutations():
38
83
class GitSmartTransport(Transport):
40
85
def __init__(self, url, _client=None):
41
86
Transport.__init__(self, url)
42
87
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
assert scheme == "git"
44
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)
88
hostport, escaped_path = urllib.splithost(loc)
89
self._path = urllib.unquote(escaped_path)
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:
86
176
self.root_transport = transport
87
177
self.transport = transport
88
178
self._lockfiles = lockfiles
179
self._mode_check_done = None
90
181
def open_repository(self):
91
182
return RemoteGitRepository(self, self._lockfiles)
93
def open_branch(self):
184
def open_branch(self, ignore_fallbacks=False):
94
185
repo = self.open_repository()
95
186
# TODO: Support for multiple branches in one bzrdir in bzrlib!
96
187
return RemoteGitBranch(self, repo, "HEAD", self._lockfiles)
98
def open_workingtree(self):
189
def open_workingtree(self, recommend_upgrade=False):
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
if self._idx is not None:
229
os.remove(self._idx_path)
230
if self._data is not None:
232
os.remove(self._data_path)
102
235
class RemoteGitRepository(GitRepository):
104
237
def __init__(self, gitdir, lockfiles):
105
238
GitRepository.__init__(self, gitdir, lockfiles)
107
def fetch_pack(self, determine_wants, graph_walker, pack_data,
242
def inventories(self):
243
raise GitSmartRemoteNotSupported()
247
raise GitSmartRemoteNotSupported()
251
raise GitSmartRemoteNotSupported()
254
if self._refs is not None:
256
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
257
lambda x: None, lambda x: trace.mutter("git: %s" % x))
260
def fetch_pack(self, determine_wants, graph_walker, pack_data,
109
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
262
return self._transport.fetch_pack(determine_wants, graph_walker,
265
def send_pack(self, get_changed_refs, generate_pack_contents):
266
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
268
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
270
fd, path = tempfile.mkstemp(suffix=".pack")
271
self.fetch_pack(determine_wants, graph_walker,
272
lambda x: os.write(fd, x), progress)
274
if os.path.getsize(path) == 0:
275
return EmptyObjectStoreIterator()
276
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
278
def lookup_bzr_revision_id(self, bzr_revid):
279
# This won't work for any round-tripped bzr revisions, but it's a start..
281
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
282
except InvalidRevisionId:
283
raise NoSuchRevision(self, bzr_revid)
286
class RemoteGitTagDict(tag.BasicTags):
288
def __init__(self, branch):
290
self.repository = branch.repository
292
def get_tag_dict(self):
294
for k, v in extract_tags(self.repository.get_refs()).iteritems():
295
tags[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
298
def set_tag(self, name, revid):
299
# FIXME: Not supported yet, should do a push of a new ref
300
raise NotImplementedError(self.set_tag)
113
303
class RemoteGitBranch(GitBranch):
115
305
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)
307
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
310
def revision_history(self):
311
raise GitSmartRemoteNotSupported()
122
313
def last_revision(self):
123
return self.mapping.revision_id_foreign_to_bzr(self._ref)
314
return self.mapping.revision_id_foreign_to_bzr(self.head)
316
def _get_config(self):
317
class EmptyConfig(object):
319
def _get_configobj(self):
320
return config.ConfigObj()
326
if self._ref is not None:
328
heads = self.repository.get_refs()
329
if not self.name in heads:
330
raise NoSuchRef(self.name)
331
self._ref = heads[self.name]
334
def _synchronize_history(self, destination, revision_id):
335
"""See Branch._synchronize_history()."""
336
destination.generate_revision_history(self.last_revision())
338
def get_push_location(self):
341
def set_push_location(self, url):