Remove unused imports.
[jelmer/subvertpy.git] / __init__.py
1 # Copyright (C) 2005-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 3 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
17 """
18 Support for Subversion branches
19 """
20 import bzrlib
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.revisionspec import SPEC_TYPES
25 from bzrlib.trace import warning, mutter
26 from bzrlib.transport import register_lazy_transport, register_transport_proto
27
28 from bzrlib.plugins.svn import format
29 from bzrlib.plugins.svn import revspec
30
31 # versions ending in 'exp' mean experimental mappings
32 # versions ending in 'dev' mean development version
33 # versions ending in 'final' mean release (well tested, etc)
34 version_info = (0, 4, 11, 'dev', 0)
35
36 if version_info[3] == 'final':
37     version_string = '%d.%d.%d' % version_info[:3]
38 else:
39     version_string = '%d.%d.%d%s%d' % version_info
40 __version__ = version_string
41
42 COMPATIBLE_BZR_VERSIONS = [(1, 4), (1, 5), (1, 6)]
43
44 def check_bzrlib_version(desired):
45     """Check that bzrlib is compatible.
46
47     If version is < all compatible version, assume incompatible.
48     If version is compatible version + 1, assume compatible, with deprecations
49     Otherwise, assume incompatible.
50     """
51     import bzrlib
52     bzrlib_version = bzrlib.version_info[:2]
53     if (bzrlib_version in desired or 
54         ((bzrlib_version[0], bzrlib_version[1]-1) in desired and 
55          bzrlib.version_info[3] == 'dev')):
56         return
57     from bzrlib.errors import BzrError
58     if bzrlib_version < desired[0]:
59         raise BzrError('Installed bzr version %s is too old to be used with bzr-svn, at least %s.%s required' % (bzrlib.__version__, desired[0][0], desired[0][1]))
60     else:
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 BzrError('Version mismatch')
66
67 def check_subversion_version():
68     """Check that Subversion is compatible.
69
70     """
71     try:
72         from bzrlib.plugins.svn import core
73     except:
74         warning("Unable to load bzr-svn extensions - did you build it?")
75     from bzrlib.plugins.svn.ra import version
76     ra_version = version()
77     if (ra_version[0] >= 5 and getattr(ra, 'SVN_REVISION', None) and 27729 <= ra.SVN_REVISION < 31470):
78         warning('Installed Subversion has buggy svn.ra.get_log() implementation, please install newer.')
79
80     mutter("bzr-svn: using Subversion %d.%d.%d (%s)" % ra_version)
81
82
83 def check_rebase_version(min_version):
84     """Check what version of bzr-rebase is installed.
85
86     Raises an exception when the version installed is older than 
87     min_version.
88
89     :raises RebaseNotPresent: Raised if bzr-rebase is not installed or too old.
90     """
91     from bzrlib.plugins.svn.errors import RebaseNotPresent
92     try:
93         from bzrlib.plugins.rebase import version_info as rebase_version_info
94         if rebase_version_info[:2] < min_version:
95             raise RebaseNotPresent("Version %r present, at least %r required" 
96                                    % (rebase_version_info, min_version))
97     except ImportError, e:
98         raise RebaseNotPresent(e)
99
100
101 check_subversion_version()
102
103 register_transport_proto('svn+ssh://', 
104     help="Access using the Subversion smart server tunneled over SSH.")
105 register_transport_proto('svn+file://', 
106     help="Access of local Subversion repositories.")
107 register_transport_proto('svn+http://',
108     help="Access of Subversion smart servers over HTTP.")
109 register_transport_proto('svn+https://',
110     help="Access of Subversion smart servers over secure HTTP.")
111 register_transport_proto('svn://', 
112     help="Access using the Subversion smart server.")
113 register_lazy_transport('svn://', 'bzrlib.plugins.svn.transport', 
114                         'SvnRaTransport')
115 register_lazy_transport('svn+', 'bzrlib.plugins.svn.transport', 
116                         'SvnRaTransport')
117 topic_registry.register_lazy('svn-branching-schemes', 
118                              'bzrlib.plugins.svn.mapping3.scheme',
119                              'help_schemes', 'Subversion branching schemes')
120
121 BzrDirFormat.register_control_format(format.SvnRemoteFormat)
122 BzrDirFormat.register_control_format(format.SvnWorkingTreeDirFormat)
123 format_registry.register("subversion", format.SvnRemoteFormat, 
124                          "Subversion repository. ", 
125                          native=False)
126 format_registry.register("subversion-wc", format.SvnWorkingTreeDirFormat, 
127                          "Subversion working copy. ", 
128                          native=False, hidden=True)
129 SPEC_TYPES.append(revspec.RevisionSpec_svn)
130
131 versions_checked = False
132 def lazy_check_versions():
133     """Check whether all dependencies have the right versions.
134     
135     :note: Only checks once, caches the result."""
136     global versions_checked
137     if versions_checked:
138         return
139     versions_checked = True
140     check_bzrlib_version(COMPATIBLE_BZR_VERSIONS)
141
142 optimizers_registered = False
143 def lazy_register_optimizers():
144     """Register optimizers for fetching between Subversion and Bazaar 
145     repositories.
146     
147     :note: Only registers on the first call."""
148     global optimizers_registered
149     if optimizers_registered:
150         return
151     from bzrlib.repository import InterRepository
152     from bzrlib.plugins.svn import commit, fetch
153     optimizers_registered = True
154     InterRepository.register_optimiser(fetch.InterFromSvnRepository)
155     InterRepository.register_optimiser(commit.InterToSvnRepository)
156
157
158 def get_scheme(schemename):
159     """Parse scheme identifier and return a branching scheme.
160     
161     :param schemename: Name of the scheme to retrieve.
162     """
163     if isinstance(schemename, unicode):
164         schemename = schemename.encode("ascii")
165     from bzrlib.plugins.svn.mapping3.scheme import BranchingScheme
166     from bzrlib.errors import BzrCommandError
167     
168     ret = BranchingScheme.find_scheme(schemename)
169     if ret is None:
170         raise BzrCommandError('No such branching scheme %r' % schemename)
171     return ret
172
173
174 class cmd_svn_import(Command):
175     """Convert a Subversion repository to a Bazaar repository.
176     
177     """
178     takes_args = ['from_location', 'to_location?']
179     takes_options = [Option('trees', help='Create working trees.'),
180                      Option('standalone', help='Create standalone branches.'),
181                      Option('all', 
182                          help='Convert all revisions, even those not in '
183                               'current branch history (forbids --standalone).'),
184                      Option('scheme', type=get_scheme,
185                          help='Branching scheme (none, trunk, etc). '
186                               'Default: auto.'),
187                      Option('prefix', type=str, 
188                          help='Only consider branches of which path starts '
189                               'with prefix.')
190                     ]
191
192     @display_command
193     def run(self, from_location, to_location=None, trees=False, 
194             standalone=False, scheme=None, all=False, prefix=None):
195         from bzrlib.branch import Branch
196         from bzrlib.bzrdir import BzrDir
197         from bzrlib.errors import BzrCommandError, NoRepositoryPresent, NotBranchError
198         from bzrlib import urlutils
199         from bzrlib.plugins.svn.convert import convert_repository
200         from bzrlib.plugins.svn.repository import SvnRepository
201         import os
202
203         if to_location is None:
204             to_location = os.path.basename(from_location.rstrip("/\\"))
205
206         if all:
207             # All implies shared repository 
208             # (otherwise there is no repository to store revisions in)
209             standalone = False
210
211         if os.path.isfile(from_location):
212             from bzrlib.plugins.svn.convert import load_dumpfile
213             import tempfile
214             tmp_repos = tempfile.mkdtemp(prefix='bzr-svn-dump-')
215             load_dumpfile(from_location, tmp_repos)
216             from_location = tmp_repos
217         else:
218             tmp_repos = None
219
220         from_dir = BzrDir.open(from_location)
221         try:
222             from_repos = from_dir.open_repository()
223         except NoRepositoryPresent, e:
224             try:
225                 Branch.open(from_location)
226                 raise BzrCommandError("No Repository found at %s. "
227                     "For individual branches, use 'bzr branch'." % from_location)
228             except NotBranchError:
229                 if prefix is not None:
230                     raise BzrCommandError("Path inside repository specified and --prefix specified")
231                 from_repos = from_dir.find_repository()
232                 prefix = urlutils.relative_url(from_repos.base, from_location)
233                 self.outf.write("Importing branches below %s\n" % 
234                         urlutils.unescape_for_display(prefix, self.outf.encoding))
235
236         if prefix is not None:
237             prefix = prefix.strip("/") + "/"
238
239         if not isinstance(from_repos, SvnRepository):
240             raise BzrCommandError(
241                     "Not a Subversion repository: %s" % from_location)
242
243         def filter_branch(branch):
244             if prefix is not None and not branch.get_branch_path().startswith(prefix):
245                 return False
246             return True
247
248         convert_repository(from_repos, to_location, scheme, None, 
249                            not standalone, trees, all, filter_branch=filter_branch)
250
251         if tmp_repos is not None:
252             from bzrlib import osutils
253             osutils.rmtree(tmp_repos)
254
255
256 register_command(cmd_svn_import)
257
258 class cmd_svn_upgrade(Command):
259     """Upgrade revisions mapped from Subversion in a Bazaar branch.
260     
261     This will change the revision ids of revisions whose parents 
262     were mapped from svn revisions.
263     """
264     takes_args = ['from_repository?']
265     takes_options = ['verbose']
266
267     @display_command
268     def run(self, from_repository=None, verbose=False):
269         from bzrlib.plugins.svn.upgrade import upgrade_branch, upgrade_workingtree
270         from bzrlib.branch import Branch
271         from bzrlib.errors import NoWorkingTree, BzrCommandError
272         from bzrlib.repository import Repository
273         from bzrlib.trace import info
274         from bzrlib.workingtree import WorkingTree
275         try:
276             wt_to = WorkingTree.open(".")
277             branch_to = wt_to.branch
278         except NoWorkingTree:
279             wt_to = None
280             branch_to = Branch.open(".")
281
282         stored_loc = branch_to.get_parent()
283         if from_repository is None:
284             if stored_loc is None:
285                 raise BzrCommandError("No pull location known or"
286                                              " specified.")
287             else:
288                 import bzrlib.urlutils as urlutils
289                 display_url = urlutils.unescape_for_display(stored_loc,
290                         self.outf.encoding)
291                 self.outf.write("Using saved location: %s\n" % display_url)
292                 from_repository = Branch.open(stored_loc).repository
293         else:
294             from_repository = Repository.open(from_repository)
295
296         if wt_to is not None:
297             renames = upgrade_workingtree(wt_to, from_repository, 
298                                           allow_changes=True, verbose=verbose)
299         else:
300             renames = upgrade_branch(branch_to, from_repository, 
301                                      allow_changes=True, verbose=verbose)
302
303         if renames == {}:
304             info("Nothing to do.")
305
306         if wt_to is not None:
307             wt_to.set_last_revision(branch_to.last_revision())
308
309 register_command(cmd_svn_upgrade)
310
311 class cmd_svn_push(Command):
312     """Push revisions to Subversion, creating a new branch if necessary.
313
314     The behaviour of this command is the same as that of "bzr push", except 
315     that it also creates new branches.
316     
317     This command is experimental and will be removed in the future when all 
318     functionality is included in "bzr push".
319     """
320     takes_args = ['location?']
321     takes_options = ['revision', 'remember', Option('directory',
322             help='Branch to push from, '
323                  'rather than the one containing the working directory.',
324             short_name='d',
325             type=unicode,
326             )]
327
328     def run(self, location=None, revision=None, remember=False, 
329             directory=None):
330         from bzrlib.bzrdir import BzrDir
331         from bzrlib.branch import Branch
332         from bzrlib.errors import NotBranchError, BzrCommandError
333         from bzrlib import urlutils
334
335         if directory is None:
336             directory = "."
337         source_branch = Branch.open_containing(directory)[0]
338         stored_loc = source_branch.get_push_location()
339         if location is None:
340             if stored_loc is None:
341                 raise BzrCommandError("No push location known or specified.")
342             else:
343                 display_url = urlutils.unescape_for_display(stored_loc,
344                         self.outf.encoding)
345                 self.outf.write("Using saved location: %s\n" % display_url)
346                 location = stored_loc
347
348         bzrdir = BzrDir.open(location)
349         if revision is not None:
350             if len(revision) > 1:
351                 raise BzrCommandError(
352                     'bzr svn-push --revision takes exactly one revision' 
353                     ' identifier')
354             revision_id = revision[0].as_revision_id(source_branch)
355         else:
356             revision_id = None
357         try:
358             target_branch = bzrdir.open_branch()
359             target_branch.lock_write()
360             try:
361                 target_branch.pull(source_branch, revision_id)
362             finally:
363                 target_branch.unlock()
364         except NotBranchError:
365             target_branch = bzrdir.import_branch(source_branch, revision_id)
366         # We successfully created the target, remember it
367         if source_branch.get_push_location() is None or remember:
368             source_branch.set_push_location(target_branch.base)
369
370 register_command(cmd_svn_push)
371
372
373 class cmd_svn_branching_scheme(Command):
374     """Show or change the branching scheme for a Subversion repository.
375
376     See 'bzr help svn-branching-schemes' for details.
377     """
378     takes_args = ['location?']
379     takes_options = [
380         Option('set', help="Change the branching scheme. "),
381         Option('repository-wide', 
382             help="Act on repository-wide setting rather than local.")
383         ]
384
385     def run(self, location=".", set=False, repository_wide=False):
386         from bzrlib.bzrdir import BzrDir
387         from bzrlib.errors import BzrCommandError
388         from bzrlib.msgeditor import edit_commit_message
389         from bzrlib.repository import Repository
390         from bzrlib.trace import info
391         from bzrlib.plugins.svn.repository import SvnRepository
392         from bzrlib.plugins.svn.mapping3.scheme import scheme_from_branch_list
393         from bzrlib.plugins.svn.mapping3 import config_set_scheme, get_property_scheme, set_property_scheme
394         def scheme_str(scheme):
395             if scheme is None:
396                 return ""
397             return "".join(map(lambda x: x+"\n", scheme.to_lines()))
398         dir = BzrDir.open_containing(location)[0]
399         repos = dir.find_repository()
400         if not isinstance(repos, SvnRepository):
401             raise BzrCommandError("Not a Subversion repository: %s" % location)
402         if repository_wide:
403             scheme = get_property_scheme(repos)
404         else:
405             scheme = repos.get_mapping().scheme
406         if set:
407             schemestr = edit_commit_message("", 
408                                             start_message=scheme_str(scheme))
409             scheme = scheme_from_branch_list(
410                 map(lambda x:x.strip("\n"), schemestr.splitlines()))
411             if repository_wide:
412                 set_property_scheme(repos, scheme)
413             else:
414                 config_set_scheme(repos, scheme, mandatory=True)
415         elif scheme is not None:
416             info(scheme_str(scheme))
417
418
419 register_command(cmd_svn_branching_scheme)
420
421
422 class cmd_svn_set_revprops(Command):
423     """Migrate Bazaar metadata to Subversion revision properties.
424
425     This requires that you have permission to change the 
426     revision properties on the repository.
427
428     To change these permissions, edit the hooks/pre-revprop-change 
429     file in the Subversion repository.
430     """
431     takes_args = ['location']
432
433     def run(self, location="."):
434         raise NotImplementedError(self.run)
435
436
437 register_command(cmd_svn_set_revprops)
438
439
440 def test_suite():
441     """Returns the testsuite for bzr-svn."""
442     from unittest import TestSuite
443     from bzrlib.plugins.svn import tests
444     suite = TestSuite()
445     suite.addTest(tests.test_suite())
446     return suite
447
448
449 if __name__ == '__main__':
450     print ("This is a Bazaar plugin. Copy this directory to ~/.bazaar/plugins "
451           "to use it.\n")
452 elif __name__ != 'bzrlib.plugins.svn':
453     raise ImportError('The Subversion plugin must be installed as'
454                       ' bzrlib.plugins.svn not %s' % __name__)