/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
1
# Copyright (C) 2008 Canonical Ltd
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3918.2.2 by Martin Pool
Add import statement
16
17
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
18
"""Foreign branch utilities."""
19
3918.2.2 by Martin Pool
Add import statement
20
4347.2.1 by Jelmer Vernooij
Move dpush onto an InterBranch object.
21
from bzrlib.branch import (
22
    Branch,
23
    InterBranch,
24
    )
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
25
from bzrlib.commands import Command, Option
3918.2.2 by Martin Pool
Add import statement
26
from bzrlib.repository import Repository
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
27
from bzrlib.revision import Revision
28
from bzrlib.lazy_import import lazy_import
29
lazy_import(globals(), """
30
from bzrlib import (
31
    errors,
3878.5.1 by Jelmer Vernooij
Add a ForeignRepository base class.
32
    osutils,
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
33
    registry,
4285.3.1 by Aaron Bentley
Implement dpush via sexy APIs
34
    transform,
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
35
    )
36
""")
37
38
class VcsMapping(object):
4585.1.7 by Jelmer Vernooij
Use scenarios and adapters.
39
    """Describes the mapping between the semantics of Bazaar and a foreign VCS.
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
40
41
    """
42
    # Whether this is an experimental mapping that is still open to changes.
43
    experimental = False
44
45
    # Whether this mapping supports exporting and importing all bzr semantics.
46
    roundtripping = False
47
4531.2.1 by Samuel Bronson
Clarify comment about bzrlib.foreign.VcsMapping's variable revid_prefix.
48
    # Prefix used when importing revisions native to the foreign VCS (as
49
    # opposed to roundtripping bzr-native revisions) using this mapping.
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
50
    revid_prefix = None
51
3949.5.1 by Jelmer Vernooij
Move ForeignVcsMapping.show_foreign_revid to ForeignVcs.
52
    def __init__(self, vcs):
53
        """Create a new VcsMapping.
54
55
        :param vcs: VCS that this mapping maps to Bazaar
56
        """
57
        self.vcs = vcs
58
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
59
    def revision_id_bzr_to_foreign(self, bzr_revid):
60
        """Parse a bzr revision id and convert it to a foreign revid.
61
62
        :param bzr_revid: The bzr revision id (a string).
63
        :return: A foreign revision id, can be any sort of object.
64
        """
65
        raise NotImplementedError(self.revision_id_bzr_to_foreign)
66
67
    def revision_id_foreign_to_bzr(self, foreign_revid):
68
        """Parse a foreign revision id and convert it to a bzr revid.
69
70
        :param foreign_revid: Foreign revision id, can be any sort of object.
71
        :return: A bzr revision id.
72
        """
73
        raise NotImplementedError(self.revision_id_foreign_to_bzr)
74
75
76
class VcsMappingRegistry(registry.Registry):
77
    """Registry for Bazaar<->foreign VCS mappings.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
78
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
79
    There should be one instance of this registry for every foreign VCS.
80
    """
81
82
    def register(self, key, factory, help):
83
        """Register a mapping between Bazaar and foreign VCS semantics.
84
85
        The factory must be a callable that takes one parameter: the key.
86
        It must produce an instance of VcsMapping when called.
87
        """
88
        if ":" in key:
89
            raise ValueError("mapping name can not contain colon (:)")
90
        registry.Registry.register(self, key, factory, help)
91
92
    def set_default(self, key):
93
        """Set the 'default' key to be a clone of the supplied key.
94
95
        This method must be called once and only once.
96
        """
97
        self._set_default_key(key)
98
99
    def get_default(self):
100
        """Convenience function for obtaining the default mapping to use."""
101
        return self.get(self._get_default_key())
102
103
    def revision_id_bzr_to_foreign(self, revid):
104
        """Convert a bzr revision id to a foreign revid."""
105
        raise NotImplementedError(self.revision_id_bzr_to_foreign)
106
107
108
class ForeignRevision(Revision):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
109
    """A Revision from a Foreign repository. Remembers
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
110
    information about foreign revision id and mapping.
111
112
    """
113
114
    def __init__(self, foreign_revid, mapping, *args, **kwargs):
3830.4.4 by Jelmer Vernooij
make inventory_sha1 default to an empty string.
115
        if not "inventory_sha1" in kwargs:
116
            kwargs["inventory_sha1"] = ""
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
117
        super(ForeignRevision, self).__init__(*args, **kwargs)
118
        self.foreign_revid = foreign_revid
119
        self.mapping = mapping
120
121
122
class ForeignVcs(object):
123
    """A foreign version control system."""
124
4585.1.10 by Jelmer Vernooij
Store only a single branch format per foreign VCS (for now).
125
    branch_format = None
4585.1.8 by Jelmer Vernooij
Make branch formats provide a factory for particular situations.
126
4585.1.11 by Jelmer Vernooij
Add tests for foreign repository formats.
127
    repository_format = None
128
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
129
    def __init__(self, mapping_registry):
130
        self.mapping_registry = mapping_registry
131
3949.5.1 by Jelmer Vernooij
Move ForeignVcsMapping.show_foreign_revid to ForeignVcs.
132
    def show_foreign_revid(self, foreign_revid):
133
        """Prepare a foreign revision id for formatting using bzr log.
4032.1.1 by John Arbash Meinel
Merge the removal of all trailing whitespace, and resolve conflicts.
134
3949.5.1 by Jelmer Vernooij
Move ForeignVcsMapping.show_foreign_revid to ForeignVcs.
135
        :param foreign_revid: Foreign revision id.
136
        :return: Dictionary mapping string keys to string values.
137
        """
138
        return { }
139
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
140
141
class ForeignVcsRegistry(registry.Registry):
142
    """Registry for Foreign VCSes.
143
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
144
    There should be one entry per foreign VCS. Example entries would be
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
145
    "git", "svn", "hg", "darcs", etc.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
146
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
147
    """
148
149
    def register(self, key, foreign_vcs, help):
150
        """Register a foreign VCS.
151
152
        :param key: Prefix of the foreign VCS in revision ids
153
        :param foreign_vcs: ForeignVCS instance
154
        :param help: Description of the foreign VCS
155
        """
156
        if ":" in key or "-" in key:
157
            raise ValueError("vcs name can not contain : or -")
158
        registry.Registry.register(self, key, foreign_vcs, help)
159
160
    def parse_revision_id(self, revid):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
161
        """Parse a bzr revision and return the matching mapping and foreign
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
162
        revid.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
163
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
164
        :param revid: The bzr revision id
165
        :return: tuple with foreign revid and vcs mapping
166
        """
4393.1.1 by Jelmer Vernooij
Check for : in foreign revids early.
167
        if not ":" in revid or not "-" in revid:
3830.4.1 by Jelmer Vernooij
Add base classes for foreign branches.
168
            raise errors.InvalidRevisionId(revid, None)
169
        try:
170
            foreign_vcs = self.get(revid.split("-")[0])
171
        except KeyError:
172
            raise errors.InvalidRevisionId(revid, None)
173
        return foreign_vcs.mapping_registry.revision_id_bzr_to_foreign(revid)
174
175
176
foreign_vcs_registry = ForeignVcsRegistry()
3878.5.1 by Jelmer Vernooij
Add a ForeignRepository base class.
177
178
179
class ForeignRepository(Repository):
180
    """A Repository that exists in a foreign version control system.
181
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
182
    The data in this repository can not be represented natively using
3878.5.1 by Jelmer Vernooij
Add a ForeignRepository base class.
183
    Bazaars internal datastructures, but have to converted using a VcsMapping.
184
    """
185
186
    # This repository's native version control system
187
    vcs = None
188
189
    def has_foreign_revision(self, foreign_revid):
190
        """Check whether the specified foreign revision is present.
191
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
192
        :param foreign_revid: A foreign revision id, in the format used
3878.5.1 by Jelmer Vernooij
Add a ForeignRepository base class.
193
                              by this Repository's VCS.
194
        """
195
        raise NotImplementedError(self.has_foreign_revision)
196
197
    def lookup_bzr_revision_id(self, revid):
198
        """Lookup a mapped or roundtripped revision by revision id.
199
200
        :param revid: Bazaar revision id
201
        :return: Tuple with foreign revision id and mapping.
202
        """
203
        raise NotImplementedError(self.lookup_revision_id)
204
205
    def all_revision_ids(self, mapping=None):
206
        """See Repository.all_revision_ids()."""
207
        raise NotImplementedError(self.all_revision_ids)
208
209
    def get_default_mapping(self):
210
        """Get the default mapping for this repository."""
211
        raise NotImplementedError(self.get_default_mapping)
212
213
    def get_inventory_xml(self, revision_id):
214
        """See Repository.get_inventory_xml()."""
215
        return self.serialise_inventory(self.get_inventory(revision_id))
216
217
    def get_inventory_sha1(self, revision_id):
218
        """Get the sha1 for the XML representation of an inventory.
219
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
220
        :param revision_id: Revision id of the inventory for which to return
3878.5.1 by Jelmer Vernooij
Add a ForeignRepository base class.
221
         the SHA1.
222
        :return: XML string
223
        """
224
225
        return osutils.sha_string(self.get_inventory_xml(revision_id))
226
227
    def get_revision_xml(self, revision_id):
228
        """Return the XML representation of a revision.
229
230
        :param revision_id: Revision for which to return the XML.
231
        :return: XML string
232
        """
233
        return self._serializer.write_revision_to_string(
234
            self.get_revision(revision_id))
235
236
3920.2.1 by Jelmer Vernooij
Add ForeignBranch class.
237
class ForeignBranch(Branch):
238
    """Branch that exists in a foreign version control system."""
239
240
    def __init__(self, mapping):
241
        self.mapping = mapping
242
        super(ForeignBranch, self).__init__()
243
3920.2.2 by Jelmer Vernooij
Import dpush command.
244
4285.3.1 by Aaron Bentley
Implement dpush via sexy APIs
245
def update_workingtree_fileids(wt, target_tree):
4285.3.2 by Jelmer Vernooij
Remove unused functions for updating the file ids of a tree.
246
    """Update the file ids in a working tree based on another tree.
247
248
    :param wt: Working tree in which to update file ids
249
    :param target_tree: Tree to retrieve new file ids from, based on path
250
    """
4285.3.1 by Aaron Bentley
Implement dpush via sexy APIs
251
    tt = transform.TreeTransform(wt)
252
    try:
253
        for f, p, c, v, d, n, k, e in target_tree.iter_changes(wt):
254
            if v == (True, False):
255
                trans_id = tt.trans_id_tree_path(p[0])
256
                tt.unversion_file(trans_id)
257
            elif v == (False, True):
258
                trans_id = tt.trans_id_tree_path(p[1])
259
                tt.version_file(f, trans_id)
260
        tt.apply()
261
    finally:
262
        tt.finalize()
263
    if len(wt.get_parent_ids()) == 1:
264
        wt.set_parent_trees([(target_tree.get_revision_id(), target_tree)])
265
    else:
266
        wt.set_last_revision(target_tree.get_revision_id())
267
268
3920.2.2 by Jelmer Vernooij
Import dpush command.
269
class cmd_dpush(Command):
4368.2.1 by Jelmer Vernooij
make dpush help and output reflect that dpush is not possible between branches
270
    """Push into a different VCS without any custom bzr metadata.
3920.2.2 by Jelmer Vernooij
Import dpush command.
271
4368.2.1 by Jelmer Vernooij
make dpush help and output reflect that dpush is not possible between branches
272
    This will afterwards rebase the local branch on the remote
3920.2.2 by Jelmer Vernooij
Import dpush command.
273
    branch unless the --no-rebase option is used, in which case 
4347.2.4 by Jelmer Vernooij
Fix one-line summary for dpush.
274
    the two branches will be out of sync after the push. 
3920.2.2 by Jelmer Vernooij
Import dpush command.
275
    """
3920.2.30 by Jelmer Vernooij
Review from John.
276
    hidden = True
3920.2.2 by Jelmer Vernooij
Import dpush command.
277
    takes_args = ['location?']
4721.2.2 by Vincent Ladeuil
Start testing and implementing --strict for dpush.
278
    takes_options = [
279
        'remember',
280
        Option('directory',
281
               help='Branch to push from, '
282
               'rather than the one containing the working directory.',
283
               short_name='d',
284
               type=unicode,
285
               ),
286
        Option('no-rebase', help="Do not rebase after push."),
287
        Option('strict',
288
               help='Refuse to push if there are uncommitted changes in'
289
               ' the working tree, --no-strict disables the check.'),
290
        ]
3920.2.2 by Jelmer Vernooij
Import dpush command.
291
4721.2.2 by Vincent Ladeuil
Start testing and implementing --strict for dpush.
292
    def run(self, location=None, remember=False, directory=None,
293
            no_rebase=False, strict=None):
3920.2.2 by Jelmer Vernooij
Import dpush command.
294
        from bzrlib import urlutils
295
        from bzrlib.bzrdir import BzrDir
296
        from bzrlib.errors import BzrCommandError, NoWorkingTree
297
        from bzrlib.workingtree import WorkingTree
298
299
        if directory is None:
300
            directory = "."
301
        try:
302
            source_wt = WorkingTree.open_containing(directory)[0]
303
            source_branch = source_wt.branch
304
        except NoWorkingTree:
3920.2.30 by Jelmer Vernooij
Review from John.
305
            source_branch = Branch.open(directory)
3920.2.2 by Jelmer Vernooij
Import dpush command.
306
            source_wt = None
4721.2.3 by Vincent Ladeuil
Make all test pass by implement --strict for dpush.
307
        if strict is None:
308
            strict = source_branch.get_config(
309
                ).get_user_option_as_bool('dpush_strict')
310
        if strict is None: strict = True # default value
311
        if strict and source_wt is not None:
4721.3.2 by Vincent Ladeuil
Simplify mutable_tree.has_changes() and update call sites.
312
            if (source_wt.has_changes()):
4721.2.3 by Vincent Ladeuil
Make all test pass by implement --strict for dpush.
313
                raise errors.UncommittedChanges(
314
                    source_wt, more='Use --no-strict to force the push.')
315
            if source_wt.last_revision() != source_wt.branch.last_revision():
316
                # The tree has lost sync with its branch, there is little
317
                # chance that the user is aware of it but he can still force
318
                # the push with --no-strict
319
                raise errors.OutOfDateTree(
320
                    source_wt, more='Use --no-strict to force the push.')
3920.2.2 by Jelmer Vernooij
Import dpush command.
321
        stored_loc = source_branch.get_push_location()
322
        if location is None:
323
            if stored_loc is None:
324
                raise BzrCommandError("No push location known or specified.")
325
            else:
326
                display_url = urlutils.unescape_for_display(stored_loc,
327
                        self.outf.encoding)
328
                self.outf.write("Using saved location: %s\n" % display_url)
329
                location = stored_loc
330
331
        bzrdir = BzrDir.open(location)
332
        target_branch = bzrdir.open_branch()
333
        target_branch.lock_write()
334
        try:
4347.2.3 by Jelmer Vernooij
Clarify name for LossyPushToSameVCS exception.
335
            try:
4347.3.1 by Jelmer Vernooij
Return BranchPushResult instance from lossy_push() and make dpush print
336
                push_result = source_branch.lossy_push(target_branch)
4347.2.3 by Jelmer Vernooij
Clarify name for LossyPushToSameVCS exception.
337
            except errors.LossyPushToSameVCS:
4368.2.1 by Jelmer Vernooij
make dpush help and output reflect that dpush is not possible between branches
338
                raise BzrCommandError("%r and %r are in the same VCS, lossy "
4368.2.2 by Jelmer Vernooij
s/not possible/not necessary/.
339
                    "push not necessary. Please use regular push." %
4368.2.1 by Jelmer Vernooij
make dpush help and output reflect that dpush is not possible between branches
340
                    (source_branch, target_branch))
3920.2.2 by Jelmer Vernooij
Import dpush command.
341
            # We successfully created the target, remember it
342
            if source_branch.get_push_location() is None or remember:
343
                source_branch.set_push_location(target_branch.base)
344
            if not no_rebase:
3920.2.36 by Jelmer Vernooij
Fix tests after CommitBuilder changes.
345
                old_last_revid = source_branch.last_revision()
3920.2.30 by Jelmer Vernooij
Review from John.
346
                source_branch.pull(target_branch, overwrite=True)
3920.2.36 by Jelmer Vernooij
Fix tests after CommitBuilder changes.
347
                new_last_revid = source_branch.last_revision()
3920.3.1 by Jelmer Vernooij
Skip tree changing if nothing changed.
348
                if source_wt is not None and old_last_revid != new_last_revid:
3920.2.2 by Jelmer Vernooij
Import dpush command.
349
                    source_wt.lock_write()
350
                    try:
4285.3.1 by Aaron Bentley
Implement dpush via sexy APIs
351
                        target = source_wt.branch.repository.revision_tree(
352
                            new_last_revid)
353
                        update_workingtree_fileids(source_wt, target)
3920.2.2 by Jelmer Vernooij
Import dpush command.
354
                    finally:
355
                        source_wt.unlock()
4347.3.1 by Jelmer Vernooij
Return BranchPushResult instance from lossy_push() and make dpush print
356
            push_result.report(self.outf)
3920.2.2 by Jelmer Vernooij
Import dpush command.
357
        finally:
358
            target_branch.unlock()
4347.2.1 by Jelmer Vernooij
Move dpush onto an InterBranch object.
359
360
361
class InterToForeignBranch(InterBranch):
362
4347.2.2 by Jelmer Vernooij
Rename dpush to lossy_push.
363
    def lossy_push(self, stop_revision=None):
364
        """Push deltas into another branch.
4347.2.1 by Jelmer Vernooij
Move dpush onto an InterBranch object.
365
366
        :note: This does not, like push, retain the revision ids from 
367
            the source branch and will, rather than adding bzr-specific 
368
            metadata, push only those semantics of the revision that can be 
369
            natively represented by this branch' VCS.
370
371
        :param target: Target branch
372
        :param stop_revision: Revision to push, defaults to last revision.
4347.3.1 by Jelmer Vernooij
Return BranchPushResult instance from lossy_push() and make dpush print
373
        :return: BranchPushResult with an extra member revidmap: 
374
            A dictionary mapping revision ids from the target branch 
4347.2.1 by Jelmer Vernooij
Move dpush onto an InterBranch object.
375
            to new revision ids in the target branch, for each 
376
            revision that was pushed.
377
        """
4347.2.2 by Jelmer Vernooij
Rename dpush to lossy_push.
378
        raise NotImplementedError(self.lossy_push)