/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 breezy/plugins/rewrite/upgrade.py

  • Committer: Jelmer Vernooij
  • Date: 2020-05-06 02:13:25 UTC
  • mfrom: (7490.7.21 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200506021325-awbmmqu1zyorz7sj
Merge 3.1 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2006-2009 by Jelmer Vernooij
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
5
5
# the Free Software Foundation; either version 3 of the License, or
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
16
18
"""Upgrading revisions made with older versions of the mapping."""
17
19
 
18
 
from bzrlib import ui
19
 
from bzrlib.errors import (
20
 
    DependencyNotPresent,
 
20
from ... import (
 
21
    osutils,
 
22
    trace,
 
23
    ui,
 
24
    )
 
25
from ...errors import (
21
26
    BzrError,
22
 
    InvalidRevisionId,
23
 
    NoSuchRevision,
24
 
    )
25
 
from bzrlib.trace import info
26
 
 
27
 
import itertools
28
 
 
29
 
class RebaseNotPresent(DependencyNotPresent):
30
 
    _fmt = "Unable to import bzr-rebase (required for upgrade support): %(error)s"
31
 
 
32
 
    def __init__(self, error):
33
 
        DependencyNotPresent.__init__(self, 'bzr-rebase', error)
34
 
 
35
 
 
36
 
def check_rebase_version(min_version):
37
 
    """Check what version of bzr-rebase is installed.
38
 
 
39
 
    Raises an exception when the version installed is older than 
40
 
    min_version.
41
 
 
42
 
    :raises RebaseNotPresent: Raised if bzr-rebase is not installed or too old.
43
 
    """
44
 
    try:
45
 
        from bzrlib.plugins.rebase import version_info as rebase_version_info
46
 
        if rebase_version_info[:len(min_version)] < min_version:
47
 
            raise RebaseNotPresent("Version %r present, at least %r required" 
48
 
                                   % (rebase_version_info, min_version))
49
 
    except ImportError, e:
50
 
        raise RebaseNotPresent(e)
51
 
 
 
27
    )
 
28
from .rebase import (
 
29
    generate_transpose_plan,
 
30
    CommitBuilderRevisionRewriter,
 
31
    rebase,
 
32
    rebase_todo,
 
33
    )
52
34
 
53
35
 
54
36
class UpgradeChangesContent(BzrError):
59
41
        self.revid = revid
60
42
 
61
43
 
 
44
def create_deterministic_revid(revid, new_parents):
 
45
    """Create a new deterministic revision id with specified new parents.
62
46
 
63
 
def create_upgraded_revid(revid, mapping_suffix, upgrade_suffix="-upgrade"):
64
 
    """Create a new revision id for an upgraded version of a revision.
65
 
    
66
47
    Prevents suffix to be appended needlessly.
67
48
 
68
49
    :param revid: Original revision id.
69
50
    :return: New revision id
70
51
    """
71
 
    if revid.endswith(upgrade_suffix):
72
 
        return revid[0:revid.rfind("-svn")] + mapping_suffix + upgrade_suffix
73
 
    else:
74
 
        return revid + mapping_suffix + upgrade_suffix
75
 
 
76
 
 
77
 
def determine_fileid_renames(old_inv, new_inv):
78
 
    """Determine the file ids based on a old and a new inventory that 
79
 
    are equal in content.
80
 
 
81
 
    :param old_inv: Old inventory
82
 
    :param new_inv: New inventory
83
 
    :return: Dictionary a (old_id, new_id) tuple for each path in the 
84
 
        inventories.
85
 
    """
86
 
    ret = {}
87
 
    if len(old_inv) != len(new_inv):
88
 
        raise AssertionError("Inventories are not of the same size")
89
 
    for old_file_id in old_inv:
90
 
        new_file_id = new_inv.path2id(old_inv.id2path(old_file_id))
91
 
        if new_file_id is None:
92
 
            raise AssertionError(
93
 
                "Unable to find %s in new inventory" % old_file_id)
94
 
        ret[new_inv.id2path(new_file_id)] = (old_file_id, new_file_id)
95
 
    return ret
96
 
 
97
 
 
98
 
def update_workinginv_fileids(wt, old_inv, new_inv):
99
 
    """Update all file ids in wt according to old_tree/new_tree. 
100
 
 
101
 
    old_tree and new_tree should be two RevisionTree's that differ only
102
 
    in file ids.
103
 
    """
104
 
    fileid_renames = determine_fileid_renames(old_inv, new_inv)
105
 
    old_fileids = []
106
 
    new_fileids = []
107
 
    new_root_id = None
108
 
    # Adjust file ids in working tree
109
 
    # Sorted, so we process parents before children
110
 
    for path in sorted(fileid_renames.keys()):
111
 
        if path != "":
112
 
            old_fileids.append(fileid_renames[path][0])
113
 
            new_fileids.append((path, fileid_renames[path][1]))
114
 
        else:
115
 
            new_root_id = fileid_renames[path][1]
116
 
    new_fileids.reverse()
117
 
    wt.unversion(old_fileids)
118
 
    if new_root_id is not None:
119
 
        wt.set_root_id(new_root_id)
120
 
    wt.add([x[0] for x in new_fileids], [x[1] for x in new_fileids])
121
 
    wt.set_last_revision(new_inv.revision_id)
122
 
 
123
 
 
124
 
def upgrade_workingtree(wt, foreign_repository, new_mapping, 
125
 
                        allow_changes=False, verbose=False):
126
 
    """Upgrade a working tree.
127
 
 
128
 
    :param foreign_repository: Foreign repository object
129
 
    """
130
 
    wt.lock_write()
131
 
    try:
132
 
        old_revid = wt.last_revision()
133
 
        revid_renames = upgrade_branch(wt.branch, foreign_repository, new_mapping=new_mapping,
134
 
                                 allow_changes=allow_changes, verbose=verbose)
135
 
        last_revid = wt.branch.last_revision()
136
 
        if old_revid == last_revid:
137
 
            return revid_renames
138
 
        old_inv = wt.branch.repository.get_inventory(old_revid)
139
 
        new_inv = wt.branch.repository.get_inventory(last_revid)
140
 
        update_workinginv_fileids(wt, old_inv, new_inv)
141
 
    finally:
142
 
        wt.unlock()
143
 
 
144
 
    return revid_renames
145
 
 
146
 
 
147
 
def upgrade_tags(tags, repository, foreign_repository, new_mapping, 
148
 
                 allow_changes=False, verbose=False, branch_renames=None):
 
52
    if "-rebase-" in revid:
 
53
        revid = revid[0:revid.rfind("-rebase-")]
 
54
    return revid + "-rebase-" + osutils.sha_string(":".join(new_parents))[:8]
 
55
 
 
56
 
 
57
def upgrade_tags(tags, repository, generate_rebase_map, determine_new_revid,
 
58
                 allow_changes=False, verbose=False, branch_renames=None,
 
59
                 branch_ancestry=None):
149
60
    """Upgrade a tags dictionary."""
150
61
    renames = {}
151
62
    if branch_renames is not None:
153
64
    pb = ui.ui_factory.nested_progress_bar()
154
65
    try:
155
66
        tags_dict = tags.get_tag_dict()
156
 
        for i, (name, revid) in enumerate(tags_dict.items()):
 
67
        for i, (name, revid) in enumerate(tags_dict.iteritems()):
157
68
            pb.update("upgrading tags", i, len(tags_dict))
158
 
            if not revid in renames:
159
 
                renames.update(upgrade_repository(repository, foreign_repository, 
160
 
                      revision_id=revid, new_mapping=new_mapping,
161
 
                      allow_changes=allow_changes, verbose=verbose))
162
 
            if revid in renames:
 
69
            if revid not in renames:
 
70
                try:
 
71
                    repository.lock_read()
 
72
                    revid_exists = repository.has_revision(revid)
 
73
                finally:
 
74
                    repository.unlock()
 
75
                if revid_exists:
 
76
                    renames.update(upgrade_repository(
 
77
                        repository,
 
78
                        generate_rebase_map, determine_new_revid,
 
79
                        revision_id=revid, allow_changes=allow_changes,
 
80
                        verbose=verbose))
 
81
            if (revid in renames and
 
82
                    (branch_ancestry is None or revid not in branch_ancestry)):
163
83
                tags.set_tag(name, renames[revid])
164
84
    finally:
165
85
        pb.finished()
166
86
 
167
87
 
168
 
def upgrade_branch(branch, foreign_repository, new_mapping, 
 
88
def upgrade_branch(branch, generate_rebase_map, determine_new_revid,
169
89
                   allow_changes=False, verbose=False):
170
90
    """Upgrade a branch to the current mapping version.
171
 
    
 
91
 
172
92
    :param branch: Branch to upgrade.
173
93
    :param foreign_repository: Repository to fetch new revisions from
174
94
    :param allow_changes: Allow changes in mappings.
175
95
    :param verbose: Whether to print verbose list of rewrites
176
96
    """
177
97
    revid = branch.last_revision()
178
 
    renames = upgrade_repository(branch.repository, foreign_repository, 
179
 
              revision_id=revid, new_mapping=new_mapping,
180
 
              allow_changes=allow_changes, verbose=verbose)
181
 
    upgrade_tags(branch.tags, branch.repository, foreign_repository, 
182
 
           new_mapping=new_mapping, 
183
 
           allow_changes=allow_changes, verbose=verbose, branch_renames=renames)
 
98
    renames = upgrade_repository(
 
99
        branch.repository, generate_rebase_map,
 
100
        determine_new_revid, revision_id=revid,
 
101
        allow_changes=allow_changes, verbose=verbose)
184
102
    if revid in renames:
185
103
        branch.generate_revision_history(renames[revid])
 
104
    ancestry = branch.repository.get_ancestry(
 
105
        branch.last_revision(), topo_sorted=False)
 
106
    upgrade_tags(
 
107
        branch.tags, branch.repository, generate_rebase_map,
 
108
        determine_new_revid, allow_changes=allow_changes, verbose=verbose,
 
109
        branch_renames=renames, branch_ancestry=ancestry)
186
110
    return renames
187
111
 
188
112
 
189
113
def check_revision_changed(oldrev, newrev):
190
 
    """Check if two revisions are different. This is exactly the same 
 
114
    """Check if two revisions are different. This is exactly the same
191
115
    as Revision.equals() except that it does not check the revision_id."""
192
116
    if (newrev.inventory_sha1 != oldrev.inventory_sha1 or
193
 
        newrev.timestamp != oldrev.timestamp or
194
 
        newrev.message != oldrev.message or
195
 
        newrev.timezone != oldrev.timezone or
196
 
        newrev.committer != oldrev.committer or
197
 
        newrev.properties != oldrev.properties):
 
117
            newrev.timestamp != oldrev.timestamp or
 
118
            newrev.message != oldrev.message or
 
119
            newrev.timezone != oldrev.timezone or
 
120
            newrev.committer != oldrev.committer or
 
121
            newrev.properties != oldrev.properties):
198
122
        raise UpgradeChangesContent(oldrev.revision_id)
199
123
 
200
124
 
201
 
def generate_upgrade_map(revs, vcs, determine_upgraded_revid):
202
 
    """Generate an upgrade map for use by bzr-rebase.
203
 
 
204
 
    :param new_mapping: Mapping to upgrade revisions to.
205
 
    :param vcs: The foreign vcs
206
 
    :param revs: Iterator over revisions to upgrade.
207
 
    :return: Map from old revids as keys, new revids as values stored in a 
208
 
             dictionary.
209
 
    """
210
 
    rename_map = {}
211
 
    # Create a list of revisions that can be renamed during the upgrade
212
 
    for revid in revs:
213
 
        assert isinstance(revid, str)
214
 
        try:
215
 
            (foreign_revid, old_mapping) = vcs.mapping_registry.parse_revision_id(revid)
216
 
        except InvalidRevisionId:
217
 
            # Not a foreign revision, nothing to do
218
 
            continue
219
 
        newrevid = determine_upgraded_revid(foreign_revid)
220
 
        if newrevid in (revid, None):
221
 
            continue
222
 
        rename_map[revid] = newrevid
223
 
    return rename_map
224
 
 
225
 
MIN_REBASE_VERSION = (0, 4, 3)
226
 
 
227
 
def create_upgrade_plan(repository, foreign_repository, new_mapping,
 
125
def create_upgrade_plan(repository, generate_rebase_map, determine_new_revid,
228
126
                        revision_id=None, allow_changes=False):
229
127
    """Generate a rebase plan for upgrading revisions.
230
128
 
231
129
    :param repository: Repository to do upgrade in
232
 
    :param foreign_repository: Subversion repository to fetch new revisions from.
 
130
    :param foreign_repository: Subversion repository to fetch new revisions
 
131
        from.
233
132
    :param new_mapping: New mapping to use.
234
 
    :param revision_id: Revision to upgrade (None for all revisions in 
 
133
    :param revision_id: Revision to upgrade (None for all revisions in
235
134
        repository.)
236
135
    :param allow_changes: Whether an upgrade is allowed to change the contents
237
136
        of revisions.
238
137
    :return: Tuple with a rebase plan and map of renamed revisions.
239
138
    """
240
 
    from bzrlib.plugins.rebase.rebase import generate_transpose_plan
241
 
    check_rebase_version(MIN_REBASE_VERSION)
242
139
 
243
140
    graph = repository.get_graph()
244
 
    if revision_id is None:
245
 
        potential = repository.all_revision_ids()
246
 
    else:
247
 
        potential = itertools.imap(lambda (rev, parents): rev, 
248
 
                graph.iter_ancestry([revision_id]))
249
 
 
250
 
    def determine_upgraded_revid(foreign_revid):
251
 
        # FIXME: Try all mappings until new_mapping rather than just new_mapping
252
 
        new_revid = foreign_repository.upgrade_foreign_revision_id(foreign_revid, new_mapping)
253
 
        if new_revid is None:
254
 
            return None
255
 
        # Make sure the revision is there
256
 
        if not repository.has_revision(new_revid):
257
 
            try:
258
 
                repository.fetch(foreign_repository, new_revid)
259
 
            except NoSuchRevision:
260
 
                return None
261
 
            if not repository.has_revision(new_revid):
262
 
                return None
263
 
        return new_revid
264
 
 
265
 
    upgrade_map = generate_upgrade_map(potential, foreign_repository.vcs, 
266
 
                                       determine_upgraded_revid)
267
 
   
 
141
    upgrade_map = generate_rebase_map(revision_id)
 
142
 
268
143
    if not allow_changes:
269
144
        for oldrevid, newrevid in upgrade_map.iteritems():
270
145
            oldrev = repository.get_revision(oldrevid)
272
147
            check_revision_changed(oldrev, newrev)
273
148
 
274
149
    if revision_id is None:
275
 
        heads = repository.all_revision_ids() 
 
150
        heads = repository.all_revision_ids()
276
151
    else:
277
152
        heads = [revision_id]
278
153
 
279
 
    def determine_new_revid(old_revid):
280
 
        # If this revision id already exists round-tripped upstream, 
281
 
        # leave it alone.
282
 
        if foreign_repository.has_revision(old_revid):
283
 
            return old_revid
284
 
        # if not, return old_revid'
285
 
        return create_upgraded_revid(old_revid, new_mapping.upgrade_suffix)
286
 
 
287
 
    plan = generate_transpose_plan(graph.iter_ancestry(heads), upgrade_map, 
288
 
      graph, determine_new_revid)
289
 
    def remove_parents((oldrevid, (newrevid, parents))):
 
154
    plan = generate_transpose_plan(
 
155
        graph.iter_ancestry(heads), upgrade_map, graph, determine_new_revid)
 
156
    def remove_parents(entry):
 
157
        (oldrevid, (newrevid, parents)) = entry
290
158
        return (oldrevid, newrevid)
291
159
    upgrade_map.update(dict(map(remove_parents, plan.iteritems())))
292
160
 
293
161
    return (plan, upgrade_map)
294
162
 
295
 
 
296
 
def upgrade_repository(repository, foreign_repository, new_mapping, 
297
 
                       revision_id=None, allow_changes=False, 
298
 
                       verbose=False):
 
163
 
 
164
def upgrade_repository(repository, generate_rebase_map,
 
165
                       determine_new_revid, revision_id=None,
 
166
                       allow_changes=False, verbose=False):
299
167
    """Upgrade the revisions in repository until the specified stop revision.
300
168
 
301
169
    :param repository: Repository in which to upgrade.
302
170
    :param foreign_repository: Repository to fetch new revisions from.
303
171
    :param new_mapping: New mapping.
304
 
    :param revision_id: Revision id up until which to upgrade, or None for 
 
172
    :param revision_id: Revision id up until which to upgrade, or None for
305
173
                        all revisions.
306
174
    :param allow_changes: Allow changes to mappings.
307
175
    :param verbose: Whether to print list of rewrites
308
176
    :return: Dictionary of mapped revisions
309
177
    """
310
 
    check_rebase_version(MIN_REBASE_VERSION)
311
 
    from bzrlib.plugins.rebase.rebase import (
312
 
        replay_snapshot, rebase, rebase_todo)
313
 
 
314
178
    # Find revisions that need to be upgraded, create
315
179
    # dictionary with revision ids in key, new parents in value
316
 
    try:
317
 
        repository.lock_write()
318
 
        foreign_repository.lock_read()
319
 
        (plan, revid_renames) = create_upgrade_plan(repository, foreign_repository, 
320
 
                                                    new_mapping, 
321
 
                                                    revision_id=revision_id,
322
 
                                                    allow_changes=allow_changes)
 
180
    with repository.lock_write():
 
181
        (plan, revid_renames) = create_upgrade_plan(
 
182
            repository, generate_rebase_map, determine_new_revid,
 
183
            revision_id=revision_id, allow_changes=allow_changes)
323
184
        if verbose:
324
185
            for revid in rebase_todo(repository, plan):
325
 
                info("%s -> %s" % (revid, plan[revid][0]))
326
 
        rebase(repository, plan, replay_snapshot)
 
186
                trace.note("%s -> %s" % (revid, plan[revid][0]))
 
187
        rebase(repository, plan, CommitBuilderRevisionRewriter(repository))
327
188
        return revid_renames
328
 
    finally:
329
 
        repository.unlock()
330
 
        foreign_repository.unlock()
331