/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.205.12 by Jelmer Vernooij
Import upgrade code for upgrading mappings.
1
# Copyright (C) 2006,2008 by Jelmer Vernooij
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 3 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
"""Upgrading revisions made with older versions of the mapping."""
17
18
from bzrlib import ui
0.205.13 by Jelmer Vernooij
Fix syntax errors.
19
from bzrlib.errors import BzrError, InvalidRevisionId, DependencyNotPresent
0.205.12 by Jelmer Vernooij
Import upgrade code for upgrading mappings.
20
from bzrlib.revision import Revision
21
from bzrlib.trace import info
22
23
import itertools
24
25
26
class RebaseNotPresent(DependencyNotPresent):
27
    _fmt = "Unable to import bzr-rebase (required for upgrade support): %(error)s"
28
29
    def __init__(self, error):
30
        DependencyNotPresent.__init__(self, 'bzr-rebase', error)
31
32
33
def check_rebase_version(min_version):
34
    """Check what version of bzr-rebase is installed.
35
36
    Raises an exception when the version installed is older than 
37
    min_version.
38
39
    :raises RebaseNotPresent: Raised if bzr-rebase is not installed or too old.
40
    """
41
    try:
42
        from bzrlib.plugins.rebase import version_info as rebase_version_info
43
        if rebase_version_info[:2] < min_version:
44
            raise RebaseNotPresent("Version %r present, at least %r required" 
45
                                   % (rebase_version_info, min_version))
46
    except ImportError, e:
47
        raise RebaseNotPresent(e)
48
49
50
51
class UpgradeChangesContent(BzrError):
52
    """Inconsistency was found upgrading the mapping of a revision."""
53
    _fmt = """Upgrade will change contents in revision %(revid)s. Use --allow-changes to override."""
54
55
    def __init__(self, revid):
56
        self.revid = revid
57
58
59
60
def create_upgraded_revid(revid, mapping_suffix, upgrade_suffix="-upgrade"):
61
    """Create a new revision id for an upgraded version of a revision.
62
    
63
    Prevents suffix to be appended needlessly.
64
65
    :param revid: Original revision id.
66
    :return: New revision id
67
    """
68
    if revid.endswith(upgrade_suffix):
69
        return revid[0:revid.rfind("-svn")] + mapping_suffix + upgrade_suffix
70
    else:
71
        return revid + mapping_suffix + upgrade_suffix
72
73
74
def determine_fileid_renames(old_tree, new_tree):
75
    for old_file_id in old_tree:
76
        new_file_id = new_tree.path2id(old_tree.id2path(old_file_id))
77
        if new_file_id is not None:
78
            yield 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
        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
        wt.set_last_revision(last_revid)
95
96
        # Adjust file ids in working tree
97
        for (old_fileid, new_fileid) in determine_fileid_renames(wt.branch.repository.revision_tree(old_revid), wt.basis_tree()):
98
            path = wt.id2path(old_fileid)
99
            wt.remove(path)
100
            wt.add([path], [new_fileid])
101
    finally:
102
        wt.unlock()
103
104
    return renames
105
106
0.205.14 by Jelmer Vernooij
Fix upgrade_branch.
107
def upgrade_branch(branch, foreign_repository, new_mapping, 
108
                   mapping_registry, allow_changes=False, verbose=False):
0.205.12 by Jelmer Vernooij
Import upgrade code for upgrading mappings.
109
    """Upgrade a branch to the current mapping version.
110
    
111
    :param branch: Branch to upgrade.
112
    :param foreign_repository: Repository to fetch new revisions from
113
    :param allow_changes: Allow changes in mappings.
114
    :param verbose: Whether to print verbose list of rewrites
115
    """
116
    revid = branch.last_revision()
117
    renames = upgrade_repository(branch.repository, foreign_repository, 
118
              revision_id=revid, new_mapping=new_mapping,
0.205.14 by Jelmer Vernooij
Fix upgrade_branch.
119
              mapping_registry=mapping_registry,
0.205.12 by Jelmer Vernooij
Import upgrade code for upgrading mappings.
120
              allow_changes=allow_changes, verbose=verbose)
121
    if len(renames) > 0:
122
        branch.generate_revision_history(renames[revid])
123
    return renames
124
125
126
def check_revision_changed(oldrev, newrev):
127
    """Check if two revisions are different. This is exactly the same 
128
    as Revision.equals() except that it does not check the revision_id."""
129
    if (newrev.inventory_sha1 != oldrev.inventory_sha1 or
130
        newrev.timestamp != oldrev.timestamp or
131
        newrev.message != oldrev.message or
132
        newrev.timezone != oldrev.timezone or
133
        newrev.committer != oldrev.committer or
134
        newrev.properties != oldrev.properties):
135
        raise UpgradeChangesContent(oldrev.revision_id)
136
137
138
def generate_upgrade_map(new_mapping, revs, mapping_registry):
139
    """Generate an upgrade map for use by bzr-rebase.
140
141
    :param new_mapping: Mapping to upgrade revisions to.
142
    :param revs: Iterator over revisions to upgrade.
143
    :return: Map from old revids as keys, new revids as values stored in a 
144
             dictionary.
145
    """
146
    rename_map = {}
147
    # Create a list of revisions that can be renamed during the upgade
148
    for revid in revs:
149
        assert isinstance(revid, str)
150
        try:
151
            (foreign_revid, mapping) = mapping_registry.parse_revision_id(revid)
152
        except InvalidRevisionId:
153
            # Not a foreign revision, nothing to do
154
            continue
155
        newrevid = new_mapping.revision_id_foreign_to_bzr(foreign_revid)
156
        if revid == newrevid:
157
            continue
158
        rename_map[revid] = newrevid
159
160
    return rename_map
161
162
MIN_REBASE_VERSION = (0, 4)
163
164
def create_upgrade_plan(repository, foreign_repository, new_mapping,
165
                        mapping_registry, revision_id=None, allow_changes=False):
166
    """Generate a rebase plan for upgrading revisions.
167
168
    :param repository: Repository to do upgrade in
169
    :param foreign_repository: Subversion repository to fetch new revisions from.
170
    :param new_mapping: New mapping to use.
171
    :param revision_id: Revision to upgrade (None for all revisions in 
172
        repository.)
173
    :param allow_changes: Whether an upgrade is allowed to change the contents
174
        of revisions.
175
    :return: Tuple with a rebase plan and map of renamed revisions.
176
    """
177
    from bzrlib.plugins.rebase.rebase import generate_transpose_plan
178
    check_rebase_version(MIN_REBASE_VERSION)
179
180
    graph = repository.get_graph()
181
    if revision_id is None:
182
        potential = repository.all_revision_ids()
183
    else:
184
        potential = itertools.imap(lambda (rev, parents): rev, 
185
                graph.iter_ancestry([revision_id]))
186
    upgrade_map = generate_upgrade_map(new_mapping, potential, mapping_registry)
187
   
188
    # Make sure all the required current version revisions are present
189
    for revid in upgrade_map.values():
190
        if not repository.has_revision(revid):
191
            repository.fetch(foreign_repository, revid)
192
193
    if not allow_changes:
194
        for oldrevid, newrevid in upgrade_map.items():
195
            oldrev = repository.get_revision(oldrevid)
196
            newrev = repository.get_revision(newrevid)
197
            check_revision_changed(oldrev, newrev)
198
199
    if revision_id is None:
200
        heads = repository.all_revision_ids() 
201
    else:
202
        heads = [revision_id]
203
204
    plan = generate_transpose_plan(graph.iter_ancestry(heads), upgrade_map, 
205
      graph,
206
      lambda revid: create_upgraded_revid(revid, new_mapping.upgrade_suffix))
207
    def remove_parents((oldrevid, (newrevid, parents))):
208
        return (oldrevid, newrevid)
209
    upgrade_map.update(dict(map(remove_parents, plan.items())))
210
211
    return (plan, upgrade_map)
212
213
 
214
def upgrade_repository(repository, foreign_repository, new_mapping, 
215
                       mapping_registry, revision_id=None, allow_changes=False, 
216
                       verbose=False):
217
    """Upgrade the revisions in repository until the specified stop revision.
218
219
    :param repository: Repository in which to upgrade.
220
    :param foreign_repository: Repository to fetch new revisions from.
221
    :param new_mapping: New mapping.
222
    :param revision_id: Revision id up until which to upgrade, or None for 
223
                        all revisions.
224
    :param allow_changes: Allow changes to mappings.
225
    :param verbose: Whether to print list of rewrites
226
    :return: Dictionary of mapped revisions
227
    """
228
    check_rebase_version(MIN_REBASE_VERSION)
229
    from bzrlib.plugins.rebase.rebase import (
230
        replay_snapshot, rebase, rebase_todo)
231
232
    # Find revisions that need to be upgraded, create
233
    # dictionary with revision ids in key, new parents in value
234
    try:
235
        repository.lock_write()
236
        foreign_repository.lock_read()
237
        (plan, revid_renames) = create_upgrade_plan(repository, foreign_repository, 
238
                                                    new_mapping, mapping_registry,
239
                                                    revision_id=revision_id,
240
                                                    allow_changes=allow_changes)
241
        if verbose:
242
            for revid in rebase_todo(repository, plan):
243
                info("%s -> %s" % (revid, plan[revid][0]))
244
        def fix_revid(revid):
245
            try:
246
                (foreign_revid, mapping) = mapping_registry.parse_revision_id(revid)
247
            except InvalidRevisionId:
248
                return revid
249
            return new_mapping.revision_id_foreign_to_bzr(foreign_revid)
250
        def replay(repository, oldrevid, newrevid, new_parents):
251
            return replay_snapshot(repository, oldrevid, newrevid, new_parents,
252
                                   revid_renames, fix_revid)
253
        rebase(repository, plan, replay)
254
        return revid_renames
255
    finally:
256
        repository.unlock()
257
        foreign_repository.unlock()
258