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

  • Committer: Jelmer Vernooij
  • Date: 2009-02-08 19:20:14 UTC
  • mto: (0.436.139 foreign)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20090208192014-0g17picqdx7edl92
Import foreign-mapping-upgrade command, fixes for bzr-svn.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006,2008 by Jelmer Vernooij
 
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
16
16
"""Upgrading revisions made with older versions of the mapping."""
17
17
 
18
18
from bzrlib import ui
19
 
from bzrlib.errors import BzrError, InvalidRevisionId, DependencyNotPresent
 
19
from bzrlib.errors import (
 
20
    DependencyNotPresent,
 
21
    BzrError,
 
22
    InvalidRevisionId,
 
23
    NoSuchRevision,
 
24
    )
20
25
from bzrlib.trace import info
21
26
 
22
27
import itertools
38
43
    """
39
44
    try:
40
45
        from bzrlib.plugins.rebase import version_info as rebase_version_info
41
 
        if rebase_version_info[:2] < min_version:
 
46
        if rebase_version_info[:len(min_version)] < min_version:
42
47
            raise RebaseNotPresent("Version %r present, at least %r required" 
43
48
                                   % (rebase_version_info, min_version))
44
49
    except ImportError, e:
69
74
        return revid + mapping_suffix + upgrade_suffix
70
75
 
71
76
 
72
 
def determine_fileid_renames(old_tree, new_tree):
73
 
    for old_file_id in old_tree:
74
 
        new_file_id = new_tree.path2id(old_tree.id2path(old_file_id))
75
 
        if old_file_id == new_file_id:
76
 
            continue
77
 
        if new_file_id is not None:
78
 
            yield new_tree.id2path(new_file_id), old_file_id, new_file_id
79
 
 
80
 
 
81
 
def upgrade_workingtree(wt, foreign_repository, new_mapping, mapping_registry, 
 
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, 
82
125
                        allow_changes=False, verbose=False):
83
126
    """Upgrade a working tree.
84
127
 
88
131
    try:
89
132
        old_revid = wt.last_revision()
90
133
        revid_renames = upgrade_branch(wt.branch, foreign_repository, new_mapping=new_mapping,
91
 
                                 mapping_registry=mapping_registry,
92
134
                                 allow_changes=allow_changes, verbose=verbose)
93
135
        last_revid = wt.branch.last_revision()
94
136
        if old_revid == last_revid:
95
137
            return revid_renames
96
 
 
97
 
        fileid_renames = dict([(path, (old_fileid, new_fileid)) for (path, old_fileid, new_fileid) in determine_fileid_renames(wt.branch.repository.revision_tree(old_revid), wt.branch.repository.revision_tree(last_revid))])
98
 
        old_fileids = []
99
 
        new_fileids = []
100
 
        new_root_id = None
101
 
        # Adjust file ids in working tree
102
 
        for path in sorted(fileid_renames.keys(), reverse=True):
103
 
            if path != "":
104
 
                old_fileids.append(fileid_renames[path][0])
105
 
                new_fileids.append((path, fileid_renames[path][1]))
106
 
            else:
107
 
                new_root_id = fileid_renames[path][1]
108
 
        new_fileids.reverse()
109
 
        wt.unversion(old_fileids)
110
 
        if new_root_id is not None:
111
 
            wt.set_root_id(new_root_id)
112
 
        wt.add([x[0] for x in new_fileids], [x[1] for x in new_fileids])
113
 
        wt.set_last_revision(last_revid)
 
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)
114
141
    finally:
115
142
        wt.unlock()
116
143
 
117
144
    return revid_renames
118
145
 
119
146
 
120
 
def upgrade_tags(tags, repository, foreign_repository, new_mapping, mapping_registry, 
 
147
def upgrade_tags(tags, repository, foreign_repository, new_mapping, 
121
148
                 allow_changes=False, verbose=False, branch_renames=None):
122
149
    """Upgrade a tags dictionary."""
 
150
    renames = {}
 
151
    if branch_renames is not None:
 
152
        renames.update(branch_renames)
123
153
    pb = ui.ui_factory.nested_progress_bar()
124
154
    try:
125
155
        tags_dict = tags.get_tag_dict()
126
156
        for i, (name, revid) in enumerate(tags_dict.items()):
127
157
            pb.update("upgrading tags", i, len(tags_dict))
128
 
            if branch_renames is not None and revid in branch_renames:
129
 
                renames = branch_renames
130
 
            else:
131
 
                renames = upgrade_repository(repository, foreign_repository, 
 
158
            if not revid in renames:
 
159
                renames.update(upgrade_repository(repository, foreign_repository, 
132
160
                      revision_id=revid, new_mapping=new_mapping,
133
 
                      mapping_registry=mapping_registry,
134
 
                      allow_changes=allow_changes, verbose=verbose)
 
161
                      allow_changes=allow_changes, verbose=verbose))
135
162
            if revid in renames:
136
163
                tags.set_tag(name, renames[revid])
137
164
    finally:
139
166
 
140
167
 
141
168
def upgrade_branch(branch, foreign_repository, new_mapping, 
142
 
                   mapping_registry, allow_changes=False, verbose=False):
 
169
                   allow_changes=False, verbose=False):
143
170
    """Upgrade a branch to the current mapping version.
144
171
    
145
172
    :param branch: Branch to upgrade.
150
177
    revid = branch.last_revision()
151
178
    renames = upgrade_repository(branch.repository, foreign_repository, 
152
179
              revision_id=revid, new_mapping=new_mapping,
153
 
              mapping_registry=mapping_registry,
154
180
              allow_changes=allow_changes, verbose=verbose)
155
181
    upgrade_tags(branch.tags, branch.repository, foreign_repository, 
156
 
           new_mapping=new_mapping, mapping_registry=mapping_registry, 
157
 
           allow_changes=allow_changes, verbose=verbose)
158
 
    if len(renames) > 0:
 
182
           new_mapping=new_mapping, 
 
183
           allow_changes=allow_changes, verbose=verbose, branch_renames=renames)
 
184
    if revid in renames:
159
185
        branch.generate_revision_history(renames[revid])
160
186
    return renames
161
187
 
172
198
        raise UpgradeChangesContent(oldrev.revision_id)
173
199
 
174
200
 
175
 
def generate_upgrade_map(new_mapping, revs, mapping_registry):
 
201
def generate_upgrade_map(revs, vcs, determine_upgraded_revid):
176
202
    """Generate an upgrade map for use by bzr-rebase.
177
203
 
178
204
    :param new_mapping: Mapping to upgrade revisions to.
 
205
    :param vcs: The foreign vcs
179
206
    :param revs: Iterator over revisions to upgrade.
180
207
    :return: Map from old revids as keys, new revids as values stored in a 
181
208
             dictionary.
185
212
    for revid in revs:
186
213
        assert isinstance(revid, str)
187
214
        try:
188
 
            (foreign_revid, _) = mapping_registry.parse_revision_id(revid)
 
215
            (foreign_revid, old_mapping) = vcs.mapping_registry.parse_revision_id(revid)
189
216
        except InvalidRevisionId:
190
217
            # Not a foreign revision, nothing to do
191
218
            continue
192
 
        newrevid = new_mapping.revision_id_foreign_to_bzr(foreign_revid)
193
 
        if revid == newrevid:
 
219
        newrevid = determine_upgraded_revid(foreign_revid)
 
220
        if newrevid in (revid, None):
194
221
            continue
195
222
        rename_map[revid] = newrevid
196
 
 
197
223
    return rename_map
198
224
 
199
 
MIN_REBASE_VERSION = (0, 4)
 
225
MIN_REBASE_VERSION = (0, 4, 3)
200
226
 
201
227
def create_upgrade_plan(repository, foreign_repository, new_mapping,
202
 
                        mapping_registry, revision_id=None, allow_changes=False):
 
228
                        revision_id=None, allow_changes=False):
203
229
    """Generate a rebase plan for upgrading revisions.
204
230
 
205
231
    :param repository: Repository to do upgrade in
220
246
    else:
221
247
        potential = itertools.imap(lambda (rev, parents): rev, 
222
248
                graph.iter_ancestry([revision_id]))
223
 
    upgrade_map = generate_upgrade_map(new_mapping, potential, mapping_registry)
 
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)
224
267
   
225
 
    # Make sure all the required current version revisions are present
226
 
    for revid in upgrade_map.values():
227
 
        if not repository.has_revision(revid):
228
 
            repository.fetch(foreign_repository, revid)
229
 
 
230
268
    if not allow_changes:
231
269
        for oldrevid, newrevid in upgrade_map.iteritems():
232
270
            oldrev = repository.get_revision(oldrevid)
238
276
    else:
239
277
        heads = [revision_id]
240
278
 
 
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
 
241
287
    plan = generate_transpose_plan(graph.iter_ancestry(heads), upgrade_map, 
242
 
      graph, lambda revid: create_upgraded_revid(revid, new_mapping.upgrade_suffix))
 
288
      graph, determine_new_revid)
243
289
    def remove_parents((oldrevid, (newrevid, parents))):
244
290
        return (oldrevid, newrevid)
245
291
    upgrade_map.update(dict(map(remove_parents, plan.iteritems())))
248
294
 
249
295
 
250
296
def upgrade_repository(repository, foreign_repository, new_mapping, 
251
 
                       mapping_registry, revision_id=None, allow_changes=False, 
 
297
                       revision_id=None, allow_changes=False, 
252
298
                       verbose=False):
253
299
    """Upgrade the revisions in repository until the specified stop revision.
254
300
 
271
317
        repository.lock_write()
272
318
        foreign_repository.lock_read()
273
319
        (plan, revid_renames) = create_upgrade_plan(repository, foreign_repository, 
274
 
                                                    new_mapping, mapping_registry,
 
320
                                                    new_mapping, 
275
321
                                                    revision_id=revision_id,
276
322
                                                    allow_changes=allow_changes)
277
323
        if verbose:
278
324
            for revid in rebase_todo(repository, plan):
279
325
                info("%s -> %s" % (revid, plan[revid][0]))
280
 
        def fix_revid(revid):
281
 
            try:
282
 
                (foreign_revid, mapping) = mapping_registry.parse_revision_id(revid)
283
 
            except InvalidRevisionId:
284
 
                return revid
285
 
            return new_mapping.revision_id_foreign_to_bzr(foreign_revid)
286
 
        def replay(repository, oldrevid, newrevid, new_parents):
287
 
            return replay_snapshot(repository, oldrevid, newrevid, new_parents,
288
 
                                   revid_renames, fix_revid)
289
 
        rebase(repository, plan, replay)
 
326
        rebase(repository, plan, replay_snapshot)
290
327
        return revid_renames
291
328
    finally:
292
329
        repository.unlock()