Merge upstream.
[jelmer/subvertpy.git] / format.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.bzrdir import BzrDirFormat, BzrDir
19 from bzrlib.errors import (NotBranchError, NotLocalUrl, NoRepositoryPresent,
20                            NoWorkingTree)
21 from bzrlib.lockable_files import TransportLock
22 from bzrlib.transport.local import LocalTransport
23
24 from svn.core import SubversionException
25 import svn.core, svn.repos
26
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
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, scheme=None):
40         """See BzrDir.__init__()."""
41         _transport = get_svn_ra_transport(_transport)
42         super(SvnRemoteAccess, self).__init__(_transport, _format)
43
44         svn_url = bzr_to_svn_url(self.root_transport.base)
45         self.svn_root_url = _transport.get_repos_root()
46
47         assert svn_url.startswith(self.svn_root_url)
48         self.branch_path = svn_url[len(self.svn_root_url):]
49
50         if scheme is None:
51             self.scheme = BranchingScheme.guess_scheme(self.branch_path)
52         else:
53             self.scheme = scheme
54
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)
59
60     def clone(self, url, revision_id=None, force_new_repo=False):
61         """See BzrDir.clone().
62
63         Not supported on Subversion connections.
64         """
65         raise NotImplementedError(SvnRemoteAccess.clone)
66
67     def sprout(self, url, revision_id=None, force_new_repo=False,
68             recurse='down'):
69         """See BzrDir.sprout()."""
70         # FIXME: Use recurse
71         result = BzrDirFormat.get_default_format().initialize(url)
72         repo = self.find_repository()
73         if force_new_repo:
74             result_repo = repo.clone(result, revision_id)
75         else:
76             try:
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)
81
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()
86         return result
87
88     def open_repository(self):
89         """Open the repository associated with this BzrDir.
90         
91         :return: instance of SvnRepository.
92         """
93         if self.branch_path == "":
94             return SvnRepository(self, self.root_transport)
95         raise NoRepositoryPresent(self)
96
97     def find_repository(self):
98         """Open the repository associated with this BzrDir.
99         
100         :return: instance of SvnRepository.
101         """
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)
106
107     def open_workingtree(self, _unsupported=False,
108             recommend_upgrade=True):
109         """See BzrDir.open_workingtree().
110
111         Will always raise NotLocalUrl as this 
112         BzrDir can not be associated with working trees.
113         """
114         # Working trees never exist on remote Subversion repositories
115         raise NoWorkingTree(self.root_transport.base)
116
117     def create_workingtree(self, revision_id=None):
118         """See BzrDir.create_workingtree().
119
120         Will always raise NotLocalUrl as this 
121         BzrDir can not be associated with working trees.
122         """
123         raise NotLocalUrl(self.root_transport.base)
124
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)
131         branch.bzrdir = self
132         return branch
133
134     def open_branch(self, unsupported=True):
135         """See BzrDir.open_branch()."""
136
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)
140
141         repos = self.find_repository()
142         branch = SvnBranch(self.root_transport.base, repos, self.branch_path)
143         branch.bzrdir = self
144         return branch
145
146
147 class SvnFormat(BzrDirFormat):
148     """Format for the Subversion smart server."""
149     _lock_class = TransportLock
150
151     @classmethod
152     def probe_transport(klass, transport):
153         format = klass()
154
155         transport = get_svn_ra_transport(transport)
156
157         if isinstance(transport, SvnRaTransport):
158             return format
159
160         raise NotBranchError(path=transport.base)
161
162     def _open(self, transport):
163         try: 
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)
168             raise
169
170     def get_format_string(self):
171         return 'Subversion Smart Server'
172
173     def get_format_description(self):
174         return 'Subversion Smart Server'
175
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")
182
183         local_path = transport._local_base.rstrip("/")
184         svn.repos.create(local_path, '', '', None, None)
185         return self.open(SvnRaTransport(transport.base), _found=True)
186
187     def is_supported(self):
188         """See BzrDir.is_supported()."""
189         return True
190