~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/foreign.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-04-30 15:00:23 UTC
  • mfrom: (4273.1.21 branch-subtree-locations)
  • Revision ID: pqm@pqm.ubuntu.com-20090430150023-1cw4lwqf312vpuu8
(abentley) Implement references command.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2008, 2009, 2010 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
18
18
"""Foreign branch utilities."""
19
19
 
20
20
 
21
 
from bzrlib.branch import (
22
 
    Branch,
23
 
    InterBranch,
24
 
    )
 
21
from bzrlib.branch import Branch
25
22
from bzrlib.commands import Command, Option
26
23
from bzrlib.repository import Repository
27
24
from bzrlib.revision import Revision
36
33
""")
37
34
 
38
35
class VcsMapping(object):
39
 
    """Describes the mapping between the semantics of Bazaar and a foreign VCS.
 
36
    """Describes the mapping between the semantics of Bazaar and a foreign vcs.
40
37
 
41
38
    """
42
39
    # Whether this is an experimental mapping that is still open to changes.
45
42
    # Whether this mapping supports exporting and importing all bzr semantics.
46
43
    roundtripping = False
47
44
 
48
 
    # Prefix used when importing revisions native to the foreign VCS (as
49
 
    # opposed to roundtripping bzr-native revisions) using this mapping.
 
45
    # Prefix used when importing native foreign revisions (not roundtripped)
 
46
    # using this mapping.
50
47
    revid_prefix = None
51
48
 
52
49
    def __init__(self, vcs):
119
116
        self.mapping = mapping
120
117
 
121
118
 
 
119
def show_foreign_properties(rev):
 
120
    """Custom log displayer for foreign revision identifiers.
 
121
 
 
122
    :param rev: Revision object.
 
123
    """
 
124
    # Revision comes directly from a foreign repository
 
125
    if isinstance(rev, ForeignRevision):
 
126
        return rev.mapping.vcs.show_foreign_revid(rev.foreign_revid)
 
127
 
 
128
    # Revision was once imported from a foreign repository
 
129
    try:
 
130
        foreign_revid, mapping = \
 
131
            foreign_vcs_registry.parse_revision_id(rev.revision_id)
 
132
    except errors.InvalidRevisionId:
 
133
        return {}
 
134
 
 
135
    return mapping.vcs.show_foreign_revid(foreign_revid)
 
136
 
 
137
 
122
138
class ForeignVcs(object):
123
139
    """A foreign version control system."""
124
140
 
125
 
    branch_format = None
126
 
 
127
 
    repository_format = None
128
 
 
129
 
    def __init__(self, mapping_registry, abbreviation=None):
130
 
        """Create a new foreign vcs instance.
131
 
 
132
 
        :param mapping_registry: Registry with mappings for this VCS.
133
 
        :param abbreviation: Optional abbreviation ('bzr', 'svn', 'git', etc)
134
 
        """
135
 
        self.abbreviation = abbreviation
 
141
    def __init__(self, mapping_registry):
136
142
        self.mapping_registry = mapping_registry
137
143
 
138
144
    def show_foreign_revid(self, foreign_revid):
143
149
        """
144
150
        return { }
145
151
 
146
 
    def serialize_foreign_revid(self, foreign_revid):
147
 
        """Serialize a foreign revision id for this VCS.
148
 
 
149
 
        :param foreign_revid: Foreign revision id
150
 
        :return: Bytestring with serialized revid, will not contain any 
151
 
            newlines.
152
 
        """
153
 
        raise NotImplementedError(self.serialize_foreign_revid)
154
 
 
155
152
 
156
153
class ForeignVcsRegistry(registry.Registry):
157
154
    """Registry for Foreign VCSes.
179
176
        :param revid: The bzr revision id
180
177
        :return: tuple with foreign revid and vcs mapping
181
178
        """
182
 
        if not ":" in revid or not "-" in revid:
 
179
        if not "-" in revid:
183
180
            raise errors.InvalidRevisionId(revid, None)
184
181
        try:
185
182
            foreign_vcs = self.get(revid.split("-")[0])
225
222
        """Get the default mapping for this repository."""
226
223
        raise NotImplementedError(self.get_default_mapping)
227
224
 
 
225
    def get_inventory_xml(self, revision_id):
 
226
        """See Repository.get_inventory_xml()."""
 
227
        return self.serialise_inventory(self.get_inventory(revision_id))
 
228
 
 
229
    def get_inventory_sha1(self, revision_id):
 
230
        """Get the sha1 for the XML representation of an inventory.
 
231
 
 
232
        :param revision_id: Revision id of the inventory for which to return
 
233
         the SHA1.
 
234
        :return: XML string
 
235
        """
 
236
 
 
237
        return osutils.sha_string(self.get_inventory_xml(revision_id))
 
238
 
 
239
    def get_revision_xml(self, revision_id):
 
240
        """Return the XML representation of a revision.
 
241
 
 
242
        :param revision_id: Revision for which to return the XML.
 
243
        :return: XML string
 
244
        """
 
245
        return self._serializer.write_revision_to_string(
 
246
            self.get_revision(revision_id))
 
247
 
228
248
 
229
249
class ForeignBranch(Branch):
230
250
    """Branch that exists in a foreign version control system."""
233
253
        self.mapping = mapping
234
254
        super(ForeignBranch, self).__init__()
235
255
 
 
256
    def dpull(self, source, stop_revision=None):
 
257
        """Pull deltas from another branch.
 
258
 
 
259
        :note: This does not, like pull, retain the revision ids from 
 
260
            the source branch and will, rather than adding bzr-specific 
 
261
            metadata, push only those semantics of the revision that can be 
 
262
            natively represented by this branch' VCS.
 
263
 
 
264
        :param source: Source branch
 
265
        :param stop_revision: Revision to pull, defaults to last revision.
 
266
        :return: Dictionary mapping revision ids from the source branch 
 
267
            to new revision ids in the target branch, for each 
 
268
            revision that was pull.
 
269
        """
 
270
        raise NotImplementedError(self.dpull)
 
271
 
236
272
 
237
273
def update_workingtree_fileids(wt, target_tree):
238
274
    """Update the file ids in a working tree based on another tree.
259
295
 
260
296
 
261
297
class cmd_dpush(Command):
262
 
    __doc__ = """Push into a different VCS without any custom bzr metadata.
 
298
    """Push diffs into a foreign version control system without any 
 
299
    Bazaar-specific metadata.
263
300
 
264
 
    This will afterwards rebase the local branch on the remote
 
301
    This will afterwards rebase the local Bazaar branch on the remote
265
302
    branch unless the --no-rebase option is used, in which case 
266
 
    the two branches will be out of sync after the push. 
 
303
    the two branches will be out of sync. 
267
304
    """
268
305
    hidden = True
269
306
    takes_args = ['location?']
270
 
    takes_options = [
271
 
        'remember',
272
 
        Option('directory',
273
 
               help='Branch to push from, '
274
 
               'rather than the one containing the working directory.',
275
 
               short_name='d',
276
 
               type=unicode,
277
 
               ),
278
 
        Option('no-rebase', help="Do not rebase after push."),
279
 
        Option('strict',
280
 
               help='Refuse to push if there are uncommitted changes in'
281
 
               ' the working tree, --no-strict disables the check.'),
282
 
        ]
 
307
    takes_options = ['remember', Option('directory',
 
308
            help='Branch to push from, '
 
309
                 'rather than the one containing the working directory.',
 
310
            short_name='d',
 
311
            type=unicode,
 
312
            ),
 
313
            Option('no-rebase', help="Do not rebase after push.")]
283
314
 
284
 
    def run(self, location=None, remember=False, directory=None,
285
 
            no_rebase=False, strict=None):
 
315
    def run(self, location=None, remember=False, directory=None, 
 
316
            no_rebase=False):
286
317
        from bzrlib import urlutils
287
318
        from bzrlib.bzrdir import BzrDir
288
319
        from bzrlib.errors import BzrCommandError, NoWorkingTree
 
320
        from bzrlib.trace import info
289
321
        from bzrlib.workingtree import WorkingTree
290
322
 
291
323
        if directory is None:
296
328
        except NoWorkingTree:
297
329
            source_branch = Branch.open(directory)
298
330
            source_wt = None
299
 
        if source_wt is not None:
300
 
            source_wt.check_changed_or_out_of_date(
301
 
                strict, 'dpush_strict',
302
 
                more_error='Use --no-strict to force the push.',
303
 
                more_warning='Uncommitted changes will not be pushed.')
304
331
        stored_loc = source_branch.get_push_location()
305
332
        if location is None:
306
333
            if stored_loc is None:
313
340
 
314
341
        bzrdir = BzrDir.open(location)
315
342
        target_branch = bzrdir.open_branch()
 
343
        dpull = getattr(target_branch, "dpull", None)
 
344
        if dpull is None:
 
345
            raise BzrCommandError("%r is not a foreign branch, use "
 
346
                                  "regular push." % target_branch)
316
347
        target_branch.lock_write()
317
348
        try:
318
 
            try:
319
 
                push_result = source_branch.lossy_push(target_branch)
320
 
            except errors.LossyPushToSameVCS:
321
 
                raise BzrCommandError("%r and %r are in the same VCS, lossy "
322
 
                    "push not necessary. Please use regular push." %
323
 
                    (source_branch, target_branch))
 
349
            revid_map = dpull(source_branch)
324
350
            # We successfully created the target, remember it
325
351
            if source_branch.get_push_location() is None or remember:
326
352
                source_branch.set_push_location(target_branch.base)
336
362
                        update_workingtree_fileids(source_wt, target)
337
363
                    finally:
338
364
                        source_wt.unlock()
339
 
            push_result.report(self.outf)
340
365
        finally:
341
366
            target_branch.unlock()
342
 
 
343
 
 
344
 
class InterToForeignBranch(InterBranch):
345
 
 
346
 
    def lossy_push(self, stop_revision=None):
347
 
        """Push deltas into another branch.
348
 
 
349
 
        :note: This does not, like push, retain the revision ids from 
350
 
            the source branch and will, rather than adding bzr-specific 
351
 
            metadata, push only those semantics of the revision that can be 
352
 
            natively represented by this branch' VCS.
353
 
 
354
 
        :param target: Target branch
355
 
        :param stop_revision: Revision to push, defaults to last revision.
356
 
        :return: BranchPushResult with an extra member revidmap: 
357
 
            A dictionary mapping revision ids from the target branch 
358
 
            to new revision ids in the target branch, for each 
359
 
            revision that was pushed.
360
 
        """
361
 
        raise NotImplementedError(self.lossy_push)