1
# Copyright (C) 2008-2011 Canonical Ltd
1
# Copyright (C) 2008 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
29
29
lazy_import(globals(), """
30
30
from bzrlib import (
37
38
class VcsMapping(object):
38
"""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.
41
42
# Whether this is an experimental mapping that is still open to changes.
44
45
# Whether this mapping supports exporting and importing all bzr semantics.
45
46
roundtripping = False
47
# Prefix used when importing revisions native to the foreign VCS (as
48
# opposed to roundtripping bzr-native revisions) using this mapping.
48
# Prefix used when importing native foreign revisions (not roundtripped)
49
50
revid_prefix = None
51
52
def __init__(self, vcs):
118
119
self.mapping = mapping
122
def show_foreign_properties(rev):
123
"""Custom log displayer for foreign revision identifiers.
125
:param rev: Revision object.
127
# Revision comes directly from a foreign repository
128
if isinstance(rev, ForeignRevision):
129
return rev.mapping.vcs.show_foreign_revid(rev.foreign_revid)
131
# Revision was once imported from a foreign repository
133
foreign_revid, mapping = \
134
foreign_vcs_registry.parse_revision_id(rev.revision_id)
135
except errors.InvalidRevisionId:
138
return mapping.vcs.show_foreign_revid(foreign_revid)
121
141
class ForeignVcs(object):
122
142
"""A foreign version control system."""
126
repository_format = None
128
def __init__(self, mapping_registry, abbreviation=None):
129
"""Create a new foreign vcs instance.
131
:param mapping_registry: Registry with mappings for this VCS.
132
:param abbreviation: Optional abbreviation ('bzr', 'svn', 'git', etc)
134
self.abbreviation = abbreviation
144
def __init__(self, mapping_registry):
135
145
self.mapping_registry = mapping_registry
137
147
def show_foreign_revid(self, foreign_revid):
145
def serialize_foreign_revid(self, foreign_revid):
146
"""Serialize a foreign revision id for this VCS.
148
:param foreign_revid: Foreign revision id
149
:return: Bytestring with serialized revid, will not contain any
152
raise NotImplementedError(self.serialize_foreign_revid)
155
156
class ForeignVcsRegistry(registry.Registry):
156
157
"""Registry for Foreign VCSes.
178
179
:param revid: The bzr revision id
179
180
:return: tuple with foreign revid and vcs mapping
181
if not ":" in revid or not "-" in revid:
182
183
raise errors.InvalidRevisionId(revid, None)
184
185
foreign_vcs = self.get(revid.split("-")[0])
224
225
"""Get the default mapping for this repository."""
225
226
raise NotImplementedError(self.get_default_mapping)
228
def get_inventory_xml(self, revision_id):
229
"""See Repository.get_inventory_xml()."""
230
return self.serialise_inventory(self.get_inventory(revision_id))
232
def get_inventory_sha1(self, revision_id):
233
"""Get the sha1 for the XML representation of an inventory.
235
:param revision_id: Revision id of the inventory for which to return
240
return osutils.sha_string(self.get_inventory_xml(revision_id))
242
def get_revision_xml(self, revision_id):
243
"""Return the XML representation of a revision.
245
:param revision_id: Revision for which to return the XML.
248
return self._serializer.write_revision_to_string(
249
self.get_revision(revision_id))
228
252
class ForeignBranch(Branch):
229
253
"""Branch that exists in a foreign version control system."""
260
284
class cmd_dpush(Command):
261
__doc__ = """Push into a different VCS without any custom bzr metadata.
285
"""Push into a foreign VCS without any custom bzr metadata.
263
This will afterwards rebase the local branch on the remote
287
This will afterwards rebase the local Bazaar branch on the remote
264
288
branch unless the --no-rebase option is used, in which case
265
289
the two branches will be out of sync after the push.
268
292
takes_args = ['location?']
272
help='Branch to push from, '
273
'rather than the one containing the working directory.',
277
Option('no-rebase', help="Do not rebase after push."),
279
help='Refuse to push if there are uncommitted changes in'
280
' the working tree, --no-strict disables the check.'),
293
takes_options = ['remember', Option('directory',
294
help='Branch to push from, '
295
'rather than the one containing the working directory.',
299
Option('no-rebase', help="Do not rebase after push.")]
283
def run(self, location=None, remember=False, directory=None,
284
no_rebase=False, strict=None):
301
def run(self, location=None, remember=False, directory=None,
285
303
from bzrlib import urlutils
286
304
from bzrlib.bzrdir import BzrDir
287
305
from bzrlib.errors import BzrCommandError, NoWorkingTree
306
from bzrlib.trace import info
288
307
from bzrlib.workingtree import WorkingTree
290
309
if directory is None:
295
314
except NoWorkingTree:
296
315
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.')
303
317
stored_loc = source_branch.get_push_location()
304
318
if location is None:
305
319
if stored_loc is None:
315
329
target_branch.lock_write()
318
push_result = source_branch.lossy_push(target_branch)
332
revid_map = source_branch.lossy_push(target_branch)
319
333
except errors.LossyPushToSameVCS:
320
raise BzrCommandError("%r and %r are in the same VCS, lossy "
321
"push not necessary. Please use regular push." %
322
(source_branch, target_branch))
334
raise BzrCommandError("%r is not a foreign branch, use regular "
335
"push." % target_branch)
323
336
# We successfully created the target, remember it
324
337
if source_branch.get_push_location() is None or remember:
325
338
source_branch.set_push_location(target_branch.base)
353
365
:param target: Target branch
354
366
:param stop_revision: Revision to push, defaults to last revision.
355
:return: BranchPushResult with an extra member revidmap:
356
A dictionary mapping revision ids from the target branch
367
:return: Dictionary mapping revision ids from the target branch
357
368
to new revision ids in the target branch, for each
358
369
revision that was pushed.