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 (
56
from bzrlib.plugins.git.dir import (
59
from bzrlib.plugins.git.foreign import (
62
from bzrlib.plugins.git.repository import (
68
from dulwich.errors import (
71
from dulwich.pack import (
35
from dulwich.pack import PackData
81
from dulwich.pack import load_pack_index
83
from dulwich.pack import PackIndex as load_pack_index
86
# Don't run any tests on GitSmartTransport as it is not intended to be
87
# a full implementation of Transport
88
def get_test_permutations():
38
92
class GitSmartTransport(Transport):
40
94
def __init__(self, url, _client=None):
41
95
Transport.__init__(self, url)
42
96
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
43
assert scheme == "git"
44
97
hostport, self._path = urllib.splithost(loc)
45
98
(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)
99
self._client = _client
101
def has(self, relpath):
104
def _get_client(self):
105
raise NotImplementedError(self._get_client)
51
107
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
52
108
if progress is None:
53
109
def progress(text):
54
110
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)
111
client = self._get_client()
64
for o in p.iterobjects():
113
client.fetch_pack(self._path, determine_wants,
114
graph_walker, pack_data, progress)
115
except GitProtocolError, e:
69
118
def get(self, path):
70
119
raise NoSuchFile(path)
121
def abspath(self, relpath):
122
return urlutils.join(self.base, relpath)
72
124
def clone(self, offset=None):
73
125
"""See Transport.clone()."""
74
126
if offset is None:
77
129
newurl = urlutils.join(self.base, offset)
79
return GitSmartTransport(newurl, self._client)
131
return self.__class__(newurl, self._client)
134
class TCPGitSmartTransport(GitSmartTransport):
136
def _get_client(self):
137
if self._client is not None:
141
return git.client.TCPGitClient(self._host, self._port, thin_packs=False)
144
class SSHGitSmartTransport(GitSmartTransport):
146
def _get_client(self):
147
if self._client is not None:
151
return git.client.SSHGitClient(self._host, self._port, thin_packs=False)
82
154
class RemoteGitDir(GitDir):
99
171
raise NotLocalUrl(self.transport.base)
174
class EmptyObjectStoreIterator(dict):
176
def iterobjects(self):
180
class TemporaryPackIterator(Pack):
182
def __init__(self, path, resolve_ext_ref):
183
super(TemporaryPackIterator, self).__init__(path)
184
self.resolve_ext_ref = resolve_ext_ref
188
if self._idx is None:
189
if self._data is None:
190
self._data = PackData(self._data_path)
191
self._data.create_index_v2(self._idx_path, self.resolve_ext_ref)
192
self._idx = load_pack_index(self._idx_path)
196
os.remove(self._data_path)
197
os.remove(self._idx_path)
102
200
class RemoteGitRepository(GitRepository):
104
202
def __init__(self, gitdir, lockfiles):
105
203
GitRepository.__init__(self, gitdir, lockfiles)
207
if self._refs is not None:
209
def determine_wants(heads):
212
self.bzrdir.root_transport.fetch_pack(determine_wants, None,
213
lambda x: None, lambda x: mutter("git: %s" % x))
107
216
def fetch_pack(self, determine_wants, graph_walker, pack_data,
109
218
self._transport.fetch_pack(determine_wants, graph_walker, pack_data,
221
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
222
fd, path = tempfile.mkstemp(suffix=".pack")
223
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
225
if os.path.getsize(path) == 0:
226
return EmptyObjectStoreIterator()
227
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
230
class RemoteGitTagDict(tag.BasicTags):
232
def __init__(self, branch):
234
self.repository = branch.repository
236
def get_tag_dict(self):
238
refs = self.repository.get_refs()
239
for k,v in refs.iteritems():
240
if k.startswith("refs/tags/") and not k.endswith("^{}"):
241
v = refs.get(k+"^{}", v)
242
ret[k[len("refs/tags/"):]] = self.branch.mapping.revision_id_foreign_to_bzr(v)
245
def set_tag(self, name, revid):
246
# FIXME: Not supported yet, should do a push of a new ref
247
raise NotImplementedError(self.set_tag)
113
250
class RemoteGitBranch(GitBranch):
115
252
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))
253
heads = repository.get_refs()
254
if not name in heads:
255
raise NoSuchRef(name)
256
self._ref = heads[name]
120
257
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
122
259
def last_revision(self):
123
260
return self.mapping.revision_id_foreign_to_bzr(self._ref)
262
def _synchronize_history(self, destination, revision_id):
263
"""See Branch._synchronize_history()."""
264
destination.generate_revision_history(self.last_revision())