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.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
25
from bzrlib.errors import (
32
from bzrlib.transport import (
36
from bzrlib.plugins.git import (
41
from bzrlib.plugins.git.branch import (
45
from bzrlib.plugins.git.errors import (
46
GitSmartRemoteNotSupported,
49
from bzrlib.plugins.git.dir import (
52
from bzrlib.plugins.git.mapping import (
55
from bzrlib.plugins.git.repository import (
60
from dulwich.errors import (
63
from dulwich.pack import (
38
from dulwich.pack import PackData, Pack
71
urlparse.uses_netloc.extend(['git', 'git+ssh'])
73
from dulwich.pack import load_pack_index
76
# Don't run any tests on GitSmartTransport as it is not intended to be
77
# a full implementation of Transport
78
def get_test_permutations():
82
def split_git_url(url):
86
:return: Tuple with host, port, username, path.
88
(scheme, netloc, loc, _, _) = urlparse.urlsplit(url)
89
path = urllib.unquote(loc)
90
if path.startswith("/~"):
92
(username, hostport) = urllib.splituser(netloc)
93
(host, port) = urllib.splitnport(hostport, None)
94
return (host, port, username, path)
41
97
class GitSmartTransport(Transport):
43
99
def __init__(self, url, _client=None):
44
100
Transport.__init__(self, url)
45
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
46
assert scheme == "git"
47
hostport, self._path = urllib.splithost(loc)
48
(self._host, self._port) = urllib.splitnport(hostport, git.protocol.TCP_GIT_PORT)
101
(self._host, self._port, self._username, self._path) = \
103
if 'transport' in debug.debug_flags:
104
trace.mutter('host: %r, user: %r, port: %r, path: %r',
105
self._host, self._username, self._port, self._path)
49
106
self._client = _client
51
def _get_client(self):
52
if self._client is not None:
56
return git.client.TCPGitClient(self._host, self._port)
108
def external_url(self):
111
def has(self, relpath):
114
def _get_client(self, thin_packs):
115
raise NotImplementedError(self._get_client)
58
120
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
59
121
if progress is None:
60
122
def progress(text):
61
info("git: %s" % text)
62
self._get_client().fetch_pack(self._path, determine_wants,
63
graph_walker, pack_data, progress)
123
trace.info("git: %s" % text)
124
client = self._get_client(thin_packs=False)
126
return client.fetch_pack(self._get_path(), determine_wants,
127
graph_walker, pack_data, progress)
128
except GitProtocolError, e:
131
def send_pack(self, get_changed_refs, generate_pack_contents):
132
client = self._get_client(thin_packs=False)
134
return client.send_pack(self._get_path(), get_changed_refs,
135
generate_pack_contents)
136
except GitProtocolError, e:
65
139
def get(self, path):
66
140
raise NoSuchFile(path)
85
190
self.root_transport = transport
86
191
self.transport = transport
87
192
self._lockfiles = lockfiles
193
self._mode_check_done = None
195
def _branch_name_to_ref(self, name):
196
from bzrlib.plugins.git.branch import branch_name_to_ref
197
return branch_name_to_ref(name, default="refs/heads/master")
89
199
def open_repository(self):
90
200
return RemoteGitRepository(self, self._lockfiles)
92
def open_branch(self):
202
def _open_branch(self, name=None, ignore_fallbacks=False,
93
204
repo = self.open_repository()
94
# TODO: Support for multiple branches in one bzrdir in bzrlib!
95
return RemoteGitBranch(self, repo, "HEAD", self._lockfiles)
205
refname = self._branch_name_to_ref(name)
206
return RemoteGitBranch(self, repo, refname, self._lockfiles)
97
def open_workingtree(self):
208
def open_workingtree(self, recommend_upgrade=False):
98
209
raise NotLocalUrl(self.transport.base)
212
class EmptyObjectStoreIterator(dict):
214
def iterobjects(self):
218
class TemporaryPackIterator(Pack):
220
def __init__(self, path, resolve_ext_ref):
221
super(TemporaryPackIterator, self).__init__(path)
222
self.resolve_ext_ref = resolve_ext_ref
226
if self._data is None:
227
self._data = PackData(self._data_path)
232
if self._idx is None:
233
if not os.path.exists(self._idx_path):
234
pb = ui.ui_factory.nested_progress_bar()
236
def report_progress(cur, total):
237
pb.update("generating index", cur, total)
238
self.data.create_index(self._idx_path, self.resolve_ext_ref,
239
progress=report_progress)
242
self._idx = load_pack_index(self._idx_path)
246
if self._idx is not None:
248
os.remove(self._idx_path)
249
if self._data is not None:
251
os.remove(self._data_path)
101
254
class RemoteGitRepository(GitRepository):
103
256
def __init__(self, gitdir, lockfiles):
104
257
GitRepository.__init__(self, gitdir, lockfiles)
106
def fetch_pack(self, determine_wants, graph_walker, pack_data,
261
def inventories(self):
262
raise GitSmartRemoteNotSupported()
266
raise GitSmartRemoteNotSupported()
270
raise GitSmartRemoteNotSupported()
273
if self._refs is not None:
275
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
276
lambda x: None, lambda x: trace.mutter("git: %s" % x))
279
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):
281
return self._transport.fetch_pack(determine_wants, graph_walker,
284
def send_pack(self, get_changed_refs, generate_pack_contents):
285
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
287
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
112
289
fd, path = tempfile.mkstemp(suffix=".pack")
113
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
290
self.fetch_pack(determine_wants, graph_walker,
291
lambda x: os.write(fd, x), progress)
293
if os.path.getsize(path) == 0:
294
return EmptyObjectStoreIterator()
295
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
297
def lookup_bzr_revision_id(self, bzr_revid):
298
# 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():
300
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
301
except InvalidRevisionId:
302
raise NoSuchRevision(self, bzr_revid)
305
class RemoteGitTagDict(tag.BasicTags):
307
def __init__(self, branch):
309
self.repository = branch.repository
311
def get_tag_dict(self):
313
for k, v in extract_tags(self.repository.get_refs()).iteritems():
314
tags[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
317
def set_tag(self, name, revid):
318
# FIXME: Not supported yet, should do a push of a new ref
319
raise NotImplementedError(self.set_tag)
125
322
class RemoteGitBranch(GitBranch):
127
324
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))
134
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
326
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
329
def revision_history(self):
330
raise GitSmartRemoteNotSupported()
136
332
def last_revision(self):
137
return self.mapping.revision_id_foreign_to_bzr(self._ref)
333
return self.mapping.revision_id_foreign_to_bzr(self.head)
335
def _get_config(self):
336
class EmptyConfig(object):
338
def _get_configobj(self):
339
return config.ConfigObj()
345
if self._ref is not None:
347
heads = self.repository.get_refs()
348
if self.name in heads:
349
self._ref = heads[self.name]
350
elif ("refs/heads/" + self.name) in heads:
351
self._ref = heads["refs/heads/" + self.name]
353
raise NoSuchRef(self.name)
139
356
def _synchronize_history(self, destination, revision_id):
140
357
"""See Branch._synchronize_history()."""
141
358
destination.generate_revision_history(self.last_revision())
360
def get_push_location(self):
363
def set_push_location(self, url):