/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: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006,2008 by Jelmer Vernooij
2
 
 
1
# Copyright (C) 2006-2009 by Jelmer Vernooij
 
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 BzrError, InvalidRevisionId, DependencyNotPresent
20
 
from bzrlib.trace import info
21
 
 
22
 
import itertools
23
 
 
24
 
class RebaseNotPresent(DependencyNotPresent):
25
 
    _fmt = "Unable to import bzr-rebase (required for upgrade support): %(error)s"
26
 
 
27
 
    def __init__(self, error):
28
 
        DependencyNotPresent.__init__(self, 'bzr-rebase', error)
29
 
 
30
 
 
31
 
def check_rebase_version(min_version):
32
 
    """Check what version of bzr-rebase is installed.
33
 
 
34
 
    Raises an exception when the version installed is older than 
35
 
    min_version.
36
 
 
37
 
    :raises RebaseNotPresent: Raised if bzr-rebase is not installed or too old.
38
 
    """
39
 
    try:
40
 
        from bzrlib.plugins.rebase import version_info as rebase_version_info
41
 
        if rebase_version_info[:2] < min_version:
42
 
            raise RebaseNotPresent("Version %r present, at least %r required" 
43
 
                                   % (rebase_version_info, min_version))
44
 
    except ImportError, e:
45
 
        raise RebaseNotPresent(e)
46
 
 
 
20
from ... import (
 
21
    osutils,
 
22
    trace,
 
23
    ui,
 
24
    )
 
25
from ...errors import (
 
26
    BzrError,
 
27
    )
 
28
from .rebase import (
 
29
    generate_transpose_plan,
 
30
    CommitBuilderRevisionRewriter,
 
31
    rebase,
 
32
    rebase_todo,
 
33
    )
47
34
 
48
35
 
49
36
class UpgradeChangesContent(BzrError):
54
41
        self.revid = revid
55
42
 
56
43
 
 
44
def create_deterministic_revid(revid, new_parents):
 
45
    """Create a new deterministic revision id with specified new parents.
57
46
 
58
 
def create_upgraded_revid(revid, mapping_suffix, upgrade_suffix="-upgrade"):
59
 
    """Create a new revision id for an upgraded version of a revision.
60
 
    
61
47
    Prevents suffix to be appended needlessly.
62
48
 
63
49
    :param revid: Original revision id.
64
50
    :return: New revision id
65
51
    """
66
 
    if revid.endswith(upgrade_suffix):
67
 
        return revid[0:revid.rfind("-svn")] + mapping_suffix + upgrade_suffix
68
 
    else:
69
 
        return revid + mapping_suffix + upgrade_suffix
70
 
 
71
 
 
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, 
82
 
                        allow_changes=False, verbose=False):
83
 
    """Upgrade a working tree.
84
 
 
85
 
    :param foreign_repository: Foreign repository object
86
 
    """
87
 
    wt.lock_write()
88
 
    try:
89
 
        old_revid = wt.last_revision()
90
 
        revid_renames = upgrade_branch(wt.branch, foreign_repository, new_mapping=new_mapping,
91
 
                                 mapping_registry=mapping_registry,
92
 
                                 allow_changes=allow_changes, verbose=verbose)
93
 
        last_revid = wt.branch.last_revision()
94
 
        if old_revid == last_revid:
95
 
            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)
114
 
    finally:
115
 
        wt.unlock()
116
 
 
117
 
    return revid_renames
118
 
 
119
 
 
120
 
def upgrade_tags(tags, repository, foreign_repository, new_mapping, mapping_registry, 
121
 
                 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):
122
60
    """Upgrade a tags dictionary."""
 
61
    renames = {}
 
62
    if branch_renames is not None:
 
63
        renames.update(branch_renames)
123
64
    pb = ui.ui_factory.nested_progress_bar()
124
65
    try:
125
66
        tags_dict = tags.get_tag_dict()
126
 
        for i, (name, revid) in enumerate(tags_dict.items()):
 
67
        for i, (name, revid) in enumerate(tags_dict.iteritems()):
127
68
            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, 
132
 
                      revision_id=revid, new_mapping=new_mapping,
133
 
                      mapping_registry=mapping_registry,
134
 
                      allow_changes=allow_changes, verbose=verbose)
135
 
            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)):
136
83
                tags.set_tag(name, renames[revid])
137
84
    finally:
138
85
        pb.finished()
139
86
 
140
87
 
141
 
def upgrade_branch(branch, foreign_repository, new_mapping, 
142
 
                   mapping_registry, allow_changes=False, verbose=False):
 
88
def upgrade_branch(branch, generate_rebase_map, determine_new_revid,
 
89
                   allow_changes=False, verbose=False):
143
90
    """Upgrade a branch to the current mapping version.
144
 
    
 
91
 
145
92
    :param branch: Branch to upgrade.
146
93
    :param foreign_repository: Repository to fetch new revisions from
147
94
    :param allow_changes: Allow changes in mappings.
148
95
    :param verbose: Whether to print verbose list of rewrites
149
96
    """
150
97
    revid = branch.last_revision()
151
 
    renames = upgrade_repository(branch.repository, foreign_repository, 
152
 
              revision_id=revid, new_mapping=new_mapping,
153
 
              mapping_registry=mapping_registry,
154
 
              allow_changes=allow_changes, verbose=verbose)
155
 
    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:
 
98
    renames = upgrade_repository(
 
99
        branch.repository, generate_rebase_map,
 
100
        determine_new_revid, revision_id=revid,
 
101
        allow_changes=allow_changes, verbose=verbose)
 
102
    if revid in renames:
159
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)
160
110
    return renames
161
111
 
162
112
 
163
113
def check_revision_changed(oldrev, newrev):
164
 
    """Check if two revisions are different. This is exactly the same 
 
114
    """Check if two revisions are different. This is exactly the same
165
115
    as Revision.equals() except that it does not check the revision_id."""
166
116
    if (newrev.inventory_sha1 != oldrev.inventory_sha1 or
167
 
        newrev.timestamp != oldrev.timestamp or
168
 
        newrev.message != oldrev.message or
169
 
        newrev.timezone != oldrev.timezone or
170
 
        newrev.committer != oldrev.committer or
171
 
        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):
172
122
        raise UpgradeChangesContent(oldrev.revision_id)
173
123
 
174
124
 
175
 
def generate_upgrade_map(new_mapping, revs, mapping_registry):
176
 
    """Generate an upgrade map for use by bzr-rebase.
177
 
 
178
 
    :param new_mapping: Mapping to upgrade revisions to.
179
 
    :param revs: Iterator over revisions to upgrade.
180
 
    :return: Map from old revids as keys, new revids as values stored in a 
181
 
             dictionary.
182
 
    """
183
 
    rename_map = {}
184
 
    # Create a list of revisions that can be renamed during the upgrade
185
 
    for revid in revs:
186
 
        assert isinstance(revid, str)
187
 
        try:
188
 
            (foreign_revid, _) = mapping_registry.parse_revision_id(revid)
189
 
        except InvalidRevisionId:
190
 
            # Not a foreign revision, nothing to do
191
 
            continue
192
 
        newrevid = new_mapping.revision_id_foreign_to_bzr(foreign_revid)
193
 
        if revid == newrevid:
194
 
            continue
195
 
        rename_map[revid] = newrevid
196
 
 
197
 
    return rename_map
198
 
 
199
 
MIN_REBASE_VERSION = (0, 4)
200
 
 
201
 
def create_upgrade_plan(repository, foreign_repository, new_mapping,
202
 
                        mapping_registry, revision_id=None, allow_changes=False):
 
125
def create_upgrade_plan(repository, generate_rebase_map, determine_new_revid,
 
126
                        revision_id=None, allow_changes=False):
203
127
    """Generate a rebase plan for upgrading revisions.
204
128
 
205
129
    :param repository: Repository to do upgrade in
206
 
    :param foreign_repository: Subversion repository to fetch new revisions from.
 
130
    :param foreign_repository: Subversion repository to fetch new revisions
 
131
        from.
207
132
    :param new_mapping: New mapping to use.
208
 
    :param revision_id: Revision to upgrade (None for all revisions in 
 
133
    :param revision_id: Revision to upgrade (None for all revisions in
209
134
        repository.)
210
135
    :param allow_changes: Whether an upgrade is allowed to change the contents
211
136
        of revisions.
212
137
    :return: Tuple with a rebase plan and map of renamed revisions.
213
138
    """
214
 
    from bzrlib.plugins.rebase.rebase import generate_transpose_plan
215
 
    check_rebase_version(MIN_REBASE_VERSION)
216
139
 
217
140
    graph = repository.get_graph()
218
 
    if revision_id is None:
219
 
        potential = repository.all_revision_ids()
220
 
    else:
221
 
        potential = itertools.imap(lambda (rev, parents): rev, 
222
 
                graph.iter_ancestry([revision_id]))
223
 
    upgrade_map = generate_upgrade_map(new_mapping, potential, mapping_registry)
224
 
   
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)
 
141
    upgrade_map = generate_rebase_map(revision_id)
229
142
 
230
143
    if not allow_changes:
231
144
        for oldrevid, newrevid in upgrade_map.iteritems():
234
147
            check_revision_changed(oldrev, newrev)
235
148
 
236
149
    if revision_id is None:
237
 
        heads = repository.all_revision_ids() 
 
150
        heads = repository.all_revision_ids()
238
151
    else:
239
152
        heads = [revision_id]
240
153
 
241
 
    plan = generate_transpose_plan(graph.iter_ancestry(heads), upgrade_map, 
242
 
      graph, lambda revid: create_upgraded_revid(revid, new_mapping.upgrade_suffix))
243
 
    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
244
158
        return (oldrevid, newrevid)
245
159
    upgrade_map.update(dict(map(remove_parents, plan.iteritems())))
246
160
 
247
161
    return (plan, upgrade_map)
248
162
 
249
 
 
250
 
def upgrade_repository(repository, foreign_repository, new_mapping, 
251
 
                       mapping_registry, revision_id=None, allow_changes=False, 
252
 
                       verbose=False):
 
163
 
 
164
def upgrade_repository(repository, generate_rebase_map,
 
165
                       determine_new_revid, revision_id=None,
 
166
                       allow_changes=False, verbose=False):
253
167
    """Upgrade the revisions in repository until the specified stop revision.
254
168
 
255
169
    :param repository: Repository in which to upgrade.
256
170
    :param foreign_repository: Repository to fetch new revisions from.
257
171
    :param new_mapping: New mapping.
258
 
    :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
259
173
                        all revisions.
260
174
    :param allow_changes: Allow changes to mappings.
261
175
    :param verbose: Whether to print list of rewrites
262
176
    :return: Dictionary of mapped revisions
263
177
    """
264
 
    check_rebase_version(MIN_REBASE_VERSION)
265
 
    from bzrlib.plugins.rebase.rebase import (
266
 
        replay_snapshot, rebase, rebase_todo)
267
 
 
268
178
    # Find revisions that need to be upgraded, create
269
179
    # dictionary with revision ids in key, new parents in value
270
 
    try:
271
 
        repository.lock_write()
272
 
        foreign_repository.lock_read()
273
 
        (plan, revid_renames) = create_upgrade_plan(repository, foreign_repository, 
274
 
                                                    new_mapping, mapping_registry,
275
 
                                                    revision_id=revision_id,
276
 
                                                    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)
277
184
        if verbose:
278
185
            for revid in rebase_todo(repository, plan):
279
 
                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)
 
186
                trace.note("%s -> %s" % (revid, plan[revid][0]))
 
187
        rebase(repository, plan, CommitBuilderRevisionRewriter(repository))
290
188
        return revid_renames
291
 
    finally:
292
 
        repository.unlock()
293
 
        foreign_repository.unlock()
294