/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.438.3 by Jelmer Vernooij
Add stop_revid argumen to generate_simple_plan.
121
def generate_simple_plan(history, start_revid, stop_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
0.438.3 by Jelmer Vernooij
Add stop_revid argumen to generate_simple_plan.
128
    :param stop_revid: Id of revision until which to stop replaying
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
129
    :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.
130
    :param onto_ancestry: Ancestry of onto_revid
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
131
    :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.
132
    :param generate_revid: Function for generating new revision ids
0.436.3 by Jelmer Vernooij
Fill in commands.
133
0.436.4 by Jelmer Vernooij
Add some tests.
134
    :return: replace map
0.436.3 by Jelmer Vernooij
Fill in commands.
135
    """
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
136
    assert start_revid in history
137
    replace_map = {}
0.438.3 by Jelmer Vernooij
Add stop_revid argumen to generate_simple_plan.
138
    if start_revid is not None:
139
        start_revno = history.index(start_revid)
140
    else:
141
        start_revno = None
142
    if stop_revid is not None:
143
        stop_revno = history.index(stop_revid)+1
144
    else:
145
        stop_revno = None
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
146
    new_parent = onto_revid
0.438.3 by Jelmer Vernooij
Add stop_revid argumen to generate_simple_plan.
147
    for oldrevid in history[start_revno:stop_revno]: 
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
148
        parents = get_parents(oldrevid)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
149
        assert len(parents) == 0 or \
150
                parents[0] == history[history.index(oldrevid)-1]
151
        parents[0] = new_parent
0.438.1 by Jelmer Vernooij
Split out function for determining rebase base.
152
        parents = filter(lambda p: p not in onto_ancestry or p == onto_revid, 
153
                         parents) 
0.436.39 by Jelmer Vernooij
Some more refactoring, add test that demonstrates #126743.
154
        newrevid = generate_revid(oldrevid)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
155
        assert newrevid != oldrevid
156
        replace_map[oldrevid] = (newrevid, parents)
157
        new_parent = newrevid
158
    return replace_map
159
160
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
161
def generate_transpose_plan(graph, renames, get_parents, generate_revid):
162
    """Create a rebase plan that replaces a bunch of revisions
163
    in a revision graph.
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
164
165
    :param graph: Revision graph in which to operate
166
    :param renames: Renames of revision
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
167
    :param get_parents: Function for determining parents
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
168
    :param generate_revid: Function for creating new revision ids
169
    """
170
    replace_map = {}
171
    todo = []
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
172
    children = {}
173
    for r in graph:
174
        if not children.has_key(r):
175
            children[r] = []
176
        for p in graph[r]:
177
            if not children.has_key(p):
178
                children[p] = []
179
            children[p].append(r)
180
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
181
    # todo contains a list of revisions that need to 
182
    # be rewritten
183
    for r in renames:
184
        replace_map[r] = (renames[r], get_parents(renames[r]))
185
        todo.append(r)
186
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
187
    total = len(todo)
188
    processed = set()
189
    i = 0
190
    pb = ui.ui_factory.nested_progress_bar()
191
    try:
192
        while len(todo) > 0:
193
            r = todo.pop()
194
            i += 1
195
            pb.update('determining dependencies', i, total)
196
            # Add entry for them in replace_map
197
            for c in children[r]:
198
                if c in renames:
199
                    continue
200
                if replace_map.has_key(c):
201
                    parents = replace_map[c][1]
202
                else:
0.436.36 by Jelmer Vernooij
Fix compatibility with bzr 0.19.
203
                    parents = list(graph[c])
204
                assert isinstance(parents, list), \
205
                        "Expected list of parents, got: %r" % parents
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
206
                # replace r in parents with replace_map[r][0]
207
                if not replace_map[r][0] in parents:
208
                    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
209
                replace_map[c] = (generate_revid(c), parents)
210
                assert replace_map[c][0] != c
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
211
            processed.add(r)
212
            # Add them to todo[]
0.436.15 by Jelmer Vernooij
Fix inverse bug - needs tests.
213
            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.
214
    finally:
215
        pb.finished()
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
216
0.436.31 by Jelmer Vernooij
Refactor generate_transpose_plan() to not take a repository object but
217
    # Remove items from the map that already exist
218
    for revid in renames:
219
        if replace_map.has_key(revid):
220
            del replace_map[revid]
221
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
222
    return replace_map
223
224
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
225
def rebase_todo(repository, replace_map):
226
    """Figure out what revisions still need to be rebased.
227
228
    :param repository: Repository that contains the revisions
229
    :param replace_map: Replace map
230
    """
231
    for revid in replace_map:
232
        if not repository.has_revision(replace_map[revid][0]):
233
            yield revid
234
235
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
236
def rebase(repository, replace_map, replay_fn):
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
237
    """Rebase a working tree according to the specified map.
238
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
239
    :param repository: Repository that contains the revisions
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
240
    :param replace_map: Dictionary with revisions to (optionally) rewrite
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
241
    :param merge_fn: Function for replaying a revision
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
242
    """
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
243
    todo = list(rebase_todo(repository, replace_map))
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
244
    dependencies = {}
245
246
    # Figure out the dependencies
247
    for revid in todo:
248
        for p in replace_map[revid][1]:
249
            if repository.has_revision(p):
250
                continue
251
            if not dependencies.has_key(p):
252
                dependencies[p] = []
253
            dependencies[p].append(revid)
254
255
    pb = ui.ui_factory.nested_progress_bar()
0.436.22 by Jelmer Vernooij
Try to improve the progress bar a bit.
256
    total = len(todo)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
257
    i = 0
258
    try:
259
        while len(todo) > 0:
0.436.22 by Jelmer Vernooij
Try to improve the progress bar a bit.
260
            pb.update('rebase revisions', i, total)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
261
            i += 1
262
            revid = todo.pop()
263
            (newrevid, newparents) = replace_map[revid]
0.436.19 by Jelmer Vernooij
- Add blackbox tests
264
            if filter(repository.has_revision, newparents) != newparents:
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
265
                # Not all parents present yet, avoid for now
266
                continue
267
            if repository.has_revision(newrevid):
268
                # Was already converted, no need to worry about it again
269
                continue
270
            replay_fn(repository, revid, newrevid, newparents)
271
            assert repository.has_revision(newrevid)
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
272
            assert repository.revision_parents(newrevid) == newparents, \
273
                   "expected parents %r, got %r" % (newparents, 
274
                           repository.revision_parents(newrevid))
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
275
            if dependencies.has_key(newrevid):
276
                todo.extend(dependencies[newrevid])
277
                del dependencies[newrevid]
278
    finally:
279
        pb.finished()
280
        
0.436.19 by Jelmer Vernooij
- Add blackbox tests
281
    #assert all(map(repository.has_revision, 
282
    #           [replace_map[r][0] for r in replace_map]))
0.436.16 by Jelmer Vernooij
Some more work on maptree.
283
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
284
285
0.436.34 by Jelmer Vernooij
Some more tests.
286
def replay_snapshot(repository, oldrevid, newrevid, new_parents, 
0.436.35 by Jelmer Vernooij
Make revid_renames argument mandatory.
287
                    revid_renames):
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
288
    """Replay a commit by simply commiting the same snapshot with different 
289
    parents.
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
290
291
    :param repository: Repository in which the revision is present.
292
    :param oldrevid: Revision id of the revision to copy.
293
    :param newrevid: Revision id of the revision to create.
294
    :param new_parents: Revision ids of the new parent revisions.
0.436.34 by Jelmer Vernooij
Some more tests.
295
    :param revid_renames: Revision id renames for texts.
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
296
    """
297
    assert isinstance(new_parents, list)
0.436.16 by Jelmer Vernooij
Some more work on maptree.
298
    mutter('creating copy %r of %r with new parents %r' % 
299
                               (newrevid, oldrevid, new_parents))
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
300
    oldrev = repository.get_revision(oldrevid)
301
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
302
    revprops = dict(oldrev.properties)
0.436.27 by Jelmer Vernooij
Note revision property 'rebase-of', add explanation of use of pregenerated revision ids.
303
    revprops[REVPROP_REBASE_OF] = oldrevid
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
304
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
305
    builder = repository.get_commit_builder(branch=None, parents=new_parents, 
306
                                  config=Config(),
307
                                  committer=oldrev.committer,
308
                                  timestamp=oldrev.timestamp,
309
                                  timezone=oldrev.timezone,
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
310
                                  revprops=revprops,
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
311
                                  revision_id=newrevid)
312
313
    # Check what new_ie.file_id should be
314
    # use old and new parent inventories to generate new_id map
0.436.16 by Jelmer Vernooij
Some more work on maptree.
315
    fileid_map = map_file_ids(repository, oldrev.parent_ids, new_parents)
316
    oldtree = MapTree(repository.revision_tree(oldrevid), fileid_map)
317
    total = len(oldtree.inventory)
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
318
    pb = ui.ui_factory.nested_progress_bar()
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
319
    i = 0
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
320
    try:
0.436.14 by Jelmer Vernooij
More speed optimizations, deal with already created revisions.
321
        parent_invs = map(repository.get_revision_inventory, new_parents)
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
322
        transact = repository.get_transaction()
0.436.16 by Jelmer Vernooij
Some more work on maptree.
323
        for path, ie in oldtree.inventory.iter_entries():
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
324
            pb.update('upgrading file', i, total)
0.436.34 by Jelmer Vernooij
Some more tests.
325
            ie = ie.copy()
326
            # Either this file was modified last in this revision, 
327
            # in which case it has to be rewritten
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
328
            if ie.revision == oldrevid:
329
                ie.revision = None
330
            else:
0.436.34 by Jelmer Vernooij
Some more tests.
331
                # or it was already there before the commit, in 
332
                # which case the right revision should be used
333
                if revid_renames.has_key(ie.revision):
334
                    ie.revision = revid_renames[ie.revision]
335
                # make sure at least one of the new parents contains 
336
                # the ie.file_id, ie.revision combination
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
337
                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.
338
                    raise ReplayParentsInconsistent(ie.file_id, ie.revision)
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
339
            i += 1
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
340
            builder.record_entry_contents(ie, parent_invs, path, oldtree)
0.436.5 by Jelmer Vernooij
Import change_revision_parent from bzr-svn.
341
    finally:
342
        pb.finished()
343
344
    builder.finish_inventory()
345
    return builder.commit(oldrev.message)
346
347
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
348
def commit_rebase(wt, oldrev, newrevid):
349
    """Commit a rebase.
350
    
351
    :param wt: Mutable tree with the changes.
352
    :param oldrev: Revision info of new revision to commit.
353
    :param newrevid: New revision id."""
354
    assert oldrev.revision_id != newrevid
355
    revprops = dict(oldrev.properties)
0.436.27 by Jelmer Vernooij
Note revision property 'rebase-of', add explanation of use of pregenerated revision ids.
356
    revprops[REVPROP_REBASE_OF] = oldrev.revision_id
0.436.37 by Jelmer Vernooij
Store parents correctly.
357
    wt.commit(message=oldrev.message, timestamp=oldrev.timestamp, 
358
              timezone=oldrev.timezone, revprops=revprops, rev_id=newrevid)
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
359
    write_active_rebase_revid(wt, None)
360
361
0.438.1 by Jelmer Vernooij
Split out function for determining rebase base.
362
def replay_delta_workingtree(wt, oldrevid, newrevid, newparents, 
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
363
                             merge_type=None):
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
364
    """Replay a commit in a working tree, with a different base.
365
366
    :param wt: Working tree in which to do the replays.
367
    :param oldrevid: Old revision id
368
    :param newrevid: New revision id
369
    :param newparents: New parent revision ids
370
    """
371
    repository = wt.branch.repository
372
    if merge_type is None:
373
        from bzrlib.merge import Merge3Merger
374
        merge_type = Merge3Merger
375
    oldrev = wt.branch.repository.get_revision(oldrevid)
376
    # Make sure there are no conflicts or pending merges/changes 
377
    # in the working tree
378
    if wt.changes_from(wt.basis_tree()).has_changed():
379
        raise BzrError("Working tree has uncommitted changes.")
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
380
    complete_revert(wt, [newparents[0]])
0.436.8 by Jelmer Vernooij
Couple more minor fixes.
381
    assert not wt.changes_from(wt.basis_tree()).has_changed()
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
382
383
    oldtree = repository.revision_tree(oldrevid)
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
384
    write_active_rebase_revid(wt, oldrevid)
0.438.2 by Jelmer Vernooij
More work using proper merge bases.
385
    merger = Merger(wt.branch, this_tree=wt)
386
    merger.set_other_revision(oldrevid, wt.branch)
387
    try:
388
        merger.find_base()
389
    except UnrelatedBranches:
390
        merger.set_base_revision(NULL_REVISION, wt.branch)
391
    merger.merge_type = merge_type
392
    merger.do_merge()
393
    for newparent in newparents[1:]:
394
        wt.add_pending_merge(newparent)
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
395
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
396
    commit_rebase(wt, oldrev, newrevid)
0.436.8 by Jelmer Vernooij
Couple more minor fixes.
397
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
398
0.436.13 by Jelmer Vernooij
Add progress bar, some optimizations. Make merge type configurable.
399
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.
400
    """Returns a function that can replay revisions in wt.
401
402
    :param wt: Working tree in which to do the replays.
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
403
    :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.
404
    """
405
    def replay(repository, oldrevid, newrevid, newparents):
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
406
        assert wt.branch.repository == repository
0.436.16 by Jelmer Vernooij
Some more work on maptree.
407
        return replay_delta_workingtree(wt, oldrevid, newrevid, newparents, 
408
                                        merge_type=merge_type)
0.436.6 by Jelmer Vernooij
Add somewhat more complex plan generation function, rebase implementation.
409
    return replay
0.436.7 by Jelmer Vernooij
Add more test, make basic rebase work.
410
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
411
412
def write_active_rebase_revid(wt, revid):
0.436.16 by Jelmer Vernooij
Some more work on maptree.
413
    """Write the id of the revision that is currently being rebased. 
414
415
    :param wt: Working Tree that is being used for the rebase.
416
    :param revid: Revision id to write
417
    """
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
418
    if revid is None:
419
        revid = NULL_REVISION
420
    wt._control_files.put_utf8(REBASE_CURRENT_REVID_FILENAME, revid)
421
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
422
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
423
def read_active_rebase_revid(wt):
0.436.16 by Jelmer Vernooij
Some more work on maptree.
424
    """Read the id of the revision that is currently being rebased.
425
426
    :param wt: Working Tree that is being used for the rebase.
427
    :return: Id of the revision that is being rebased.
428
    """
0.436.9 by Jelmer Vernooij
Add rebase-todo command, fix rebase-continue.
429
    try:
430
        text = wt._control_files.get(REBASE_CURRENT_REVID_FILENAME).read().rstrip("\n")
431
        if text == NULL_REVISION:
432
            return None
433
        return text
434
    except NoSuchFile:
435
        return None
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
436
437
438
def complete_revert(wt, newparents):
0.436.16 by Jelmer Vernooij
Some more work on maptree.
439
    """Simple helper that reverts to specified new parents and makes sure none 
440
    of the extra files are left around.
441
442
    :param wt: Working tree to use for rebase
443
    :param newparents: New parents of the working tree
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
444
    """
445
    newtree = wt.branch.repository.revision_tree(newparents[0])
446
    delta = wt.changes_from(newtree)
447
    wt.branch.generate_revision_history(newparents[0])
0.436.38 by Jelmer Vernooij
Handle directories in revert.
448
    wt.set_parent_ids(newparents[:1])
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
449
    for (f, _, _) in delta.added:
450
        abs_path = wt.abspath(f)
451
        if osutils.lexists(abs_path):
0.436.38 by Jelmer Vernooij
Handle directories in revert.
452
            if osutils.isdir(abs_path):
453
                osutils.rmtree(abs_path)
454
            else:
455
                os.unlink(abs_path)
0.436.10 by Jelmer Vernooij
Add more agressive version of revert.
456
    wt.revert([], old_tree=newtree, backups=False)
0.436.38 by Jelmer Vernooij
Handle directories in revert.
457
    assert not wt.changes_from(wt.basis_tree()).has_changed()
0.436.37 by Jelmer Vernooij
Store parents correctly.
458
    wt.set_parent_ids(newparents)
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
459
460
0.436.34 by Jelmer Vernooij
Some more tests.
461
class ReplaySnapshotError(BzrError):
0.436.32 by Jelmer Vernooij
Properly detect invalid snapshot replays.
462
    _fmt = """Replaying the snapshot failed: %(message)s."""
463
464
    def __init__(self, message):
465
        BzrError.__init__(self)
466
        self.message = message
0.436.34 by Jelmer Vernooij
Some more tests.
467
468
469
class ReplayParentsInconsistent(BzrError):
470
    _fmt = """Parents were inconsistent while replaying commit for file id %(fileid)s, revision %(revid)s."""
471
472
    def __init__(self, fileid, revid):
473
        BzrError.__init__(self)
474
        self.fileid = fileid
475
        self.revid = revid