/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to __init__.py

  • Committer: Jelmer Vernooij
  • Date: 2008-11-12 14:36:10 UTC
  • mto: (0.219.2 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20081112143610-30109vbbkeuj94y0
import bzr-svn improvements.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Foreign branch utilities."""
 
18
 
 
19
from bzrlib import errors, registry
 
20
from bzrlib.branch import Branch
 
21
from bzrlib.commands import Command, Option
 
22
from bzrlib.errors import InvalidRevisionId
 
23
from bzrlib.revision import Revision
 
24
from bzrlib.trace import info
 
25
 
 
26
class VcsMapping(object):
 
27
    """Describes the mapping between the semantics of Bazaar and a foreign vcs.
 
28
 
 
29
    """
 
30
    # Whether this is an experimental mapping that is still open to changes.
 
31
    experimental = False
 
32
 
 
33
    # Whether this mapping supports exporting and importing all bzr semantics.
 
34
    roundtripping = False
 
35
 
 
36
    # Prefix used when importing native foreign revisions (not roundtripped) 
 
37
    # using this mapping.
 
38
    revid_prefix = None
 
39
 
 
40
    def revision_id_bzr_to_foreign(self, bzr_revid):
 
41
        """Parse a bzr revision id and convert it to a foreign revid.
 
42
 
 
43
        :param bzr_revid: The bzr revision id (a string).
 
44
        :return: A foreign revision id, can be any sort of object.
 
45
        """
 
46
        raise NotImplementedError(self.revision_id_bzr_to_foreign)
 
47
 
 
48
    def revision_id_foreign_to_bzr(self, foreign_revid):
 
49
        """Parse a foreign revision id and convert it to a bzr revid.
 
50
 
 
51
        :param foreign_revid: Foreign revision id, can be any sort of object.
 
52
        :return: A bzr revision id.
 
53
        """
 
54
        raise NotImplementedError(self.revision_id_foreign_to_bzr)
 
55
 
 
56
    def show_foreign_revid(self, foreign_revid):
 
57
        """Prepare a foreign revision id for formatting using bzr log.
 
58
        
 
59
        :param foreign_revid: Foreign revision id.
 
60
        :return: Dictionary mapping string keys to string values.
 
61
        """
 
62
        return { }
 
63
 
 
64
 
 
65
class VcsMappingRegistry(registry.Registry):
 
66
    """Registry for Bazaar<->foreign VCS mappings.
 
67
    
 
68
    There should be one instance of this registry for every foreign VCS.
 
69
    """
 
70
 
 
71
    def register(self, key, factory, help):
 
72
        """Register a mapping between Bazaar and foreign VCS semantics.
 
73
 
 
74
        The factory must be a callable that takes one parameter: the key.
 
75
        It must produce an instance of VcsMapping when called.
 
76
        """
 
77
        registry.Registry.register(self, key, factory, help)
 
78
 
 
79
    def set_default(self, key):
 
80
        """Set the 'default' key to be a clone of the supplied key.
 
81
 
 
82
        This method must be called once and only once.
 
83
        """
 
84
        self._set_default_key(key)
 
85
 
 
86
    def get_default(self):
 
87
        """Convenience function for obtaining the default mapping to use."""
 
88
        return self.get(self._get_default_key())
 
89
 
 
90
 
 
91
class ForeignBranch(Branch):
 
92
    """Branch that exists in a foreign version control system."""
 
93
 
 
94
    def __init__(self, mapping):
 
95
        super(ForeignBranch, self).__init__()
 
96
        self.mapping = mapping
 
97
 
 
98
    def dpull(self, source, stop_revision=None):
 
99
        """Pull deltas from another branch.
 
100
 
 
101
        :note: This does not, like pull, retain the revision ids from 
 
102
        the source branch.
 
103
 
 
104
        :param source: Source branch
 
105
        :param stop_revision: Revision to pull, defaults to last revision.
 
106
        """
 
107
        raise NotImplementedError(self.pull)
 
108
 
 
109
 
 
110
class FakeControlFiles(object):
 
111
    """Dummy implementation of ControlFiles.
 
112
    
 
113
    This is required as some code relies on controlfiles being 
 
114
    available."""
 
115
    def get_utf8(self, name):
 
116
        raise errors.NoSuchFile(name)
 
117
 
 
118
    def get(self, name):
 
119
        raise errors.NoSuchFile(name)
 
120
 
 
121
    def break_lock(self):
 
122
        pass
 
123
 
 
124
 
 
125
class cmd_dpush(Command):
 
126
    """Push diffs into a foreign version control system without any 
 
127
    Bazaar-specific metadata.
 
128
 
 
129
    This will afterwards rebase the local Bazaar branch on the remote
 
130
    branch unless the --no-rebase option is used, in which case 
 
131
    the two branches will be out of sync. 
 
132
    """
 
133
    takes_args = ['location?']
 
134
    takes_options = ['remember', Option('directory',
 
135
            help='Branch to push from, '
 
136
                 'rather than the one containing the working directory.',
 
137
            short_name='d',
 
138
            type=unicode,
 
139
            ),
 
140
            Option('no-rebase', help="Don't rebase after push")]
 
141
 
 
142
    def run(self, location=None, remember=False, directory=None, 
 
143
            no_rebase=False):
 
144
        from bzrlib import urlutils
 
145
        from bzrlib.bzrdir import BzrDir
 
146
        from bzrlib.errors import BzrCommandError, NoWorkingTree
 
147
        from bzrlib.workingtree import WorkingTree
 
148
 
 
149
        if directory is None:
 
150
            directory = "."
 
151
        try:
 
152
            source_wt = WorkingTree.open_containing(directory)[0]
 
153
            source_branch = source_wt.branch
 
154
        except NoWorkingTree:
 
155
            source_branch = Branch.open_containing(directory)[0]
 
156
            source_wt = None
 
157
        stored_loc = source_branch.get_push_location()
 
158
        if location is None:
 
159
            if stored_loc is None:
 
160
                raise BzrCommandError("No push location known or specified.")
 
161
            else:
 
162
                display_url = urlutils.unescape_for_display(stored_loc,
 
163
                        self.outf.encoding)
 
164
                self.outf.write("Using saved location: %s\n" % display_url)
 
165
                location = stored_loc
 
166
 
 
167
        bzrdir = BzrDir.open(location)
 
168
        target_branch = bzrdir.open_branch()
 
169
        target_branch.lock_write()
 
170
        if not isinstance(target_branch, ForeignBranch):
 
171
            info("target branch is not a foreign branch, using regular push.")
 
172
            target_branch.pull(source_branch)
 
173
            no_rebase = True
 
174
        else:
 
175
            revid_map = target_branch.dpull(source_branch)
 
176
        # We successfully created the target, remember it
 
177
        if source_branch.get_push_location() is None or remember:
 
178
            source_branch.set_push_location(target_branch.base)
 
179
        if not no_rebase:
 
180
            _, old_last_revid = source_branch.last_revision_info()
 
181
            new_last_revid = revid_map[old_last_revid]
 
182
            if source_wt is not None:
 
183
                source_wt.pull(target_branch, overwrite=True, 
 
184
                               stop_revision=new_last_revid)
 
185
            else:
 
186
                source_branch.pull(target_branch, overwrite=True, 
 
187
                                   stop_revision=new_last_revid)
 
188
 
 
189
def test_suite():
 
190
    from unittest import TestSuite
 
191
    from bzrlib.tests import TestUtil
 
192
    loader = TestUtil.TestLoader()
 
193
    suite = TestSuite()
 
194
    testmod_names = ['test_versionedfiles', ]
 
195
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
 
196
    return suite
 
197
 
 
198
 
 
199
def escape_commit_message(message):
 
200
    """Replace xml-incompatible control characters."""
 
201
    if message is None:
 
202
        return None
 
203
    import re
 
204
    # FIXME: RBC 20060419 this should be done by the revision
 
205
    # serialiser not by commit. Then we can also add an unescaper
 
206
    # in the deserializer and start roundtripping revision messages
 
207
    # precisely. See repository_implementations/test_repository.py
 
208
    
 
209
    # Python strings can include characters that can't be
 
210
    # represented in well-formed XML; escape characters that
 
211
    # aren't listed in the XML specification
 
212
    # (http://www.w3.org/TR/REC-xml/#NT-Char).
 
213
    message, _ = re.subn(
 
214
        u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
 
215
        lambda match: match.group(0).encode('unicode_escape'),
 
216
        message)
 
217
    return message
 
218
 
 
219
 
 
220
class ForeignRevision(Revision):
 
221
    """A Revision from a Foreign repository. Remembers 
 
222
    information about foreign revision id and mapping.
 
223
 
 
224
    """
 
225
 
 
226
    def __init__(self, foreign_revid, mapping, *args, **kwargs):
 
227
        super(ForeignRevision, self).__init__(*args, **kwargs)
 
228
        self.foreign_revid = foreign_revid
 
229
        self.mapping = mapping
 
230
 
 
231
 
 
232
def show_foreign_properties(mapping_registry, rev):
 
233
    """Custom log displayer for foreign revision identifiers.
 
234
 
 
235
    :param rev: Revision object.
 
236
    """
 
237
    # Revision comes directly from a foreign repository
 
238
    if isinstance(rev, ForeignRevision):
 
239
        return rev.mapping.show_foreign_revid(rev.foreign_revid)
 
240
 
 
241
    # Revision was once imported from a foreign repository
 
242
    try:
 
243
        foreign_revid, mapping = mapping_registry.parse_revision_id(rev.revision_id)
 
244
    except InvalidRevisionId:
 
245
        return {}
 
246
 
 
247
    return mapping.show_foreign_revid(foreign_revid)
 
248
 
 
249