~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/foreign.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2008-2011 Canonical Ltd
 
1
# Copyright (C) 2008 Canonical Ltd
2
2
#
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 (
31
31
    errors,
 
32
    osutils,
32
33
    registry,
33
34
    transform,
34
35
    )
35
36
""")
36
37
 
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.
39
40
 
40
41
    """
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
46
47
 
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
    # using this mapping.
49
50
    revid_prefix = None
50
51
 
51
52
    def __init__(self, vcs):
118
119
        self.mapping = mapping
119
120
 
120
121
 
 
122
def show_foreign_properties(rev):
 
123
    """Custom log displayer for foreign revision identifiers.
 
124
 
 
125
    :param rev: Revision object.
 
126
    """
 
127
    # Revision comes directly from a foreign repository
 
128
    if isinstance(rev, ForeignRevision):
 
129
        return rev.mapping.vcs.show_foreign_revid(rev.foreign_revid)
 
130
 
 
131
    # Revision was once imported from a foreign repository
 
132
    try:
 
133
        foreign_revid, mapping = \
 
134
            foreign_vcs_registry.parse_revision_id(rev.revision_id)
 
135
    except errors.InvalidRevisionId:
 
136
        return {}
 
137
 
 
138
    return mapping.vcs.show_foreign_revid(foreign_revid)
 
139
 
 
140
 
121
141
class ForeignVcs(object):
122
142
    """A foreign version control system."""
123
143
 
124
 
    branch_format = None
125
 
 
126
 
    repository_format = None
127
 
 
128
 
    def __init__(self, mapping_registry, abbreviation=None):
129
 
        """Create a new foreign vcs instance.
130
 
 
131
 
        :param mapping_registry: Registry with mappings for this VCS.
132
 
        :param abbreviation: Optional abbreviation ('bzr', 'svn', 'git', etc)
133
 
        """
134
 
        self.abbreviation = abbreviation
 
144
    def __init__(self, mapping_registry):
135
145
        self.mapping_registry = mapping_registry
136
146
 
137
147
    def show_foreign_revid(self, foreign_revid):
142
152
        """
143
153
        return { }
144
154
 
145
 
    def serialize_foreign_revid(self, foreign_revid):
146
 
        """Serialize a foreign revision id for this VCS.
147
 
 
148
 
        :param foreign_revid: Foreign revision id
149
 
        :return: Bytestring with serialized revid, will not contain any 
150
 
            newlines.
151
 
        """
152
 
        raise NotImplementedError(self.serialize_foreign_revid)
153
 
 
154
155
 
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
180
181
        """
181
 
        if not ":" in revid or not "-" in revid:
 
182
        if not "-" in revid:
182
183
            raise errors.InvalidRevisionId(revid, None)
183
184
        try:
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)
226
227
 
 
228
    def get_inventory_xml(self, revision_id):
 
229
        """See Repository.get_inventory_xml()."""
 
230
        return self.serialise_inventory(self.get_inventory(revision_id))
 
231
 
 
232
    def get_inventory_sha1(self, revision_id):
 
233
        """Get the sha1 for the XML representation of an inventory.
 
234
 
 
235
        :param revision_id: Revision id of the inventory for which to return
 
236
         the SHA1.
 
237
        :return: XML string
 
238
        """
 
239
 
 
240
        return osutils.sha_string(self.get_inventory_xml(revision_id))
 
241
 
 
242
    def get_revision_xml(self, revision_id):
 
243
        """Return the XML representation of a revision.
 
244
 
 
245
        :param revision_id: Revision for which to return the XML.
 
246
        :return: XML string
 
247
        """
 
248
        return self._serializer.write_revision_to_string(
 
249
            self.get_revision(revision_id))
 
250
 
227
251
 
228
252
class ForeignBranch(Branch):
229
253
    """Branch that exists in a foreign version control system."""
258
282
 
259
283
 
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.
262
286
 
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. 
266
290
    """
267
291
    hidden = True
268
292
    takes_args = ['location?']
269
 
    takes_options = [
270
 
        'remember',
271
 
        Option('directory',
272
 
               help='Branch to push from, '
273
 
               'rather than the one containing the working directory.',
274
 
               short_name='d',
275
 
               type=unicode,
276
 
               ),
277
 
        Option('no-rebase', help="Do not rebase after push."),
278
 
        Option('strict',
279
 
               help='Refuse to push if there are uncommitted changes in'
280
 
               ' the working tree, --no-strict disables the check.'),
281
 
        ]
 
293
    takes_options = ['remember', Option('directory',
 
294
            help='Branch to push from, '
 
295
                 'rather than the one containing the working directory.',
 
296
            short_name='d',
 
297
            type=unicode,
 
298
            ),
 
299
            Option('no-rebase', help="Do not rebase after push.")]
282
300
 
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, 
 
302
            no_rebase=False):
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
289
308
 
290
309
        if directory is None:
295
314
        except NoWorkingTree:
296
315
            source_branch = Branch.open(directory)
297
316
            source_wt = None
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()
316
330
        try:
317
331
            try:
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)
335
348
                        update_workingtree_fileids(source_wt, target)
336
349
                    finally:
337
350
                        source_wt.unlock()
338
 
            push_result.report(self.outf)
339
351
        finally:
340
352
            target_branch.unlock()
341
353
 
352
364
 
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.
359
370
        """