# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-"""
-Support for Subversion branches
+"""Support for Subversion branches
+
+Bazaar can be used with Subversion branches through the bzr-svn plugin.
+
+Most Bazaar commands should work fine with Subversion branches. To
+create new branches in Subversion using push, it is currently necessary
+to use the svn-push command rather than the standard push command.
+
+bzr-svn also adds two new commands to Bazaar:
+
+ - bzr svn-import
+ - bzr dpush
+
+For more information about bzr-svn, see the bzr-svn FAQ.
+
"""
import bzrlib
+from bzrlib import log
from bzrlib.bzrdir import BzrDirFormat, format_registry
+from bzrlib.errors import BzrError
from bzrlib.commands import Command, register_command, display_command, Option
from bzrlib.help_topics import topic_registry
from bzrlib.revisionspec import SPEC_TYPES
from bzrlib.trace import warning, mutter
from bzrlib.transport import register_lazy_transport, register_transport_proto
-from bzrlib.plugins.svn import format
-from bzrlib.plugins.svn import revspec
+import os
# versions ending in 'exp' mean experimental mappings
# versions ending in 'dev' mean development version
# versions ending in 'final' mean release (well tested, etc)
-version_info = (0, 4, 11, 'dev', 0)
+version_info = (0, 4, 13, 'final', 0)
if version_info[3] == 'final':
version_string = '%d.%d.%d' % version_info[:3]
version_string = '%d.%d.%d%s%d' % version_info
__version__ = version_string
-COMPATIBLE_BZR_VERSIONS = [(1, 4), (1, 5)]
+COMPATIBLE_BZR_VERSIONS = [(1, 6), (1, 7)]
def check_bzrlib_version(desired):
"""Check that bzrlib is compatible.
If version is compatible version + 1, assume compatible, with deprecations
Otherwise, assume incompatible.
"""
- import bzrlib
bzrlib_version = bzrlib.version_info[:2]
if (bzrlib_version in desired or
((bzrlib_version[0], bzrlib_version[1]-1) in desired and
- bzrlib.version_info[3] == 'dev')):
+ bzrlib.version_info[3] in ('dev', 'exp'))):
return
- from bzrlib.errors import BzrError
if bzrlib_version < desired[0]:
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]))
else:
"""Check that Subversion is compatible.
"""
+ def check_mtime(m):
+ """Check whether a C extension is out of date."""
+ (base, _) = os.path.splitext(m.__file__)
+ c_file = "%s.c" % base
+ if not os.path.exists(c_file):
+ return True
+ if os.path.getmtime(m.__file__) < os.path.getmtime(c_file):
+ return False
+ return True
try:
- import svn.delta
+ from bzrlib.plugins.svn import client, ra, repos, wc
+ for x in client, ra, repos, wc:
+ if not check_mtime(x):
+ warning("bzr-svn extensions are outdated and need to be rebuilt")
+ break
except ImportError:
- warning('No Python bindings for Subversion installed. See the '
- 'bzr-svn README for details.')
- raise bzrlib.errors.BzrError("missing python subversion bindings")
- if (not hasattr(svn.delta, 'svn_delta_invoke_txdelta_window_handler') and
- not hasattr(svn.delta, 'tx_invoke_window_handler')):
- warning('Installed Subversion version does not have updated Python '
- 'bindings. See the bzr-svn README for details.')
- raise bzrlib.errors.BzrError("incompatible python subversion bindings")
- import svn.core
- if (svn.core.SVN_VER_MINOR >= 5 and
- 27729 <= svn.core.SVN_VER_REVISION < 31470):
- warning('Installed Subversion has buggy svn.ra.get_log() implementation, please install newer.')
-
- mutter("bzr-svn: using Subversion %d.%d.%d (%s)", svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR, svn.core.SVN_VER_MICRO, svn.core.__file__)
+ warning("Unable to load bzr-svn extensions - did you build it?")
+ raise
+ ra_version = ra.version()
+ if (ra_version[0] >= 5 and getattr(ra, 'SVN_REVISION', None) and
+ 27729 <= ra.SVN_REVISION < 31470):
+ warning('Installed Subversion has buggy svn.ra.get_log() '
+ 'implementation, please install newer.')
+
+ mutter("bzr-svn: using Subversion %d.%d.%d (%s)" % ra_version)
def check_rebase_version(min_version):
check_subversion_version()
+from bzrlib.plugins.svn import format, revspec
+
register_transport_proto('svn+ssh://',
help="Access using the Subversion smart server tunneled over SSH.")
register_transport_proto('svn+file://',
native=False, hidden=True)
SPEC_TYPES.append(revspec.RevisionSpec_svn)
-versions_checked = False
+log.properties_handler_registry.register_lazy("subversion",
+ "bzrlib.plugins.svn.log",
+ "show_subversion_properties")
+
+_versions_checked = False
def lazy_check_versions():
"""Check whether all dependencies have the right versions.
:note: Only checks once, caches the result."""
- global versions_checked
- if versions_checked:
+ global _versions_checked
+ if _versions_checked:
return
- versions_checked = True
+ _versions_checked = True
check_bzrlib_version(COMPATIBLE_BZR_VERSIONS)
-optimizers_registered = False
+_optimizers_registered = False
def lazy_register_optimizers():
"""Register optimizers for fetching between Subversion and Bazaar
repositories.
:note: Only registers on the first call."""
- global optimizers_registered
- if optimizers_registered:
+ global _optimizers_registered
+ if _optimizers_registered:
return
from bzrlib.repository import InterRepository
from bzrlib.plugins.svn import commit, fetch
- optimizers_registered = True
+ _optimizers_registered = True
InterRepository.register_optimiser(fetch.InterFromSvnRepository)
InterRepository.register_optimiser(commit.InterToSvnRepository)
class cmd_svn_import(Command):
"""Convert a Subversion repository to a Bazaar repository.
+ To save disk space, only branches will be created by default
+ (no working trees). To create a tree for a branch, run "bzr co" in
+ it.
"""
takes_args = ['from_location', 'to_location?']
takes_options = [Option('trees', help='Create working trees.'),
Option('scheme', type=get_scheme,
help='Branching scheme (none, trunk, etc). '
'Default: auto.'),
+ Option('keep',
+ help="Don't delete branches removed in Subversion."),
+ Option('incremental',
+ help="Import revisions incrementally."),
Option('prefix', type=str,
help='Only consider branches of which path starts '
'with prefix.')
@display_command
def run(self, from_location, to_location=None, trees=False,
- standalone=False, scheme=None, all=False, prefix=None):
- from bzrlib.branch import Branch
+ standalone=False, scheme=None, all=False, prefix=None, keep=False,
+ incremental=False):
from bzrlib.bzrdir import BzrDir
- from bzrlib.errors import BzrCommandError, NoRepositoryPresent, NotBranchError
+ from bzrlib.errors import BzrCommandError, NoRepositoryPresent
from bzrlib import urlutils
from bzrlib.plugins.svn.convert import convert_repository
+ from bzrlib.plugins.svn.mapping3 import repository_guess_scheme
from bzrlib.plugins.svn.repository import SvnRepository
- import os
if to_location is None:
to_location = os.path.basename(from_location.rstrip("/\\"))
try:
from_repos = from_dir.open_repository()
except NoRepositoryPresent, e:
- try:
- Branch.open(from_location)
- raise BzrCommandError("No Repository found at %s. "
- "For individual branches, use 'bzr branch'." % from_location)
- except NotBranchError:
- if prefix is not None:
- raise BzrCommandError("Path inside repository specified and --prefix specified")
- from_repos = from_dir.find_repository()
- prefix = urlutils.relative_url(from_repos.base, from_location)
- self.outf.write("Importing branches below %s\n" %
- urlutils.unescape_for_display(prefix, self.outf.encoding))
-
- if prefix is not None:
- prefix = prefix.strip("/") + "/"
-
- if not isinstance(from_repos, SvnRepository):
- raise BzrCommandError(
- "Not a Subversion repository: %s" % from_location)
-
- def filter_branch(branch):
- if prefix is not None and not branch.get_branch_path().startswith(prefix):
- return False
- return True
+ if prefix is not None:
+ raise BzrCommandError("Path inside repository specified "
+ "and --prefix specified")
+ from_repos = from_dir.find_repository()
+ prefix = urlutils.relative_url(from_repos.base, from_location)
+ prefix = prefix.encode("utf-8")
+
+ from_repos.lock_read()
+ try:
+ (guessed_scheme, scheme) = repository_guess_scheme(from_repos,
+ from_repos.get_latest_revnum())
- convert_repository(from_repos, to_location, scheme, None,
- not standalone, trees, all, filter_branch=filter_branch)
+ if prefix is not None:
+ prefix = prefix.strip("/") + "/"
+ if guessed_scheme.is_branch(prefix):
+ raise BzrCommandError("%s appears to contain a branch. "
+ "For individual branches, use 'bzr branch'." %
+ from_location)
- if tmp_repos is not None:
- from bzrlib import osutils
- osutils.rmtree(tmp_repos)
+ self.outf.write("Importing branches with prefix /%s\n" %
+ urlutils.unescape_for_display(prefix, self.outf.encoding))
+
+ if not isinstance(from_repos, SvnRepository):
+ raise BzrCommandError(
+ "Not a Subversion repository: %s" % from_location)
+
+ def filter_branch(branch):
+ if (prefix is not None and
+ not branch.get_branch_path().startswith(prefix)):
+ return False
+ return True
+
+ convert_repository(from_repos, to_location, scheme, None,
+ not standalone, trees, all,
+ filter_branch=filter_branch,
+ keep=keep, incremental=incremental)
+
+ if tmp_repos is not None:
+ from bzrlib import osutils
+ osutils.rmtree(tmp_repos)
+ finally:
+ from_repos.unlock()
register_command(cmd_svn_import)
@display_command
def run(self, from_repository=None, verbose=False):
- from bzrlib.plugins.svn.upgrade import upgrade_branch, upgrade_workingtree
+ from bzrlib.plugins.svn.upgrade import (upgrade_branch,
+ upgrade_workingtree)
from bzrlib.branch import Branch
from bzrlib.errors import NoWorkingTree, BzrCommandError
from bzrlib.repository import Repository
'rather than the one containing the working directory.',
short_name='d',
type=unicode,
- )]
+ ),
+ Option("merged", help="Push merged (right hand side) revisions.")]
def run(self, location=None, revision=None, remember=False,
- directory=None):
+ directory=None, merged=None):
from bzrlib.bzrdir import BzrDir
from bzrlib.branch import Branch
from bzrlib.errors import NotBranchError, BzrCommandError
self.outf.write("Using saved location: %s\n" % display_url)
location = stored_loc
- bzrdir = BzrDir.open(location)
- if revision is not None:
- if len(revision) > 1:
- raise BzrCommandError(
- 'bzr svn-push --revision takes exactly one revision'
- ' identifier')
- revision_id = revision[0].as_revision_id(source_branch)
- else:
- revision_id = None
+ source_branch.lock_read()
try:
- target_branch = bzrdir.open_branch()
- target_branch.lock_write()
+ bzrdir = BzrDir.open(location)
+ if revision is not None:
+ if len(revision) > 1:
+ raise BzrCommandError(
+ 'bzr svn-push --revision takes exactly one revision'
+ ' identifier')
+ revision_id = revision[0].as_revision_id(source_branch)
+ else:
+ revision_id = None
try:
- target_branch.pull(source_branch, revision_id)
- finally:
- target_branch.unlock()
- except NotBranchError:
- target_branch = bzrdir.import_branch(source_branch, revision_id)
+ target_branch = bzrdir.open_branch()
+ target_branch.lock_write()
+ try:
+ target_branch.pull(source_branch, stop_revision=revision_id, _push_merged=merged)
+ finally:
+ target_branch.unlock()
+ except NotBranchError:
+ target_branch = bzrdir.import_branch(source_branch, revision_id, _push_merged=merged)
+ finally:
+ source_branch.unlock()
# We successfully created the target, remember it
if source_branch.get_push_location() is None or remember:
source_branch.set_push_location(target_branch.base)
register_command(cmd_svn_push)
+class cmd_dpush(Command):
+ """Push diffs into Subversion without any Bazaar-specific properties set.
+
+ This will afterwards rebase the local Bazaar branch on the Subversion
+ branch unless the --no-rebase option is used, in which case
+ the two branches will be out of sync.
+ """
+ takes_args = ['location?']
+ takes_options = ['remember', Option('directory',
+ help='Branch to push from, '
+ 'rather than the one containing the working directory.',
+ short_name='d',
+ type=unicode,
+ ),
+ Option('no-rebase', help="Don't rebase after push")]
+
+ def run(self, location=None, remember=False, directory=None,
+ no_rebase=False):
+ from bzrlib import urlutils
+ from bzrlib.bzrdir import BzrDir
+ from bzrlib.branch import Branch
+ from bzrlib.errors import BzrCommandError, NoWorkingTree
+ from bzrlib.workingtree import WorkingTree
+
+ from bzrlib.plugins.svn.commit import dpush
+
+ if directory is None:
+ directory = "."
+ try:
+ source_wt = WorkingTree.open_containing(directory)[0]
+ source_branch = source_wt.branch
+ except NoWorkingTree:
+ source_branch = Branch.open_containing(directory)[0]
+ source_wt = None
+ stored_loc = source_branch.get_push_location()
+ if location is None:
+ if stored_loc is None:
+ raise BzrCommandError("No push location known or specified.")
+ else:
+ display_url = urlutils.unescape_for_display(stored_loc,
+ self.outf.encoding)
+ self.outf.write("Using saved location: %s\n" % display_url)
+ location = stored_loc
+
+ bzrdir = BzrDir.open(location)
+ target_branch = bzrdir.open_branch()
+ target_branch.lock_write()
+ revid_map = dpush(target_branch, source_branch)
+ # We successfully created the target, remember it
+ if source_branch.get_push_location() is None or remember:
+ source_branch.set_push_location(target_branch.base)
+ if not no_rebase:
+ _, old_last_revid = source_branch.last_revision_info()
+ new_last_revid = revid_map[old_last_revid]
+ if source_wt is not None:
+ source_wt.pull(target_branch, overwrite=True,
+ stop_revision=new_last_revid)
+ else:
+ source_branch.pull(target_branch, overwrite=True,
+ stop_revision=new_last_revid)
+
+
+register_command(cmd_dpush)
+
class cmd_svn_branching_scheme(Command):
"""Show or change the branching scheme for a Subversion repository.
from bzrlib.bzrdir import BzrDir
from bzrlib.errors import BzrCommandError
from bzrlib.msgeditor import edit_commit_message
- from bzrlib.repository import Repository
from bzrlib.trace import info
from bzrlib.plugins.svn.repository import SvnRepository
from bzrlib.plugins.svn.mapping3.scheme import scheme_from_branch_list
- from bzrlib.plugins.svn.mapping3 import config_set_scheme, get_property_scheme, set_property_scheme
+ from bzrlib.plugins.svn.mapping3 import (config_set_scheme,
+ get_property_scheme, set_property_scheme)
def scheme_str(scheme):
if scheme is None:
return ""
if repository_wide:
set_property_scheme(repos, scheme)
else:
- config_set_scheme(repos, scheme, mandatory=True)
+ config_set_scheme(repos, scheme, None, mandatory=True)
elif scheme is not None:
info(scheme_str(scheme))