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 (
29
from bzrlib.trace import (
32
from bzrlib.transport import (
36
from bzrlib.plugins.git import (
41
from bzrlib.plugins.git.branch import (
44
from bzrlib.plugins.git.errors import (
45
GitSmartRemoteNotSupported,
48
from bzrlib.plugins.git.dir import (
51
from bzrlib.plugins.git.repository import (
57
from dulwich.errors import (
60
from dulwich.pack import (
35
from dulwich.pack import PackData
70
from dulwich.pack import load_pack_index
72
from dulwich.pack import PackIndex as load_pack_index
75
# Don't run any tests on GitSmartTransport as it is not intended to be
76
# a full implementation of Transport
77
def get_test_permutations():
38
81
class GitSmartTransport(Transport):
40
83
def __init__(self, url, _client=None):
41
84
Transport.__init__(self, url)
42
85
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
assert scheme == "git"
44
86
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)
87
(self._host, self._port) = urllib.splitnport(hostport, None)
88
self._client = _client
90
def has(self, relpath):
93
def _get_client(self):
94
raise NotImplementedError(self._get_client)
51
96
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
52
97
if progress is None:
53
98
def progress(text):
54
99
info("git: %s" % text)
55
self._client.fetch_pack(self._path, determine_wants, graph_walker,
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)
100
client = self._get_client()
64
for o in p.iterobjects():
102
client.fetch_pack(self._path, determine_wants,
103
graph_walker, pack_data, progress)
104
except GitProtocolError, e:
69
107
def get(self, path):
70
108
raise NoSuchFile(path)
110
def abspath(self, relpath):
111
return urlutils.join(self.base, relpath)
72
113
def clone(self, offset=None):
73
114
"""See Transport.clone()."""
74
115
if offset is None:
77
118
newurl = urlutils.join(self.base, offset)
79
return GitSmartTransport(newurl, self._client)
120
return self.__class__(newurl, self._client)
123
class TCPGitSmartTransport(GitSmartTransport):
127
def _get_client(self):
128
if self._client is not None:
132
return git.client.TCPGitClient(self._host, self._port, thin_packs=False,
133
report_activity=self._report_activity)
136
class SSHGitSmartTransport(GitSmartTransport):
140
def _get_client(self):
141
if self._client is not None:
145
return git.client.SSHGitClient(self._host, self._port, thin_packs=False,
146
report_activity=self._report_activity)
82
149
class RemoteGitDir(GitDir):
99
167
raise NotLocalUrl(self.transport.base)
170
class EmptyObjectStoreIterator(dict):
172
def iterobjects(self):
176
class TemporaryPackIterator(Pack):
178
def __init__(self, path, resolve_ext_ref):
179
super(TemporaryPackIterator, self).__init__(path)
180
self.resolve_ext_ref = resolve_ext_ref
184
if self._idx is None:
185
if self._data is None:
186
self._data = PackData(self._data_path)
187
pb = ui.ui_factory.nested_progress_bar()
189
def report_progress(cur, total):
190
pb.update("generating index", cur, total)
191
self._data.create_index_v2(self._idx_path, self.resolve_ext_ref,
192
progress=report_progress)
195
self._idx = load_pack_index(self._idx_path)
199
os.remove(self._data_path)
200
os.remove(self._idx_path)
102
203
class RemoteGitRepository(GitRepository):
104
205
def __init__(self, gitdir, lockfiles):
105
206
GitRepository.__init__(self, gitdir, lockfiles)
210
def inventories(self):
211
raise GitSmartRemoteNotSupported()
215
raise GitSmartRemoteNotSupported()
219
raise GitSmartRemoteNotSupported()
222
if self._refs is not None:
224
def determine_wants(heads):
227
self.bzrdir.root_transport.fetch_pack(determine_wants, None,
228
lambda x: None, lambda x: mutter("git: %s" % x))
107
231
def fetch_pack(self, determine_wants, graph_walker, pack_data,
109
233
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
236
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
237
fd, path = tempfile.mkstemp(suffix=".pack")
238
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
240
if os.path.getsize(path) == 0:
241
return EmptyObjectStoreIterator()
242
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
245
class RemoteGitTagDict(tag.BasicTags):
247
def __init__(self, branch):
249
self.repository = branch.repository
251
def get_tag_dict(self):
253
refs = self.repository.get_refs()
254
for k,v in refs.iteritems():
255
if k.startswith("refs/tags/") and not k.endswith("^{}"):
256
v = refs.get(k+"^{}", v)
257
ret[k[len("refs/tags/"):]] = self.branch.mapping.revision_id_foreign_to_bzr(v)
260
def set_tag(self, name, revid):
261
# FIXME: Not supported yet, should do a push of a new ref
262
raise NotImplementedError(self.set_tag)
113
265
class RemoteGitBranch(GitBranch):
115
267
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))
268
heads = repository.get_refs()
269
if not name in heads:
270
raise NoSuchRef(name)
271
self._ref = heads[name]
120
272
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
274
def revision_history(self):
275
raise GitSmartRemoteNotSupported()
122
277
def last_revision(self):
123
278
return self.mapping.revision_id_foreign_to_bzr(self._ref)
280
def _synchronize_history(self, destination, revision_id):
281
"""See Branch._synchronize_history()."""
282
destination.generate_revision_history(self.last_revision())