14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18
"""Foreign branch utilities."""
19
from __future__ import absolute_import
22
21
from bzrlib.branch import (
25
25
from bzrlib.commands import Command, Option
26
26
from bzrlib.repository import Repository
29
29
lazy_import(globals(), """
30
30
from bzrlib import (
35
from bzrlib.i18n import gettext
38
38
class VcsMapping(object):
39
"""Describes the mapping between the semantics of Bazaar and a foreign VCS.
39
"""Describes the mapping between the semantics of Bazaar and a foreign vcs.
42
42
# Whether this is an experimental mapping that is still open to changes.
122
122
class ForeignVcs(object):
123
123
"""A foreign version control system."""
127
repository_format = None
129
def __init__(self, mapping_registry, abbreviation=None):
130
"""Create a new foreign vcs instance.
132
:param mapping_registry: Registry with mappings for this VCS.
133
:param abbreviation: Optional abbreviation ('bzr', 'svn', 'git', etc)
135
self.abbreviation = abbreviation
125
def __init__(self, mapping_registry):
136
126
self.mapping_registry = mapping_registry
138
128
def show_foreign_revid(self, foreign_revid):
146
def serialize_foreign_revid(self, foreign_revid):
147
"""Serialize a foreign revision id for this VCS.
149
:param foreign_revid: Foreign revision id
150
:return: Bytestring with serialized revid, will not contain any
153
raise NotImplementedError(self.serialize_foreign_revid)
156
137
class ForeignVcsRegistry(registry.Registry):
157
138
"""Registry for Foreign VCSes.
225
206
"""Get the default mapping for this repository."""
226
207
raise NotImplementedError(self.get_default_mapping)
209
def get_inventory_xml(self, revision_id):
210
"""See Repository.get_inventory_xml()."""
211
return self.serialise_inventory(self.get_inventory(revision_id))
213
def get_inventory_sha1(self, revision_id):
214
"""Get the sha1 for the XML representation of an inventory.
216
:param revision_id: Revision id of the inventory for which to return
221
return osutils.sha_string(self.get_inventory_xml(revision_id))
223
def get_revision_xml(self, revision_id):
224
"""Return the XML representation of a revision.
226
:param revision_id: Revision for which to return the XML.
229
return self._serializer.write_revision_to_string(
230
self.get_revision(revision_id))
229
233
class ForeignBranch(Branch):
230
234
"""Branch that exists in a foreign version control system."""
261
265
class cmd_dpush(Command):
262
__doc__ = """Push into a different VCS without any custom bzr metadata.
266
"""Push into a different VCS without any custom bzr metadata.
264
268
This will afterwards rebase the local branch on the remote
265
269
branch unless the --no-rebase option is used, in which case
266
270
the two branches will be out of sync after the push.
268
273
takes_args = ['location?']
269
274
takes_options = [
283
288
def run(self, location=None, remember=False, directory=None,
284
289
no_rebase=False, strict=None):
285
290
from bzrlib import urlutils
286
from bzrlib.controldir import ControlDir
291
from bzrlib.bzrdir import BzrDir
287
292
from bzrlib.errors import BzrCommandError, NoWorkingTree
288
293
from bzrlib.workingtree import WorkingTree
295
300
except NoWorkingTree:
296
301
source_branch = Branch.open(directory)
298
if source_wt is not None:
299
source_wt.check_changed_or_out_of_date(
300
strict, 'dpush_strict',
301
more_error='Use --no-strict to force the push.',
302
more_warning='Uncommitted changes will not be pushed.')
304
strict = source_branch.get_config(
305
).get_user_option_as_bool('dpush_strict')
306
if strict is None: strict = True # default value
307
if strict and source_wt is not None:
308
if (source_wt.has_changes()):
309
raise errors.UncommittedChanges(
310
source_wt, more='Use --no-strict to force the push.')
311
if source_wt.last_revision() != source_wt.branch.last_revision():
312
# The tree has lost sync with its branch, there is little
313
# chance that the user is aware of it but he can still force
314
# the push with --no-strict
315
raise errors.OutOfDateTree(
316
source_wt, more='Use --no-strict to force the push.')
303
317
stored_loc = source_branch.get_push_location()
304
318
if location is None:
305
319
if stored_loc is None:
306
raise BzrCommandError(gettext("No push location known or specified."))
320
raise BzrCommandError("No push location known or specified.")
308
322
display_url = urlutils.unescape_for_display(stored_loc,
309
323
self.outf.encoding)
311
gettext("Using saved location: %s\n") % display_url)
324
self.outf.write("Using saved location: %s\n" % display_url)
312
325
location = stored_loc
314
controldir = ControlDir.open(location)
315
target_branch = controldir.open_branch()
327
bzrdir = BzrDir.open(location)
328
target_branch = bzrdir.open_branch()
316
329
target_branch.lock_write()
319
push_result = source_branch.push(target_branch, lossy=True)
332
push_result = source_branch.lossy_push(target_branch)
320
333
except errors.LossyPushToSameVCS:
321
raise BzrCommandError(gettext("{0!r} and {1!r} are in the same VCS, lossy "
322
"push not necessary. Please use regular push.").format(
323
source_branch, target_branch))
334
raise BzrCommandError("%r and %r are in the same VCS, lossy "
335
"push not necessary. Please use regular push." %
336
(source_branch, target_branch))
324
337
# We successfully created the target, remember it
325
338
if source_branch.get_push_location() is None or remember:
326
# FIXME: Should be done only if we succeed ? -- vila 2012-01-18
327
339
source_branch.set_push_location(target_branch.base)
328
340
if not no_rebase:
329
341
old_last_revid = source_branch.last_revision()
340
352
push_result.report(self.outf)
342
354
target_branch.unlock()
357
class InterToForeignBranch(InterBranch):
359
def lossy_push(self, stop_revision=None):
360
"""Push deltas into another branch.
362
:note: This does not, like push, retain the revision ids from
363
the source branch and will, rather than adding bzr-specific
364
metadata, push only those semantics of the revision that can be
365
natively represented by this branch' VCS.
367
:param target: Target branch
368
:param stop_revision: Revision to push, defaults to last revision.
369
:return: BranchPushResult with an extra member revidmap:
370
A dictionary mapping revision ids from the target branch
371
to new revision ids in the target branch, for each
372
revision that was pushed.
374
raise NotImplementedError(self.lossy_push)