/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.436.2 by Jelmer Vernooij
Add stubs for testsuite, rebase-continue and rebase-abort commands.
1
# Copyright (C) 2006-2007 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 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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0.436.16 by Jelmer Vernooij
Some more work on maptree.
16
"""Rebase."""
0.436.3 by Jelmer Vernooij
Fill in commands.
17
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
18
from bzrlib.config import Config
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
19
from bzrlib.errors import BzrError, NoSuchFile, UnknownFormatError, UnrelatedBranches
0.436.4 by Jelmer Vernooij
Add some tests.
20
from bzrlib.generate_ids import gen_revision_id
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
21
from bzrlib.merge import Merger
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
22
from bzrlib import osutils
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
23
from bzrlib.revision import NULL_REVISION
0.436.4 by Jelmer Vernooij
Add some tests.
24
from bzrlib.trace import mutter
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
25
import bzrlib.ui as ui
0.436.4 by Jelmer Vernooij
Add some tests.
26
0.436.17 by Jelmer Vernooij
Move maptree code to separate files.
27
from maptree import MapTree, map_file_ids
0.436.38 by Jelmer Vernooij
Handle directories in revert.
28
import os
0.436.17 by Jelmer Vernooij
Move maptree code to separate files.
29
0.436.3 by Jelmer Vernooij
Fill in commands.
30
REBASE_PLAN_FILENAME = 'rebase-plan'
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
31
REBASE_CURRENT_REVID_FILENAME = 'rebase-current'
0.436.4 by Jelmer Vernooij
Add some tests.
32
REBASE_PLAN_VERSION = 1
0.436.27 by Jelmer Vernooij
Note revision property 'rebase-of', add explanation of use of pregenerated revision ids.
33
REVPROP_REBASE_OF = 'rebase-of'
0.436.3 by Jelmer Vernooij
Fill in commands.
34
35
def rebase_plan_exists(wt):
36
    """Check whether there is a rebase plan present.
37
38
    :param wt: Working tree for which to check.
39
    :return: boolean
40
    """
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
41
    try:
42
        return wt._control_files.get(REBASE_PLAN_FILENAME).read() != ''
43
    except NoSuchFile:
44
        return False
0.436.3 by Jelmer Vernooij
Fill in commands.
45
46
47
def read_rebase_plan(wt):
48
    """Read a rebase plan file.
49
50
    :param wt: Working Tree for which to write the plan.
0.436.4 by Jelmer Vernooij
Add some tests.
51
    :return: Tuple with last revision info and replace map.
0.436.3 by Jelmer Vernooij
Fill in commands.
52
    """
53
    text = wt._control_files.get(REBASE_PLAN_FILENAME).read()
54
    if text == '':
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
55
        raise NoSuchFile(REBASE_PLAN_FILENAME)
0.436.4 by Jelmer Vernooij
Add some tests.
56
    return unmarshall_rebase_plan(text)
57
58
59
def write_rebase_plan(wt, replace_map):
0.436.3 by Jelmer Vernooij
Fill in commands.
60
    """Write a rebase plan file.
61
62
    :param wt: Working Tree for which to write the plan.
0.436.4 by Jelmer Vernooij
Add some tests.
63
    :param replace_map: Replace map (old revid -> (new revid, new parents))
0.436.3 by Jelmer Vernooij
Fill in commands.
64
    """
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
65
    wt._control_files.put_utf8(REBASE_PLAN_FILENAME, 
66
            marshall_rebase_plan(wt.branch.last_revision_info(), replace_map))
0.436.3 by Jelmer Vernooij
Fill in commands.
67
68
69
def remove_rebase_plan(wt):
70
    """Remove a rebase plan file.
71
72
    :param wt: Working Tree for which to remove the plan.
73
    """
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
74
    wt._control_files.put_utf8(REBASE_PLAN_FILENAME, '')
0.436.3 by Jelmer Vernooij
Fill in commands.
75
76
0.436.4 by Jelmer Vernooij
Add some tests.
77
def marshall_rebase_plan(last_rev_info, replace_map):
0.436.3 by Jelmer Vernooij
Fill in commands.
78
    """Marshall a rebase plan.
79
80
    :param last_rev_info: Last revision info tuple.
0.436.4 by Jelmer Vernooij
Add some tests.
81
    :param replace_map: Replace map (old revid -> (new revid, new parents))
0.436.3 by Jelmer Vernooij
Fill in commands.
82
    :return: string
83
    """
0.436.4 by Jelmer Vernooij
Add some tests.
84
    ret = "# Bazaar rebase plan %d\n" % REBASE_PLAN_VERSION
85
    ret += "%d %s\n" % last_rev_info
86
    for oldrev in replace_map:
87
        (newrev, newparents) = replace_map[oldrev]
88
        ret += "%s %s" % (oldrev, newrev) + \
89
            "".join([" %s" % p for p in newparents]) + "\n"
90
    return ret
91
92
93
def unmarshall_rebase_plan(text):
0.436.3 by Jelmer Vernooij
Fill in commands.
94
    """Unmarshall a rebase plan.
95
96
    :param text: Text to parse
0.436.4 by Jelmer Vernooij
Add some tests.
97
    :return: Tuple with last revision info, replace map.
0.436.3 by Jelmer Vernooij
Fill in commands.
98
    """
0.436.4 by Jelmer Vernooij
Add some tests.
99
    lines = text.split('\n')
100
    # Make sure header is there
101
    if lines[0] != "# Bazaar rebase plan %d" % REBASE_PLAN_VERSION:
102
        raise UnknownFormatError(lines[0])
103
104
    pts = lines[1].split(" ", 1)
105
    last_revision_info = (int(pts[0]), pts[1])
106
    replace_map = {}
107
    for l in lines[2:]:
108
        if l == "":
109
            # Skip empty lines
110
            continue
111
        pts = l.split(" ")
112
        replace_map[pts[0]] = (pts[1], pts[2:])
113
    return (last_revision_info, replace_map)
114
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
115
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
116
def regenerate_default_revid(repository, revid):
117
    rev = repository.get_revision(revid)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
118
    return gen_revision_id(rev.committer, rev.timestamp)
119
120
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
121
def generate_simple_plan(history, start_revid, onto_revid, 
0.438.1 by Jelmer Vernooij
Split out function for determining rebase base.
122
                         onto_ancestry, get_parents, generate_revid):
0.436.3 by Jelmer Vernooij
Fill in commands.
123
    """Create a simple rebase plan that replays history based 
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
124
    on one revision being replayed on top of another.
0.436.3 by Jelmer Vernooij
Fill in commands.
125
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
126
    :param history: Revision history
127
    :param start_revid: Id of revision at which to start replaying
128
    :param onto_revid: Id of revision on top of which to replay
0.438.1 by Jelmer Vernooij
Split out function for determining rebase base.
129
    :param onto_ancestry: Ancestry of onto_revid
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
130
    :param get_parents: Function for obtaining the parents of a revision
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
131
    :param generate_revid: Function for generating new revision ids
0.436.3 by Jelmer Vernooij
Fill in commands.
132
0.436.4 by Jelmer Vernooij
Add some tests.
133
    :return: replace map
0.436.3 by Jelmer Vernooij
Fill in commands.
134
    """
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
135
    assert start_revid in history
136
    replace_map = {}
137
    i = history.index(start_revid)
138
    new_parent = onto_revid
139
    for oldrevid in history[i:]: 
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
140
        parents = get_parents(oldrevid)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
141
        assert len(parents) == 0 or \
142
                parents[0] == history[history.index(oldrevid)-1]
143
        parents[0] = new_parent
0.438.1 by Jelmer Vernooij
Split out function for determining rebase base.
144
        parents = filter(lambda p: p not in onto_ancestry or p == onto_revid, 
145
                         parents) 
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
146
        newrevid = generate_revid(oldrevid)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
147
        assert newrevid != oldrevid
148
        replace_map[oldrevid] = (newrevid, parents)
149
        new_parent = newrevid
150
    return replace_map
151
152
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
153
def generate_transpose_plan(graph, renames, get_parents, generate_revid):
154
    """Create a rebase plan that replaces a bunch of revisions
155
    in a revision graph.
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
156
157
    :param graph: Revision graph in which to operate
158
    :param renames: Renames of revision
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
159
    :param get_parents: Function for determining parents
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
160
    :param generate_revid: Function for creating new revision ids
161
    """
162
    replace_map = {}
163
    todo = []
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
164
    children = {}
165
    for r in graph:
166
        if not children.has_key(r):
167
            children[r] = []
168
        for p in graph[r]:
169
            if not children.has_key(p):
170
                children[p] = []
171
            children[p].append(r)
172
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
173
    # todo contains a list of revisions that need to 
174
    # be rewritten
175
    for r in renames:
176
        replace_map[r] = (renames[r], get_parents(renames[r]))
177
        todo.append(r)
178
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
179
    total = len(todo)
180
    processed = set()
181
    i = 0
182
    pb = ui.ui_factory.nested_progress_bar()
183
    try:
184
        while len(todo) > 0:
185
            r = todo.pop()
186
            i += 1
187
            pb.update('determining dependencies', i, total)
188
            # Add entry for them in replace_map
189
            for c in children[r]:
190
                if c in renames:
191
                    continue
192
                if replace_map.has_key(c):
193
                    parents = replace_map[c][1]
194
                else:
0.436.36 by Jelmer Vernooij
Fix compatibility with bzr 0.19.
195
                    parents = list(graph[c])
196
                assert isinstance(parents, list), \
197
                        "Expected list of parents, got: %r" % parents
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
198
                # replace r in parents with replace_map[r][0]
199
                if not replace_map[r][0] in parents:
200
                    parents[parents.index(r)] = replace_map[r][0]
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
201
                replace_map[c] = (generate_revid(c), parents)
202
                assert replace_map[c][0] != c
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
203
            processed.add(r)
204
            # Add them to todo[]
0.436.15 by Jelmer Vernooij
Fix inverse bug - needs tests.
205
            todo.extend(filter(lambda x: not x in processed, children[r]))
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
206
    finally:
207
        pb.finished()
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
208
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
209
    # Remove items from the map that already exist
210
    for revid in renames:
211
        if replace_map.has_key(revid):
212
            del replace_map[revid]
213
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
214
    return replace_map
215
216
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
217
def rebase_todo(repository, replace_map):
218
    """Figure out what revisions still need to be rebased.
219
220
    :param repository: Repository that contains the revisions
221
    :param replace_map: Replace map
222
    """
223
    for revid in replace_map:
224
        if not repository.has_revision(replace_map[revid][0]):
225
            yield revid
226
227
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
228
def rebase(repository, replace_map, replay_fn):
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
229
    """Rebase a working tree according to the specified map.
230
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
231
    :param repository: Repository that contains the revisions
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
232
    :param replace_map: Dictionary with revisions to (optionally) rewrite
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
233
    :param merge_fn: Function for replaying a revision
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
234
    """
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
235
    todo = list(rebase_todo(repository, replace_map))
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
236
    dependencies = {}
237
238
    # Figure out the dependencies
239
    for revid in todo:
240
        for p in replace_map[revid][1]:
241
            if repository.has_revision(p):
242
                continue
243
            if not dependencies.has_key(p):
244
                dependencies[p] = []
245
            dependencies[p].append(revid)
246
247
    pb = ui.ui_factory.nested_progress_bar()
0.436.22 by Jelmer Vernooij
Try to improve the progress bar a bit.
248
    total = len(todo)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
249
    i = 0
250
    try:
251
        while len(todo) > 0:
0.436.22 by Jelmer Vernooij
Try to improve the progress bar a bit.
252
            pb.update('rebase revisions', i, total)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
253
            i += 1
254
            revid = todo.pop()
255
            (newrevid, newparents) = replace_map[revid]
0.436.19 by Jelmer Vernooij
- Add blackbox tests
256
            if filter(repository.has_revision, newparents) != newparents:
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
257
                # Not all parents present yet, avoid for now
258
                continue
259
            if repository.has_revision(newrevid):
260
                # Was already converted, no need to worry about it again
261
                continue
262
            replay_fn(repository, revid, newrevid, newparents)
263
            assert repository.has_revision(newrevid)
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
264
            assert repository.revision_parents(newrevid) == newparents, \
265
                   "expected parents %r, got %r" % (newparents, 
266
                           repository.revision_parents(newrevid))
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
267
            if dependencies.has_key(newrevid):
268
                todo.extend(dependencies[newrevid])
269
                del dependencies[newrevid]
270
    finally:
271
        pb.finished()
272
        
0.436.19 by Jelmer Vernooij
- Add blackbox tests
273
    #assert all(map(repository.has_revision, 
274
    #           [replace_map[r][0] for r in replace_map]))
0.436.16 by Jelmer Vernooij
Some more work on maptree.
275
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
276
277
0.436.34 by Jelmer Vernooij
Some more tests.
278
def replay_snapshot(repository, oldrevid, newrevid, new_parents, 
0.436.35 by Jelmer Vernooij
Make revid_renames argument mandatory.
279
                    revid_renames):
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
280
    """Replay a commit by simply commiting the same snapshot with different 
281
    parents.
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
282
283
    :param repository: Repository in which the revision is present.
284
    :param oldrevid: Revision id of the revision to copy.
285
    :param newrevid: Revision id of the revision to create.
286
    :param new_parents: Revision ids of the new parent revisions.
0.436.34 by Jelmer Vernooij
Some more tests.
287
    :param revid_renames: Revision id renames for texts.
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
288
    """
289
    assert isinstance(new_parents, list)
0.436.16 by Jelmer Vernooij
Some more work on maptree.
290
    mutter('creating copy %r of %r with new parents %r' % 
291
                               (newrevid, oldrevid, new_parents))
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
292
    oldrev = repository.get_revision(oldrevid)
293
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
294
    revprops = dict(oldrev.properties)
0.436.27 by Jelmer Vernooij
Note revision property 'rebase-of', add explanation of use of pregenerated revision ids.
295
    revprops[REVPROP_REBASE_OF] = oldrevid
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
296
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
297
    builder = repository.get_commit_builder(branch=None, parents=new_parents, 
298
                                  config=Config(),
299
                                  committer=oldrev.committer,
300
                                  timestamp=oldrev.timestamp,
301
                                  timezone=oldrev.timezone,
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
302
                                  revprops=revprops,
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
303
                                  revision_id=newrevid)
304
305
    # Check what new_ie.file_id should be
306
    # use old and new parent inventories to generate new_id map
0.436.16 by Jelmer Vernooij
Some more work on maptree.
307
    fileid_map = map_file_ids(repository, oldrev.parent_ids, new_parents)
308
    oldtree = MapTree(repository.revision_tree(oldrevid), fileid_map)
309
    total = len(oldtree.inventory)
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
310
    pb = ui.ui_factory.nested_progress_bar()
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
311
    i = 0
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
312
    try:
0.436.14 by Jelmer Vernooij
More speed optimizations, deal with already created revisions.
313
        parent_invs = map(repository.get_revision_inventory, new_parents)
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
314
        transact = repository.get_transaction()
0.436.16 by Jelmer Vernooij
Some more work on maptree.
315
        for path, ie in oldtree.inventory.iter_entries():
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
316
            pb.update('upgrading file', i, total)
0.436.34 by Jelmer Vernooij
Some more tests.
317
            ie = ie.copy()
318
            # Either this file was modified last in this revision, 
319
            # in which case it has to be rewritten
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
320
            if ie.revision == oldrevid:
321
                ie.revision = None
322
            else:
0.436.34 by Jelmer Vernooij
Some more tests.
323
                # or it was already there before the commit, in 
324
                # which case the right revision should be used
325
                if revid_renames.has_key(ie.revision):
326
                    ie.revision = revid_renames[ie.revision]
327
                # make sure at least one of the new parents contains 
328
                # the ie.file_id, ie.revision combination
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
329
                if len(filter(lambda inv: ie.file_id in inv and inv[ie.file_id].revision == ie.revision, parent_invs)) == 0:
0.436.34 by Jelmer Vernooij
Some more tests.
330
                    raise ReplayParentsInconsistent(ie.file_id, ie.revision)
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
331
            i += 1
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
332
            builder.record_entry_contents(ie, parent_invs, path, oldtree)
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
333
    finally:
334
        pb.finished()
335
336
    builder.finish_inventory()
337
    return builder.commit(oldrev.message)
338
339
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
340
def commit_rebase(wt, oldrev, newrevid):
341
    """Commit a rebase.
342
    
343
    :param wt: Mutable tree with the changes.
344
    :param oldrev: Revision info of new revision to commit.
345
    :param newrevid: New revision id."""
346
    assert oldrev.revision_id != newrevid
347
    revprops = dict(oldrev.properties)
0.436.27 by Jelmer Vernooij
Note revision property 'rebase-of', add explanation of use of pregenerated revision ids.
348
    revprops[REVPROP_REBASE_OF] = oldrev.revision_id
0.436.37 by Jelmer Vernooij
Store parents correctly.
349
    wt.commit(message=oldrev.message, timestamp=oldrev.timestamp, 
350
              timezone=oldrev.timezone, revprops=revprops, rev_id=newrevid)
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
351
    write_active_rebase_revid(wt, None)
352
353
0.438.1 by Jelmer Vernooij
Split out function for determining rebase base.
354
def replay_delta_workingtree(wt, oldrevid, newrevid, newparents, 
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
355
                             merge_type=None):
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
356
    """Replay a commit in a working tree, with a different base.
357
358
    :param wt: Working tree in which to do the replays.
359
    :param oldrevid: Old revision id
360
    :param newrevid: New revision id
361
    :param newparents: New parent revision ids
362
    """
363
    repository = wt.branch.repository
364
    if merge_type is None:
365
        from bzrlib.merge import Merge3Merger
366
        merge_type = Merge3Merger
367
    oldrev = wt.branch.repository.get_revision(oldrevid)
368
    # Make sure there are no conflicts or pending merges/changes 
369
    # in the working tree
370
    if wt.changes_from(wt.basis_tree()).has_changed():
371
        raise BzrError("Working tree has uncommitted changes.")
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
372
    complete_revert(wt, [newparents[0]])
0.436.8 by Jelmer Vernooij
Couple more minor fixes.
373
    assert not wt.changes_from(wt.basis_tree()).has_changed()
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
374
375
    oldtree = repository.revision_tree(oldrevid)
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
376
    write_active_rebase_revid(wt, oldrevid)
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
377
    merger = Merger(wt.branch, this_tree=wt)
378
    merger.set_other_revision(oldrevid, wt.branch)
379
    try:
380
        merger.find_base()
381
    except UnrelatedBranches:
382
        merger.set_base_revision(NULL_REVISION, wt.branch)
383
    merger.merge_type = merge_type
384
    merger.do_merge()
385
    for newparent in newparents[1:]:
386
        wt.add_pending_merge(newparent)
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
387
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
388
    commit_rebase(wt, oldrev, newrevid)
0.436.8 by Jelmer Vernooij
Couple more minor fixes.
389
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
390
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
391
def workingtree_replay(wt, map_ids=False, merge_type=None):
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
392
    """Returns a function that can replay revisions in wt.
393
394
    :param wt: Working tree in which to do the replays.
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
395
    :param map_ids: Whether to try to map between file ids (False for path-based merge)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
396
    """
397
    def replay(repository, oldrevid, newrevid, newparents):
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
398
        assert wt.branch.repository == repository
0.436.16 by Jelmer Vernooij
Some more work on maptree.
399
        return replay_delta_workingtree(wt, oldrevid, newrevid, newparents, 
400
                                        merge_type=merge_type)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
401
    return replay
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
402
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
403
404
def write_active_rebase_revid(wt, revid):
0.436.16 by Jelmer Vernooij
Some more work on maptree.
405
    """Write the id of the revision that is currently being rebased. 
406
407
    :param wt: Working Tree that is being used for the rebase.
408
    :param revid: Revision id to write
409
    """
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
410
    if revid is None:
411
        revid = NULL_REVISION
412
    wt._control_files.put_utf8(REBASE_CURRENT_REVID_FILENAME, revid)
413
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
414
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
415
def read_active_rebase_revid(wt):
0.436.16 by Jelmer Vernooij
Some more work on maptree.
416
    """Read the id of the revision that is currently being rebased.
417
418
    :param wt: Working Tree that is being used for the rebase.
419
    :return: Id of the revision that is being rebased.
420
    """
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
421
    try:
422
        text = wt._control_files.get(REBASE_CURRENT_REVID_FILENAME).read().rstrip("\n")
423
        if text == NULL_REVISION:
424
            return None
425
        return text
426
    except NoSuchFile:
427
        return None
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
428
429
430
def complete_revert(wt, newparents):
0.436.16 by Jelmer Vernooij
Some more work on maptree.
431
    """Simple helper that reverts to specified new parents and makes sure none 
432
    of the extra files are left around.
433
434
    :param wt: Working tree to use for rebase
435
    :param newparents: New parents of the working tree
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
436
    """
437
    newtree = wt.branch.repository.revision_tree(newparents[0])
438
    delta = wt.changes_from(newtree)
439
    wt.branch.generate_revision_history(newparents[0])
0.436.38 by Jelmer Vernooij
Handle directories in revert.
440
    wt.set_parent_ids(newparents[:1])
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
441
    for (f, _, _) in delta.added:
442
        abs_path = wt.abspath(f)
443
        if osutils.lexists(abs_path):
0.436.38 by Jelmer Vernooij
Handle directories in revert.
444
            if osutils.isdir(abs_path):
445
                osutils.rmtree(abs_path)
446
            else:
447
                os.unlink(abs_path)
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
448
    wt.revert([], old_tree=newtree, backups=False)
0.436.38 by Jelmer Vernooij
Handle directories in revert.
449
    assert not wt.changes_from(wt.basis_tree()).has_changed()
0.436.37 by Jelmer Vernooij
Store parents correctly.
450
    wt.set_parent_ids(newparents)
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
451
452
0.436.34 by Jelmer Vernooij
Some more tests.
453
class ReplaySnapshotError(BzrError):
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
454
    _fmt = """Replaying the snapshot failed: %(message)s."""
455
456
    def __init__(self, message):
457
        BzrError.__init__(self)
458
        self.message = message
0.436.34 by Jelmer Vernooij
Some more tests.
459
460
461
class ReplayParentsInconsistent(BzrError):
462
    _fmt = """Parents were inconsistent while replaying commit for file id %(fileid)s, revision %(revid)s."""
463
464
    def __init__(self, fileid, revid):
465
        BzrError.__init__(self)
466
        self.fileid = fileid
467
        self.revid = revid