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
23
from bzrlib.bzrdir import (
27
from bzrlib.errors import (
32
from bzrlib.lockable_files import (
35
from bzrlib.repository import (
38
from bzrlib.trace import (
41
from bzrlib.transport import (
45
from bzrlib.plugins.git import (
50
from bzrlib.plugins.git.branch import (
53
from bzrlib.plugins.git.errors import (
54
GitSmartRemoteNotSupported,
57
from bzrlib.plugins.git.dir import (
60
from bzrlib.plugins.git.foreign import (
63
from bzrlib.plugins.git.repository import (
69
from dulwich.errors import (
72
from dulwich.pack import (
35
from dulwich.pack import PackData
82
from dulwich.pack import load_pack_index
84
from dulwich.pack import PackIndex as load_pack_index
87
# Don't run any tests on GitSmartTransport as it is not intended to be
88
# a full implementation of Transport
89
def get_test_permutations():
38
93
class GitSmartTransport(Transport):
40
95
def __init__(self, url, _client=None):
41
96
Transport.__init__(self, url)
42
97
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
assert scheme == "git"
44
98
hostport, self._path = urllib.splithost(loc)
45
99
(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)
100
self._client = _client
102
def has(self, relpath):
105
def _get_client(self):
106
raise NotImplementedError(self._get_client)
51
108
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
52
109
if progress is None:
53
110
def progress(text):
54
111
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)
112
client = self._get_client()
64
for o in p.iterobjects():
114
client.fetch_pack(self._path, determine_wants,
115
graph_walker, pack_data, progress)
116
except GitProtocolError, e:
69
119
def get(self, path):
70
120
raise NoSuchFile(path)
122
def abspath(self, relpath):
123
return urlutils.join(self.base, relpath)
72
125
def clone(self, offset=None):
73
126
"""See Transport.clone()."""
74
127
if offset is None:
77
130
newurl = urlutils.join(self.base, offset)
79
return GitSmartTransport(newurl, self._client)
132
return self.__class__(newurl, self._client)
135
class TCPGitSmartTransport(GitSmartTransport):
137
def _get_client(self):
138
if self._client is not None:
142
return git.client.TCPGitClient(self._host, self._port, thin_packs=False)
145
class SSHGitSmartTransport(GitSmartTransport):
147
def _get_client(self):
148
if self._client is not None:
152
return git.client.SSHGitClient(self._host, self._port, thin_packs=False)
82
155
class RemoteGitDir(GitDir):
99
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
self._data.create_index_v2(self._idx_path, self.resolve_ext_ref)
193
self._idx = load_pack_index(self._idx_path)
197
os.remove(self._data_path)
198
os.remove(self._idx_path)
102
201
class RemoteGitRepository(GitRepository):
104
203
def __init__(self, gitdir, lockfiles):
105
204
GitRepository.__init__(self, gitdir, lockfiles)
208
def inventories(self):
209
raise GitSmartRemoteNotSupported()
213
raise GitSmartRemoteNotSupported()
217
raise GitSmartRemoteNotSupported()
220
if self._refs is not None:
222
def determine_wants(heads):
225
self.bzrdir.root_transport.fetch_pack(determine_wants, None,
226
lambda x: None, lambda x: mutter("git: %s" % x))
107
229
def fetch_pack(self, determine_wants, graph_walker, pack_data,
109
231
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
234
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
235
fd, path = tempfile.mkstemp(suffix=".pack")
236
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
238
if os.path.getsize(path) == 0:
239
return EmptyObjectStoreIterator()
240
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
243
class RemoteGitTagDict(tag.BasicTags):
245
def __init__(self, branch):
247
self.repository = branch.repository
249
def get_tag_dict(self):
251
refs = self.repository.get_refs()
252
for k,v in refs.iteritems():
253
if k.startswith("refs/tags/") and not k.endswith("^{}"):
254
v = refs.get(k+"^{}", v)
255
ret[k[len("refs/tags/"):]] = self.branch.mapping.revision_id_foreign_to_bzr(v)
258
def set_tag(self, name, revid):
259
# FIXME: Not supported yet, should do a push of a new ref
260
raise NotImplementedError(self.set_tag)
113
263
class RemoteGitBranch(GitBranch):
115
265
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))
266
heads = repository.get_refs()
267
if not name in heads:
268
raise NoSuchRef(name)
269
self._ref = heads[name]
120
270
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
122
272
def last_revision(self):
123
273
return self.mapping.revision_id_foreign_to_bzr(self._ref)
275
def _synchronize_history(self, destination, revision_id):
276
"""See Branch._synchronize_history()."""
277
destination.generate_revision_history(self.last_revision())