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
17
19
from bzrlib.bzrdir import BzrDir, BzrDirFormat
18
from bzrlib.errors import NotLocalUrl
19
from bzrlib.foreign import ForeignRepository
20
from bzrlib.errors import NoSuchFile, NotLocalUrl
20
21
from bzrlib.lockable_files import TransportLock
22
from bzrlib.plugins.git import git
23
from bzrlib.plugins.git.repository import GitFormat
22
from bzrlib.repository import Repository
24
23
from bzrlib.trace import info
25
24
from bzrlib.transport import Transport
27
from git.client import TCPGitClient, TCP_GIT_PORT
26
from bzrlib.plugins.git import git
27
from bzrlib.plugins.git.branch import GitBranch
28
from bzrlib.plugins.git.foreign import ForeignBranch
29
from bzrlib.plugins.git.repository import GitFormat, GitRepository
33
35
class GitSmartTransport(Transport):
35
def __init__(self, url):
37
def __init__(self, url, _client=None):
36
38
Transport.__init__(self, url)
37
(scheme, netloc, self._path, _, _) = urlparse.urlsplit(url)
39
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
38
40
assert scheme == "git"
39
(self._host, self._port) = urllib.splitnport(netloc, TCP_GIT_PORT)
40
self._client = TCPGitClient(self._host, self._port)
41
hostport, self._path = urllib.splithost(loc)
42
(self._host, self._port) = urllib.splitnport(hostport, git.protocol.TCP_GIT_PORT)
43
if _client is not None:
44
self._client = _client
46
self._client = git.client.TCPGitClient(self._host, self._port)
42
def fetch_pack(self, determine_wants, graph_walker, pack_data):
44
info("git: %s" % text)
48
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
51
info("git: %s" % text)
45
52
self._client.fetch_pack(self._path, determine_wants, graph_walker,
46
53
pack_data, progress)
56
raise NoSuchFile(path)
58
def clone(self, offset=None):
59
"""See Transport.clone()."""
63
newurl = urlutils.join(self.base, offset)
65
return GitSmartTransport(newurl, self._client)
49
68
class RemoteGitDir(BzrDir):
51
_gitrepository_class = RemoteGitRepository
53
def __init__(self, transport, lockfiles, gitrepo, format):
70
def __init__(self, transport, lockfiles, format):
54
71
self._format = format
55
72
self.root_transport = transport
57
73
self.transport = transport
58
74
self._lockfiles = lockfiles
66
82
def open_branch(self):
67
83
repo = self.open_repository()
68
84
# TODO: Support for multiple branches in one bzrdir in bzrlib!
69
return RemoteGitBranch(repo, "HEAD")
85
return RemoteGitBranch(self, repo, "HEAD", self._lockfiles)
71
87
def open_workingtree(self):
72
88
raise NotLocalUrl(self.transport.base)
75
class RemoteGitRepository(ForeignRepository):
90
def cloning_metadir(self, stacked=False):
91
"""Produce a metadir suitable for cloning with."""
93
return bzrlib.bzrdir.format_registry.make_bzrdir("1.6.1-rich-root")
95
return bzrlib.bzrdir.format_registry.make_bzrdir("rich-root-pack")
98
class RemoteGitRepository(GitRepository):
77
100
def __init__(self, gitdir, lockfiles):
78
Repository.__init__(self, GitFormat(), gitdir, lockfiles)
101
GitRepository.__init__(self, gitdir, lockfiles)
80
103
def fetch_pack(self, determine_wants, graph_walker, pack_data):
81
104
self._transport.fetch_pack(determine_wants, graph_walker, pack_data)
84
def RemoteGitBranch(ForeignBranch):
86
def __init__(self, repository, name):
87
super(RemoteGitBranch, self).__init__(repository.get_mapping())
88
self.repository = repository
92
class RemoteGitBzrDirFormat(BzrDirFormat):
93
"""The .git directory control format."""
95
_gitdir_class = RemoteGitDir
96
_lock_class = TransportLock
99
def _known_formats(self):
100
return set([GitBzrDirFormat()])
102
def open(self, transport, _found=None):
103
"""Open this directory.
106
from bzrlib.plugins.git import git
107
# we dont grok readonly - git isn't integrated with transport.
109
if url.startswith('readonly+'):
110
url = url[len('readonly+'):]
113
gitrepo = git.repo.Repo(transport.local_abspath("."))
114
except errors.bzr_errors.NotLocalUrl:
115
raise errors.bzr_errors.NotBranchError(path=transport.base)
116
lockfiles = GitLockableFiles(transport, GitLock())
117
return self._gitdir_class(transport, lockfiles, gitrepo, self)
120
def probe_transport(klass, transport):
121
"""Our format is present if the transport ends in '.not/'."""
122
# little ugly, but works
124
# delegate to the main opening code. This pays a double rtt cost at the
125
# moment, so perhaps we want probe_transport to return the opened thing
126
# rather than an openener ? or we could return a curried thing with the
127
# dir to open already instantiated ? Needs more thought.
129
format.open(transport)
132
raise errors.bzr_errors.NotBranchError(path=transport.base)
133
raise errors.bzr_errors.NotBranchError(path=transport.base)
135
def get_format_description(self):
136
return "Remote Git Repository"
138
def get_format_string(self):
139
return "Remote Git Repository"
141
def initialize_on_transport(self, transport):
142
raise UninitializableFormat(self)
144
def is_supported(self):
107
class RemoteGitBranch(GitBranch):
109
def __init__(self, bzrdir, repository, name, lockfiles):
110
def determine_wants(heads):
111
self._ref = heads[name]
112
bzrdir.root_transport.fetch_pack(determine_wants, None, lambda x: None,
113
lambda x: mutter("git: %s" % x))
114
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
116
def last_revision(self):