Support custom user options for repository config.
[jelmer/subvertpy.git] / remote.py
1 # Copyright (C) 2006-2007 Jelmer Vernooij <jelmer@samba.org>
2
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.
7
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.
12
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."""
17
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
23
24 from svn.core import SubversionException
25 import svn.core, svn.repos
26
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
31
32
33 class SvnRemoteAccess(BzrDir):
34     """BzrDir implementation for Subversion connections.
35     
36     This is used for all non-checkout connections 
37     to Subversion repositories.
38     """
39     def __init__(self, _transport, _format=None):
40         """See BzrDir.__init__()."""
41         _transport = get_svn_ra_transport(_transport)
42         if _format is None:
43             _format = SvnRemoteFormat()
44         self._format = _format
45         self.transport = None
46         self.root_transport = _transport
47
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()
51
52         assert svn_url.startswith(self.svn_root_url)
53         self.branch_path = svn_url[len(self.svn_root_url):]
54
55     def clone(self, url, revision_id=None, force_new_repo=False):
56         """See BzrDir.clone().
57
58         Not supported on Subversion connections.
59         """
60         raise NotImplementedError(SvnRemoteAccess.clone)
61
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
66         # FIXME: Use recurse
67         format = get_rich_root_format()
68         result = format.initialize(url)
69         repo = self.find_repository()
70         if force_new_repo:
71             result_repo = repo.clone(result, revision_id)
72         else:
73             try:
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()
82         return result
83
84     def open_repository(self, _unsupported=False):
85         """Open the repository associated with this BzrDir.
86         
87         :return: instance of SvnRepository.
88         """
89         if self.branch_path == "":
90             return SvnRepository(self, self.root_transport)
91         raise NoSvnRepositoryPresent(self.root_transport.base)
92
93     def find_repository(self):
94         """Open the repository associated with this BzrDir.
95         
96         :return: instance of SvnRepository.
97         """
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)
102
103     def open_workingtree(self, _unsupported=False,
104             recommend_upgrade=True):
105         """See BzrDir.open_workingtree().
106
107         Will always raise NotLocalUrl as this 
108         BzrDir can not be associated with working trees.
109         """
110         # Working trees never exist on remote Subversion repositories
111         raise NoWorkingTree(self.root_transport.base)
112
113     def create_workingtree(self, revision_id=None):
114         """See BzrDir.create_workingtree().
115
116         Will always raise NotLocalUrl as this 
117         BzrDir can not be associated with working trees.
118         """
119         raise NotLocalUrl(self.root_transport.base)
120
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.
125         if format is None:
126             format = BzrDirFormat.get_default_format()
127         return not isinstance(self._format, format.__class__)
128
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.
132         
133         :param source: Source branch
134         :param stop_revision: Tip of new branch
135         :return: Branch object
136         """
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, 
143                                         target_branch_path)
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)
150         return branch
151
152     def create_branch(self):
153         """See BzrDir.create_branch()."""
154         from branch import SvnBranch
155         repos = self.find_repository()
156
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)
164         branch.bzrdir = self
165         return branch
166
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)
172         branch.bzrdir = self
173         return branch
174
175     def create_repository(self, shared=False, format=None):
176         """See BzrDir.create_repository."""
177         return self.open_repository()
178
179