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 import urlutils
19 from bzrlib.bzrdir import BzrDirFormat, BzrDir, format_registry
20 from bzrlib.errors import (NotBranchError, NotLocalUrl, NoRepositoryPresent,
21 NoWorkingTree, AlreadyBranchError)
22 from bzrlib.transport.local import LocalTransport
24 from svn.core import SubversionException
25 import svn.core, svn.repos
27 from errors import NoSvnRepositoryPresent
28 from format import get_rich_root_format, SvnRemoteFormat
29 from repository import SvnRepository
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=None):
40 """See BzrDir.__init__()."""
41 _transport = get_svn_ra_transport(_transport)
43 _format = SvnRemoteFormat()
44 self._format = _format
46 self.root_transport = _transport
48 svn_url = bzr_to_svn_url(self.root_transport.base)
49 self.svn_root_url = _transport.get_svn_repos_root()
50 self.root_url = _transport.get_repos_root()
52 assert svn_url.startswith(self.svn_root_url)
53 self.branch_path = svn_url[len(self.svn_root_url):]
55 def clone(self, url, revision_id=None, force_new_repo=False):
56 """See BzrDir.clone().
58 Not supported on Subversion connections.
60 raise NotImplementedError(SvnRemoteAccess.clone)
62 def sprout(self, url, revision_id=None, force_new_repo=False,
63 recurse='down', possible_transports=None):
64 """See BzrDir.sprout()."""
65 # FIXME: Use possible_transports
67 format = get_rich_root_format()
68 result = format.initialize(url)
69 repo = self.find_repository()
71 result_repo = repo.clone(result, revision_id)
74 result_repo = result.find_repository()
75 result_repo.fetch(repo, revision_id=revision_id)
76 except NoRepositoryPresent:
77 result_repo = repo.clone(result, revision_id)
78 branch = self.open_branch()
79 result_branch = branch.sprout(result, revision_id)
80 if result_branch.repository.make_working_trees():
81 result.create_workingtree()
84 def open_repository(self, _unsupported=False):
85 """Open the repository associated with this BzrDir.
87 :return: instance of SvnRepository.
89 if self.branch_path == "":
90 return SvnRepository(self, self.root_transport)
91 raise NoSvnRepositoryPresent(self.root_transport.base)
93 def find_repository(self):
94 """Open the repository associated with this BzrDir.
96 :return: instance of SvnRepository.
98 transport = self.root_transport
99 if self.root_url != transport.base:
100 transport = transport.clone_root()
101 return SvnRepository(self, transport, self.branch_path)
103 def open_workingtree(self, _unsupported=False,
104 recommend_upgrade=True):
105 """See BzrDir.open_workingtree().
107 Will always raise NotLocalUrl as this
108 BzrDir can not be associated with working trees.
110 # Working trees never exist on remote Subversion repositories
111 raise NoWorkingTree(self.root_transport.base)
113 def create_workingtree(self, revision_id=None):
114 """See BzrDir.create_workingtree().
116 Will always raise NotLocalUrl as this
117 BzrDir can not be associated with working trees.
119 raise NotLocalUrl(self.root_transport.base)
121 def needs_format_conversion(self, format=None):
122 """See BzrDir.needs_format_conversion()."""
123 # if the format is not the same as the system default,
124 # an upgrade is needed.
126 format = BzrDirFormat.get_default_format()
127 return not isinstance(self._format, format.__class__)
129 def import_branch(self, source, stop_revision=None):
130 """Create a new branch in this repository, possibly
131 with the specified history, optionally importing revisions.
133 :param source: Source branch
134 :param stop_revision: Tip of new branch
135 :return: Branch object
137 from commit import push_new
138 if stop_revision is None:
139 stop_revision = source.last_revision()
140 target_branch_path = self.branch_path.strip("/")
141 repos = self.find_repository()
142 full_branch_url = urlutils.join(repos.transport.base,
144 if repos.transport.check_path(target_branch_path,
145 repos.transport.get_latest_revnum()) != svn.core.svn_node_none:
146 raise AlreadyBranchError(full_branch_url)
147 push_new(repos, target_branch_path, source, stop_revision)
148 branch = self.open_branch()
149 branch.pull(source, stop_revision=stop_revision)
152 def create_branch(self):
153 """See BzrDir.create_branch()."""
154 from branch import SvnBranch
155 repos = self.find_repository()
157 if self.branch_path != "":
158 # TODO: Set NULL_REVISION in SVN_PROP_BZR_BRANCHING_SCHEME
159 repos.transport.mkdir(self.branch_path.strip("/"))
160 elif repos.transport.get_latest_revnum() > 0:
161 # Bail out if there are already revisions in this repository
162 raise AlreadyBranchError(self.root_transport.base)
163 branch = SvnBranch(self.root_transport.base, repos, self.branch_path)
167 def open_branch(self, unsupported=True):
168 """See BzrDir.open_branch()."""
169 from branch import SvnBranch
170 repos = self.find_repository()
171 branch = SvnBranch(self.root_transport.base, repos, self.branch_path)
175 def create_repository(self, shared=False, format=None):
176 """See BzrDir.create_repository."""
177 return self.open_repository()