1 # Copyright (C) 2006-2007 Jelmer Vernooij <jelmer@samba.org>
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 """Subversion BzrDir formats."""
18 from bzrlib.bzrdir import BzrDirFormat, BzrDir
19 from bzrlib.errors import (NotBranchError, NotLocalUrl, NoRepositoryPresent,
21 from bzrlib.lockable_files import TransportLock
22 from bzrlib.transport.local import LocalTransport
24 from svn.core import SubversionException
25 import svn.core, svn.repos
27 from branch import SvnBranch
28 from repository import SvnRepository
29 from scheme import BranchingScheme
30 from transport import SvnRaTransport, bzr_to_svn_url, get_svn_ra_transport
33 class SvnRemoteAccess(BzrDir):
34 """BzrDir implementation for Subversion connections.
36 This is used for all non-checkout connections
37 to Subversion repositories.
39 def __init__(self, _transport, _format, scheme=None):
40 """See BzrDir.__init__()."""
41 _transport = get_svn_ra_transport(_transport)
42 super(SvnRemoteAccess, self).__init__(_transport, _format)
44 svn_url = bzr_to_svn_url(self.root_transport.base)
45 self.svn_root_url = _transport.get_repos_root()
47 assert svn_url.startswith(self.svn_root_url)
48 self.branch_path = svn_url[len(self.svn_root_url):]
51 self.scheme = BranchingScheme.guess_scheme(self.branch_path)
55 if (not self.scheme.is_branch(self.branch_path) and
56 not self.scheme.is_tag(self.branch_path) and
57 self.branch_path != ""):
58 raise NotBranchError(path=self.root_transport.base)
60 def clone(self, url, revision_id=None, force_new_repo=False):
61 """See BzrDir.clone().
63 Not supported on Subversion connections.
65 raise NotImplementedError(SvnRemoteAccess.clone)
67 def sprout(self, url, revision_id=None, force_new_repo=False,
69 """See BzrDir.sprout()."""
71 result = BzrDirFormat.get_default_format().initialize(url)
72 repo = self.find_repository()
74 result_repo = repo.clone(result, revision_id)
77 result_repo = result.find_repository()
78 result_repo.fetch(repo, revision_id=revision_id)
79 except NoRepositoryPresent:
80 result_repo = repo.clone(result, revision_id)
82 branch = self.open_branch()
83 result_branch = branch.sprout(result, revision_id)
84 if result_branch.repository.make_working_trees():
85 result.create_workingtree()
88 def open_repository(self):
89 """Open the repository associated with this BzrDir.
91 :return: instance of SvnRepository.
93 if self.branch_path == "":
94 return SvnRepository(self, self.root_transport)
95 raise NoRepositoryPresent(self)
97 def find_repository(self):
98 """Open the repository associated with this BzrDir.
100 :return: instance of SvnRepository.
102 transport = self.root_transport
103 if self.svn_root_url != transport.base:
104 transport = SvnRaTransport(self.svn_root_url)
105 return SvnRepository(self, transport)
107 def open_workingtree(self, _unsupported=False,
108 recommend_upgrade=True):
109 """See BzrDir.open_workingtree().
111 Will always raise NotLocalUrl as this
112 BzrDir can not be associated with working trees.
114 # Working trees never exist on remote Subversion repositories
115 raise NoWorkingTree(self.root_transport.base)
117 def create_workingtree(self, revision_id=None):
118 """See BzrDir.create_workingtree().
120 Will always raise NotLocalUrl as this
121 BzrDir can not be associated with working trees.
123 raise NotLocalUrl(self.root_transport.base)
125 def create_branch(self):
126 """See BzrDir.create_branch()."""
127 repos = self.open_repository()
128 # TODO: Check if there are any revisions in this repository
129 # yet if it is the top-level one
130 branch = SvnBranch(self.root_transport.base, repos, self.branch_path)
134 def open_branch(self, unsupported=True):
135 """See BzrDir.open_branch()."""
137 if not self.scheme.is_branch(self.branch_path) and \
138 not self.scheme.is_tag(self.branch_path):
139 raise NotBranchError(path=self.root_transport.base)
141 repos = self.find_repository()
142 branch = SvnBranch(self.root_transport.base, repos, self.branch_path)
147 class SvnFormat(BzrDirFormat):
148 """Format for the Subversion smart server."""
149 _lock_class = TransportLock
152 def probe_transport(klass, transport):
155 transport = get_svn_ra_transport(transport)
157 if isinstance(transport, SvnRaTransport):
160 raise NotBranchError(path=transport.base)
162 def _open(self, transport):
164 return SvnRemoteAccess(transport, self)
165 except SubversionException, (_, num):
166 if num == svn.core.SVN_ERR_RA_DAV_REQUEST_FAILED:
167 raise NotBranchError(transport.base)
170 def get_format_string(self):
171 return 'Subversion Smart Server'
173 def get_format_description(self):
174 return 'Subversion Smart Server'
176 def initialize_on_transport(self, transport):
177 """See BzrDir.initialize_on_transport()."""
178 if not isinstance(transport, LocalTransport):
179 raise NotImplementedError(self.initialize,
180 "Can't create Subversion Repositories/branches on "
181 "non-local transports")
183 local_path = transport._local_base.rstrip("/")
184 svn.repos.create(local_path, '', '', None, None)
185 return self.open(SvnRaTransport(transport.base), _found=True)
187 def is_supported(self):
188 """See BzrDir.is_supported()."""