1 # Copyright (C) 2005-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
18 Support for Subversion branches
21 from bzrlib.bzrdir import BzrDirFormat, format_registry
22 from bzrlib.commands import Command, register_command, display_command, Option
23 from bzrlib.help_topics import topic_registry
24 from bzrlib.trace import warning
25 from bzrlib.transport import register_lazy_transport, register_transport_proto
29 # versions ending in 'exp' mean experimental mappings
30 # versions ending in 'dev' mean development version
31 # versions ending in 'final' mean release (well tested, etc)
32 version_info = (0, 4, 4, 'dev', 0)
34 if version_info[3] == 'final':
35 version_string = '%d.%d.%d' % version_info[:3]
37 version_string = '%d.%d.%d%s%d' % version_info
38 __version__ = version_string
40 COMPATIBLE_BZR_VERSIONS = [(0, 90), (0, 91)]
42 def check_bzrlib_version(desired):
43 """Check that bzrlib is compatible.
45 If version is < all compatible version, assume incompatible.
46 If version is compatible version + 1, assume compatible, with deprecations
47 Otherwise, assume incompatible.
50 bzrlib_version = bzrlib.version_info[:2]
51 if (bzrlib_version in desired or
52 ((bzrlib_version[0], bzrlib_version[1]-1) in desired and
53 bzrlib.version_info[3] == 'dev')):
55 if bzrlib_version < desired[0]:
56 warning('Installed bzr version %s is too old to be used with bzr-svn'
57 ' %s.' % (bzrlib.__version__, __version__))
58 # Not using BzrNewError, because it may not exist.
59 raise Exception, ('Version mismatch', desired)
61 warning('bzr-svn is not up to date with installed bzr version %s.'
62 ' \nThere should be a newer version of bzr-svn available.'
63 % (bzrlib.__version__))
64 if not (bzrlib_version[0], bzrlib_version[1]-1) in desired:
65 raise Exception, 'Version mismatch'
67 def check_bzrsvn_version():
68 """Warn about use of experimental mappings."""
69 if version_info[3] == "exp":
70 warning('version of bzr-svn is experimental; output may change between revisions')
72 def check_subversion_version():
73 """Check that Subversion is compatible.
79 warning('No Python bindings for Subversion installed. See the '
80 'bzr-svn README for details.')
81 raise bzrlib.errors.BzrError("missing python subversion bindings")
82 if (not hasattr(svn.delta, 'svn_delta_invoke_txdelta_window_handler') and
83 not hasattr(svn.delta, 'tx_invoke_window_handler')):
84 warning('Installed Subversion version does not have updated Python '
85 'bindings. See the bzr-svn README for details.')
86 raise bzrlib.errors.BzrError("incompatible python subversion bindings")
88 check_subversion_version()
90 register_transport_proto('svn+ssh://',
91 help="Access using the Subversion smart server tunneled over SSH.")
92 register_transport_proto('svn+file://',
93 help="Access of local Subversion repositories.")
94 register_transport_proto('svn+http://',
95 help="Access of Subversion smart servers over HTTP.")
96 register_transport_proto('svn+https://',
97 help="Access of Subversion smart servers over secure HTTP.")
98 register_transport_proto('svn://',
99 help="Access using the Subversion smart server.")
100 register_lazy_transport('svn://', 'bzrlib.plugins.svn.transport',
102 register_lazy_transport('svn+', 'bzrlib.plugins.svn.transport',
104 topic_registry.register_lazy('svn-branching-schemes',
105 'bzrlib.plugins.svn.scheme',
106 'help_schemes', 'Subversion branching schemes')
108 BzrDirFormat.register_control_format(format.SvnRemoteFormat)
109 BzrDirFormat.register_control_format(format.SvnWorkingTreeDirFormat)
110 format_registry.register("subversion", format.SvnRemoteFormat,
111 "Subversion repository. ",
113 format_registry.register("subversion-wc", format.SvnWorkingTreeDirFormat,
114 "Subversion working copy. ",
117 versions_checked = False
118 def lazy_check_versions():
119 global versions_checked
122 versions_checked = True
123 check_bzrlib_version(COMPATIBLE_BZR_VERSIONS)
124 check_bzrsvn_version()
126 optimizers_registered = False
127 def lazy_register_optimizers():
128 global optimizers_registered
129 if optimizers_registered:
131 from bzrlib.repository import InterRepository
134 optimizers_registered = True
135 InterRepository.register_optimiser(fetch.InterFromSvnRepository)
136 InterRepository.register_optimiser(commit.InterToSvnRepository)
138 def get_scheme(schemename):
139 """Parse scheme identifier and return a branching scheme."""
140 from scheme import BranchingScheme
141 from bzrlib.errors import BzrCommandError
143 ret = BranchingScheme.find_scheme(schemename)
145 raise BzrCommandError('No such branching scheme %r' % schemename)
149 class cmd_svn_import(Command):
150 """Convert a Subversion repository to a Bazaar repository.
153 takes_args = ['from_location', 'to_location?']
154 takes_options = [Option('trees', help='Create working trees.'),
155 Option('standalone', help='Create standalone branches.'),
157 help='Convert all revisions, even those not in '
158 'current branch history (forbids --standalone).'),
159 Option('scheme', type=get_scheme,
160 help='Branching scheme (none, trunk, etc). '
162 Option('prefix', type=str,
163 help='Only consider branches of which path starts '
168 def run(self, from_location, to_location=None, trees=False,
169 standalone=False, scheme=None, all=False, prefix=None):
170 from bzrlib.errors import NoRepositoryPresent
171 from bzrlib.bzrdir import BzrDir
172 from convert import convert_repository
175 if to_location is None:
176 to_location = os.path.basename(from_location.rstrip("/\\"))
179 # All implies shared repository
180 # (otherwise there is no repository to store revisions in)
183 if os.path.isfile(from_location):
184 from convert import load_dumpfile
186 tmp_repos = tempfile.mkdtemp(prefix='bzr-svn-dump-')
187 load_dumpfile(from_location, tmp_repos)
188 from_location = tmp_repos
192 from_dir = BzrDir.open(from_location)
194 from_repos = from_dir.open_repository()
195 except NoRepositoryPresent, e:
196 from bzrlib.errors import BzrCommandError
197 raise BzrCommandError("No Repository found at %s. "
198 "For individual branches, use 'bzr branch'." % from_location)
200 def filter_branch((branch_path, revnum, exists)):
201 if prefix is not None and not branch_path.startswith(prefix):
205 convert_repository(from_repos, to_location, scheme, not standalone,
206 trees, all, filter_branch=filter_branch)
208 if tmp_repos is not None:
209 from bzrlib import osutils
210 osutils.rmtree(tmp_repos)
213 register_command(cmd_svn_import)
215 class cmd_svn_upgrade(Command):
216 """Upgrade revisions mapped from Subversion in a Bazaar branch.
218 This will change the revision ids of revisions whose parents
219 were mapped from svn revisions.
221 takes_args = ['from_repository?']
222 takes_options = ['verbose']
225 def run(self, from_repository=None, verbose=False):
226 from upgrade import upgrade_branch, upgrade_workingtree
227 from bzrlib.branch import Branch
228 from bzrlib.errors import NoWorkingTree, BzrCommandError
229 from bzrlib.repository import Repository
230 from bzrlib.workingtree import WorkingTree
232 wt_to = WorkingTree.open(".")
233 branch_to = wt_to.branch
234 except NoWorkingTree:
236 branch_to = Branch.open(".")
238 stored_loc = branch_to.get_parent()
239 if from_repository is None:
240 if stored_loc is None:
241 raise BzrCommandError("No pull location known or"
244 import bzrlib.urlutils as urlutils
245 display_url = urlutils.unescape_for_display(stored_loc,
247 self.outf.write("Using saved location: %s\n" % display_url)
248 from_repository = Branch.open(stored_loc).repository
250 from_repository = Repository.open(from_repository)
252 if wt_to is not None:
253 upgrade_workingtree(wt_to, from_repository, allow_changes=True,
256 upgrade_branch(branch_to, from_repository, allow_changes=True,
259 if wt_to is not None:
260 wt_to.set_last_revision(branch_to.last_revision())
262 register_command(cmd_svn_upgrade)
264 class cmd_svn_push(Command):
265 """Push revisions to Subversion, creating a new branch if necessary.
267 The behaviour of this command is the same as that of "bzr push", except
268 that it also creates new branches.
270 This command is experimental and will be removed in the future when all
271 functionality is included in "bzr push".
273 takes_args = ['location']
274 takes_options = ['revision']
276 def run(self, location, revision=None):
277 from bzrlib.bzrdir import BzrDir
278 from bzrlib.branch import Branch
279 from bzrlib.errors import NotBranchError, BzrCommandError
280 bzrdir = BzrDir.open(location)
281 source_branch = Branch.open_containing(".")[0]
282 if revision is not None:
283 if len(revision) > 1:
284 raise BzrCommandError(
285 'bzr svn-push --revision takes exactly one revision'
287 revision_id = revision[0].in_history(source_branch).rev_id
291 target_branch = bzrdir.open_branch()
292 target_branch.pull(source_branch, revision_id)
293 except NotBranchError:
294 target_branch = bzrdir.import_branch(source_branch, revision_id)
296 register_command(cmd_svn_push)
299 class cmd_svn_branching_scheme(Command):
300 """Show or change the branching scheme for a Subversion repository.
302 See 'bzr help svn-branching-scheme' for details.
304 takes_args = ['location?']
306 Option('set', help="Change the branching scheme. "),
307 Option('repository-wide',
308 help="Act on repository-wide setting rather than local.")
311 def run(self, location=".", set=False, repository_wide=False):
312 from bzrlib.msgeditor import edit_commit_message
313 from bzrlib.repository import Repository
314 from bzrlib.trace import info
315 from scheme import scheme_from_branch_list
316 def scheme_str(scheme):
319 return "".join(map(lambda x: x+"\n", scheme.to_lines()))
320 repos = Repository.open(location)
322 scheme = repos._get_property_scheme()
324 scheme = repos.get_scheme()
326 schemestr = edit_commit_message("",
327 start_message=scheme_str(scheme))
328 scheme = scheme_from_branch_list(
329 map(lambda x:x.strip("\n"), schemestr.splitlines()))
331 repos.set_property_scheme(scheme)
333 repos.set_branching_scheme(scheme)
334 elif scheme is not None:
335 info(scheme_str(scheme))
338 register_command(cmd_svn_branching_scheme)
342 from unittest import TestSuite
345 suite.addTest(tests.test_suite())
349 if __name__ == '__main__':
350 print ("This is a Bazaar plugin. Copy this directory to ~/.bazaar/plugins "
352 elif __name__ != 'bzrlib.plugins.svn':
353 raise ImportError('The Subversion plugin must be installed as'
354 ' bzrlib.plugins.svn not %s' % __name__)
357 sys.path.append(os.path.dirname(os.path.abspath(__file__)))