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